@tangle-network/ui 11.17.0 → 11.19.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.
- package/CHANGELOG.md +17 -0
- package/dist/index.d.ts +10 -1
- package/dist/index.js +10 -1
- package/dist/primitives/alert-dialog.d.ts +34 -0
- package/dist/primitives/alert-dialog.js +68 -0
- package/dist/primitives/checkbox.d.ts +12 -0
- package/dist/primitives/checkbox.js +34 -0
- package/dist/primitives/collapsible.d.ts +12 -0
- package/dist/primitives/collapsible.js +13 -0
- package/dist/primitives/context-menu.d.ts +36 -0
- package/dist/primitives/context-menu.js +86 -0
- package/dist/primitives/popover.d.ts +15 -0
- package/dist/primitives/popover.js +25 -0
- package/dist/primitives/separator.d.ts +11 -0
- package/dist/primitives/separator.js +21 -0
- package/dist/primitives/sheet.d.ts +28 -0
- package/dist/primitives/sheet.js +70 -0
- package/dist/primitives/slider.d.ts +14 -0
- package/dist/primitives/slider.js +37 -0
- package/dist/primitives/theme-toggle.js +8 -0
- package/dist/primitives/tooltip.d.ts +16 -0
- package/dist/primitives/tooltip.js +32 -0
- package/dist/primitives.d.ts +10 -1
- package/dist/primitives.js +10 -1
- package/package.json +9 -2
- package/src/primitives/alert-dialog.tsx +139 -0
- package/src/primitives/checkbox-separator-sheet-tooltip.stories.tsx +92 -0
- package/src/primitives/checkbox-separator-sheet-tooltip.test.tsx +107 -0
- package/src/primitives/checkbox.tsx +42 -0
- package/src/primitives/collapsible.tsx +16 -0
- package/src/primitives/context-menu.tsx +168 -0
- package/src/primitives/index.ts +57 -0
- package/src/primitives/popover-collapsible-alert-dialog-context-menu-slider.stories.tsx +124 -0
- package/src/primitives/popover-collapsible-alert-dialog-context-menu-slider.test.tsx +165 -0
- package/src/primitives/popover.tsx +45 -0
- package/src/primitives/separator.tsx +30 -0
- package/src/primitives/sheet.tsx +134 -0
- package/src/primitives/slider.tsx +71 -0
- package/src/primitives/theme-toggle.test.tsx +2 -1
- package/src/primitives/theme-toggle.tsx +2 -0
- package/src/primitives/tooltip.tsx +54 -0
- package/src/stories/theme-showcase.stories.tsx +2 -0
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
import * as SliderPrimitive from "@radix-ui/react-slider";
|
|
3
|
+
//#region src/primitives/slider.d.ts
|
|
4
|
+
/**
|
|
5
|
+
* Range input with one thumb per value. A single value renders one thumb; an
|
|
6
|
+
* array of two renders a range. The thumbs are what assistive technology
|
|
7
|
+
* focuses, so the names go on them: `aria-label` / `aria-labelledby` name a
|
|
8
|
+
* single thumb, and `thumbLabels` names each thumb of a range.
|
|
9
|
+
*/
|
|
10
|
+
declare const Slider: React.ForwardRefExoticComponent<Omit<SliderPrimitive.SliderProps & React.RefAttributes<HTMLSpanElement>, "ref"> & {
|
|
11
|
+
thumbLabels?: string[];
|
|
12
|
+
} & React.RefAttributes<HTMLSpanElement>>;
|
|
13
|
+
//#endregion
|
|
14
|
+
export { Slider };
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { focusRing } from "../lib/focus.js";
|
|
3
|
+
import { cn } from "../lib/utils.js";
|
|
4
|
+
import * as React from "react";
|
|
5
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
6
|
+
import * as SliderPrimitive from "@radix-ui/react-slider";
|
|
7
|
+
//#region src/primitives/slider.tsx
|
|
8
|
+
/**
|
|
9
|
+
* Range input with one thumb per value. A single value renders one thumb; an
|
|
10
|
+
* array of two renders a range. The thumbs are what assistive technology
|
|
11
|
+
* focuses, so the names go on them: `aria-label` / `aria-labelledby` name a
|
|
12
|
+
* single thumb, and `thumbLabels` names each thumb of a range.
|
|
13
|
+
*/
|
|
14
|
+
const Slider = React.forwardRef(({ className, defaultValue, value, min = 0, max = 100, thumbLabels, "aria-label": ariaLabel, "aria-labelledby": ariaLabelledBy, ...props }, ref) => {
|
|
15
|
+
const values = Array.isArray(value) ? value : Array.isArray(defaultValue) ? defaultValue : [min];
|
|
16
|
+
const single = values.length === 1;
|
|
17
|
+
return /* @__PURE__ */ jsxs(SliderPrimitive.Root, {
|
|
18
|
+
ref,
|
|
19
|
+
defaultValue,
|
|
20
|
+
value,
|
|
21
|
+
min,
|
|
22
|
+
max,
|
|
23
|
+
className: cn("relative flex w-full touch-none select-none items-center data-[disabled]:opacity-50", "data-[orientation=vertical]:h-full data-[orientation=vertical]:min-h-44 data-[orientation=vertical]:w-auto data-[orientation=vertical]:flex-col", className),
|
|
24
|
+
...props,
|
|
25
|
+
children: [/* @__PURE__ */ jsx(SliderPrimitive.Track, {
|
|
26
|
+
className: "relative grow overflow-hidden rounded-full bg-muted data-[orientation=horizontal]:h-1.5 data-[orientation=vertical]:h-full data-[orientation=horizontal]:w-full data-[orientation=vertical]:w-1.5",
|
|
27
|
+
children: /* @__PURE__ */ jsx(SliderPrimitive.Range, { className: "absolute bg-primary data-[orientation=horizontal]:h-full data-[orientation=vertical]:w-full" })
|
|
28
|
+
}), values.map((_, index) => /* @__PURE__ */ jsx(SliderPrimitive.Thumb, {
|
|
29
|
+
"aria-label": thumbLabels?.[index] ?? (single ? ariaLabel : void 0),
|
|
30
|
+
"aria-labelledby": single && !thumbLabels?.[index] ? ariaLabelledBy : void 0,
|
|
31
|
+
className: cn("block size-4 shrink-0 rounded-full border border-primary bg-background shadow-sm transition-[box-shadow] disabled:pointer-events-none", focusRing)
|
|
32
|
+
}, index))]
|
|
33
|
+
});
|
|
34
|
+
});
|
|
35
|
+
Slider.displayName = SliderPrimitive.Root.displayName;
|
|
36
|
+
//#endregion
|
|
37
|
+
export { Slider };
|
|
@@ -12,9 +12,17 @@ const namedModes = [
|
|
|
12
12
|
dark: "arena",
|
|
13
13
|
light: "arena-light"
|
|
14
14
|
},
|
|
15
|
+
{
|
|
16
|
+
dark: "super",
|
|
17
|
+
light: "super-light"
|
|
18
|
+
},
|
|
15
19
|
{
|
|
16
20
|
dark: "tangle-dark",
|
|
17
21
|
light: "tangle-light"
|
|
22
|
+
},
|
|
23
|
+
{
|
|
24
|
+
dark: "agents",
|
|
25
|
+
light: "agents-light"
|
|
18
26
|
}
|
|
19
27
|
];
|
|
20
28
|
let preference;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
import * as TooltipPrimitive from "@radix-ui/react-tooltip";
|
|
3
|
+
//#region src/primitives/tooltip.d.ts
|
|
4
|
+
declare function TooltipProvider({ delayDuration, skipDelayDuration, ...props }: React.ComponentProps<typeof TooltipPrimitive.Provider>): React.JSX.Element;
|
|
5
|
+
declare namespace TooltipProvider {
|
|
6
|
+
var displayName: string;
|
|
7
|
+
}
|
|
8
|
+
declare const Tooltip: React.FC<TooltipPrimitive.TooltipProps>;
|
|
9
|
+
declare const TooltipTrigger: React.ForwardRefExoticComponent<TooltipPrimitive.TooltipTriggerProps & React.RefAttributes<HTMLButtonElement>>;
|
|
10
|
+
/**
|
|
11
|
+
* Inverse-surface label for a control whose name is otherwise only an icon.
|
|
12
|
+
* It is supplementary: the trigger still needs its own accessible name.
|
|
13
|
+
*/
|
|
14
|
+
declare const TooltipContent: React.ForwardRefExoticComponent<Omit<TooltipPrimitive.TooltipContentProps & React.RefAttributes<HTMLDivElement>, "ref"> & React.RefAttributes<HTMLDivElement>>;
|
|
15
|
+
//#endregion
|
|
16
|
+
export { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger };
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { cn } from "../lib/utils.js";
|
|
3
|
+
import * as React from "react";
|
|
4
|
+
import { jsx } from "react/jsx-runtime";
|
|
5
|
+
import * as TooltipPrimitive from "@radix-ui/react-tooltip";
|
|
6
|
+
//#region src/primitives/tooltip.tsx
|
|
7
|
+
/**
|
|
8
|
+
* Wrap an app (or a toolbar) once. The open delay applies to the first tooltip;
|
|
9
|
+
* moving between triggers inside `skipDelayDuration` opens the next one at
|
|
10
|
+
* once, which keeps an icon rail fast to scan.
|
|
11
|
+
*/
|
|
12
|
+
const TooltipProvider = ({ delayDuration = 400, skipDelayDuration = 300, ...props }) => /* @__PURE__ */ jsx(TooltipPrimitive.Provider, {
|
|
13
|
+
delayDuration,
|
|
14
|
+
skipDelayDuration,
|
|
15
|
+
...props
|
|
16
|
+
});
|
|
17
|
+
TooltipProvider.displayName = "TooltipProvider";
|
|
18
|
+
const Tooltip = TooltipPrimitive.Root;
|
|
19
|
+
const TooltipTrigger = TooltipPrimitive.Trigger;
|
|
20
|
+
/**
|
|
21
|
+
* Inverse-surface label for a control whose name is otherwise only an icon.
|
|
22
|
+
* It is supplementary: the trigger still needs its own accessible name.
|
|
23
|
+
*/
|
|
24
|
+
const TooltipContent = React.forwardRef(({ className, sideOffset = 6, ...props }, ref) => /* @__PURE__ */ jsx(TooltipPrimitive.Portal, { children: /* @__PURE__ */ jsx(TooltipPrimitive.Content, {
|
|
25
|
+
ref,
|
|
26
|
+
sideOffset,
|
|
27
|
+
className: cn("z-50 max-w-xs origin-(--radix-tooltip-content-transform-origin) rounded-md bg-foreground px-2.5 py-1.5 text-background text-xs leading-snug shadow-md", "data-[state=delayed-open]:animate-in data-[state=delayed-open]:fade-in-0 data-[state=delayed-open]:zoom-in-95", "data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95", "duration-150 ease-out motion-reduce:animate-none", className),
|
|
28
|
+
...props
|
|
29
|
+
}) }));
|
|
30
|
+
TooltipContent.displayName = TooltipPrimitive.Content.displayName;
|
|
31
|
+
//#endregion
|
|
32
|
+
export { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger };
|
package/dist/primitives.d.ts
CHANGED
|
@@ -2,6 +2,11 @@ import { Button, ButtonProps, buttonVariants } from "./primitives/button.js";
|
|
|
2
2
|
import { ArtifactPane, ArtifactPaneProps } from "./primitives/artifact-pane.js";
|
|
3
3
|
import { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle, CardTitleProps } from "./primitives/card.js";
|
|
4
4
|
import { Dialog, DialogClose, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogOverlay, DialogPortal, DialogTitle, DialogTrigger } from "./primitives/dialog.js";
|
|
5
|
+
import { AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogOverlay, AlertDialogPortal, AlertDialogTitle, AlertDialogTrigger } from "./primitives/alert-dialog.js";
|
|
6
|
+
import { Collapsible, CollapsibleContent, CollapsibleTrigger } from "./primitives/collapsible.js";
|
|
7
|
+
import { ContextMenu, ContextMenuCheckboxItem, ContextMenuContent, ContextMenuGroup, ContextMenuItem, ContextMenuLabel, ContextMenuPortal, ContextMenuRadioGroup, ContextMenuRadioItem, ContextMenuSeparator, ContextMenuShortcut, ContextMenuSub, ContextMenuSubContent, ContextMenuSubTrigger, ContextMenuTrigger } from "./primitives/context-menu.js";
|
|
8
|
+
import { Popover, PopoverAnchor, PopoverClose, PopoverContent, PopoverTrigger } from "./primitives/popover.js";
|
|
9
|
+
import { Slider } from "./primitives/slider.js";
|
|
5
10
|
import { Input, InputProps, Textarea, TextareaProps } from "./primitives/input.js";
|
|
6
11
|
import { Badge, BadgeProps, badgeVariants } from "./primitives/badge.js";
|
|
7
12
|
import { Avatar, AvatarFallback, AvatarImage } from "./primitives/avatar.js";
|
|
@@ -12,6 +17,10 @@ import { Tabs, TabsContent, TabsList, TabsTrigger } from "./primitives/tabs.js";
|
|
|
12
17
|
import { SegmentedControl, SegmentedControlOption, SegmentedControlProps } from "./primitives/segmented-control.js";
|
|
13
18
|
import { Progress } from "./primitives/progress.js";
|
|
14
19
|
import { Switch } from "./primitives/switch.js";
|
|
20
|
+
import { Checkbox } from "./primitives/checkbox.js";
|
|
21
|
+
import { Separator } from "./primitives/separator.js";
|
|
22
|
+
import { Sheet, SheetClose, SheetContent, SheetDescription, SheetFooter, SheetHeader, SheetOverlay, SheetPortal, SheetTitle, SheetTrigger } from "./primitives/sheet.js";
|
|
23
|
+
import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from "./primitives/tooltip.js";
|
|
15
24
|
import { Skeleton, SkeletonCard, SkeletonTable } from "./primitives/skeleton.js";
|
|
16
25
|
import { TextShimmer, TextShimmerProps } from "./primitives/text-shimmer.js";
|
|
17
26
|
import { Toast, ToastContainer, ToastProvider, useToast } from "./primitives/toast.js";
|
|
@@ -36,4 +45,4 @@ import { IconTile, IconTileProps, initialsOf } from "./primitives/icon-tile.js";
|
|
|
36
45
|
import { Metric, MetricProps, MetricStrip, MetricStripProps } from "./primitives/metric-strip.js";
|
|
37
46
|
import { FilterField, FilterFieldProps, Toolbar, ToolbarProps } from "./primitives/toolbar.js";
|
|
38
47
|
import { Logo, LogoProps, TangleKnot } from "@tangle-network/brand";
|
|
39
|
-
export { ArtifactPane, type ArtifactPaneProps, Avatar, AvatarFallback, AvatarImage, Badge, type BadgeProps, Button, type ButtonProps, CATEGORY_TONES, Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle, type CardTitleProps, type CategoryTone, Chip, type ChipProps, CodeBlock, type CodeBlockProps, CopyButton, Dialog, DialogClose, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogOverlay, DialogPortal, DialogTitle, DialogTrigger, DropZone, type DropZoneProps, DropdownMenu, DropdownMenuCheckboxItem, DropdownMenuContent, DropdownMenuGroup, DropdownMenuItem, DropdownMenuLabel, DropdownMenuPortal, DropdownMenuRadioGroup, DropdownMenuRadioItem, DropdownMenuSeparator, DropdownMenuShortcut, DropdownMenuSub, DropdownMenuSubContent, DropdownMenuSubTrigger, DropdownMenuTrigger, EmptyState, type EmptyStateProps, FilterField, type FilterFieldProps, Heading, type HeadingProps, type HeadingVariant, IconTile, type IconTileProps, InlineCode, type InlineCodeProps, Input, type InputProps, Label, Logo, type LogoProps, Metric, type MetricProps, MetricStrip, type MetricStripProps, PageHeader, type PageHeaderProps, PageShell, type PageShellProps, Progress, SegmentedControl, type SegmentedControlOption, type SegmentedControlProps, Select, SelectContent, SelectGroup, SelectItem, SelectLabel, SelectScrollDownButton, SelectScrollUpButton, SelectSeparator, SelectTrigger, SelectValue, SidebarDropZone, type SidebarDropZoneProps, Skeleton, SkeletonCard, SkeletonTable, StatCard, type StatCardProps, StatusPill, type StatusPillProps, type StatusTone, Switch, TONE_CLASSES, Table, TableBody, TableCaption, TableCell, TableFooter, TableHead, TableHeader, type TableProps, TableRow, Tabs, TabsContent, TabsList, TabsTrigger, Tag, type TagProps, TangleKnot, TerminalCursor, TerminalDisplay, TerminalInput, TerminalLine, TextShimmer, type TextShimmerProps, Textarea, type TextareaProps, ThemeToggle, type Toast, ToastContainer, ToastProvider, type Tone, type ToneClasses, Toolbar, type ToolbarProps, type UploadFile, UploadProgress, type UploadProgressProps, badgeVariants, buttonVariants, initialsOf, toneFor, useTheme, useToast };
|
|
48
|
+
export { AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogOverlay, AlertDialogPortal, AlertDialogTitle, AlertDialogTrigger, ArtifactPane, type ArtifactPaneProps, Avatar, AvatarFallback, AvatarImage, Badge, type BadgeProps, Button, type ButtonProps, CATEGORY_TONES, Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle, type CardTitleProps, type CategoryTone, Checkbox, Chip, type ChipProps, CodeBlock, type CodeBlockProps, Collapsible, CollapsibleContent, CollapsibleTrigger, ContextMenu, ContextMenuCheckboxItem, ContextMenuContent, ContextMenuGroup, ContextMenuItem, ContextMenuLabel, ContextMenuPortal, ContextMenuRadioGroup, ContextMenuRadioItem, ContextMenuSeparator, ContextMenuShortcut, ContextMenuSub, ContextMenuSubContent, ContextMenuSubTrigger, ContextMenuTrigger, CopyButton, Dialog, DialogClose, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogOverlay, DialogPortal, DialogTitle, DialogTrigger, DropZone, type DropZoneProps, DropdownMenu, DropdownMenuCheckboxItem, DropdownMenuContent, DropdownMenuGroup, DropdownMenuItem, DropdownMenuLabel, DropdownMenuPortal, DropdownMenuRadioGroup, DropdownMenuRadioItem, DropdownMenuSeparator, DropdownMenuShortcut, DropdownMenuSub, DropdownMenuSubContent, DropdownMenuSubTrigger, DropdownMenuTrigger, EmptyState, type EmptyStateProps, FilterField, type FilterFieldProps, Heading, type HeadingProps, type HeadingVariant, IconTile, type IconTileProps, InlineCode, type InlineCodeProps, Input, type InputProps, Label, Logo, type LogoProps, Metric, type MetricProps, MetricStrip, type MetricStripProps, PageHeader, type PageHeaderProps, PageShell, type PageShellProps, Popover, PopoverAnchor, PopoverClose, PopoverContent, PopoverTrigger, Progress, SegmentedControl, type SegmentedControlOption, type SegmentedControlProps, Select, SelectContent, SelectGroup, SelectItem, SelectLabel, SelectScrollDownButton, SelectScrollUpButton, SelectSeparator, SelectTrigger, SelectValue, Separator, Sheet, SheetClose, SheetContent, SheetDescription, SheetFooter, SheetHeader, SheetOverlay, SheetPortal, SheetTitle, SheetTrigger, SidebarDropZone, type SidebarDropZoneProps, Skeleton, SkeletonCard, SkeletonTable, Slider, StatCard, type StatCardProps, StatusPill, type StatusPillProps, type StatusTone, Switch, TONE_CLASSES, Table, TableBody, TableCaption, TableCell, TableFooter, TableHead, TableHeader, type TableProps, TableRow, Tabs, TabsContent, TabsList, TabsTrigger, Tag, type TagProps, TangleKnot, TerminalCursor, TerminalDisplay, TerminalInput, TerminalLine, TextShimmer, type TextShimmerProps, Textarea, type TextareaProps, ThemeToggle, type Toast, ToastContainer, ToastProvider, type Tone, type ToneClasses, Toolbar, type ToolbarProps, Tooltip, TooltipContent, TooltipProvider, TooltipTrigger, type UploadFile, UploadProgress, type UploadProgressProps, badgeVariants, buttonVariants, initialsOf, toneFor, useTheme, useToast };
|
package/dist/primitives.js
CHANGED
|
@@ -2,6 +2,11 @@ import { Button, buttonVariants } from "./primitives/button.js";
|
|
|
2
2
|
import { Heading } from "./primitives/heading.js";
|
|
3
3
|
import { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle } from "./primitives/card.js";
|
|
4
4
|
import { Dialog, DialogClose, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogOverlay, DialogPortal, DialogTitle, DialogTrigger } from "./primitives/dialog.js";
|
|
5
|
+
import { AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogOverlay, AlertDialogPortal, AlertDialogTitle, AlertDialogTrigger } from "./primitives/alert-dialog.js";
|
|
6
|
+
import { Collapsible, CollapsibleContent, CollapsibleTrigger } from "./primitives/collapsible.js";
|
|
7
|
+
import { ContextMenu, ContextMenuCheckboxItem, ContextMenuContent, ContextMenuGroup, ContextMenuItem, ContextMenuLabel, ContextMenuPortal, ContextMenuRadioGroup, ContextMenuRadioItem, ContextMenuSeparator, ContextMenuShortcut, ContextMenuSub, ContextMenuSubContent, ContextMenuSubTrigger, ContextMenuTrigger } from "./primitives/context-menu.js";
|
|
8
|
+
import { Popover, PopoverAnchor, PopoverClose, PopoverContent, PopoverTrigger } from "./primitives/popover.js";
|
|
9
|
+
import { Slider } from "./primitives/slider.js";
|
|
5
10
|
import { Label } from "./primitives/label.js";
|
|
6
11
|
import { Input, Textarea } from "./primitives/input.js";
|
|
7
12
|
import { Badge, badgeVariants } from "./primitives/badge.js";
|
|
@@ -13,6 +18,10 @@ import { Tabs, TabsContent, TabsList, TabsTrigger } from "./primitives/tabs.js";
|
|
|
13
18
|
import { SegmentedControl } from "./primitives/segmented-control.js";
|
|
14
19
|
import { Progress } from "./primitives/progress.js";
|
|
15
20
|
import { Switch } from "./primitives/switch.js";
|
|
21
|
+
import { Checkbox } from "./primitives/checkbox.js";
|
|
22
|
+
import { Separator } from "./primitives/separator.js";
|
|
23
|
+
import { Sheet, SheetClose, SheetContent, SheetDescription, SheetFooter, SheetHeader, SheetOverlay, SheetPortal, SheetTitle, SheetTrigger } from "./primitives/sheet.js";
|
|
24
|
+
import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from "./primitives/tooltip.js";
|
|
16
25
|
import { Skeleton, SkeletonCard, SkeletonTable } from "./primitives/skeleton.js";
|
|
17
26
|
import { TextShimmer } from "./primitives/text-shimmer.js";
|
|
18
27
|
import { ToastContainer, ToastProvider, useToast } from "./primitives/toast.js";
|
|
@@ -36,4 +45,4 @@ import { IconTile, initialsOf } from "./primitives/icon-tile.js";
|
|
|
36
45
|
import { Metric, MetricStrip } from "./primitives/metric-strip.js";
|
|
37
46
|
import { FilterField, Toolbar } from "./primitives/toolbar.js";
|
|
38
47
|
import { Logo, TangleKnot } from "@tangle-network/brand";
|
|
39
|
-
export { ArtifactPane, Avatar, AvatarFallback, AvatarImage, Badge, Button, CATEGORY_TONES, Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle, Chip, CodeBlock, CopyButton, Dialog, DialogClose, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogOverlay, DialogPortal, DialogTitle, DialogTrigger, DropZone, DropdownMenu, DropdownMenuCheckboxItem, DropdownMenuContent, DropdownMenuGroup, DropdownMenuItem, DropdownMenuLabel, DropdownMenuPortal, DropdownMenuRadioGroup, DropdownMenuRadioItem, DropdownMenuSeparator, DropdownMenuShortcut, DropdownMenuSub, DropdownMenuSubContent, DropdownMenuSubTrigger, DropdownMenuTrigger, EmptyState, FilterField, Heading, IconTile, InlineCode, Input, Label, Logo, Metric, MetricStrip, PageHeader, PageShell, Progress, SegmentedControl, Select, SelectContent, SelectGroup, SelectItem, SelectLabel, SelectScrollDownButton, SelectScrollUpButton, SelectSeparator, SelectTrigger, SelectValue, SidebarDropZone, Skeleton, SkeletonCard, SkeletonTable, StatCard, StatusPill, Switch, TONE_CLASSES, Table, TableBody, TableCaption, TableCell, TableFooter, TableHead, TableHeader, TableRow, Tabs, TabsContent, TabsList, TabsTrigger, Tag, TangleKnot, TerminalCursor, TerminalDisplay, TerminalInput, TerminalLine, TextShimmer, Textarea, ThemeToggle, ToastContainer, ToastProvider, Toolbar, UploadProgress, badgeVariants, buttonVariants, initialsOf, toneFor, useTheme, useToast };
|
|
48
|
+
export { AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogOverlay, AlertDialogPortal, AlertDialogTitle, AlertDialogTrigger, ArtifactPane, Avatar, AvatarFallback, AvatarImage, Badge, Button, CATEGORY_TONES, Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle, Checkbox, Chip, CodeBlock, Collapsible, CollapsibleContent, CollapsibleTrigger, ContextMenu, ContextMenuCheckboxItem, ContextMenuContent, ContextMenuGroup, ContextMenuItem, ContextMenuLabel, ContextMenuPortal, ContextMenuRadioGroup, ContextMenuRadioItem, ContextMenuSeparator, ContextMenuShortcut, ContextMenuSub, ContextMenuSubContent, ContextMenuSubTrigger, ContextMenuTrigger, CopyButton, Dialog, DialogClose, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogOverlay, DialogPortal, DialogTitle, DialogTrigger, DropZone, DropdownMenu, DropdownMenuCheckboxItem, DropdownMenuContent, DropdownMenuGroup, DropdownMenuItem, DropdownMenuLabel, DropdownMenuPortal, DropdownMenuRadioGroup, DropdownMenuRadioItem, DropdownMenuSeparator, DropdownMenuShortcut, DropdownMenuSub, DropdownMenuSubContent, DropdownMenuSubTrigger, DropdownMenuTrigger, EmptyState, FilterField, Heading, IconTile, InlineCode, Input, Label, Logo, Metric, MetricStrip, PageHeader, PageShell, Popover, PopoverAnchor, PopoverClose, PopoverContent, PopoverTrigger, Progress, SegmentedControl, Select, SelectContent, SelectGroup, SelectItem, SelectLabel, SelectScrollDownButton, SelectScrollUpButton, SelectSeparator, SelectTrigger, SelectValue, Separator, Sheet, SheetClose, SheetContent, SheetDescription, SheetFooter, SheetHeader, SheetOverlay, SheetPortal, SheetTitle, SheetTrigger, SidebarDropZone, Skeleton, SkeletonCard, SkeletonTable, Slider, StatCard, StatusPill, Switch, TONE_CLASSES, Table, TableBody, TableCaption, TableCell, TableFooter, TableHead, TableHeader, TableRow, Tabs, TabsContent, TabsList, TabsTrigger, Tag, TangleKnot, TerminalCursor, TerminalDisplay, TerminalInput, TerminalLine, TextShimmer, Textarea, ThemeToggle, ToastContainer, ToastProvider, Toolbar, Tooltip, TooltipContent, TooltipProvider, TooltipTrigger, UploadProgress, badgeVariants, buttonVariants, initialsOf, toneFor, useTheme, useToast };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tangle-network/ui",
|
|
3
|
-
"version": "11.
|
|
3
|
+
"version": "11.19.0",
|
|
4
4
|
"description": "Generic React UI components for Tangle products — primitives, chat, run, files, editor, markdown.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -116,16 +116,23 @@
|
|
|
116
116
|
"dependencies": {
|
|
117
117
|
"@pierre/theme": "1.1.0",
|
|
118
118
|
"@pierre/trees": "1.0.0-beta.6",
|
|
119
|
+
"@radix-ui/react-alert-dialog": "^1.1.23",
|
|
119
120
|
"@radix-ui/react-avatar": "^1.2.6",
|
|
121
|
+
"@radix-ui/react-checkbox": "^1.3.11",
|
|
120
122
|
"@radix-ui/react-collapsible": "^1.1.20",
|
|
123
|
+
"@radix-ui/react-context-menu": "^2.3.7",
|
|
121
124
|
"@radix-ui/react-dialog": "^1.1.23",
|
|
122
125
|
"@radix-ui/react-dropdown-menu": "^2.1.24",
|
|
123
126
|
"@radix-ui/react-label": "^2.1.15",
|
|
127
|
+
"@radix-ui/react-popover": "^1.1.23",
|
|
124
128
|
"@radix-ui/react-progress": "^1.1.16",
|
|
125
129
|
"@radix-ui/react-select": "^2.3.7",
|
|
130
|
+
"@radix-ui/react-separator": "^1.1.15",
|
|
131
|
+
"@radix-ui/react-slider": "^1.4.7",
|
|
126
132
|
"@radix-ui/react-slot": "^1.3.3",
|
|
127
133
|
"@radix-ui/react-switch": "^1.3.7",
|
|
128
134
|
"@radix-ui/react-tabs": "^1.1.21",
|
|
135
|
+
"@radix-ui/react-tooltip": "^1.2.16",
|
|
129
136
|
"class-variance-authority": "^0.7.1",
|
|
130
137
|
"clsx": "^2.1.1",
|
|
131
138
|
"github-slugger": "^2.0.0",
|
|
@@ -142,7 +149,7 @@
|
|
|
142
149
|
"peerDependencies": {
|
|
143
150
|
"@hocuspocus/provider": ">=2.15.0 <5.0.0",
|
|
144
151
|
"@nanostores/react": ">=0.8.4 <3.0.0",
|
|
145
|
-
"@tangle-network/brand": "^1.
|
|
152
|
+
"@tangle-network/brand": "^1.13.0",
|
|
146
153
|
"@tiptap/core": ">=3.20.4 <4.0.0",
|
|
147
154
|
"@tiptap/extension-collaboration": ">=3.20.4 <4.0.0",
|
|
148
155
|
"@tiptap/extension-collaboration-caret": ">=3.7.0 <4.0.0",
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import * as AlertDialogPrimitive from "@radix-ui/react-alert-dialog";
|
|
4
|
+
import * as React from "react";
|
|
5
|
+
import { cn } from "../lib/utils";
|
|
6
|
+
import { buttonVariants } from "./button";
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* A dialog that interrupts for a decision. Unlike `Dialog` it has no close
|
|
10
|
+
* button and ignores outside clicks; Escape and `AlertDialogCancel` dismiss it.
|
|
11
|
+
* Radix focuses `AlertDialogCancel` on open, so a destructive action is never
|
|
12
|
+
* under the Enter key when the dialog appears.
|
|
13
|
+
*/
|
|
14
|
+
const AlertDialog = AlertDialogPrimitive.Root;
|
|
15
|
+
|
|
16
|
+
const AlertDialogTrigger = AlertDialogPrimitive.Trigger;
|
|
17
|
+
|
|
18
|
+
const AlertDialogPortal = AlertDialogPrimitive.Portal;
|
|
19
|
+
|
|
20
|
+
const AlertDialogOverlay = React.forwardRef<
|
|
21
|
+
React.ElementRef<typeof AlertDialogPrimitive.Overlay>,
|
|
22
|
+
React.ComponentPropsWithoutRef<typeof AlertDialogPrimitive.Overlay>
|
|
23
|
+
>(({ className, ...props }, ref) => (
|
|
24
|
+
<AlertDialogPrimitive.Overlay
|
|
25
|
+
ref={ref}
|
|
26
|
+
className={cn(
|
|
27
|
+
"fixed inset-0 z-50 bg-black/40",
|
|
28
|
+
"data-[state=closed]:animate-out data-[state=open]:animate-in",
|
|
29
|
+
"data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0",
|
|
30
|
+
className,
|
|
31
|
+
)}
|
|
32
|
+
{...props}
|
|
33
|
+
/>
|
|
34
|
+
));
|
|
35
|
+
AlertDialogOverlay.displayName = AlertDialogPrimitive.Overlay.displayName;
|
|
36
|
+
|
|
37
|
+
const AlertDialogContent = React.forwardRef<
|
|
38
|
+
React.ElementRef<typeof AlertDialogPrimitive.Content>,
|
|
39
|
+
React.ComponentPropsWithoutRef<typeof AlertDialogPrimitive.Content>
|
|
40
|
+
>(({ className, ...props }, ref) => (
|
|
41
|
+
<AlertDialogPortal>
|
|
42
|
+
<AlertDialogOverlay />
|
|
43
|
+
<AlertDialogPrimitive.Content
|
|
44
|
+
ref={ref}
|
|
45
|
+
className={cn(
|
|
46
|
+
"fixed top-[50%] left-[50%] z-50 grid w-full max-w-[calc(100%-2rem)] translate-x-[-50%] translate-y-[-50%] sm:max-w-lg",
|
|
47
|
+
"gap-4 rounded-lg border border-border bg-card p-6 text-foreground shadow-lg duration-200 outline-hidden",
|
|
48
|
+
"data-[state=closed]:animate-out data-[state=open]:animate-in",
|
|
49
|
+
"data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0",
|
|
50
|
+
"data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95",
|
|
51
|
+
"motion-reduce:animate-none",
|
|
52
|
+
className,
|
|
53
|
+
)}
|
|
54
|
+
{...props}
|
|
55
|
+
/>
|
|
56
|
+
</AlertDialogPortal>
|
|
57
|
+
));
|
|
58
|
+
AlertDialogContent.displayName = AlertDialogPrimitive.Content.displayName;
|
|
59
|
+
|
|
60
|
+
const AlertDialogHeader = ({ className, ...props }: React.HTMLAttributes<HTMLDivElement>) => (
|
|
61
|
+
<div className={cn("flex flex-col gap-2 text-center sm:text-left", className)} {...props} />
|
|
62
|
+
);
|
|
63
|
+
AlertDialogHeader.displayName = "AlertDialogHeader";
|
|
64
|
+
|
|
65
|
+
const AlertDialogFooter = ({ className, ...props }: React.HTMLAttributes<HTMLDivElement>) => (
|
|
66
|
+
<div
|
|
67
|
+
className={cn("flex flex-col-reverse gap-2 sm:flex-row sm:justify-end", className)}
|
|
68
|
+
{...props}
|
|
69
|
+
/>
|
|
70
|
+
);
|
|
71
|
+
AlertDialogFooter.displayName = "AlertDialogFooter";
|
|
72
|
+
|
|
73
|
+
const AlertDialogTitle = React.forwardRef<
|
|
74
|
+
React.ElementRef<typeof AlertDialogPrimitive.Title>,
|
|
75
|
+
React.ComponentPropsWithoutRef<typeof AlertDialogPrimitive.Title>
|
|
76
|
+
>(({ className, ...props }, ref) => (
|
|
77
|
+
<AlertDialogPrimitive.Title
|
|
78
|
+
ref={ref}
|
|
79
|
+
className={cn("font-semibold text-lg leading-snug [overflow-wrap:anywhere]", className)}
|
|
80
|
+
{...props}
|
|
81
|
+
/>
|
|
82
|
+
));
|
|
83
|
+
AlertDialogTitle.displayName = AlertDialogPrimitive.Title.displayName;
|
|
84
|
+
|
|
85
|
+
const AlertDialogDescription = React.forwardRef<
|
|
86
|
+
React.ElementRef<typeof AlertDialogPrimitive.Description>,
|
|
87
|
+
React.ComponentPropsWithoutRef<typeof AlertDialogPrimitive.Description>
|
|
88
|
+
>(({ className, ...props }, ref) => (
|
|
89
|
+
<AlertDialogPrimitive.Description
|
|
90
|
+
ref={ref}
|
|
91
|
+
className={cn("text-muted-foreground text-sm [overflow-wrap:anywhere]", className)}
|
|
92
|
+
{...props}
|
|
93
|
+
/>
|
|
94
|
+
));
|
|
95
|
+
AlertDialogDescription.displayName = AlertDialogPrimitive.Description.displayName;
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* The confirming action. `tone="destructive"` paints it with the danger fill;
|
|
99
|
+
* the default is the primary button.
|
|
100
|
+
*/
|
|
101
|
+
const AlertDialogAction = React.forwardRef<
|
|
102
|
+
React.ElementRef<typeof AlertDialogPrimitive.Action>,
|
|
103
|
+
React.ComponentPropsWithoutRef<typeof AlertDialogPrimitive.Action> & {
|
|
104
|
+
tone?: "default" | "destructive";
|
|
105
|
+
}
|
|
106
|
+
>(({ className, tone = "default", ...props }, ref) => (
|
|
107
|
+
<AlertDialogPrimitive.Action
|
|
108
|
+
ref={ref}
|
|
109
|
+
className={cn(buttonVariants({ variant: tone === "destructive" ? "destructive" : "default" }), className)}
|
|
110
|
+
{...props}
|
|
111
|
+
/>
|
|
112
|
+
));
|
|
113
|
+
AlertDialogAction.displayName = AlertDialogPrimitive.Action.displayName;
|
|
114
|
+
|
|
115
|
+
const AlertDialogCancel = React.forwardRef<
|
|
116
|
+
React.ElementRef<typeof AlertDialogPrimitive.Cancel>,
|
|
117
|
+
React.ComponentPropsWithoutRef<typeof AlertDialogPrimitive.Cancel>
|
|
118
|
+
>(({ className, ...props }, ref) => (
|
|
119
|
+
<AlertDialogPrimitive.Cancel
|
|
120
|
+
ref={ref}
|
|
121
|
+
className={cn(buttonVariants({ variant: "outline" }), className)}
|
|
122
|
+
{...props}
|
|
123
|
+
/>
|
|
124
|
+
));
|
|
125
|
+
AlertDialogCancel.displayName = AlertDialogPrimitive.Cancel.displayName;
|
|
126
|
+
|
|
127
|
+
export {
|
|
128
|
+
AlertDialog,
|
|
129
|
+
AlertDialogAction,
|
|
130
|
+
AlertDialogCancel,
|
|
131
|
+
AlertDialogContent,
|
|
132
|
+
AlertDialogDescription,
|
|
133
|
+
AlertDialogFooter,
|
|
134
|
+
AlertDialogHeader,
|
|
135
|
+
AlertDialogOverlay,
|
|
136
|
+
AlertDialogPortal,
|
|
137
|
+
AlertDialogTitle,
|
|
138
|
+
AlertDialogTrigger,
|
|
139
|
+
};
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import type { Meta, StoryObj } from '@storybook/react'
|
|
2
|
+
import { Info } from 'lucide-react'
|
|
3
|
+
import { Button } from './button'
|
|
4
|
+
import { Checkbox } from './checkbox'
|
|
5
|
+
import { Label } from './label'
|
|
6
|
+
import { Separator } from './separator'
|
|
7
|
+
import { Sheet, SheetContent, SheetDescription, SheetFooter, SheetHeader, SheetTitle, SheetTrigger } from './sheet'
|
|
8
|
+
import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from './tooltip'
|
|
9
|
+
|
|
10
|
+
const meta: Meta = {
|
|
11
|
+
title: 'Primitives/Checkbox, Separator, Sheet, Tooltip',
|
|
12
|
+
parameters: { layout: 'centered' },
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export default meta
|
|
16
|
+
type Story = StoryObj
|
|
17
|
+
|
|
18
|
+
export const Checkboxes: Story = {
|
|
19
|
+
render: () => (
|
|
20
|
+
<div className="flex flex-col gap-3">
|
|
21
|
+
{[
|
|
22
|
+
{ id: 'a', label: 'Record a video of every run', checked: true },
|
|
23
|
+
{ id: 'b', label: 'Retry failed steps once', checked: false },
|
|
24
|
+
{ id: 'c', label: 'Select every suite in this workspace', checked: 'indeterminate' as const },
|
|
25
|
+
{ id: 'd', label: 'Disabled until billing is set up', checked: false, disabled: true },
|
|
26
|
+
].map((row) => (
|
|
27
|
+
<div key={row.id} className="flex items-center gap-2">
|
|
28
|
+
<Checkbox id={row.id} defaultChecked={row.checked} disabled={row.disabled} />
|
|
29
|
+
<Label htmlFor={row.id}>{row.label}</Label>
|
|
30
|
+
</div>
|
|
31
|
+
))}
|
|
32
|
+
</div>
|
|
33
|
+
),
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export const Separators: Story = {
|
|
37
|
+
render: () => (
|
|
38
|
+
<div className="w-72 text-sm">
|
|
39
|
+
<p>Account</p>
|
|
40
|
+
<Separator className="my-3" />
|
|
41
|
+
<div className="flex h-5 items-center gap-3">
|
|
42
|
+
<span>Runs</span>
|
|
43
|
+
<Separator orientation="vertical" />
|
|
44
|
+
<span>Suites</span>
|
|
45
|
+
<Separator orientation="vertical" />
|
|
46
|
+
<span>Settings</span>
|
|
47
|
+
</div>
|
|
48
|
+
</div>
|
|
49
|
+
),
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export const Sheets: Story = {
|
|
53
|
+
render: () => (
|
|
54
|
+
<div className="flex gap-2">
|
|
55
|
+
{(['left', 'right', 'bottom'] as const).map((side) => (
|
|
56
|
+
<Sheet key={side}>
|
|
57
|
+
<SheetTrigger asChild>
|
|
58
|
+
<Button variant="outline">Open {side}</Button>
|
|
59
|
+
</SheetTrigger>
|
|
60
|
+
<SheetContent side={side}>
|
|
61
|
+
<SheetHeader>
|
|
62
|
+
<SheetTitle>Run assistant</SheetTitle>
|
|
63
|
+
<SheetDescription>Ask why a step failed or what to test next.</SheetDescription>
|
|
64
|
+
</SheetHeader>
|
|
65
|
+
<SheetFooter>
|
|
66
|
+
<Button>Send</Button>
|
|
67
|
+
</SheetFooter>
|
|
68
|
+
</SheetContent>
|
|
69
|
+
</Sheet>
|
|
70
|
+
))}
|
|
71
|
+
</div>
|
|
72
|
+
),
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
export const Tooltips: Story = {
|
|
76
|
+
render: () => (
|
|
77
|
+
<TooltipProvider>
|
|
78
|
+
<div className="flex gap-2">
|
|
79
|
+
{['Runs', 'Test suites', 'A much longer label that wraps at the maximum tooltip width'].map((label) => (
|
|
80
|
+
<Tooltip key={label}>
|
|
81
|
+
<TooltipTrigger asChild>
|
|
82
|
+
<Button size="icon" variant="ghost" aria-label={label}>
|
|
83
|
+
<Info className="size-4" />
|
|
84
|
+
</Button>
|
|
85
|
+
</TooltipTrigger>
|
|
86
|
+
<TooltipContent>{label}</TooltipContent>
|
|
87
|
+
</Tooltip>
|
|
88
|
+
))}
|
|
89
|
+
</div>
|
|
90
|
+
</TooltipProvider>
|
|
91
|
+
),
|
|
92
|
+
}
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
import { fireEvent, render, screen, waitFor } from "@testing-library/react";
|
|
2
|
+
import userEvent from "@testing-library/user-event";
|
|
3
|
+
import { describe, expect, it } from "vitest";
|
|
4
|
+
import { Checkbox } from "./checkbox";
|
|
5
|
+
import { Label } from "./label";
|
|
6
|
+
import { Separator } from "./separator";
|
|
7
|
+
import { Sheet, SheetContent, SheetDescription, SheetTitle, SheetTrigger } from "./sheet";
|
|
8
|
+
import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from "./tooltip";
|
|
9
|
+
|
|
10
|
+
describe("Checkbox", () => {
|
|
11
|
+
it("toggles from its label and exposes checkbox state", () => {
|
|
12
|
+
render(
|
|
13
|
+
<>
|
|
14
|
+
<Checkbox id="notify" />
|
|
15
|
+
<Label htmlFor="notify">Email me</Label>
|
|
16
|
+
</>,
|
|
17
|
+
);
|
|
18
|
+
const box = screen.getByRole("checkbox", { name: "Email me" });
|
|
19
|
+
expect(box).toHaveAttribute("aria-checked", "false");
|
|
20
|
+
fireEvent.click(screen.getByText("Email me"));
|
|
21
|
+
expect(box).toHaveAttribute("aria-checked", "true");
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
it("reports the indeterminate state as mixed", () => {
|
|
25
|
+
render(<Checkbox aria-label="Select all" checked="indeterminate" />);
|
|
26
|
+
expect(screen.getByRole("checkbox", { name: "Select all" })).toHaveAttribute(
|
|
27
|
+
"aria-checked",
|
|
28
|
+
"mixed",
|
|
29
|
+
);
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
it("draws the dash for an uncontrolled indeterminate box too", () => {
|
|
33
|
+
const { container } = render(<Checkbox aria-label="Some" defaultChecked="indeterminate" />);
|
|
34
|
+
expect(screen.getByRole("checkbox")).toHaveAttribute("aria-checked", "mixed");
|
|
35
|
+
const dash = container.querySelector("svg.lucide-minus");
|
|
36
|
+
const tick = container.querySelector("svg.lucide-check");
|
|
37
|
+
expect(dash?.getAttribute("class")).toContain("group-data-[state=indeterminate]/checkbox:block");
|
|
38
|
+
expect(tick?.getAttribute("class")).toContain("group-data-[state=indeterminate]/checkbox:hidden");
|
|
39
|
+
expect(screen.getByRole("checkbox")).toHaveAttribute("data-state", "indeterminate");
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
it("paints with tokens, never palette utilities", () => {
|
|
43
|
+
render(<Checkbox aria-label="Agree" defaultChecked />);
|
|
44
|
+
const cls = screen.getByRole("checkbox").className;
|
|
45
|
+
expect(cls).toContain("data-[state=checked]:bg-primary");
|
|
46
|
+
expect(cls).not.toMatch(/\b(?:bg|text|border)-(?:slate|zinc|gray|neutral|blue|green|red|amber|emerald)-\d/);
|
|
47
|
+
});
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
describe("Separator", () => {
|
|
51
|
+
it("is hidden from assistive technology unless it is semantic", () => {
|
|
52
|
+
const { container, rerender } = render(<Separator />);
|
|
53
|
+
expect(container.firstElementChild).toHaveAttribute("role", "none");
|
|
54
|
+
rerender(<Separator decorative={false} orientation="vertical" />);
|
|
55
|
+
const rule = screen.getByRole("separator");
|
|
56
|
+
expect(rule).toHaveAttribute("aria-orientation", "vertical");
|
|
57
|
+
expect(rule.className).toContain("w-px");
|
|
58
|
+
});
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
describe("Sheet", () => {
|
|
62
|
+
it("opens as a labelled dialog and closes from its close button", async () => {
|
|
63
|
+
render(
|
|
64
|
+
<Sheet>
|
|
65
|
+
<SheetTrigger>Open chat</SheetTrigger>
|
|
66
|
+
<SheetContent side="left">
|
|
67
|
+
<SheetTitle>Assistant</SheetTitle>
|
|
68
|
+
<SheetDescription>Ask about this run.</SheetDescription>
|
|
69
|
+
</SheetContent>
|
|
70
|
+
</Sheet>,
|
|
71
|
+
);
|
|
72
|
+
fireEvent.click(screen.getByText("Open chat"));
|
|
73
|
+
const dialog = await screen.findByRole("dialog", { name: "Assistant" });
|
|
74
|
+
expect(dialog.className).toContain("slide-in-from-left");
|
|
75
|
+
fireEvent.click(screen.getByRole("button", { name: "Close" }));
|
|
76
|
+
await waitFor(() => expect(screen.queryByRole("dialog")).not.toBeInTheDocument());
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
it("can hide its close button", async () => {
|
|
80
|
+
render(
|
|
81
|
+
<Sheet defaultOpen>
|
|
82
|
+
<SheetContent hideCloseButton>
|
|
83
|
+
<SheetTitle>Filters</SheetTitle>
|
|
84
|
+
<SheetDescription>Narrow the list.</SheetDescription>
|
|
85
|
+
</SheetContent>
|
|
86
|
+
</Sheet>,
|
|
87
|
+
);
|
|
88
|
+
await screen.findByRole("dialog", { name: "Filters" });
|
|
89
|
+
expect(screen.queryByRole("button", { name: "Close" })).not.toBeInTheDocument();
|
|
90
|
+
});
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
describe("Tooltip", () => {
|
|
94
|
+
it("shows its label when the trigger receives keyboard focus", async () => {
|
|
95
|
+
const user = userEvent.setup();
|
|
96
|
+
render(
|
|
97
|
+
<TooltipProvider delayDuration={0}>
|
|
98
|
+
<Tooltip>
|
|
99
|
+
<TooltipTrigger aria-label="Runs">R</TooltipTrigger>
|
|
100
|
+
<TooltipContent>Runs</TooltipContent>
|
|
101
|
+
</Tooltip>
|
|
102
|
+
</TooltipProvider>,
|
|
103
|
+
);
|
|
104
|
+
await user.tab();
|
|
105
|
+
expect(await screen.findByRole("tooltip")).toHaveTextContent("Runs");
|
|
106
|
+
});
|
|
107
|
+
});
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import * as CheckboxPrimitive from "@radix-ui/react-checkbox";
|
|
4
|
+
import { Check, Minus } from "lucide-react";
|
|
5
|
+
import * as React from "react";
|
|
6
|
+
import { focusRing } from "../lib/focus";
|
|
7
|
+
import { cn } from "../lib/utils";
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* A two- or three-state checkbox. An indeterminate state, controlled
|
|
11
|
+
* (`checked`) or uncontrolled (`defaultChecked`), draws a dash.
|
|
12
|
+
* Pair it with a `Label` through `id`/`htmlFor`; `aria-invalid` paints the
|
|
13
|
+
* danger hairline.
|
|
14
|
+
*/
|
|
15
|
+
const Checkbox = React.forwardRef<
|
|
16
|
+
React.ElementRef<typeof CheckboxPrimitive.Root>,
|
|
17
|
+
React.ComponentPropsWithoutRef<typeof CheckboxPrimitive.Root>
|
|
18
|
+
>(({ className, ...props }, ref) => (
|
|
19
|
+
<CheckboxPrimitive.Root
|
|
20
|
+
ref={ref}
|
|
21
|
+
className={cn(
|
|
22
|
+
"peer group/checkbox inline-grid size-4 shrink-0 cursor-pointer place-content-center rounded-[4px] border border-[var(--border-strong)] bg-transparent transition-[background-color,border-color,box-shadow] duration-150 ease-out",
|
|
23
|
+
"disabled:cursor-not-allowed disabled:opacity-50",
|
|
24
|
+
"aria-invalid:border-[var(--surface-danger-border)]",
|
|
25
|
+
"data-[state=checked]:border-primary data-[state=checked]:bg-primary data-[state=checked]:text-primary-foreground",
|
|
26
|
+
"data-[state=indeterminate]:border-primary data-[state=indeterminate]:bg-primary data-[state=indeterminate]:text-primary-foreground",
|
|
27
|
+
focusRing,
|
|
28
|
+
className,
|
|
29
|
+
)}
|
|
30
|
+
{...props}
|
|
31
|
+
>
|
|
32
|
+
<CheckboxPrimitive.Indicator className="grid place-content-center text-current">
|
|
33
|
+
{/* Both glyphs render and the Root's Radix state picks one, so a
|
|
34
|
+
controlled or uncontrolled indeterminate box draws the same dash. */}
|
|
35
|
+
<Check aria-hidden="true" className="size-3.5 group-data-[state=indeterminate]/checkbox:hidden" strokeWidth={3} />
|
|
36
|
+
<Minus aria-hidden="true" className="hidden size-3.5 group-data-[state=indeterminate]/checkbox:block" strokeWidth={3} />
|
|
37
|
+
</CheckboxPrimitive.Indicator>
|
|
38
|
+
</CheckboxPrimitive.Root>
|
|
39
|
+
));
|
|
40
|
+
Checkbox.displayName = CheckboxPrimitive.Root.displayName;
|
|
41
|
+
|
|
42
|
+
export { Checkbox };
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import * as CollapsiblePrimitive from "@radix-ui/react-collapsible";
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Unstyled show/hide region. The trigger carries `aria-expanded` and
|
|
7
|
+
* `data-state`, so a chevron can rotate with
|
|
8
|
+
* `group-data-[state=open]:rotate-90` without local state.
|
|
9
|
+
*/
|
|
10
|
+
const Collapsible = CollapsiblePrimitive.Root;
|
|
11
|
+
|
|
12
|
+
const CollapsibleTrigger = CollapsiblePrimitive.CollapsibleTrigger;
|
|
13
|
+
|
|
14
|
+
const CollapsibleContent = CollapsiblePrimitive.CollapsibleContent;
|
|
15
|
+
|
|
16
|
+
export { Collapsible, CollapsibleContent, CollapsibleTrigger };
|