@olympusoss/canvas 2.6.19
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +179 -0
- package/src/components/atoms/README.md +11 -0
- package/src/components/atoms/aspect-ratio.tsx +32 -0
- package/src/components/atoms/avatar.tsx +98 -0
- package/src/components/atoms/badge.tsx +44 -0
- package/src/components/atoms/brand-mark.tsx +74 -0
- package/src/components/atoms/button.tsx +104 -0
- package/src/components/atoms/checkbox.tsx +63 -0
- package/src/components/atoms/flex-box.tsx +105 -0
- package/src/components/atoms/icon.tsx +34 -0
- package/src/components/atoms/input.tsx +91 -0
- package/src/components/atoms/label.tsx +41 -0
- package/src/components/atoms/logo.tsx +89 -0
- package/src/components/atoms/progress.tsx +55 -0
- package/src/components/atoms/radio-group.tsx +122 -0
- package/src/components/atoms/scroll-area.tsx +106 -0
- package/src/components/atoms/section.tsx +48 -0
- package/src/components/atoms/separator.tsx +45 -0
- package/src/components/atoms/skeleton.tsx +17 -0
- package/src/components/atoms/slider.tsx +93 -0
- package/src/components/atoms/switch.tsx +60 -0
- package/src/components/atoms/textarea.tsx +78 -0
- package/src/components/atoms/toggle.tsx +80 -0
- package/src/components/charts/activity-heatmap.tsx +96 -0
- package/src/components/charts/axes.tsx +21 -0
- package/src/components/charts/chart-container.tsx +195 -0
- package/src/components/charts/chart-legend.tsx +67 -0
- package/src/components/charts/chart-tooltip.tsx +161 -0
- package/src/components/charts/chart-types.tsx +49 -0
- package/src/components/charts/containers.tsx +11 -0
- package/src/components/charts/data.tsx +16 -0
- package/src/components/charts/details.tsx +25 -0
- package/src/components/charts/gauge.tsx +106 -0
- package/src/components/charts/grids.tsx +8 -0
- package/src/components/charts/index.ts +62 -0
- package/src/components/charts/labeled-bar-list.tsx +85 -0
- package/src/components/charts/references.tsx +8 -0
- package/src/components/charts/service-health-list.tsx +73 -0
- package/src/components/charts/sparkline.tsx +52 -0
- package/src/components/charts/stacked-bar.tsx +104 -0
- package/src/components/charts/text.tsx +10 -0
- package/src/components/charts/world-heat-map-inner.tsx +317 -0
- package/src/components/charts/world-heat-map.tsx +184 -0
- package/src/components/molecules/README.md +12 -0
- package/src/components/molecules/action-bar.tsx +73 -0
- package/src/components/molecules/activity-item.tsx +74 -0
- package/src/components/molecules/alert.tsx +80 -0
- package/src/components/molecules/animated-background.tsx +92 -0
- package/src/components/molecules/brand-lockup.tsx +48 -0
- package/src/components/molecules/breadcrumb.tsx +161 -0
- package/src/components/molecules/button-group.tsx +104 -0
- package/src/components/molecules/calendar.tsx +216 -0
- package/src/components/molecules/card.tsx +101 -0
- package/src/components/molecules/code-block.tsx +48 -0
- package/src/components/molecules/empty-state.tsx +55 -0
- package/src/components/molecules/error-state.tsx +42 -0
- package/src/components/molecules/field-display.tsx +35 -0
- package/src/components/molecules/input-otp.tsx +74 -0
- package/src/components/molecules/loading-state.tsx +36 -0
- package/src/components/molecules/notification-item.tsx +67 -0
- package/src/components/molecules/notification-list.tsx +45 -0
- package/src/components/molecules/number-badge.tsx +53 -0
- package/src/components/molecules/page-header.tsx +88 -0
- package/src/components/molecules/page-tabs.tsx +94 -0
- package/src/components/molecules/pagination.tsx +150 -0
- package/src/components/molecules/phone-input.tsx +200 -0
- package/src/components/molecules/search-bar.tsx +64 -0
- package/src/components/molecules/secret-field.tsx +158 -0
- package/src/components/molecules/section-card.tsx +91 -0
- package/src/components/molecules/stat-card.tsx +96 -0
- package/src/components/molecules/status-badge.tsx +42 -0
- package/src/components/molecules/stepper.tsx +96 -0
- package/src/components/molecules/table.tsx +157 -0
- package/src/components/molecules/toggle-group.tsx +145 -0
- package/src/components/molecules/tooltip.tsx +150 -0
- package/src/components/molecules/user-avatar-chip.tsx +71 -0
- package/src/components/organisms/README.md +14 -0
- package/src/components/organisms/accordion.tsx +149 -0
- package/src/components/organisms/alert-dialog.tsx +269 -0
- package/src/components/organisms/carousel.tsx +244 -0
- package/src/components/organisms/collapsible.tsx +69 -0
- package/src/components/organisms/command.tsx +143 -0
- package/src/components/organisms/context-menu.tsx +333 -0
- package/src/components/organisms/dashboard-grid.tsx +360 -0
- package/src/components/organisms/data-table.tsx +330 -0
- package/src/components/organisms/dialog.tsx +304 -0
- package/src/components/organisms/drawer.tsx +100 -0
- package/src/components/organisms/dropdown-menu.tsx +434 -0
- package/src/components/organisms/editors/code-editor.tsx +144 -0
- package/src/components/organisms/editors/index.ts +4 -0
- package/src/components/organisms/editors/markdown-editor.tsx +153 -0
- package/src/components/organisms/editors/markdown-renderer.ts +27 -0
- package/src/components/organisms/editors/prose-canvas-classes.ts +45 -0
- package/src/components/organisms/editors/rich-text-editor.tsx +126 -0
- package/src/components/organisms/editors/toolbar/md-toolbar.tsx +129 -0
- package/src/components/organisms/editors/toolbar/rte-toolbar.tsx +211 -0
- package/src/components/organisms/editors/toolbar/toolbar-shell.tsx +45 -0
- package/src/components/organisms/editors/use-codemirror-theme.ts +61 -0
- package/src/components/organisms/error-boundary.tsx +61 -0
- package/src/components/organisms/form.tsx +174 -0
- package/src/components/organisms/hover-card.tsx +114 -0
- package/src/components/organisms/menubar.tsx +491 -0
- package/src/components/organisms/navbar.tsx +101 -0
- package/src/components/organisms/navigation-menu.tsx +234 -0
- package/src/components/organisms/popover.tsx +144 -0
- package/src/components/organisms/resizable.tsx +39 -0
- package/src/components/organisms/schema-form.tsx +232 -0
- package/src/components/organisms/select.tsx +303 -0
- package/src/components/organisms/sheet.tsx +256 -0
- package/src/components/organisms/sidebar.tsx +1037 -0
- package/src/components/organisms/sonner.tsx +96 -0
- package/src/components/organisms/tabs.tsx +132 -0
- package/src/components/organisms/theme-provider.tsx +101 -0
- package/src/hooks/use-mobile.tsx +19 -0
- package/src/index.ts +547 -0
- package/src/lib/portal-container.tsx +35 -0
- package/src/lib/utils.ts +6 -0
- package/src/native.ts +23 -0
- package/src/tokens/colors.ts +91 -0
- package/src/tokens/index.ts +3 -0
- package/src/tokens/spacing.ts +55 -0
- package/src/tokens/typography.ts +27 -0
- package/styles/canvas.css +55 -0
- package/styles/dashboard-grid.css +47 -0
- package/styles/leaflet.css +13 -0
- package/styles/tokens.css +234 -0
- package/tailwind.config.ts +70 -0
- package/tsconfig.json +23 -0
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import * as ToggleGroupPrimitive from "@radix-ui/react-toggle-group";
|
|
4
|
+
import type { VariantProps } from "class-variance-authority";
|
|
5
|
+
import * as React from "react";
|
|
6
|
+
|
|
7
|
+
import { cn } from "../../lib/utils";
|
|
8
|
+
import { toggleVariants } from "../atoms/toggle";
|
|
9
|
+
|
|
10
|
+
const ToggleGroupContext = React.createContext<VariantProps<typeof toggleVariants>>({
|
|
11
|
+
size: "default",
|
|
12
|
+
variant: "default",
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
export interface ToggleGroupProps {
|
|
16
|
+
/**
|
|
17
|
+
* Selection mode. `"single"` allows one item active at a time;
|
|
18
|
+
* `"multiple"` allows independent toggles.
|
|
19
|
+
*/
|
|
20
|
+
type: "single" | "multiple";
|
|
21
|
+
/**
|
|
22
|
+
* Controlled value. For `type="single"` it's a string; for
|
|
23
|
+
* `type="multiple"` it's an array of strings.
|
|
24
|
+
*/
|
|
25
|
+
value?: string | string[];
|
|
26
|
+
/** Initial value for uncontrolled usage. */
|
|
27
|
+
defaultValue?: string | string[];
|
|
28
|
+
/** Fires when the user toggles an item. */
|
|
29
|
+
onValueChange?: (value: string & string[]) => void;
|
|
30
|
+
/**
|
|
31
|
+
* Disable every toggle in the group.
|
|
32
|
+
* @default false
|
|
33
|
+
*/
|
|
34
|
+
disabled?: boolean;
|
|
35
|
+
/**
|
|
36
|
+
* Layout direction.
|
|
37
|
+
* @default "horizontal"
|
|
38
|
+
*/
|
|
39
|
+
orientation?: "horizontal" | "vertical";
|
|
40
|
+
/**
|
|
41
|
+
* Reading direction. Affects keyboard arrow navigation.
|
|
42
|
+
* @default "ltr"
|
|
43
|
+
*/
|
|
44
|
+
dir?: "ltr" | "rtl";
|
|
45
|
+
/**
|
|
46
|
+
* When true, arrow-key navigation wraps from the last item to the first.
|
|
47
|
+
* @default true
|
|
48
|
+
*/
|
|
49
|
+
loop?: boolean;
|
|
50
|
+
/**
|
|
51
|
+
* Filled vs outlined preset (inherits from `<Toggle>`).
|
|
52
|
+
* @default "default"
|
|
53
|
+
*/
|
|
54
|
+
variant?: "default" | "outline";
|
|
55
|
+
/**
|
|
56
|
+
* Size preset (inherits from `<Toggle>`).
|
|
57
|
+
* @default "default"
|
|
58
|
+
*/
|
|
59
|
+
size?: "default" | "sm" | "lg";
|
|
60
|
+
/**
|
|
61
|
+
* Render as a Radix Slot — forwards props onto the immediate child.
|
|
62
|
+
* @default false
|
|
63
|
+
*/
|
|
64
|
+
asChild?: boolean;
|
|
65
|
+
/** A flat list of `<ToggleGroupItem>`s. */
|
|
66
|
+
children?: React.ReactNode;
|
|
67
|
+
/** Tailwind / CSS classes merged onto the group via `cn()`. */
|
|
68
|
+
className?: string;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
const ToggleGroupImpl = React.forwardRef<
|
|
72
|
+
React.ElementRef<typeof ToggleGroupPrimitive.Root>,
|
|
73
|
+
ToggleGroupProps
|
|
74
|
+
>(({ className, variant, size, children, ...props }, ref) => (
|
|
75
|
+
<ToggleGroupPrimitive.Root
|
|
76
|
+
ref={ref}
|
|
77
|
+
{...(props as React.ComponentPropsWithoutRef<typeof ToggleGroupPrimitive.Root>)}
|
|
78
|
+
className={cn("flex items-center justify-center gap-1", className)}
|
|
79
|
+
>
|
|
80
|
+
<ToggleGroupContext.Provider value={{ variant, size }}>{children}</ToggleGroupContext.Provider>
|
|
81
|
+
</ToggleGroupPrimitive.Root>
|
|
82
|
+
));
|
|
83
|
+
|
|
84
|
+
ToggleGroupImpl.displayName = ToggleGroupPrimitive.Root.displayName;
|
|
85
|
+
|
|
86
|
+
const ToggleGroup = ToggleGroupImpl as React.ForwardRefExoticComponent<
|
|
87
|
+
ToggleGroupProps & React.RefAttributes<HTMLDivElement>
|
|
88
|
+
>;
|
|
89
|
+
|
|
90
|
+
export interface ToggleGroupItemProps
|
|
91
|
+
extends React.ComponentPropsWithoutRef<typeof ToggleGroupPrimitive.Item>,
|
|
92
|
+
VariantProps<typeof toggleVariants> {
|
|
93
|
+
/** Required — value reported when this toggle is active. */
|
|
94
|
+
value: string;
|
|
95
|
+
/**
|
|
96
|
+
* Disable only this toggle.
|
|
97
|
+
* @default false
|
|
98
|
+
*/
|
|
99
|
+
disabled?: boolean;
|
|
100
|
+
/**
|
|
101
|
+
* Filled vs outlined. Defaults to inheriting from the parent
|
|
102
|
+
* `<ToggleGroup>`.
|
|
103
|
+
*/
|
|
104
|
+
variant?: "default" | "outline";
|
|
105
|
+
/**
|
|
106
|
+
* Size preset. Defaults to inheriting from the parent `<ToggleGroup>`.
|
|
107
|
+
*/
|
|
108
|
+
size?: "default" | "sm" | "lg";
|
|
109
|
+
/**
|
|
110
|
+
* Render as a Radix Slot — forwards props onto the immediate child.
|
|
111
|
+
* @default false
|
|
112
|
+
*/
|
|
113
|
+
asChild?: boolean;
|
|
114
|
+
/** Toggle label or icon. */
|
|
115
|
+
children?: React.ReactNode;
|
|
116
|
+
/** Tailwind / CSS classes merged onto the toggle via `cn()`. */
|
|
117
|
+
className?: string;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
const ToggleGroupItem = React.forwardRef<
|
|
121
|
+
React.ElementRef<typeof ToggleGroupPrimitive.Item>,
|
|
122
|
+
ToggleGroupItemProps
|
|
123
|
+
>(({ className, children, variant, size, ...props }, ref) => {
|
|
124
|
+
const context = React.useContext(ToggleGroupContext);
|
|
125
|
+
|
|
126
|
+
return (
|
|
127
|
+
<ToggleGroupPrimitive.Item
|
|
128
|
+
ref={ref}
|
|
129
|
+
className={cn(
|
|
130
|
+
toggleVariants({
|
|
131
|
+
variant: context.variant || variant,
|
|
132
|
+
size: context.size || size,
|
|
133
|
+
}),
|
|
134
|
+
className,
|
|
135
|
+
)}
|
|
136
|
+
{...props}
|
|
137
|
+
>
|
|
138
|
+
{children}
|
|
139
|
+
</ToggleGroupPrimitive.Item>
|
|
140
|
+
);
|
|
141
|
+
});
|
|
142
|
+
|
|
143
|
+
ToggleGroupItem.displayName = ToggleGroupPrimitive.Item.displayName;
|
|
144
|
+
|
|
145
|
+
export { ToggleGroup, ToggleGroupItem };
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import * as TooltipPrimitive from "@radix-ui/react-tooltip";
|
|
4
|
+
import * as React from "react";
|
|
5
|
+
|
|
6
|
+
import { cn } from "../../lib/utils";
|
|
7
|
+
|
|
8
|
+
export interface TooltipProviderProps
|
|
9
|
+
extends React.ComponentPropsWithoutRef<typeof TooltipPrimitive.Provider> {
|
|
10
|
+
/**
|
|
11
|
+
* Delay in ms before any tooltip in the provider opens. Set to 0 for
|
|
12
|
+
* instant tooltips (e.g. icon rails).
|
|
13
|
+
* @default 700
|
|
14
|
+
*/
|
|
15
|
+
delayDuration?: number;
|
|
16
|
+
/**
|
|
17
|
+
* Delay in ms before a tooltip closes after the cursor leaves. Useful
|
|
18
|
+
* for letting users drag from the trigger to the content.
|
|
19
|
+
* @default 300
|
|
20
|
+
*/
|
|
21
|
+
skipDelayDuration?: number;
|
|
22
|
+
/**
|
|
23
|
+
* When true, the tooltip will not close while the user is interacting
|
|
24
|
+
* with content inside it (e.g. hover, focus).
|
|
25
|
+
* @default false
|
|
26
|
+
*/
|
|
27
|
+
disableHoverableContent?: boolean;
|
|
28
|
+
/** All `<Tooltip>`s in the subtree share this provider's delays. */
|
|
29
|
+
children: React.ReactNode;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
const TooltipProvider = TooltipPrimitive.Provider as React.FC<TooltipProviderProps>;
|
|
33
|
+
|
|
34
|
+
export interface TooltipProps extends React.ComponentPropsWithoutRef<typeof TooltipPrimitive.Root> {
|
|
35
|
+
/** Controlled open state. */
|
|
36
|
+
open?: boolean;
|
|
37
|
+
/** Initial open state for uncontrolled usage. */
|
|
38
|
+
defaultOpen?: boolean;
|
|
39
|
+
/** Fires whenever the tooltip opens or closes. */
|
|
40
|
+
onOpenChange?: (open: boolean) => void;
|
|
41
|
+
/**
|
|
42
|
+
* Override the parent provider's `delayDuration` for this tooltip
|
|
43
|
+
* specifically.
|
|
44
|
+
*/
|
|
45
|
+
delayDuration?: number;
|
|
46
|
+
/**
|
|
47
|
+
* Override the parent provider's `disableHoverableContent` for this
|
|
48
|
+
* tooltip.
|
|
49
|
+
*/
|
|
50
|
+
disableHoverableContent?: boolean;
|
|
51
|
+
/** Trigger + Content. */
|
|
52
|
+
children?: React.ReactNode;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
const Tooltip = TooltipPrimitive.Root as React.FC<TooltipProps>;
|
|
56
|
+
|
|
57
|
+
export interface TooltipTriggerProps
|
|
58
|
+
extends React.ComponentPropsWithoutRef<typeof TooltipPrimitive.Trigger> {
|
|
59
|
+
/**
|
|
60
|
+
* Render as a Radix Slot — forwards props onto the immediate child.
|
|
61
|
+
* Common pattern for wrapping a `<Button>` or icon.
|
|
62
|
+
* @default false
|
|
63
|
+
*/
|
|
64
|
+
asChild?: boolean;
|
|
65
|
+
/** The element that opens the tooltip on hover/focus. */
|
|
66
|
+
children?: React.ReactNode;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
const TooltipTrigger = TooltipPrimitive.Trigger as React.ForwardRefExoticComponent<
|
|
70
|
+
TooltipTriggerProps & React.RefAttributes<HTMLButtonElement>
|
|
71
|
+
>;
|
|
72
|
+
|
|
73
|
+
export interface TooltipContentProps
|
|
74
|
+
extends React.ComponentPropsWithoutRef<typeof TooltipPrimitive.Content> {
|
|
75
|
+
/**
|
|
76
|
+
* Distance in pixels between the trigger and the tooltip content.
|
|
77
|
+
* @default 4
|
|
78
|
+
*/
|
|
79
|
+
sideOffset?: number;
|
|
80
|
+
/**
|
|
81
|
+
* Distance from the alignment edge.
|
|
82
|
+
* @default 0
|
|
83
|
+
*/
|
|
84
|
+
alignOffset?: number;
|
|
85
|
+
/**
|
|
86
|
+
* Preferred side of the trigger to render on.
|
|
87
|
+
* @default "top"
|
|
88
|
+
*/
|
|
89
|
+
side?: "top" | "right" | "bottom" | "left";
|
|
90
|
+
/**
|
|
91
|
+
* Alignment along the chosen side.
|
|
92
|
+
* @default "center"
|
|
93
|
+
*/
|
|
94
|
+
align?: "start" | "center" | "end";
|
|
95
|
+
/**
|
|
96
|
+
* Avoid colliding with the viewport edges by flipping/shifting.
|
|
97
|
+
* @default true
|
|
98
|
+
*/
|
|
99
|
+
avoidCollisions?: boolean;
|
|
100
|
+
/**
|
|
101
|
+
* Padding kept from collision boundaries.
|
|
102
|
+
* @default 0
|
|
103
|
+
*/
|
|
104
|
+
collisionPadding?: number | { top?: number; right?: number; bottom?: number; left?: number };
|
|
105
|
+
/**
|
|
106
|
+
* Stick to the trigger or partially follow on scroll.
|
|
107
|
+
* @default "partial"
|
|
108
|
+
*/
|
|
109
|
+
sticky?: "partial" | "always";
|
|
110
|
+
/** Hide the content when the trigger is detached or covered. */
|
|
111
|
+
hideWhenDetached?: boolean;
|
|
112
|
+
/**
|
|
113
|
+
* Force the content to mount even when closed. Pair with a CSS
|
|
114
|
+
* animation that fades in/out based on `data-state`.
|
|
115
|
+
* @default false
|
|
116
|
+
*/
|
|
117
|
+
forceMount?: true;
|
|
118
|
+
/**
|
|
119
|
+
* Render as a Radix Slot — forwards props onto the immediate child.
|
|
120
|
+
* @default false
|
|
121
|
+
*/
|
|
122
|
+
asChild?: boolean;
|
|
123
|
+
/** Tooltip body. Keep terse — one short line is the convention. */
|
|
124
|
+
children?: React.ReactNode;
|
|
125
|
+
/** Tailwind / CSS classes merged onto the content via `cn()`. */
|
|
126
|
+
className?: string;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
const TooltipContent = React.forwardRef<
|
|
130
|
+
React.ElementRef<typeof TooltipPrimitive.Content>,
|
|
131
|
+
TooltipContentProps
|
|
132
|
+
>(({ className, sideOffset = 6, children, ...props }, ref) => (
|
|
133
|
+
<TooltipPrimitive.Portal>
|
|
134
|
+
<TooltipPrimitive.Content
|
|
135
|
+
ref={ref}
|
|
136
|
+
sideOffset={sideOffset}
|
|
137
|
+
className={cn(
|
|
138
|
+
"z-50 max-w-xs overflow-hidden rounded-md border border-border/50 bg-popover px-2 py-1 text-[11px] font-medium text-popover-foreground shadow-md animate-in fade-in-0 zoom-in-95 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[side=bottom]:slide-in-from-top-1 data-[side=left]:slide-in-from-right-1 data-[side=right]:slide-in-from-left-1 data-[side=top]:slide-in-from-bottom-1 origin-[var(--radix-tooltip-content-transform-origin)]",
|
|
139
|
+
className,
|
|
140
|
+
)}
|
|
141
|
+
{...props}
|
|
142
|
+
>
|
|
143
|
+
{children}
|
|
144
|
+
<TooltipPrimitive.Arrow width={10} height={5} style={{ fill: "hsl(var(--popover))" }} />
|
|
145
|
+
</TooltipPrimitive.Content>
|
|
146
|
+
</TooltipPrimitive.Portal>
|
|
147
|
+
));
|
|
148
|
+
TooltipContent.displayName = TooltipPrimitive.Content.displayName;
|
|
149
|
+
|
|
150
|
+
export { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger };
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import { ChevronDown } from "lucide-react";
|
|
4
|
+
import * as React from "react";
|
|
5
|
+
|
|
6
|
+
import { cn } from "../../lib/utils";
|
|
7
|
+
import { Avatar, AvatarFallback, AvatarImage } from "../atoms/avatar";
|
|
8
|
+
|
|
9
|
+
export interface UserAvatarChipProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {
|
|
10
|
+
/** Display name (rendered next to the avatar). */
|
|
11
|
+
name: string;
|
|
12
|
+
/** Optional secondary line. Hidden when `collapsed`. */
|
|
13
|
+
email?: string;
|
|
14
|
+
/** Initials shown by AvatarFallback when no image is provided. */
|
|
15
|
+
fallback?: string;
|
|
16
|
+
/** Avatar image src. */
|
|
17
|
+
imageSrc?: string;
|
|
18
|
+
/** When true, renders only the avatar without name + chevron. */
|
|
19
|
+
collapsed?: boolean;
|
|
20
|
+
/** Set to false to hide the trailing ChevronDown affordance. */
|
|
21
|
+
chevron?: boolean;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export const UserAvatarChip = React.forwardRef<HTMLButtonElement, UserAvatarChipProps>(
|
|
25
|
+
(
|
|
26
|
+
{ name, email, fallback, imageSrc, collapsed = false, chevron = true, className, ...props },
|
|
27
|
+
ref,
|
|
28
|
+
) => {
|
|
29
|
+
const initials =
|
|
30
|
+
fallback ??
|
|
31
|
+
name
|
|
32
|
+
.split(" ")
|
|
33
|
+
.map((part) => part[0])
|
|
34
|
+
.filter(Boolean)
|
|
35
|
+
.slice(0, 2)
|
|
36
|
+
.join("")
|
|
37
|
+
.toUpperCase();
|
|
38
|
+
return (
|
|
39
|
+
<button
|
|
40
|
+
ref={ref}
|
|
41
|
+
type="button"
|
|
42
|
+
aria-label={collapsed ? name : undefined}
|
|
43
|
+
className={cn(
|
|
44
|
+
"inline-flex items-center gap-2 rounded-full border border-border bg-card text-[13px] font-medium text-foreground transition-colors hover:bg-accent",
|
|
45
|
+
collapsed ? "p-1" : "py-1 pl-1 pr-3",
|
|
46
|
+
className,
|
|
47
|
+
)}
|
|
48
|
+
{...props}
|
|
49
|
+
>
|
|
50
|
+
<Avatar className="h-7 w-7">
|
|
51
|
+
{imageSrc && <AvatarImage src={imageSrc} alt={name} />}
|
|
52
|
+
<AvatarFallback className="text-[11px] font-semibold">{initials}</AvatarFallback>
|
|
53
|
+
</Avatar>
|
|
54
|
+
{!collapsed && (
|
|
55
|
+
<>
|
|
56
|
+
<div className="flex flex-col items-start leading-tight">
|
|
57
|
+
<span className="truncate">{name}</span>
|
|
58
|
+
{email && (
|
|
59
|
+
<span className="truncate text-[11px] font-normal text-muted-foreground">
|
|
60
|
+
{email}
|
|
61
|
+
</span>
|
|
62
|
+
)}
|
|
63
|
+
</div>
|
|
64
|
+
{chevron && <ChevronDown className="h-3 w-3 text-muted-foreground" aria-hidden />}
|
|
65
|
+
</>
|
|
66
|
+
)}
|
|
67
|
+
</button>
|
|
68
|
+
);
|
|
69
|
+
},
|
|
70
|
+
);
|
|
71
|
+
UserAvatarChip.displayName = "UserAvatarChip";
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
# Organisms
|
|
2
|
+
|
|
3
|
+
Stateful surfaces. Compositions of atoms + molecules that own interactive
|
|
4
|
+
state (open/close, selection, form state) or complete complex UX.
|
|
5
|
+
|
|
6
|
+
**Can import**: `tokens/`, `lib/utils`, `atoms/`, `molecules/`, React.
|
|
7
|
+
|
|
8
|
+
**Cannot import**: anything from `templates/`.
|
|
9
|
+
|
|
10
|
+
Organisms are reusable — they don't know about specific app routes or domain
|
|
11
|
+
data. `DataTable` is an organism; `IdentitiesTable` (which knows how to render
|
|
12
|
+
a `Kratos.Identity`) is app-specific and belongs in that app's `features/`.
|
|
13
|
+
|
|
14
|
+
See [CONTRIBUTING.md](../../../CONTRIBUTING.md) for the full atomic-design rules.
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import * as AccordionPrimitive from "@radix-ui/react-accordion";
|
|
4
|
+
import { ChevronDown } from "lucide-react";
|
|
5
|
+
import * as React from "react";
|
|
6
|
+
|
|
7
|
+
import { cn } from "../../lib/utils";
|
|
8
|
+
|
|
9
|
+
export interface AccordionProps {
|
|
10
|
+
/**
|
|
11
|
+
* Selection mode. `"single"` allows one item open at a time;
|
|
12
|
+
* `"multiple"` allows multiple items open simultaneously.
|
|
13
|
+
*/
|
|
14
|
+
type: "single" | "multiple";
|
|
15
|
+
/**
|
|
16
|
+
* Controlled value. For `type="single"` it's a string (id of the open
|
|
17
|
+
* item); for `type="multiple"` it's a string array.
|
|
18
|
+
*/
|
|
19
|
+
value?: string | string[];
|
|
20
|
+
/** Initial value for uncontrolled usage. */
|
|
21
|
+
defaultValue?: string | string[];
|
|
22
|
+
/** Fires when the user opens/closes an item. */
|
|
23
|
+
onValueChange?: (value: string & string[]) => void;
|
|
24
|
+
/**
|
|
25
|
+
* For `type="single"` only — when true, an open item can be collapsed
|
|
26
|
+
* by clicking it again.
|
|
27
|
+
* @default false
|
|
28
|
+
*/
|
|
29
|
+
collapsible?: boolean;
|
|
30
|
+
/**
|
|
31
|
+
* Disable the entire accordion.
|
|
32
|
+
* @default false
|
|
33
|
+
*/
|
|
34
|
+
disabled?: boolean;
|
|
35
|
+
/**
|
|
36
|
+
* Reading direction. Affects keyboard arrow navigation.
|
|
37
|
+
* @default "ltr"
|
|
38
|
+
*/
|
|
39
|
+
dir?: "ltr" | "rtl";
|
|
40
|
+
/**
|
|
41
|
+
* Layout direction.
|
|
42
|
+
* @default "vertical"
|
|
43
|
+
*/
|
|
44
|
+
orientation?: "vertical" | "horizontal";
|
|
45
|
+
/**
|
|
46
|
+
* Render as a Radix Slot.
|
|
47
|
+
* @default false
|
|
48
|
+
*/
|
|
49
|
+
asChild?: boolean;
|
|
50
|
+
/** A list of `<AccordionItem>`s. */
|
|
51
|
+
children?: React.ReactNode;
|
|
52
|
+
className?: string;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
const Accordion = AccordionPrimitive.Root as React.ForwardRefExoticComponent<
|
|
56
|
+
AccordionProps & React.RefAttributes<HTMLDivElement>
|
|
57
|
+
>;
|
|
58
|
+
|
|
59
|
+
export interface AccordionItemProps
|
|
60
|
+
extends React.ComponentPropsWithoutRef<typeof AccordionPrimitive.Item> {
|
|
61
|
+
/** Required — unique value identifying this item. */
|
|
62
|
+
value: string;
|
|
63
|
+
/**
|
|
64
|
+
* Disable only this item.
|
|
65
|
+
* @default false
|
|
66
|
+
*/
|
|
67
|
+
disabled?: boolean;
|
|
68
|
+
/**
|
|
69
|
+
* Render as a Radix Slot.
|
|
70
|
+
* @default false
|
|
71
|
+
*/
|
|
72
|
+
asChild?: boolean;
|
|
73
|
+
/** A `<AccordionTrigger>` + `<AccordionContent>`. */
|
|
74
|
+
children?: React.ReactNode;
|
|
75
|
+
className?: string;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
const AccordionItem = React.forwardRef<
|
|
79
|
+
React.ElementRef<typeof AccordionPrimitive.Item>,
|
|
80
|
+
AccordionItemProps
|
|
81
|
+
>(({ className, ...props }, ref) => (
|
|
82
|
+
<AccordionPrimitive.Item ref={ref} className={cn("border-b", className)} {...props} />
|
|
83
|
+
));
|
|
84
|
+
AccordionItem.displayName = "AccordionItem";
|
|
85
|
+
|
|
86
|
+
export interface AccordionTriggerProps
|
|
87
|
+
extends React.ComponentPropsWithoutRef<typeof AccordionPrimitive.Trigger> {
|
|
88
|
+
/**
|
|
89
|
+
* Render as a Radix Slot.
|
|
90
|
+
* @default false
|
|
91
|
+
*/
|
|
92
|
+
asChild?: boolean;
|
|
93
|
+
/** Trigger label — typically a section heading. */
|
|
94
|
+
children?: React.ReactNode;
|
|
95
|
+
className?: string;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
const AccordionTrigger = React.forwardRef<
|
|
99
|
+
React.ElementRef<typeof AccordionPrimitive.Trigger>,
|
|
100
|
+
AccordionTriggerProps
|
|
101
|
+
>(({ className, children, ...props }, ref) => (
|
|
102
|
+
<AccordionPrimitive.Header className="flex">
|
|
103
|
+
<AccordionPrimitive.Trigger
|
|
104
|
+
ref={ref}
|
|
105
|
+
className={cn(
|
|
106
|
+
"flex flex-1 items-center justify-between py-4 text-sm font-medium transition-all hover:underline text-left [&[data-state=open]>svg]:rotate-180",
|
|
107
|
+
className,
|
|
108
|
+
)}
|
|
109
|
+
{...props}
|
|
110
|
+
>
|
|
111
|
+
{children}
|
|
112
|
+
<ChevronDown className="h-4 w-4 shrink-0 text-muted-foreground transition-transform duration-200" />
|
|
113
|
+
</AccordionPrimitive.Trigger>
|
|
114
|
+
</AccordionPrimitive.Header>
|
|
115
|
+
));
|
|
116
|
+
AccordionTrigger.displayName = AccordionPrimitive.Trigger.displayName;
|
|
117
|
+
|
|
118
|
+
export interface AccordionContentProps
|
|
119
|
+
extends React.ComponentPropsWithoutRef<typeof AccordionPrimitive.Content> {
|
|
120
|
+
/**
|
|
121
|
+
* Force the content to mount even when collapsed.
|
|
122
|
+
* @default false
|
|
123
|
+
*/
|
|
124
|
+
forceMount?: true;
|
|
125
|
+
/**
|
|
126
|
+
* Render as a Radix Slot.
|
|
127
|
+
* @default false
|
|
128
|
+
*/
|
|
129
|
+
asChild?: boolean;
|
|
130
|
+
/** Item body. */
|
|
131
|
+
children?: React.ReactNode;
|
|
132
|
+
className?: string;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
const AccordionContent = React.forwardRef<
|
|
136
|
+
React.ElementRef<typeof AccordionPrimitive.Content>,
|
|
137
|
+
AccordionContentProps
|
|
138
|
+
>(({ className, children, ...props }, ref) => (
|
|
139
|
+
<AccordionPrimitive.Content
|
|
140
|
+
ref={ref}
|
|
141
|
+
className="overflow-hidden text-sm data-[state=closed]:animate-accordion-up data-[state=open]:animate-accordion-down"
|
|
142
|
+
{...props}
|
|
143
|
+
>
|
|
144
|
+
<div className={cn("pb-4 pt-0", className)}>{children}</div>
|
|
145
|
+
</AccordionPrimitive.Content>
|
|
146
|
+
));
|
|
147
|
+
AccordionContent.displayName = AccordionPrimitive.Content.displayName;
|
|
148
|
+
|
|
149
|
+
export { Accordion, AccordionContent, AccordionItem, AccordionTrigger };
|