@nikala-ui/core 0.11.0 → 0.12.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +20 -0
- package/README.md +97 -20
- package/package.json +43 -2
- package/registry/api-table.json +21 -0
- package/registry/banner.json +1 -1
- package/registry/button.json +1 -1
- package/registry/callout.json +19 -0
- package/registry/checkbox.json +4 -1
- package/registry/code-block.json +26 -0
- package/registry/code-group.json +20 -0
- package/registry/combobox.json +1 -1
- package/registry/command.json +3 -2
- package/registry/component-viewer.json +25 -0
- package/registry/container.json +18 -0
- package/registry/context-menu.json +1 -1
- package/registry/create-app-updater.json +13 -0
- package/registry/create-document-tabs.json +13 -0
- package/registry/create-global-shortcut.json +13 -0
- package/registry/create-tauri-window.json +13 -0
- package/registry/create-tiptap-editor.json +34 -0
- package/registry/dialog.json +1 -1
- package/registry/dropdown-menu.json +3 -2
- package/registry/field.json +1 -1
- package/registry/file-tree.json +21 -0
- package/registry/footer.json +1 -1
- package/registry/form-message.json +3 -2
- package/registry/icon-button.json +1 -1
- package/registry/index.json +336 -5
- package/registry/navbar.json +1 -1
- package/registry/navigation-menu.json +1 -1
- package/registry/number-input.json +1 -1
- package/registry/package-manager-tabs.json +24 -0
- package/registry/pager.json +21 -0
- package/registry/popover.json +4 -1
- package/registry/resizable.json +1 -1
- package/registry/rich-text-editor.json +95 -0
- package/registry/scroll-area.json +1 -1
- package/registry/section-heading.json +21 -0
- package/registry/select.json +3 -2
- package/registry/sheet.json +1 -1
- package/registry/sidebar.json +1 -1
- package/registry/status.json +1 -1
- package/registry/steps.json +20 -0
- package/registry/switch.json +4 -1
- package/registry/table-of-contents.json +23 -0
- package/registry/tabs.json +4 -1
- package/registry/theme-manager.json +6 -5
- package/registry/titlebar-tabs.json +24 -0
- package/registry/titlebar.json +26 -0
- package/registry/toggle-group.json +1 -1
- package/registry/updater-modal.json +26 -0
- package/src/index.ts +48 -0
- package/src/registry/components/ui/api-table.tsx +117 -0
- package/src/registry/components/ui/banner.tsx +0 -2
- package/src/registry/components/ui/button.tsx +1 -1
- package/src/registry/components/ui/callout.tsx +137 -0
- package/src/registry/components/ui/checkbox.tsx +1 -1
- package/src/registry/components/ui/code-block.tsx +326 -0
- package/src/registry/components/ui/code-group.tsx +105 -0
- package/src/registry/components/ui/combobox.tsx +83 -18
- package/src/registry/components/ui/command.tsx +110 -106
- package/src/registry/components/ui/component-viewer.tsx +363 -0
- package/src/registry/components/ui/container.tsx +45 -0
- package/src/registry/components/ui/context-menu.tsx +67 -22
- package/src/registry/components/ui/dialog.tsx +42 -32
- package/src/registry/components/ui/dropdown-menu.tsx +69 -31
- package/src/registry/components/ui/field.tsx +7 -3
- package/src/registry/components/ui/file-tree.tsx +181 -0
- package/src/registry/components/ui/footer.tsx +1 -1
- package/src/registry/components/ui/form-message.tsx +2 -2
- package/src/registry/components/ui/icon-button.tsx +1 -1
- package/src/registry/components/ui/navbar.tsx +18 -11
- package/src/registry/components/ui/navigation-menu.tsx +2 -2
- package/src/registry/components/ui/number-input.tsx +3 -3
- package/src/registry/components/ui/package-manager-tabs.tsx +226 -0
- package/src/registry/components/ui/pager.tsx +102 -0
- package/src/registry/components/ui/popover.tsx +1 -1
- package/src/registry/components/ui/resizable.tsx +3 -1
- package/src/registry/components/ui/rich-text-editor/bubble-menu.tsx +236 -0
- package/src/registry/components/ui/rich-text-editor/editor.tsx +308 -0
- package/src/registry/components/ui/rich-text-editor/extensions.ts +116 -0
- package/src/registry/components/ui/rich-text-editor/footer.tsx +36 -0
- package/src/registry/components/ui/rich-text-editor/image-dialog.tsx +75 -0
- package/src/registry/components/ui/rich-text-editor/index.ts +11 -0
- package/src/registry/components/ui/rich-text-editor/link-dialog.tsx +48 -0
- package/src/registry/components/ui/rich-text-editor/markdown.ts +170 -0
- package/src/registry/components/ui/rich-text-editor/slash-command.tsx +301 -0
- package/src/registry/components/ui/rich-text-editor/table-controls.tsx +68 -0
- package/src/registry/components/ui/rich-text-editor/toolbar.tsx +465 -0
- package/src/registry/components/ui/rich-text-editor/use-editor.ts +231 -0
- package/src/registry/components/ui/scroll-area.tsx +12 -2
- package/src/registry/components/ui/section-heading.tsx +108 -0
- package/src/registry/components/ui/select.tsx +16 -19
- package/src/registry/components/ui/sheet.tsx +58 -53
- package/src/registry/components/ui/sidebar.tsx +4 -4
- package/src/registry/components/ui/status.tsx +7 -5
- package/src/registry/components/ui/steps.tsx +198 -0
- package/src/registry/components/ui/switch.tsx +1 -1
- package/src/registry/components/ui/table-of-contents.tsx +131 -0
- package/src/registry/components/ui/tabs.tsx +1 -1
- package/src/registry/components/ui/theme-toggle.tsx +175 -139
- package/src/registry/components/ui/titlebar-tabs.tsx +773 -0
- package/src/registry/components/ui/titlebar.tsx +468 -0
- package/src/registry/components/ui/toggle-group.tsx +1 -1
- package/src/registry/components/ui/updater-modal.tsx +254 -0
- package/src/registry/metadata.ts +167 -6
- package/src/registry/providers/theme-provider.tsx +16 -8
- package/src/registry/providers/theme-script.tsx +29 -9
- package/src/registry/providers/theme-transitions.ts +81 -50
|
@@ -1,30 +1,29 @@
|
|
|
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 "
|
|
4
|
+
import { ScrollArea } from "@/components/ui/scroll-area";
|
|
5
5
|
import { cn } from "@/lib/cn";
|
|
6
6
|
|
|
7
7
|
export type DialogRootProps = DialogPrimitive.DialogRootProps;
|
|
8
8
|
|
|
9
9
|
/**
|
|
10
|
-
* Root Dialog
|
|
10
|
+
* Root Dialog component managing modal open state.
|
|
11
11
|
*/
|
|
12
12
|
export const Dialog: Component<DialogRootProps> = (props) => {
|
|
13
13
|
return <DialogPrimitive.Root {...props} />;
|
|
14
14
|
};
|
|
15
15
|
|
|
16
16
|
export const DialogTrigger = DialogPrimitive.Trigger;
|
|
17
|
-
export const DialogClose = DialogPrimitive.CloseButton;
|
|
18
17
|
|
|
19
18
|
export type DialogOverlayProps<T extends ValidComponent = "div"> =
|
|
20
19
|
DialogPrimitive.DialogOverlayProps<T> & {
|
|
21
|
-
/** Whether to apply background
|
|
20
|
+
/** Whether to apply background blur effect (default: true) */
|
|
22
21
|
blur?: boolean;
|
|
23
22
|
class?: string;
|
|
24
23
|
};
|
|
25
24
|
|
|
26
25
|
/**
|
|
27
|
-
*
|
|
26
|
+
* Backdrop overlay wrapper with optional backdrop blur styling.
|
|
28
27
|
*/
|
|
29
28
|
export const DialogOverlay = <T extends ValidComponent = "div">(
|
|
30
29
|
props: PolymorphicProps<T, DialogOverlayProps<T>>
|
|
@@ -34,8 +33,8 @@ export const DialogOverlay = <T extends ValidComponent = "div">(
|
|
|
34
33
|
return (
|
|
35
34
|
<DialogPrimitive.Overlay
|
|
36
35
|
class={cn(
|
|
37
|
-
"fixed inset-0 z-50
|
|
38
|
-
local.blur !== false
|
|
36
|
+
"fixed inset-0 z-50 bg-black/80 data-expanded:animate-in data-closed:animate-out data-[closed]:fade-out-0 data-[expanded]:fade-in-0",
|
|
37
|
+
local.blur !== false && "backdrop-blur-sm",
|
|
39
38
|
local.class
|
|
40
39
|
)}
|
|
41
40
|
{...(rest as any)}
|
|
@@ -124,6 +123,9 @@ export interface DialogHeaderProps extends JSX.HTMLAttributes<HTMLDivElement> {
|
|
|
124
123
|
class?: string;
|
|
125
124
|
}
|
|
126
125
|
|
|
126
|
+
/**
|
|
127
|
+
* Dialog top header container.
|
|
128
|
+
*/
|
|
127
129
|
export const DialogHeader: Component<DialogHeaderProps> = (props) => {
|
|
128
130
|
const [local, rest] = splitProps(props, ["class"]);
|
|
129
131
|
|
|
@@ -139,52 +141,60 @@ export interface DialogFooterProps extends JSX.HTMLAttributes<HTMLDivElement> {
|
|
|
139
141
|
class?: string;
|
|
140
142
|
}
|
|
141
143
|
|
|
144
|
+
/**
|
|
145
|
+
* Dialog bottom action buttons area.
|
|
146
|
+
*/
|
|
142
147
|
export const DialogFooter: Component<DialogFooterProps> = (props) => {
|
|
143
148
|
const [local, rest] = splitProps(props, ["class"]);
|
|
144
149
|
|
|
145
150
|
return (
|
|
146
151
|
<div
|
|
147
|
-
class={cn(
|
|
148
|
-
"flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2 pt-4",
|
|
149
|
-
local.class
|
|
150
|
-
)}
|
|
152
|
+
class={cn("flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2", local.class)}
|
|
151
153
|
{...rest}
|
|
152
154
|
/>
|
|
153
155
|
);
|
|
154
156
|
};
|
|
155
157
|
|
|
156
|
-
export
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
}
|
|
158
|
+
export type DialogTitleProps<T extends ValidComponent = "h2"> =
|
|
159
|
+
DialogPrimitive.DialogTitleProps<T> & {
|
|
160
|
+
class?: string;
|
|
161
|
+
};
|
|
160
162
|
|
|
161
|
-
|
|
162
|
-
|
|
163
|
+
/**
|
|
164
|
+
* Dialog title heading.
|
|
165
|
+
*/
|
|
166
|
+
export const DialogTitle = <T extends ValidComponent = "h2">(
|
|
167
|
+
props: PolymorphicProps<T, DialogTitleProps<T>>
|
|
168
|
+
) => {
|
|
169
|
+
const [local, rest] = splitProps(props as DialogTitleProps, ["class"]);
|
|
163
170
|
|
|
164
171
|
return (
|
|
165
172
|
<DialogPrimitive.Title
|
|
166
173
|
class={cn("text-lg font-semibold leading-none tracking-tight text-foreground", local.class)}
|
|
167
|
-
{...rest}
|
|
168
|
-
|
|
169
|
-
{local.children}
|
|
170
|
-
</DialogPrimitive.Title>
|
|
174
|
+
{...(rest as any)}
|
|
175
|
+
/>
|
|
171
176
|
);
|
|
172
177
|
};
|
|
173
178
|
|
|
174
|
-
export
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
}
|
|
179
|
+
export type DialogDescriptionProps<T extends ValidComponent = "p"> =
|
|
180
|
+
DialogPrimitive.DialogDescriptionProps<T> & {
|
|
181
|
+
class?: string;
|
|
182
|
+
};
|
|
178
183
|
|
|
179
|
-
|
|
180
|
-
|
|
184
|
+
/**
|
|
185
|
+
* Dialog subtitle or description text.
|
|
186
|
+
*/
|
|
187
|
+
export const DialogDescription = <T extends ValidComponent = "p">(
|
|
188
|
+
props: PolymorphicProps<T, DialogDescriptionProps<T>>
|
|
189
|
+
) => {
|
|
190
|
+
const [local, rest] = splitProps(props as DialogDescriptionProps, ["class"]);
|
|
181
191
|
|
|
182
192
|
return (
|
|
183
193
|
<DialogPrimitive.Description
|
|
184
194
|
class={cn("text-sm text-muted-foreground", local.class)}
|
|
185
|
-
{...rest}
|
|
186
|
-
|
|
187
|
-
{local.children}
|
|
188
|
-
</DialogPrimitive.Description>
|
|
195
|
+
{...(rest as any)}
|
|
196
|
+
/>
|
|
189
197
|
);
|
|
190
|
-
};
|
|
198
|
+
};
|
|
199
|
+
|
|
200
|
+
export const DialogClose = DialogPrimitive.CloseButton;
|
|
@@ -1,10 +1,12 @@
|
|
|
1
|
-
import { splitProps, type Component, type JSX, type ValidComponent } from "solid-js";
|
|
1
|
+
import { splitProps, type Component, type JSX, type ValidComponent, createContext, useContext } from "solid-js";
|
|
2
2
|
import * as DropdownMenuPrimitive from "@kobalte/core/dropdown-menu";
|
|
3
3
|
import type { PolymorphicProps } from "@kobalte/core/polymorphic";
|
|
4
|
-
import { createClickOutside } from "
|
|
5
|
-
import { ScrollArea } from "
|
|
4
|
+
import { createClickOutside } from "@/hooks/create-click-outside";
|
|
5
|
+
import { ScrollArea } from "@/components/ui/scroll-area";
|
|
6
6
|
import { cn } from "@/lib/cn";
|
|
7
7
|
|
|
8
|
+
const DropdownGroupContext = createContext<boolean>(false);
|
|
9
|
+
|
|
8
10
|
export type DropdownMenuRootProps = Omit<
|
|
9
11
|
DropdownMenuPrimitive.DropdownMenuRootProps,
|
|
10
12
|
"placement"
|
|
@@ -29,7 +31,15 @@ export const DropdownMenu: Component<DropdownMenuRootProps> = (props) => {
|
|
|
29
31
|
};
|
|
30
32
|
|
|
31
33
|
export const DropdownMenuTrigger = DropdownMenuPrimitive.Trigger;
|
|
32
|
-
|
|
34
|
+
|
|
35
|
+
export const DropdownMenuGroup: Component<DropdownMenuPrimitive.DropdownMenuGroupProps> = (props) => {
|
|
36
|
+
return (
|
|
37
|
+
<DropdownGroupContext.Provider value={true}>
|
|
38
|
+
<DropdownMenuPrimitive.Group {...props} />
|
|
39
|
+
</DropdownGroupContext.Provider>
|
|
40
|
+
);
|
|
41
|
+
};
|
|
42
|
+
|
|
33
43
|
export const DropdownMenuSub = DropdownMenuPrimitive.Sub;
|
|
34
44
|
export const DropdownMenuRadioGroup = DropdownMenuPrimitive.RadioGroup;
|
|
35
45
|
|
|
@@ -120,7 +130,7 @@ export const DropdownMenuContent = <T extends ValidComponent = "div">(
|
|
|
120
130
|
local.class
|
|
121
131
|
)}
|
|
122
132
|
>
|
|
123
|
-
<ScrollArea class="max-h-72 w-full
|
|
133
|
+
<ScrollArea class="max-h-72 w-full">
|
|
124
134
|
<div class="p-1">
|
|
125
135
|
{local.children}
|
|
126
136
|
</div>
|
|
@@ -134,18 +144,25 @@ export type DropdownMenuItemProps<T extends ValidComponent = "div"> =
|
|
|
134
144
|
DropdownMenuPrimitive.DropdownMenuItemProps<T> & {
|
|
135
145
|
class?: string;
|
|
136
146
|
inset?: boolean;
|
|
147
|
+
variant?: "default" | "destructive";
|
|
137
148
|
};
|
|
138
149
|
|
|
139
150
|
export const DropdownMenuItem = <T extends ValidComponent = "div">(
|
|
140
151
|
props: PolymorphicProps<T, DropdownMenuItemProps<T>>
|
|
141
152
|
) => {
|
|
142
|
-
const [local, rest] = splitProps(props as DropdownMenuItemProps, [
|
|
153
|
+
const [local, rest] = splitProps(props as DropdownMenuItemProps, [
|
|
154
|
+
"class",
|
|
155
|
+
"inset",
|
|
156
|
+
"variant",
|
|
157
|
+
]);
|
|
143
158
|
|
|
144
159
|
return (
|
|
145
160
|
<DropdownMenuPrimitive.Item
|
|
146
161
|
class={cn(
|
|
147
|
-
"relative flex cursor-
|
|
162
|
+
"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",
|
|
148
163
|
local.inset && "pl-8",
|
|
164
|
+
local.variant === "destructive" &&
|
|
165
|
+
"text-destructive focus:bg-destructive/15 focus:text-destructive",
|
|
149
166
|
local.class
|
|
150
167
|
)}
|
|
151
168
|
{...(rest as any)}
|
|
@@ -157,26 +174,24 @@ export type DropdownMenuCheckboxItemProps<T extends ValidComponent = "div"> =
|
|
|
157
174
|
DropdownMenuPrimitive.DropdownMenuCheckboxItemProps<T> & {
|
|
158
175
|
class?: string;
|
|
159
176
|
children?: JSX.Element;
|
|
160
|
-
checked?: boolean;
|
|
161
177
|
};
|
|
162
178
|
|
|
163
179
|
export const DropdownMenuCheckboxItem = <T extends ValidComponent = "div">(
|
|
164
180
|
props: PolymorphicProps<T, DropdownMenuCheckboxItemProps<T>>
|
|
165
181
|
) => {
|
|
166
|
-
const [local, rest] = splitProps(props as DropdownMenuCheckboxItemProps, ["class", "children"
|
|
182
|
+
const [local, rest] = splitProps(props as DropdownMenuCheckboxItemProps, ["class", "children"]);
|
|
167
183
|
|
|
168
184
|
return (
|
|
169
185
|
<DropdownMenuPrimitive.CheckboxItem
|
|
170
|
-
checked={local.checked}
|
|
171
186
|
class={cn(
|
|
172
|
-
"relative flex cursor-
|
|
187
|
+
"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",
|
|
173
188
|
local.class
|
|
174
189
|
)}
|
|
175
190
|
{...(rest as any)}
|
|
176
191
|
>
|
|
177
192
|
<span class="absolute left-2 flex h-3.5 w-3.5 items-center justify-center">
|
|
178
193
|
<DropdownMenuPrimitive.ItemIndicator>
|
|
179
|
-
<svg class="h-4 w-4" viewBox="0 0 24 24"
|
|
194
|
+
<svg class="h-4 w-4 fill-none stroke-current stroke-2" viewBox="0 0 24 24">
|
|
180
195
|
<path stroke-linecap="round" stroke-linejoin="round" d="M5 13l4 4L19 7" />
|
|
181
196
|
</svg>
|
|
182
197
|
</DropdownMenuPrimitive.ItemIndicator>
|
|
@@ -200,16 +215,14 @@ export const DropdownMenuRadioItem = <T extends ValidComponent = "div">(
|
|
|
200
215
|
return (
|
|
201
216
|
<DropdownMenuPrimitive.RadioItem
|
|
202
217
|
class={cn(
|
|
203
|
-
"relative flex cursor-
|
|
218
|
+
"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",
|
|
204
219
|
local.class
|
|
205
220
|
)}
|
|
206
221
|
{...(rest as any)}
|
|
207
222
|
>
|
|
208
223
|
<span class="absolute left-2 flex h-3.5 w-3.5 items-center justify-center">
|
|
209
224
|
<DropdownMenuPrimitive.ItemIndicator>
|
|
210
|
-
<
|
|
211
|
-
<circle cx="4" cy="4" r="3" />
|
|
212
|
-
</svg>
|
|
225
|
+
<span class="h-2 w-2 rounded-lg bg-current" />
|
|
213
226
|
</DropdownMenuPrimitive.ItemIndicator>
|
|
214
227
|
</span>
|
|
215
228
|
{local.children}
|
|
@@ -217,7 +230,9 @@ export const DropdownMenuRadioItem = <T extends ValidComponent = "div">(
|
|
|
217
230
|
);
|
|
218
231
|
};
|
|
219
232
|
|
|
220
|
-
export
|
|
233
|
+
export const DropdownMenuGroupLabel = DropdownMenuPrimitive.GroupLabel;
|
|
234
|
+
|
|
235
|
+
export interface DropdownMenuLabelProps extends JSX.HTMLAttributes<HTMLDivElement> {
|
|
221
236
|
class?: string;
|
|
222
237
|
inset?: boolean;
|
|
223
238
|
children?: JSX.Element;
|
|
@@ -225,36 +240,59 @@ export interface DropdownMenuLabelProps {
|
|
|
225
240
|
|
|
226
241
|
export const DropdownMenuLabel: Component<DropdownMenuLabelProps> = (props) => {
|
|
227
242
|
const [local, rest] = splitProps(props, ["class", "inset", "children"]);
|
|
243
|
+
const isInsideGroup = useContext(DropdownGroupContext);
|
|
244
|
+
|
|
245
|
+
const classes = () =>
|
|
246
|
+
cn(
|
|
247
|
+
"px-2 py-1.5 text-sm font-semibold text-foreground",
|
|
248
|
+
local.inset && "pl-8",
|
|
249
|
+
local.class
|
|
250
|
+
);
|
|
228
251
|
|
|
229
252
|
return (
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
253
|
+
<>
|
|
254
|
+
{isInsideGroup ? (
|
|
255
|
+
<DropdownMenuPrimitive.GroupLabel class={classes()} {...(rest as any)}>
|
|
256
|
+
{local.children}
|
|
257
|
+
</DropdownMenuPrimitive.GroupLabel>
|
|
258
|
+
) : (
|
|
259
|
+
<div class={classes()} {...rest}>
|
|
260
|
+
{local.children}
|
|
261
|
+
</div>
|
|
262
|
+
)}
|
|
263
|
+
</>
|
|
236
264
|
);
|
|
237
265
|
};
|
|
238
266
|
|
|
239
|
-
export
|
|
267
|
+
export type DropdownMenuSeparatorProps<T extends ValidComponent = "hr"> =
|
|
268
|
+
DropdownMenuPrimitive.DropdownMenuSeparatorProps<T> & {
|
|
269
|
+
class?: string;
|
|
270
|
+
};
|
|
271
|
+
|
|
272
|
+
export const DropdownMenuSeparator = <T extends ValidComponent = "hr">(
|
|
273
|
+
props: PolymorphicProps<T, DropdownMenuSeparatorProps<T>>
|
|
274
|
+
) => {
|
|
275
|
+
const [local, rest] = splitProps(props as DropdownMenuSeparatorProps, ["class"]);
|
|
276
|
+
|
|
240
277
|
return (
|
|
241
278
|
<DropdownMenuPrimitive.Separator
|
|
242
|
-
class={cn("-mx-1 my-1 h-px bg-border",
|
|
279
|
+
class={cn("-mx-1 my-1 h-px bg-border", local.class)}
|
|
280
|
+
{...(rest as any)}
|
|
243
281
|
/>
|
|
244
282
|
);
|
|
245
283
|
};
|
|
246
284
|
|
|
247
|
-
export interface DropdownMenuShortcutProps {
|
|
285
|
+
export interface DropdownMenuShortcutProps extends JSX.HTMLAttributes<HTMLSpanElement> {
|
|
248
286
|
class?: string;
|
|
249
|
-
children?: JSX.Element;
|
|
250
287
|
}
|
|
251
288
|
|
|
252
289
|
export const DropdownMenuShortcut: Component<DropdownMenuShortcutProps> = (props) => {
|
|
253
|
-
const [local, rest] = splitProps(props, ["class"
|
|
290
|
+
const [local, rest] = splitProps(props, ["class"]);
|
|
254
291
|
|
|
255
292
|
return (
|
|
256
|
-
<span
|
|
257
|
-
{local.
|
|
258
|
-
|
|
293
|
+
<span
|
|
294
|
+
class={cn("ml-auto text-xs tracking-widest text-muted-foreground", local.class)}
|
|
295
|
+
{...rest}
|
|
296
|
+
/>
|
|
259
297
|
);
|
|
260
298
|
};
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { splitProps, type Component, type JSX } from "solid-js";
|
|
2
2
|
import { cn } from "@/lib/cn";
|
|
3
|
-
import { Label, type LabelProps } from "
|
|
3
|
+
import { Label, type LabelProps } from "@/components/ui/label";
|
|
4
4
|
|
|
5
5
|
export interface FieldProps extends JSX.HTMLAttributes<HTMLDivElement> {
|
|
6
6
|
class?: string;
|
|
@@ -17,8 +17,9 @@ export const Field: Component<FieldProps> = (props) => {
|
|
|
17
17
|
);
|
|
18
18
|
};
|
|
19
19
|
|
|
20
|
-
export interface FieldLabelProps extends LabelProps {
|
|
20
|
+
export interface FieldLabelProps extends JSX.LabelHTMLAttributes<HTMLLabelElement>, LabelProps {
|
|
21
21
|
class?: string;
|
|
22
|
+
for?: string;
|
|
22
23
|
children?: JSX.Element;
|
|
23
24
|
}
|
|
24
25
|
|
|
@@ -41,7 +42,10 @@ export const FieldDescription: Component<FieldDescriptionProps> = (props) => {
|
|
|
41
42
|
const [local, rest] = splitProps(props, ["class", "children"]);
|
|
42
43
|
|
|
43
44
|
return (
|
|
44
|
-
<p
|
|
45
|
+
<p
|
|
46
|
+
class={cn("text-sm text-muted-foreground", local.class)}
|
|
47
|
+
{...rest}
|
|
48
|
+
>
|
|
45
49
|
{local.children}
|
|
46
50
|
</p>
|
|
47
51
|
);
|
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
import {
|
|
2
|
+
createSignal,
|
|
3
|
+
splitProps,
|
|
4
|
+
Show,
|
|
5
|
+
type JSX,
|
|
6
|
+
type ParentComponent,
|
|
7
|
+
} from "solid-js";
|
|
8
|
+
import {
|
|
9
|
+
Folder,
|
|
10
|
+
FolderOpen,
|
|
11
|
+
File,
|
|
12
|
+
FileCode,
|
|
13
|
+
FileJson,
|
|
14
|
+
FileText,
|
|
15
|
+
ChevronRight,
|
|
16
|
+
} from "lucide-solid";
|
|
17
|
+
import {
|
|
18
|
+
Collapsible,
|
|
19
|
+
CollapsibleTrigger,
|
|
20
|
+
CollapsibleContent,
|
|
21
|
+
} from "@/components/ui/collapsible";
|
|
22
|
+
import { cn } from "@/lib/cn";
|
|
23
|
+
|
|
24
|
+
export interface FileTreeProps extends JSX.HTMLAttributes<HTMLDivElement> {
|
|
25
|
+
class?: string;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Root FileTree container for displaying project directory hierarchies.
|
|
30
|
+
*/
|
|
31
|
+
export const FileTree: ParentComponent<FileTreeProps> = (props) => {
|
|
32
|
+
const [local, rest] = splitProps(props, ["class", "children"]);
|
|
33
|
+
return (
|
|
34
|
+
<div
|
|
35
|
+
class={cn(
|
|
36
|
+
"my-4 w-full rounded-lg border border-border bg-card/60 p-3 font-mono text-sm shadow-2xs select-none",
|
|
37
|
+
local.class
|
|
38
|
+
)}
|
|
39
|
+
{...rest}
|
|
40
|
+
>
|
|
41
|
+
<div class="space-y-0.5">{local.children}</div>
|
|
42
|
+
</div>
|
|
43
|
+
);
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
export interface FileTreeFolderProps {
|
|
47
|
+
/** Folder name */
|
|
48
|
+
name: string;
|
|
49
|
+
/** Initial open state of the folder (default: true) */
|
|
50
|
+
defaultOpen?: boolean;
|
|
51
|
+
/** Controlled open state */
|
|
52
|
+
open?: boolean;
|
|
53
|
+
/** Callback fired when open state changes */
|
|
54
|
+
onOpenChange?: (open: boolean) => void;
|
|
55
|
+
/** Custom folder icon override */
|
|
56
|
+
icon?: JSX.Element;
|
|
57
|
+
class?: string;
|
|
58
|
+
children?: JSX.Element;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Collapsible folder node in the FileTree.
|
|
63
|
+
*/
|
|
64
|
+
export const FileTreeFolder: ParentComponent<FileTreeFolderProps> = (props) => {
|
|
65
|
+
const [local, rest] = splitProps(props, [
|
|
66
|
+
"name",
|
|
67
|
+
"defaultOpen",
|
|
68
|
+
"open",
|
|
69
|
+
"onOpenChange",
|
|
70
|
+
"icon",
|
|
71
|
+
"class",
|
|
72
|
+
"children",
|
|
73
|
+
]);
|
|
74
|
+
|
|
75
|
+
const [isOpen, setIsOpen] = createSignal(local.defaultOpen ?? true);
|
|
76
|
+
|
|
77
|
+
const openState = () => (local.open !== undefined ? local.open : isOpen());
|
|
78
|
+
|
|
79
|
+
const handleToggle = (next: boolean) => {
|
|
80
|
+
if (local.open === undefined) {
|
|
81
|
+
setIsOpen(next);
|
|
82
|
+
}
|
|
83
|
+
local.onOpenChange?.(next);
|
|
84
|
+
};
|
|
85
|
+
|
|
86
|
+
return (
|
|
87
|
+
<Collapsible
|
|
88
|
+
open={openState()}
|
|
89
|
+
onOpenChange={handleToggle}
|
|
90
|
+
class={cn("w-full", local.class)}
|
|
91
|
+
{...rest}
|
|
92
|
+
>
|
|
93
|
+
<CollapsibleTrigger class="group flex w-full items-center justify-start gap-1.5 rounded-md px-1.5 py-1 text-xs text-foreground transition-colors hover:bg-muted/70 cursor-pointer">
|
|
94
|
+
<ChevronRight
|
|
95
|
+
class={cn(
|
|
96
|
+
"size-3.5 shrink-0 text-muted-foreground transition-transform duration-200",
|
|
97
|
+
openState() && "rotate-90 text-foreground"
|
|
98
|
+
)}
|
|
99
|
+
/>
|
|
100
|
+
<Show
|
|
101
|
+
when={local.icon}
|
|
102
|
+
fallback={
|
|
103
|
+
<Show
|
|
104
|
+
when={openState()}
|
|
105
|
+
fallback={<Folder class="size-3.5 shrink-0 text-amber-500/90 dark:text-amber-400" />}
|
|
106
|
+
>
|
|
107
|
+
<FolderOpen class="size-3.5 shrink-0 text-amber-500 dark:text-amber-400" />
|
|
108
|
+
</Show>
|
|
109
|
+
}
|
|
110
|
+
>
|
|
111
|
+
{local.icon}
|
|
112
|
+
</Show>
|
|
113
|
+
<span class="font-medium text-foreground tracking-tight">{local.name}</span>
|
|
114
|
+
</CollapsibleTrigger>
|
|
115
|
+
|
|
116
|
+
<CollapsibleContent class="border-l border-border/60 ml-3.5 pl-3 pt-0.5 space-y-0.5">
|
|
117
|
+
{local.children}
|
|
118
|
+
</CollapsibleContent>
|
|
119
|
+
</Collapsible>
|
|
120
|
+
);
|
|
121
|
+
};
|
|
122
|
+
|
|
123
|
+
export interface FileTreeFileProps extends JSX.HTMLAttributes<HTMLDivElement> {
|
|
124
|
+
/** File name */
|
|
125
|
+
name: string;
|
|
126
|
+
/** Custom file icon override */
|
|
127
|
+
icon?: JSX.Element;
|
|
128
|
+
class?: string;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* Returns a smart default Lucide icon based on file extension.
|
|
133
|
+
*/
|
|
134
|
+
function getFileIcon(filename: string): JSX.Element {
|
|
135
|
+
const ext = filename.split(".").pop()?.toLowerCase();
|
|
136
|
+
switch (ext) {
|
|
137
|
+
case "tsx":
|
|
138
|
+
case "jsx":
|
|
139
|
+
case "ts":
|
|
140
|
+
case "js":
|
|
141
|
+
case "mjs":
|
|
142
|
+
case "rs":
|
|
143
|
+
case "py":
|
|
144
|
+
case "go":
|
|
145
|
+
return <FileCode class="size-3.5 shrink-0 text-sky-500 dark:text-sky-400" />;
|
|
146
|
+
case "json":
|
|
147
|
+
return <FileJson class="size-3.5 shrink-0 text-amber-500 dark:text-amber-400" />;
|
|
148
|
+
case "md":
|
|
149
|
+
case "mdx":
|
|
150
|
+
case "txt":
|
|
151
|
+
return <FileText class="size-3.5 shrink-0 text-emerald-500 dark:text-emerald-400" />;
|
|
152
|
+
default:
|
|
153
|
+
return <File class="size-3.5 shrink-0 text-muted-foreground" />;
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
/**
|
|
158
|
+
* Leaf file item inside a FileTree.
|
|
159
|
+
*/
|
|
160
|
+
export const FileTreeFile: ParentComponent<FileTreeFileProps> = (props) => {
|
|
161
|
+
const [local, rest] = splitProps(props, ["name", "icon", "class", "children"]);
|
|
162
|
+
|
|
163
|
+
return (
|
|
164
|
+
<div
|
|
165
|
+
class={cn(
|
|
166
|
+
"flex w-full items-center justify-start gap-1.5 rounded-md px-1.5 py-1 text-xs text-muted-foreground transition-colors hover:bg-muted/50 hover:text-foreground cursor-default",
|
|
167
|
+
local.class
|
|
168
|
+
)}
|
|
169
|
+
{...rest}
|
|
170
|
+
>
|
|
171
|
+
<span class="size-3.5 shrink-0" />
|
|
172
|
+
<Show when={local.icon} fallback={getFileIcon(local.name)}>
|
|
173
|
+
{local.icon}
|
|
174
|
+
</Show>
|
|
175
|
+
<span class="tracking-tight">{local.name}</span>
|
|
176
|
+
<Show when={local.children}>
|
|
177
|
+
<div class="ml-auto">{local.children}</div>
|
|
178
|
+
</Show>
|
|
179
|
+
</div>
|
|
180
|
+
);
|
|
181
|
+
};
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Show, splitProps, type JSX } from "solid-js";
|
|
2
|
-
import type { CreateFormReturn } from "
|
|
3
|
-
import { FieldError, type FieldErrorProps } from "
|
|
2
|
+
import type { CreateFormReturn } from "@/hooks/create-form";
|
|
3
|
+
import { FieldError, type FieldErrorProps } from "@/components/ui/field";
|
|
4
4
|
|
|
5
5
|
type FormState<T extends Record<string, any>> = Pick<
|
|
6
6
|
CreateFormReturn<T>,
|
|
@@ -8,7 +8,9 @@ import {
|
|
|
8
8
|
type ParentComponent,
|
|
9
9
|
type Component,
|
|
10
10
|
type Accessor,
|
|
11
|
+
type ValidComponent,
|
|
11
12
|
} from "solid-js";
|
|
13
|
+
import { Dynamic } from "solid-js/web";
|
|
12
14
|
import { cva, type VariantProps } from "class-variance-authority";
|
|
13
15
|
import { Menu, X } from "lucide-solid";
|
|
14
16
|
import { cn } from "@/lib/cn";
|
|
@@ -145,15 +147,18 @@ export const NavbarContainer: ParentComponent<NavbarContainerProps> = (props) =>
|
|
|
145
147
|
};
|
|
146
148
|
|
|
147
149
|
/* --- Navbar Brand / Logo Container --- */
|
|
148
|
-
export interface NavbarBrandProps extends JSX.AnchorHTMLAttributes<HTMLAnchorElement> {
|
|
150
|
+
export interface NavbarBrandProps<T extends ValidComponent = "a"> extends JSX.AnchorHTMLAttributes<HTMLAnchorElement> {
|
|
149
151
|
class?: string;
|
|
152
|
+
as?: T;
|
|
153
|
+
href?: string;
|
|
150
154
|
}
|
|
151
155
|
|
|
152
|
-
export const NavbarBrand
|
|
153
|
-
const [local, rest] = splitProps(props, ["class", "children"]);
|
|
156
|
+
export const NavbarBrand = <T extends ValidComponent = "a">(props: NavbarBrandProps<T>) => {
|
|
157
|
+
const [local, rest] = splitProps(props as NavbarBrandProps, ["class", "as", "children"]);
|
|
154
158
|
|
|
155
159
|
return (
|
|
156
|
-
<
|
|
160
|
+
<Dynamic
|
|
161
|
+
component={local.as || "a"}
|
|
157
162
|
class={cn(
|
|
158
163
|
"flex items-center gap-2 font-bold text-foreground transition-opacity hover:opacity-90 cursor-pointer shrink-0",
|
|
159
164
|
local.class
|
|
@@ -161,7 +166,7 @@ export const NavbarBrand: ParentComponent<NavbarBrandProps> = (props) => {
|
|
|
161
166
|
{...rest}
|
|
162
167
|
>
|
|
163
168
|
{local.children}
|
|
164
|
-
</
|
|
169
|
+
</Dynamic>
|
|
165
170
|
);
|
|
166
171
|
};
|
|
167
172
|
|
|
@@ -193,7 +198,6 @@ export const NavbarContent: ParentComponent<NavbarContentProps> = (props) => {
|
|
|
193
198
|
<div
|
|
194
199
|
class={cn(
|
|
195
200
|
navbarContentVariants({ justify: local.justify }),
|
|
196
|
-
local.hideOnMobile !== false && "hidden md:flex",
|
|
197
201
|
local.class
|
|
198
202
|
)}
|
|
199
203
|
{...rest}
|
|
@@ -248,18 +252,21 @@ export const navbarLinkVariants = cva(
|
|
|
248
252
|
}
|
|
249
253
|
);
|
|
250
254
|
|
|
251
|
-
export interface NavbarLinkProps
|
|
255
|
+
export interface NavbarLinkProps<T extends ValidComponent = "a">
|
|
252
256
|
extends JSX.AnchorHTMLAttributes<HTMLAnchorElement>,
|
|
253
257
|
VariantProps<typeof navbarLinkVariants> {
|
|
254
258
|
class?: string;
|
|
255
259
|
isActive?: boolean;
|
|
260
|
+
as?: T;
|
|
261
|
+
href?: string;
|
|
256
262
|
}
|
|
257
263
|
|
|
258
|
-
export const NavbarLink
|
|
259
|
-
const [local, rest] = splitProps(props, ["class", "variant", "isActive", "children"]);
|
|
264
|
+
export const NavbarLink = <T extends ValidComponent = "a">(props: NavbarLinkProps<T>) => {
|
|
265
|
+
const [local, rest] = splitProps(props as NavbarLinkProps, ["class", "variant", "isActive", "as", "children"]);
|
|
260
266
|
|
|
261
267
|
return (
|
|
262
|
-
<
|
|
268
|
+
<Dynamic
|
|
269
|
+
component={local.as || "a"}
|
|
263
270
|
class={cn(
|
|
264
271
|
navbarLinkVariants({
|
|
265
272
|
variant: local.isActive ? "active" : local.variant,
|
|
@@ -269,7 +276,7 @@ export const NavbarLink: ParentComponent<NavbarLinkProps> = (props) => {
|
|
|
269
276
|
{...rest}
|
|
270
277
|
>
|
|
271
278
|
{local.children}
|
|
272
|
-
</
|
|
279
|
+
</Dynamic>
|
|
273
280
|
);
|
|
274
281
|
};
|
|
275
282
|
|