@nikala-ui/core 0.9.11 → 0.10.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/package.json +1 -1
- package/registry/aspect-ratio.json +17 -0
- package/registry/button.json +4 -1
- package/registry/collapsible.json +18 -0
- package/registry/combobox.json +4 -1
- package/registry/command.json +3 -2
- package/registry/context-menu.json +24 -0
- package/registry/create-form.json +1 -1
- package/registry/dialog.json +4 -1
- package/registry/dropdown-menu.json +4 -1
- package/registry/empty.json +17 -0
- package/registry/field.json +20 -0
- package/registry/form-message.json +16 -0
- package/registry/form.json +17 -0
- package/registry/icon-button.json +20 -0
- package/registry/index.json +191 -1
- package/registry/number-input.json +24 -0
- package/registry/resizable.json +21 -0
- package/registry/scroll-area.json +21 -0
- package/registry/select.json +4 -1
- package/registry/sheet.json +4 -1
- package/registry/spinner.json +18 -0
- package/registry/status.json +18 -0
- package/registry/theme-manager.json +1 -1
- package/registry/toggle.json +18 -0
- package/src/registry/components/ui/aspect-ratio.tsx +31 -0
- package/src/registry/components/ui/button.tsx +18 -3
- package/src/registry/components/ui/collapsible.tsx +73 -0
- package/src/registry/components/ui/combobox.tsx +23 -84
- package/src/registry/components/ui/command.tsx +154 -66
- package/src/registry/components/ui/context-menu.tsx +192 -0
- package/src/registry/components/ui/dialog.tsx +39 -44
- package/src/registry/components/ui/dropdown-menu.tsx +40 -45
- package/src/registry/components/ui/empty.tsx +83 -0
- package/src/registry/components/ui/field.tsx +67 -0
- package/src/registry/components/ui/form-message.tsx +36 -0
- package/src/registry/components/ui/form.tsx +21 -0
- package/src/registry/components/ui/icon-button.tsx +34 -0
- package/src/registry/components/ui/number-input.tsx +150 -0
- package/src/registry/components/ui/resizable.tsx +193 -0
- package/src/registry/components/ui/scroll-area.tsx +218 -0
- package/src/registry/components/ui/select.tsx +22 -16
- package/src/registry/components/ui/sheet.tsx +62 -63
- package/src/registry/components/ui/spinner.tsx +41 -0
- package/src/registry/components/ui/status.tsx +119 -0
- package/src/registry/components/ui/theme-toggle.tsx +6 -4
- package/src/registry/components/ui/toggle.tsx +101 -0
- package/src/registry/metadata.ts +84 -2
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
import { splitProps, type Component, type JSX, type ValidComponent } from "solid-js";
|
|
2
|
+
import * as ContextMenuPrimitive from "@kobalte/core/context-menu";
|
|
3
|
+
import type { PolymorphicProps } from "@kobalte/core/polymorphic";
|
|
4
|
+
import { createClickOutside } from "@nikala-ui/hooks";
|
|
5
|
+
import { ScrollArea } from "./scroll-area";
|
|
6
|
+
import { Separator } from "./separator";
|
|
7
|
+
import { Kbd } from "./kbd";
|
|
8
|
+
import { cn } from "@/lib/cn";
|
|
9
|
+
|
|
10
|
+
export type ContextMenuRootProps = ContextMenuPrimitive.ContextMenuRootProps;
|
|
11
|
+
|
|
12
|
+
export const ContextMenu: Component<ContextMenuRootProps> = (props) => {
|
|
13
|
+
return <ContextMenuPrimitive.Root {...props} />;
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
export const ContextMenuTrigger = ContextMenuPrimitive.Trigger;
|
|
17
|
+
export const ContextMenuGroup = ContextMenuPrimitive.Group;
|
|
18
|
+
export const ContextMenuSub = ContextMenuPrimitive.Sub;
|
|
19
|
+
|
|
20
|
+
export type ContextMenuSubTriggerProps<T extends ValidComponent = "div"> =
|
|
21
|
+
ContextMenuPrimitive.ContextMenuSubTriggerProps<T> & {
|
|
22
|
+
class?: string;
|
|
23
|
+
children?: JSX.Element;
|
|
24
|
+
inset?: boolean;
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
export const ContextMenuSubTrigger = <T extends ValidComponent = "div">(
|
|
28
|
+
props: PolymorphicProps<T, ContextMenuSubTriggerProps<T>>
|
|
29
|
+
) => {
|
|
30
|
+
const [local, rest] = splitProps(props as ContextMenuSubTriggerProps, ["class", "children", "inset"]);
|
|
31
|
+
|
|
32
|
+
return (
|
|
33
|
+
<ContextMenuPrimitive.SubTrigger
|
|
34
|
+
class={cn(
|
|
35
|
+
"flex cursor-pointer select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none focus:bg-accent focus:text-accent-foreground data-[state=open]:bg-accent data-[state=open]:text-accent-foreground text-foreground",
|
|
36
|
+
local.inset && "pl-8",
|
|
37
|
+
local.class
|
|
38
|
+
)}
|
|
39
|
+
{...(rest as any)}
|
|
40
|
+
>
|
|
41
|
+
{local.children}
|
|
42
|
+
<svg class="ml-auto h-4 w-4" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
|
43
|
+
<path stroke-linecap="round" stroke-linejoin="round" d="M9 5l7 7-7 7" />
|
|
44
|
+
</svg>
|
|
45
|
+
</ContextMenuPrimitive.SubTrigger>
|
|
46
|
+
);
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
export type ContextMenuSubContentProps<T extends ValidComponent = "div"> =
|
|
50
|
+
ContextMenuPrimitive.ContextMenuSubContentProps<T> & {
|
|
51
|
+
class?: string;
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
export const ContextMenuSubContent = <T extends ValidComponent = "div">(
|
|
55
|
+
props: PolymorphicProps<T, ContextMenuSubContentProps<T>>
|
|
56
|
+
) => {
|
|
57
|
+
const [local, rest] = splitProps(props as ContextMenuSubContentProps, ["class"]);
|
|
58
|
+
|
|
59
|
+
return (
|
|
60
|
+
<ContextMenuPrimitive.Portal>
|
|
61
|
+
<ContextMenuPrimitive.SubContent
|
|
62
|
+
class={cn(
|
|
63
|
+
"z-50 min-w-[8rem] overflow-hidden rounded-md border border-border bg-popover p-1 text-popover-foreground shadow-md transition-all animate-in fade-in-80 slide-in-from-top-1",
|
|
64
|
+
local.class
|
|
65
|
+
)}
|
|
66
|
+
{...(rest as any)}
|
|
67
|
+
/>
|
|
68
|
+
</ContextMenuPrimitive.Portal>
|
|
69
|
+
);
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
export type ContextMenuContentProps<T extends ValidComponent = "div"> =
|
|
73
|
+
ContextMenuPrimitive.ContextMenuContentProps<T> & {
|
|
74
|
+
class?: string;
|
|
75
|
+
ref?: (el: HTMLElement) => void;
|
|
76
|
+
children?: JSX.Element;
|
|
77
|
+
};
|
|
78
|
+
|
|
79
|
+
export const ContextMenuContent = <T extends ValidComponent = "div">(
|
|
80
|
+
props: PolymorphicProps<T, ContextMenuContentProps<T>>
|
|
81
|
+
) => {
|
|
82
|
+
const [local, rest] = splitProps(props as ContextMenuContentProps, ["class", "ref", "children"]);
|
|
83
|
+
let menuRef: HTMLElement | undefined;
|
|
84
|
+
|
|
85
|
+
createClickOutside({
|
|
86
|
+
target: () => menuRef,
|
|
87
|
+
onInteractOutside: () => {
|
|
88
|
+
// Automatic portal dismiss on outside click
|
|
89
|
+
},
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
return (
|
|
93
|
+
<ContextMenuPrimitive.Portal>
|
|
94
|
+
<ContextMenuPrimitive.Content
|
|
95
|
+
ref={(el) => {
|
|
96
|
+
menuRef = el;
|
|
97
|
+
if (typeof local.ref === "function") local.ref(el);
|
|
98
|
+
}}
|
|
99
|
+
class={cn(
|
|
100
|
+
"z-50 min-w-[8rem] rounded-md border border-border bg-popover text-popover-foreground shadow-md transition-all animate-in fade-in-80 slide-in-from-top-1 max-h-72 flex flex-col",
|
|
101
|
+
local.class
|
|
102
|
+
)}
|
|
103
|
+
{...(rest as any)}
|
|
104
|
+
>
|
|
105
|
+
<ScrollArea class="max-h-72 w-full rounded-[inherit]">
|
|
106
|
+
<div class="p-1">
|
|
107
|
+
{local.children}
|
|
108
|
+
</div>
|
|
109
|
+
</ScrollArea>
|
|
110
|
+
</ContextMenuPrimitive.Content>
|
|
111
|
+
</ContextMenuPrimitive.Portal>
|
|
112
|
+
);
|
|
113
|
+
};
|
|
114
|
+
|
|
115
|
+
export type ContextMenuItemProps<T extends ValidComponent = "div"> =
|
|
116
|
+
ContextMenuPrimitive.ContextMenuItemProps<T> & {
|
|
117
|
+
class?: string;
|
|
118
|
+
inset?: boolean;
|
|
119
|
+
};
|
|
120
|
+
|
|
121
|
+
export const ContextMenuItem = <T extends ValidComponent = "div">(
|
|
122
|
+
props: PolymorphicProps<T, ContextMenuItemProps<T>>
|
|
123
|
+
) => {
|
|
124
|
+
const [local, rest] = splitProps(props as ContextMenuItemProps, ["class", "inset"]);
|
|
125
|
+
|
|
126
|
+
return (
|
|
127
|
+
<ContextMenuPrimitive.Item
|
|
128
|
+
class={cn(
|
|
129
|
+
"relative flex cursor-pointer select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none transition-colors focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50 text-foreground",
|
|
130
|
+
local.inset && "pl-8",
|
|
131
|
+
local.class
|
|
132
|
+
)}
|
|
133
|
+
{...(rest as any)}
|
|
134
|
+
/>
|
|
135
|
+
);
|
|
136
|
+
};
|
|
137
|
+
|
|
138
|
+
export type ContextMenuCheckboxItemProps<T extends ValidComponent = "div"> =
|
|
139
|
+
ContextMenuPrimitive.ContextMenuCheckboxItemProps<T> & {
|
|
140
|
+
class?: string;
|
|
141
|
+
children?: JSX.Element;
|
|
142
|
+
checked?: boolean;
|
|
143
|
+
};
|
|
144
|
+
|
|
145
|
+
export const ContextMenuCheckboxItem = <T extends ValidComponent = "div">(
|
|
146
|
+
props: PolymorphicProps<T, ContextMenuCheckboxItemProps<T>>
|
|
147
|
+
) => {
|
|
148
|
+
const [local, rest] = splitProps(props as ContextMenuCheckboxItemProps, ["class", "children", "checked"]);
|
|
149
|
+
|
|
150
|
+
return (
|
|
151
|
+
<ContextMenuPrimitive.CheckboxItem
|
|
152
|
+
checked={local.checked}
|
|
153
|
+
class={cn(
|
|
154
|
+
"relative flex cursor-pointer select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none transition-colors focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50 text-foreground",
|
|
155
|
+
local.class
|
|
156
|
+
)}
|
|
157
|
+
{...(rest as any)}
|
|
158
|
+
>
|
|
159
|
+
<span class="absolute left-2 flex h-3.5 w-3.5 items-center justify-center">
|
|
160
|
+
<ContextMenuPrimitive.ItemIndicator>
|
|
161
|
+
<svg class="h-4 w-4" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
|
162
|
+
<path stroke-linecap="round" stroke-linejoin="round" d="M5 13l4 4L19 7" />
|
|
163
|
+
</svg>
|
|
164
|
+
</ContextMenuPrimitive.ItemIndicator>
|
|
165
|
+
</span>
|
|
166
|
+
{local.children}
|
|
167
|
+
</ContextMenuPrimitive.CheckboxItem>
|
|
168
|
+
);
|
|
169
|
+
};
|
|
170
|
+
|
|
171
|
+
export interface ContextMenuShortcutProps extends JSX.HTMLAttributes<HTMLSpanElement> {
|
|
172
|
+
class?: string;
|
|
173
|
+
children?: JSX.Element;
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
export const ContextMenuShortcut: Component<ContextMenuShortcutProps> = (props) => {
|
|
177
|
+
const [local, rest] = splitProps(props, ["class", "children"]);
|
|
178
|
+
|
|
179
|
+
return (
|
|
180
|
+
<span class={cn("ml-auto text-xs tracking-widest text-muted-foreground", local.class)} {...rest}>
|
|
181
|
+
<Kbd size="sm">{local.children}</Kbd>
|
|
182
|
+
</span>
|
|
183
|
+
);
|
|
184
|
+
};
|
|
185
|
+
|
|
186
|
+
export interface ContextMenuSeparatorProps {
|
|
187
|
+
class?: string;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
export const ContextMenuSeparator: Component<ContextMenuSeparatorProps> = (props) => {
|
|
191
|
+
return <Separator class={cn("-mx-1 my-1 h-px bg-border", props.class)} />;
|
|
192
|
+
};
|
|
@@ -1,28 +1,30 @@
|
|
|
1
1
|
import { splitProps, type Component, type JSX, type ValidComponent, Show } from "solid-js";
|
|
2
2
|
import * as DialogPrimitive from "@kobalte/core/dialog";
|
|
3
3
|
import type { PolymorphicProps } from "@kobalte/core/polymorphic";
|
|
4
|
+
import { ScrollArea } from "./scroll-area";
|
|
4
5
|
import { cn } from "@/lib/cn";
|
|
5
6
|
|
|
6
7
|
export type DialogRootProps = DialogPrimitive.DialogRootProps;
|
|
7
8
|
|
|
8
9
|
/**
|
|
9
|
-
* Root Dialog
|
|
10
|
+
* Root Dialog container managing state and context.
|
|
10
11
|
*/
|
|
11
12
|
export const Dialog: Component<DialogRootProps> = (props) => {
|
|
12
13
|
return <DialogPrimitive.Root {...props} />;
|
|
13
14
|
};
|
|
14
15
|
|
|
15
16
|
export const DialogTrigger = DialogPrimitive.Trigger;
|
|
17
|
+
export const DialogClose = DialogPrimitive.CloseButton;
|
|
16
18
|
|
|
17
19
|
export type DialogOverlayProps<T extends ValidComponent = "div"> =
|
|
18
20
|
DialogPrimitive.DialogOverlayProps<T> & {
|
|
19
|
-
/** Whether to apply background blur
|
|
21
|
+
/** Whether to apply background backdrop blur (default: true) */
|
|
20
22
|
blur?: boolean;
|
|
21
23
|
class?: string;
|
|
22
24
|
};
|
|
23
25
|
|
|
24
26
|
/**
|
|
25
|
-
*
|
|
27
|
+
* Darkened background overlay behind open dialog.
|
|
26
28
|
*/
|
|
27
29
|
export const DialogOverlay = <T extends ValidComponent = "div">(
|
|
28
30
|
props: PolymorphicProps<T, DialogOverlayProps<T>>
|
|
@@ -32,8 +34,8 @@ export const DialogOverlay = <T extends ValidComponent = "div">(
|
|
|
32
34
|
return (
|
|
33
35
|
<DialogPrimitive.Overlay
|
|
34
36
|
class={cn(
|
|
35
|
-
"fixed inset-0 z-50
|
|
36
|
-
local.blur !== false
|
|
37
|
+
"fixed inset-0 z-50 transition-all duration-200 data-expanded:animate-in data-closed:animate-out data-[closed]:fade-out-0 data-[expanded]:fade-in-0",
|
|
38
|
+
local.blur !== false ? "bg-black/80 backdrop-blur-sm" : "bg-black/80",
|
|
37
39
|
local.class
|
|
38
40
|
)}
|
|
39
41
|
{...(rest as any)}
|
|
@@ -95,14 +97,18 @@ export const DialogContent = <T extends ValidComponent = "div">(
|
|
|
95
97
|
onPointerDownOutside={handlePointerDownOutside}
|
|
96
98
|
onInteractOutside={handleInteractOutside}
|
|
97
99
|
class={cn(
|
|
98
|
-
"fixed left-[50%] top-[50%] z-50 grid w-full max-w-lg translate-x-[-50%] translate-y-[-50%]
|
|
100
|
+
"fixed left-[50%] top-[50%] z-50 grid w-full max-w-lg translate-x-[-50%] translate-y-[-50%] border border-border bg-popover shadow-lg duration-200 data-expanded:animate-in data-closed:animate-out data-[closed]:fade-out-0 data-[expanded]:fade-in-0 data-closed:zoom-out-95 data-expanded:zoom-in-95 data-[closed]:slide-out-to-left-1/2 data-[closed]:slide-out-to-top-[48%] data-[expanded]:slide-in-from-left-1/2 data-[expanded]:slide-in-from-top-[48%] sm:rounded-lg text-card-foreground overflow-hidden max-h-[80vh]",
|
|
99
101
|
local.class
|
|
100
102
|
)}
|
|
101
103
|
{...(rest as any)}
|
|
102
104
|
>
|
|
103
|
-
|
|
105
|
+
<ScrollArea class="max-h-[80vh] w-full">
|
|
106
|
+
<div class="p-6 space-y-4">
|
|
107
|
+
{local.children}
|
|
108
|
+
</div>
|
|
109
|
+
</ScrollArea>
|
|
104
110
|
<Show when={local.showCloseButton !== false}>
|
|
105
|
-
<DialogPrimitive.CloseButton class="absolute right-4 top-4 rounded-sm opacity-70 ring-offset-background transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:pointer-events-none data-expanded:bg-accent data-expanded:text-muted-foreground cursor-pointer">
|
|
111
|
+
<DialogPrimitive.CloseButton class="absolute right-4 top-4 rounded-sm opacity-70 ring-offset-background transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:pointer-events-none data-expanded:bg-accent data-expanded:text-muted-foreground cursor-pointer z-50">
|
|
106
112
|
<svg class="h-4 w-4" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
|
107
113
|
<path stroke-linecap="round" stroke-linejoin="round" d="M6 18L18 6M6 6l12 12" />
|
|
108
114
|
</svg>
|
|
@@ -118,9 +124,6 @@ export interface DialogHeaderProps extends JSX.HTMLAttributes<HTMLDivElement> {
|
|
|
118
124
|
class?: string;
|
|
119
125
|
}
|
|
120
126
|
|
|
121
|
-
/**
|
|
122
|
-
* Dialog top header container.
|
|
123
|
-
*/
|
|
124
127
|
export const DialogHeader: Component<DialogHeaderProps> = (props) => {
|
|
125
128
|
const [local, rest] = splitProps(props, ["class"]);
|
|
126
129
|
|
|
@@ -136,60 +139,52 @@ export interface DialogFooterProps extends JSX.HTMLAttributes<HTMLDivElement> {
|
|
|
136
139
|
class?: string;
|
|
137
140
|
}
|
|
138
141
|
|
|
139
|
-
/**
|
|
140
|
-
* Dialog bottom action buttons area.
|
|
141
|
-
*/
|
|
142
142
|
export const DialogFooter: Component<DialogFooterProps> = (props) => {
|
|
143
143
|
const [local, rest] = splitProps(props, ["class"]);
|
|
144
144
|
|
|
145
145
|
return (
|
|
146
146
|
<div
|
|
147
|
-
class={cn(
|
|
147
|
+
class={cn(
|
|
148
|
+
"flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2 pt-4",
|
|
149
|
+
local.class
|
|
150
|
+
)}
|
|
148
151
|
{...rest}
|
|
149
152
|
/>
|
|
150
153
|
);
|
|
151
154
|
};
|
|
152
155
|
|
|
153
|
-
export
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
156
|
+
export interface DialogTitleProps {
|
|
157
|
+
class?: string;
|
|
158
|
+
children?: JSX.Element;
|
|
159
|
+
}
|
|
157
160
|
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
*/
|
|
161
|
-
export const DialogTitle = <T extends ValidComponent = "h2">(
|
|
162
|
-
props: PolymorphicProps<T, DialogTitleProps<T>>
|
|
163
|
-
) => {
|
|
164
|
-
const [local, rest] = splitProps(props as DialogTitleProps, ["class"]);
|
|
161
|
+
export const DialogTitle: Component<DialogTitleProps> = (props) => {
|
|
162
|
+
const [local, rest] = splitProps(props, ["class", "children"]);
|
|
165
163
|
|
|
166
164
|
return (
|
|
167
165
|
<DialogPrimitive.Title
|
|
168
166
|
class={cn("text-lg font-semibold leading-none tracking-tight text-foreground", local.class)}
|
|
169
|
-
{...
|
|
170
|
-
|
|
167
|
+
{...rest}
|
|
168
|
+
>
|
|
169
|
+
{local.children}
|
|
170
|
+
</DialogPrimitive.Title>
|
|
171
171
|
);
|
|
172
172
|
};
|
|
173
173
|
|
|
174
|
-
export
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
174
|
+
export interface DialogDescriptionProps {
|
|
175
|
+
class?: string;
|
|
176
|
+
children?: JSX.Element;
|
|
177
|
+
}
|
|
178
178
|
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
*/
|
|
182
|
-
export const DialogDescription = <T extends ValidComponent = "p">(
|
|
183
|
-
props: PolymorphicProps<T, DialogDescriptionProps<T>>
|
|
184
|
-
) => {
|
|
185
|
-
const [local, rest] = splitProps(props as DialogDescriptionProps, ["class"]);
|
|
179
|
+
export const DialogDescription: Component<DialogDescriptionProps> = (props) => {
|
|
180
|
+
const [local, rest] = splitProps(props, ["class", "children"]);
|
|
186
181
|
|
|
187
182
|
return (
|
|
188
183
|
<DialogPrimitive.Description
|
|
189
184
|
class={cn("text-sm text-muted-foreground", local.class)}
|
|
190
|
-
{...
|
|
191
|
-
|
|
185
|
+
{...rest}
|
|
186
|
+
>
|
|
187
|
+
{local.children}
|
|
188
|
+
</DialogPrimitive.Description>
|
|
192
189
|
);
|
|
193
|
-
};
|
|
194
|
-
|
|
195
|
-
export const DialogClose = DialogPrimitive.CloseButton;
|
|
190
|
+
};
|
|
@@ -2,6 +2,7 @@ import { splitProps, type Component, type JSX, type ValidComponent } from "solid
|
|
|
2
2
|
import * as DropdownMenuPrimitive from "@kobalte/core/dropdown-menu";
|
|
3
3
|
import type { PolymorphicProps } from "@kobalte/core/polymorphic";
|
|
4
4
|
import { createClickOutside } from "@nikala-ui/hooks";
|
|
5
|
+
import { ScrollArea } from "./scroll-area";
|
|
5
6
|
import { cn } from "@/lib/cn";
|
|
6
7
|
|
|
7
8
|
export type DropdownMenuRootProps = Omit<
|
|
@@ -87,12 +88,13 @@ export const DropdownMenuSubContent = <T extends ValidComponent = "div">(
|
|
|
87
88
|
export type DropdownMenuContentProps<T extends ValidComponent = "div"> =
|
|
88
89
|
DropdownMenuPrimitive.DropdownMenuContentProps<T> & {
|
|
89
90
|
class?: string;
|
|
91
|
+
children?: JSX.Element;
|
|
90
92
|
};
|
|
91
93
|
|
|
92
94
|
export const DropdownMenuContent = <T extends ValidComponent = "div">(
|
|
93
95
|
props: PolymorphicProps<T, DropdownMenuContentProps<T>>
|
|
94
96
|
) => {
|
|
95
|
-
const [local, rest] = splitProps(props as DropdownMenuContentProps, ["class"]);
|
|
97
|
+
const [local, rest] = splitProps(props as DropdownMenuContentProps, ["class", "children"]);
|
|
96
98
|
let contentRef: HTMLElement | undefined;
|
|
97
99
|
|
|
98
100
|
createClickOutside({
|
|
@@ -111,12 +113,19 @@ export const DropdownMenuContent = <T extends ValidComponent = "div">(
|
|
|
111
113
|
contentRef = el;
|
|
112
114
|
if (typeof (props as any).ref === "function") (props as any).ref(el);
|
|
113
115
|
}}
|
|
116
|
+
{...(rest as any)}
|
|
117
|
+
sideOffset={(rest as any).sideOffset ?? 8}
|
|
114
118
|
class={cn(
|
|
115
|
-
"z-50 min-w-32
|
|
119
|
+
"z-50 min-w-32 overflow-hidden rounded-md border border-border bg-popover text-popover-foreground shadow-md animate-in fade-in-80 max-h-72 flex flex-col mt-1",
|
|
116
120
|
local.class
|
|
117
121
|
)}
|
|
118
|
-
|
|
119
|
-
|
|
122
|
+
>
|
|
123
|
+
<ScrollArea class="max-h-72 w-full rounded-[inherit]">
|
|
124
|
+
<div class="p-1">
|
|
125
|
+
{local.children}
|
|
126
|
+
</div>
|
|
127
|
+
</ScrollArea>
|
|
128
|
+
</DropdownMenuPrimitive.Content>
|
|
120
129
|
</DropdownMenuPrimitive.Portal>
|
|
121
130
|
);
|
|
122
131
|
};
|
|
@@ -125,25 +134,18 @@ export type DropdownMenuItemProps<T extends ValidComponent = "div"> =
|
|
|
125
134
|
DropdownMenuPrimitive.DropdownMenuItemProps<T> & {
|
|
126
135
|
class?: string;
|
|
127
136
|
inset?: boolean;
|
|
128
|
-
variant?: "default" | "destructive";
|
|
129
137
|
};
|
|
130
138
|
|
|
131
139
|
export const DropdownMenuItem = <T extends ValidComponent = "div">(
|
|
132
140
|
props: PolymorphicProps<T, DropdownMenuItemProps<T>>
|
|
133
141
|
) => {
|
|
134
|
-
const [local, rest] = splitProps(props as DropdownMenuItemProps, [
|
|
135
|
-
"class",
|
|
136
|
-
"inset",
|
|
137
|
-
"variant",
|
|
138
|
-
]);
|
|
142
|
+
const [local, rest] = splitProps(props as DropdownMenuItemProps, ["class", "inset"]);
|
|
139
143
|
|
|
140
144
|
return (
|
|
141
145
|
<DropdownMenuPrimitive.Item
|
|
142
146
|
class={cn(
|
|
143
|
-
"relative flex cursor-
|
|
147
|
+
"relative flex cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none transition-colors focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50 text-foreground",
|
|
144
148
|
local.inset && "pl-8",
|
|
145
|
-
local.variant === "destructive" &&
|
|
146
|
-
"text-destructive focus:bg-destructive/15 focus:text-destructive",
|
|
147
149
|
local.class
|
|
148
150
|
)}
|
|
149
151
|
{...(rest as any)}
|
|
@@ -155,24 +157,26 @@ export type DropdownMenuCheckboxItemProps<T extends ValidComponent = "div"> =
|
|
|
155
157
|
DropdownMenuPrimitive.DropdownMenuCheckboxItemProps<T> & {
|
|
156
158
|
class?: string;
|
|
157
159
|
children?: JSX.Element;
|
|
160
|
+
checked?: boolean;
|
|
158
161
|
};
|
|
159
162
|
|
|
160
163
|
export const DropdownMenuCheckboxItem = <T extends ValidComponent = "div">(
|
|
161
164
|
props: PolymorphicProps<T, DropdownMenuCheckboxItemProps<T>>
|
|
162
165
|
) => {
|
|
163
|
-
const [local, rest] = splitProps(props as DropdownMenuCheckboxItemProps, ["class", "children"]);
|
|
166
|
+
const [local, rest] = splitProps(props as DropdownMenuCheckboxItemProps, ["class", "children", "checked"]);
|
|
164
167
|
|
|
165
168
|
return (
|
|
166
169
|
<DropdownMenuPrimitive.CheckboxItem
|
|
170
|
+
checked={local.checked}
|
|
167
171
|
class={cn(
|
|
168
|
-
"relative flex cursor-
|
|
172
|
+
"relative flex cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none transition-colors focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50 text-foreground",
|
|
169
173
|
local.class
|
|
170
174
|
)}
|
|
171
175
|
{...(rest as any)}
|
|
172
176
|
>
|
|
173
177
|
<span class="absolute left-2 flex h-3.5 w-3.5 items-center justify-center">
|
|
174
178
|
<DropdownMenuPrimitive.ItemIndicator>
|
|
175
|
-
<svg class="h-4 w-4
|
|
179
|
+
<svg class="h-4 w-4" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
|
176
180
|
<path stroke-linecap="round" stroke-linejoin="round" d="M5 13l4 4L19 7" />
|
|
177
181
|
</svg>
|
|
178
182
|
</DropdownMenuPrimitive.ItemIndicator>
|
|
@@ -196,14 +200,16 @@ export const DropdownMenuRadioItem = <T extends ValidComponent = "div">(
|
|
|
196
200
|
return (
|
|
197
201
|
<DropdownMenuPrimitive.RadioItem
|
|
198
202
|
class={cn(
|
|
199
|
-
"relative flex cursor-
|
|
203
|
+
"relative flex cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none transition-colors focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50 text-foreground",
|
|
200
204
|
local.class
|
|
201
205
|
)}
|
|
202
206
|
{...(rest as any)}
|
|
203
207
|
>
|
|
204
208
|
<span class="absolute left-2 flex h-3.5 w-3.5 items-center justify-center">
|
|
205
209
|
<DropdownMenuPrimitive.ItemIndicator>
|
|
206
|
-
<
|
|
210
|
+
<svg class="h-2 w-2 fill-current" viewBox="0 0 8 8">
|
|
211
|
+
<circle cx="4" cy="4" r="3" />
|
|
212
|
+
</svg>
|
|
207
213
|
</DropdownMenuPrimitive.ItemIndicator>
|
|
208
214
|
</span>
|
|
209
215
|
{local.children}
|
|
@@ -211,55 +217,44 @@ export const DropdownMenuRadioItem = <T extends ValidComponent = "div">(
|
|
|
211
217
|
);
|
|
212
218
|
};
|
|
213
219
|
|
|
214
|
-
export interface DropdownMenuLabelProps
|
|
220
|
+
export interface DropdownMenuLabelProps {
|
|
215
221
|
class?: string;
|
|
216
222
|
inset?: boolean;
|
|
223
|
+
children?: JSX.Element;
|
|
217
224
|
}
|
|
218
225
|
|
|
219
226
|
export const DropdownMenuLabel: Component<DropdownMenuLabelProps> = (props) => {
|
|
220
|
-
const [local, rest] = splitProps(props, ["class", "inset"]);
|
|
227
|
+
const [local, rest] = splitProps(props, ["class", "inset", "children"]);
|
|
221
228
|
|
|
222
229
|
return (
|
|
223
|
-
<
|
|
224
|
-
class={cn(
|
|
225
|
-
"px-2 py-1.5 text-sm font-semibold text-foreground",
|
|
226
|
-
local.inset && "pl-8",
|
|
227
|
-
local.class
|
|
228
|
-
)}
|
|
230
|
+
<DropdownMenuPrimitive.GroupLabel
|
|
231
|
+
class={cn("px-2 py-1.5 text-sm font-semibold text-foreground", local.inset && "pl-8", local.class)}
|
|
229
232
|
{...rest}
|
|
230
|
-
|
|
233
|
+
>
|
|
234
|
+
{local.children}
|
|
235
|
+
</DropdownMenuPrimitive.GroupLabel>
|
|
231
236
|
);
|
|
232
237
|
};
|
|
233
238
|
|
|
234
|
-
export
|
|
235
|
-
DropdownMenuPrimitive.DropdownMenuSeparatorProps<T> & {
|
|
236
|
-
class?: string;
|
|
237
|
-
};
|
|
238
|
-
|
|
239
|
-
export const DropdownMenuSeparator = <T extends ValidComponent = "hr">(
|
|
240
|
-
props: PolymorphicProps<T, DropdownMenuSeparatorProps<T>>
|
|
241
|
-
) => {
|
|
242
|
-
const [local, rest] = splitProps(props as DropdownMenuSeparatorProps, ["class"]);
|
|
243
|
-
|
|
239
|
+
export const DropdownMenuSeparator: Component<{ class?: string }> = (props) => {
|
|
244
240
|
return (
|
|
245
241
|
<DropdownMenuPrimitive.Separator
|
|
246
|
-
class={cn("-mx-1 my-1 h-px bg-border",
|
|
247
|
-
{...(rest as any)}
|
|
242
|
+
class={cn("-mx-1 my-1 h-px bg-border", props.class)}
|
|
248
243
|
/>
|
|
249
244
|
);
|
|
250
245
|
};
|
|
251
246
|
|
|
252
|
-
export interface DropdownMenuShortcutProps
|
|
247
|
+
export interface DropdownMenuShortcutProps {
|
|
253
248
|
class?: string;
|
|
249
|
+
children?: JSX.Element;
|
|
254
250
|
}
|
|
255
251
|
|
|
256
252
|
export const DropdownMenuShortcut: Component<DropdownMenuShortcutProps> = (props) => {
|
|
257
|
-
const [local, rest] = splitProps(props, ["class"]);
|
|
253
|
+
const [local, rest] = splitProps(props, ["class", "children"]);
|
|
258
254
|
|
|
259
255
|
return (
|
|
260
|
-
<span
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
/>
|
|
256
|
+
<span class={cn("ml-auto text-xs tracking-widest text-muted-foreground", local.class)} {...rest}>
|
|
257
|
+
{local.children}
|
|
258
|
+
</span>
|
|
264
259
|
);
|
|
265
260
|
};
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import { splitProps, type Component, type JSX } from "solid-js";
|
|
2
|
+
import { cn } from "@/lib/cn";
|
|
3
|
+
|
|
4
|
+
export interface EmptyProps extends JSX.HTMLAttributes<HTMLDivElement> {
|
|
5
|
+
class?: string;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
/** A centered layout for empty collections, search results, and initial states. */
|
|
9
|
+
export const Empty: Component<EmptyProps> = (props) => {
|
|
10
|
+
const [local, rest] = splitProps(props, ["class"]);
|
|
11
|
+
|
|
12
|
+
return (
|
|
13
|
+
<div
|
|
14
|
+
class={cn(
|
|
15
|
+
"flex min-h-64 w-full flex-col items-center justify-center rounded-lg border border-dashed border-border bg-card/30 p-6 text-center",
|
|
16
|
+
local.class
|
|
17
|
+
)}
|
|
18
|
+
{...rest}
|
|
19
|
+
/>
|
|
20
|
+
);
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
export interface EmptyIconProps extends JSX.HTMLAttributes<HTMLDivElement> {
|
|
24
|
+
class?: string;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export const EmptyIcon: Component<EmptyIconProps> = (props) => {
|
|
28
|
+
const [local, rest] = splitProps(props, ["class"]);
|
|
29
|
+
|
|
30
|
+
return (
|
|
31
|
+
<div
|
|
32
|
+
aria-hidden="true"
|
|
33
|
+
class={cn(
|
|
34
|
+
"mb-4 flex size-12 items-center justify-center rounded-lg bg-muted text-muted-foreground [&_svg]:size-6",
|
|
35
|
+
local.class
|
|
36
|
+
)}
|
|
37
|
+
{...rest}
|
|
38
|
+
/>
|
|
39
|
+
);
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
export interface EmptyTitleProps extends JSX.HTMLAttributes<HTMLHeadingElement> {
|
|
43
|
+
class?: string;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export const EmptyTitle: Component<EmptyTitleProps> = (props) => {
|
|
47
|
+
const [local, rest] = splitProps(props, ["class"]);
|
|
48
|
+
|
|
49
|
+
return (
|
|
50
|
+
<h3
|
|
51
|
+
class={cn("text-lg font-semibold tracking-tight text-foreground", local.class)}
|
|
52
|
+
{...rest}
|
|
53
|
+
/>
|
|
54
|
+
);
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
export interface EmptyDescriptionProps
|
|
58
|
+
extends JSX.HTMLAttributes<HTMLParagraphElement> {
|
|
59
|
+
class?: string;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
export const EmptyDescription: Component<EmptyDescriptionProps> = (props) => {
|
|
63
|
+
const [local, rest] = splitProps(props, ["class"]);
|
|
64
|
+
|
|
65
|
+
return (
|
|
66
|
+
<p
|
|
67
|
+
class={cn("mt-1 max-w-sm text-sm text-muted-foreground", local.class)}
|
|
68
|
+
{...rest}
|
|
69
|
+
/>
|
|
70
|
+
);
|
|
71
|
+
};
|
|
72
|
+
|
|
73
|
+
export interface EmptyActionProps extends JSX.HTMLAttributes<HTMLDivElement> {
|
|
74
|
+
class?: string;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
export const EmptyAction: Component<EmptyActionProps> = (props) => {
|
|
78
|
+
const [local, rest] = splitProps(props, ["class"]);
|
|
79
|
+
|
|
80
|
+
return (
|
|
81
|
+
<div class={cn("mt-5 flex items-center gap-2", local.class)} {...rest} />
|
|
82
|
+
);
|
|
83
|
+
};
|