solid-element-ui 0.2.4 → 0.2.6
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/dist/{src/alert-dialog → alert-dialog}/alert-dialog.d.ts +1 -1
- package/dist/{src/badge → badge}/badge.d.ts +2 -2
- package/dist/index.css +3 -1
- package/dist/index.js +16097 -17258
- package/dist/{src/separator → separator}/separator.d.ts +11 -5
- package/dist/{src/skeleton → skeleton}/skeleton.d.ts +2 -2
- package/dist/{src/slider → slider}/slider.d.ts +12 -0
- package/dist/{src/toast → toast}/toast.d.ts +3 -1
- package/dist/{src/toggle-button → toggle-button}/toggle-button.d.ts +0 -3
- package/package.json +11 -7
- package/src/accordion/accordion.tsx +80 -0
- package/src/alert/alert.tsx +86 -0
- package/src/alert-dialog/alert-dialog.tsx +129 -0
- package/src/badge/badge.tsx +49 -0
- package/src/breadcrumbs/breadcrumbs.tsx +69 -0
- package/src/button/button.tsx +216 -0
- package/src/checkbox/checkbox.tsx +63 -0
- package/src/collapsible/collapsible.tsx +46 -0
- package/src/color-area/color-area.tsx +46 -0
- package/src/color-channel-field/color-channel-field.tsx +46 -0
- package/src/color-field/color-field.tsx +64 -0
- package/src/color-slider/color-slider.tsx +60 -0
- package/src/color-swatch/color-swatch.tsx +33 -0
- package/src/color-wheel/color-wheel.tsx +50 -0
- package/src/combobox/combobox.tsx +97 -0
- package/src/context-menu/context-menu.tsx +102 -0
- package/src/dialog/dialog.tsx +101 -0
- package/src/dropdown-menu/dropdown-menu.tsx +111 -0
- package/src/file-field/file-field.tsx +114 -0
- package/src/hover-card/hover-card.tsx +61 -0
- package/src/image/image.tsx +59 -0
- package/src/index.tsx +94 -0
- package/src/link/link.tsx +64 -0
- package/src/menubar/menubar.tsx +85 -0
- package/src/meter/meter.tsx +89 -0
- package/src/navigation-menu/navigation-menu.tsx +90 -0
- package/src/number-field/number-field.tsx +79 -0
- package/src/pagination/pagination.tsx +67 -0
- package/src/popover/popover.tsx +58 -0
- package/src/progress/progress.tsx +83 -0
- package/src/radio-group/radio-group.tsx +94 -0
- package/src/rating-group/rating-group.tsx +101 -0
- package/src/search/search.tsx +99 -0
- package/src/segmented-control/segmented-control.tsx +92 -0
- package/src/select/select.tsx +163 -0
- package/src/separator/separator.tsx +64 -0
- package/src/skeleton/skeleton.tsx +73 -0
- package/src/slider/slider.tsx +94 -0
- package/src/style/global.css +156 -0
- package/src/switch/switch.tsx +104 -0
- package/src/tabs/tabs.tsx +73 -0
- package/src/text-field/text-field.tsx +97 -0
- package/src/time-field/time-field.tsx +103 -0
- package/src/toast/toast.tsx +132 -0
- package/src/toggle-button/toggle-button.tsx +69 -0
- package/src/toggle-group/toggle-group.tsx +85 -0
- package/src/tooltip/tooltip.tsx +73 -0
- /package/dist/{src/accordion → accordion}/accordion.d.ts +0 -0
- /package/dist/{src/alert → alert}/alert.d.ts +0 -0
- /package/dist/{src/breadcrumbs → breadcrumbs}/breadcrumbs.d.ts +0 -0
- /package/dist/{src/button → button}/button.d.ts +0 -0
- /package/dist/{src/checkbox → checkbox}/checkbox.d.ts +0 -0
- /package/dist/{src/collapsible → collapsible}/collapsible.d.ts +0 -0
- /package/dist/{src/color-area → color-area}/color-area.d.ts +0 -0
- /package/dist/{src/color-channel-field → color-channel-field}/color-channel-field.d.ts +0 -0
- /package/dist/{src/color-field → color-field}/color-field.d.ts +0 -0
- /package/dist/{src/color-slider → color-slider}/color-slider.d.ts +0 -0
- /package/dist/{src/color-swatch → color-swatch}/color-swatch.d.ts +0 -0
- /package/dist/{src/color-wheel → color-wheel}/color-wheel.d.ts +0 -0
- /package/dist/{src/combobox → combobox}/combobox.d.ts +0 -0
- /package/dist/{src/context-menu → context-menu}/context-menu.d.ts +0 -0
- /package/dist/{src/dialog → dialog}/dialog.d.ts +0 -0
- /package/dist/{src/dropdown-menu → dropdown-menu}/dropdown-menu.d.ts +0 -0
- /package/dist/{src/file-field → file-field}/file-field.d.ts +0 -0
- /package/dist/{src/hover-card → hover-card}/hover-card.d.ts +0 -0
- /package/dist/{src/image → image}/image.d.ts +0 -0
- /package/dist/{src/index.d.ts → index.d.ts} +0 -0
- /package/dist/{src/link → link}/link.d.ts +0 -0
- /package/dist/{src/menubar → menubar}/menubar.d.ts +0 -0
- /package/dist/{src/meter → meter}/meter.d.ts +0 -0
- /package/dist/{src/navigation-menu → navigation-menu}/navigation-menu.d.ts +0 -0
- /package/dist/{src/number-field → number-field}/number-field.d.ts +0 -0
- /package/dist/{src/pagination → pagination}/pagination.d.ts +0 -0
- /package/dist/{src/popover → popover}/popover.d.ts +0 -0
- /package/dist/{src/progress → progress}/progress.d.ts +0 -0
- /package/dist/{src/radio-group → radio-group}/radio-group.d.ts +0 -0
- /package/dist/{src/rating-group → rating-group}/rating-group.d.ts +0 -0
- /package/dist/{src/search → search}/search.d.ts +0 -0
- /package/dist/{src/segmented-control → segmented-control}/segmented-control.d.ts +0 -0
- /package/dist/{src/select → select}/select.d.ts +0 -0
- /package/dist/{src/switch → switch}/switch.d.ts +0 -0
- /package/dist/{src/tabs → tabs}/tabs.d.ts +0 -0
- /package/dist/{src/text-field → text-field}/text-field.d.ts +0 -0
- /package/dist/{src/time-field → time-field}/time-field.d.ts +0 -0
- /package/dist/{src/toggle-group → toggle-group}/toggle-group.d.ts +0 -0
- /package/dist/{src/tooltip → tooltip}/tooltip.d.ts +0 -0
package/src/index.tsx
ADDED
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
import "./style/global.css";
|
|
2
|
+
|
|
3
|
+
// TODO 组件 form , data等
|
|
4
|
+
// TODO background-color 等颜色相关的属性,添加 dark 模式的支持
|
|
5
|
+
|
|
6
|
+
export { Accordion } from "./accordion/accordion";
|
|
7
|
+
|
|
8
|
+
export { Alert } from "./alert/alert";
|
|
9
|
+
|
|
10
|
+
export { AlertDialog } from "./alert-dialog/alert-dialog";
|
|
11
|
+
|
|
12
|
+
export { Badge } from "./badge/badge";
|
|
13
|
+
|
|
14
|
+
export { Breadcrumbs } from "./breadcrumbs/breadcrumbs";
|
|
15
|
+
|
|
16
|
+
export { Button } from "./button/button";
|
|
17
|
+
|
|
18
|
+
export { Checkbox } from "./checkbox/checkbox";
|
|
19
|
+
|
|
20
|
+
export { Collapsible } from "./collapsible/collapsible";
|
|
21
|
+
|
|
22
|
+
export { ColorArea } from "./color-area/color-area";
|
|
23
|
+
|
|
24
|
+
export { ColorChannelField } from "./color-channel-field/color-channel-field";
|
|
25
|
+
|
|
26
|
+
export { ColorField } from "./color-field/color-field";
|
|
27
|
+
|
|
28
|
+
export { ColorSlider } from "./color-slider/color-slider";
|
|
29
|
+
|
|
30
|
+
export { ColorSwatch } from "./color-swatch/color-swatch";
|
|
31
|
+
|
|
32
|
+
export { ColorWheel } from "./color-wheel/color-wheel";
|
|
33
|
+
|
|
34
|
+
export { Combobox, ComboboxItem } from "./combobox/combobox";
|
|
35
|
+
|
|
36
|
+
export { ContextMenu } from "./context-menu/context-menu";
|
|
37
|
+
|
|
38
|
+
export { Dialog } from "./dialog/dialog";
|
|
39
|
+
|
|
40
|
+
export { DropdownMenu } from "./dropdown-menu/dropdown-menu";
|
|
41
|
+
|
|
42
|
+
export { FileField } from "./file-field/file-field";
|
|
43
|
+
|
|
44
|
+
export { HoverCard } from "./hover-card/hover-card";
|
|
45
|
+
|
|
46
|
+
export { Image } from "./image/image";
|
|
47
|
+
|
|
48
|
+
export { Link } from "./link/link";
|
|
49
|
+
|
|
50
|
+
export { Menubar } from "./menubar/menubar";
|
|
51
|
+
|
|
52
|
+
export { Meter } from "./meter/meter";
|
|
53
|
+
|
|
54
|
+
export { NavigationMenu } from "./navigation-menu/navigation-menu";
|
|
55
|
+
|
|
56
|
+
export { NumberField } from "./number-field/number-field";
|
|
57
|
+
|
|
58
|
+
export { Pagination } from "./pagination/pagination";
|
|
59
|
+
|
|
60
|
+
export { Popover } from "./popover/popover";
|
|
61
|
+
|
|
62
|
+
export { Progress } from "./progress/progress";
|
|
63
|
+
|
|
64
|
+
export { RadioGroup } from "./radio-group/radio-group";
|
|
65
|
+
|
|
66
|
+
// rating-group 组件
|
|
67
|
+
|
|
68
|
+
export { Search } from "./search/search";
|
|
69
|
+
|
|
70
|
+
export { SegmentedControl } from "./segmented-control/segmented-control";
|
|
71
|
+
|
|
72
|
+
export { Select } from "./select/select";
|
|
73
|
+
|
|
74
|
+
export { Separator } from "./separator/separator";
|
|
75
|
+
|
|
76
|
+
export { Skeleton } from "./skeleton/skeleton";
|
|
77
|
+
|
|
78
|
+
export { Slider } from "./slider/slider";
|
|
79
|
+
|
|
80
|
+
export { Switch } from "./switch/switch";
|
|
81
|
+
|
|
82
|
+
export { Tabs } from "./tabs/tabs";
|
|
83
|
+
|
|
84
|
+
export { TextField } from "./text-field/text-field";
|
|
85
|
+
|
|
86
|
+
// time-field
|
|
87
|
+
|
|
88
|
+
export { ToastProvider, showToast } from "./toast/toast";
|
|
89
|
+
|
|
90
|
+
export { ToggleButton } from "./toggle-button/toggle-button";
|
|
91
|
+
|
|
92
|
+
export { ToggleGroup } from "./toggle-group/toggle-group";
|
|
93
|
+
|
|
94
|
+
export { Tooltip } from "./tooltip/tooltip";
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { Link as KLink } from "@kobalte/core/link";
|
|
2
|
+
import { splitProps, type ComponentProps } from "solid-js";
|
|
3
|
+
import { tv, type VariantProps } from "tailwind-variants";
|
|
4
|
+
|
|
5
|
+
const linkStyles = tv(
|
|
6
|
+
{
|
|
7
|
+
base: "inline-flex items-center justify-center transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-blue-500 rounded-sm disabled:pointer-events-none disabled:opacity-50",
|
|
8
|
+
variants: {
|
|
9
|
+
variant: {
|
|
10
|
+
default:
|
|
11
|
+
"text-main hover:text-main/80 underline-offset-4",
|
|
12
|
+
primary:
|
|
13
|
+
"text-primary hover:text-primary/80 font-medium",
|
|
14
|
+
muted: "text-muted hover:text-muted/80",
|
|
15
|
+
button: "bg-reversal-bg text-reversal hover:reversal-bg/90 px-4 py-2 text-sm ",
|
|
16
|
+
},
|
|
17
|
+
underline: {
|
|
18
|
+
always: "underline",
|
|
19
|
+
hover: "no-underline hover:underline",
|
|
20
|
+
none: "no-underline",
|
|
21
|
+
},
|
|
22
|
+
},
|
|
23
|
+
defaultVariants: {
|
|
24
|
+
variant: "default",
|
|
25
|
+
underline: "hover",
|
|
26
|
+
},
|
|
27
|
+
},
|
|
28
|
+
{
|
|
29
|
+
twMerge: true,
|
|
30
|
+
},
|
|
31
|
+
);
|
|
32
|
+
|
|
33
|
+
type LinkVariants = VariantProps<typeof linkStyles>;
|
|
34
|
+
|
|
35
|
+
export interface LinkProps extends ComponentProps<typeof KLink>, LinkVariants {
|
|
36
|
+
external?: boolean;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export const Link = (props: LinkProps) => {
|
|
40
|
+
const [local, variantProps, others] = splitProps(
|
|
41
|
+
props,
|
|
42
|
+
["class", "external", "children", "href"],
|
|
43
|
+
["variant", "underline"]
|
|
44
|
+
);
|
|
45
|
+
|
|
46
|
+
const styles = () =>
|
|
47
|
+
linkStyles({
|
|
48
|
+
variant: variantProps.variant,
|
|
49
|
+
underline: variantProps.underline,
|
|
50
|
+
class: local.class,
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
return (
|
|
54
|
+
<KLink
|
|
55
|
+
href={local.href}
|
|
56
|
+
target={local.external ? "_blank" : undefined}
|
|
57
|
+
rel={local.external ? "noopener noreferrer" : undefined}
|
|
58
|
+
class={styles()}
|
|
59
|
+
{...others}
|
|
60
|
+
>
|
|
61
|
+
{local.children}
|
|
62
|
+
</KLink>
|
|
63
|
+
);
|
|
64
|
+
};
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import { Menubar as KMenubar } from "@kobalte/core/menubar";
|
|
2
|
+
import { splitProps, type ComponentProps } from "solid-js";
|
|
3
|
+
import { tv } from "tailwind-variants";
|
|
4
|
+
|
|
5
|
+
// TODO 1. 格式
|
|
6
|
+
|
|
7
|
+
const menubarStyles = tv(
|
|
8
|
+
{
|
|
9
|
+
slots: {
|
|
10
|
+
root: "flex h-10 items-center space-x-1 rounded-md border bg-app p-1 shadow-sm ",
|
|
11
|
+
trigger:
|
|
12
|
+
"flex cursor-default select-none items-center rounded-sm px-3 py-1.5 text-sm font-medium outline-none focus:foreground data-[state=open]:foreground",
|
|
13
|
+
content: [
|
|
14
|
+
"z-50 min-w-[12rem] overflow-hidden rounded-md border bg-app p-1 shadow-md border-light animate-in fade-in zoom-in-95",
|
|
15
|
+
"data-[expanded]:animate-in data-[closed]:animate-out",
|
|
16
|
+
],
|
|
17
|
+
item: [
|
|
18
|
+
"relative flex cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none ",
|
|
19
|
+
|
|
20
|
+
"focus:bg-foreground data-[disabled]:opacity-50",
|
|
21
|
+
],
|
|
22
|
+
separator: "-mx-1 my-1 h-px border-light",
|
|
23
|
+
shortcut: "ml-auto text-xs tracking-widest text-slate-500",
|
|
24
|
+
},
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
twMerge: true,
|
|
28
|
+
},
|
|
29
|
+
);
|
|
30
|
+
|
|
31
|
+
const s = menubarStyles();
|
|
32
|
+
|
|
33
|
+
export const Menubar = Object.assign(
|
|
34
|
+
(props: ComponentProps<typeof KMenubar>) => {
|
|
35
|
+
const [local, others] = splitProps(props, ["class"]);
|
|
36
|
+
return <KMenubar class={s.root({ class: local.class })} {...others} />;
|
|
37
|
+
},
|
|
38
|
+
{
|
|
39
|
+
Menu: KMenubar.Menu,
|
|
40
|
+
Trigger: (props: ComponentProps<typeof KMenubar.Trigger>) => {
|
|
41
|
+
const [local, others] = splitProps(props, ["class"]);
|
|
42
|
+
return (
|
|
43
|
+
<KMenubar.Trigger
|
|
44
|
+
class={s.trigger({ class: local.class })}
|
|
45
|
+
{...others}
|
|
46
|
+
/>
|
|
47
|
+
);
|
|
48
|
+
},
|
|
49
|
+
Content: (props: ComponentProps<typeof KMenubar.Content>) => {
|
|
50
|
+
const [local, others] = splitProps(props, ["class"]);
|
|
51
|
+
return (
|
|
52
|
+
<KMenubar.Portal>
|
|
53
|
+
<KMenubar.Content
|
|
54
|
+
class={s.content({ class: local.class })}
|
|
55
|
+
{...others}
|
|
56
|
+
/>
|
|
57
|
+
</KMenubar.Portal>
|
|
58
|
+
);
|
|
59
|
+
},
|
|
60
|
+
Item: (props: ComponentProps<typeof KMenubar.Item>) => {
|
|
61
|
+
const [local, others] = splitProps(props, ["class"]);
|
|
62
|
+
return (
|
|
63
|
+
<KMenubar.Item
|
|
64
|
+
class={s.item({ class: local.class })}
|
|
65
|
+
{...others}
|
|
66
|
+
/>
|
|
67
|
+
);
|
|
68
|
+
},
|
|
69
|
+
Separator: (props: ComponentProps<typeof KMenubar.Separator>) => {
|
|
70
|
+
const [local, others] = splitProps(props, ["class"]);
|
|
71
|
+
return (
|
|
72
|
+
<KMenubar.Separator
|
|
73
|
+
class={s.separator({ class: local.class })}
|
|
74
|
+
{...others}
|
|
75
|
+
/>
|
|
76
|
+
);
|
|
77
|
+
},
|
|
78
|
+
Shortcut: (props: ComponentProps<"span">) => {
|
|
79
|
+
const [local, others] = splitProps(props, ["class"]);
|
|
80
|
+
return (
|
|
81
|
+
<span class={s.shortcut({ class: local.class })} {...others} />
|
|
82
|
+
);
|
|
83
|
+
},
|
|
84
|
+
},
|
|
85
|
+
);
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import { Meter as KMeter } from "@kobalte/core/meter";
|
|
2
|
+
import { splitProps, type ComponentProps } from "solid-js";
|
|
3
|
+
import { tv, type VariantProps } from "tailwind-variants";
|
|
4
|
+
|
|
5
|
+
// TODO 1. 格式
|
|
6
|
+
|
|
7
|
+
const meterStyles = tv(
|
|
8
|
+
{
|
|
9
|
+
slots: {
|
|
10
|
+
root: "flex flex-col gap-2 w-full antialiased",
|
|
11
|
+
labelContainer:
|
|
12
|
+
"flex justify-between items-center text-sm font-medium text-main",
|
|
13
|
+
track: "h-2.5 w-full rounded-full bg-foreground overflow-hidden",
|
|
14
|
+
fill: "h-full transition-all duration-500 ease-out rounded-full",
|
|
15
|
+
},
|
|
16
|
+
variants: {
|
|
17
|
+
color: {
|
|
18
|
+
primary: { fill: "bg-primary" },
|
|
19
|
+
success: { fill: "bg-success" },
|
|
20
|
+
warning: { fill: "bg-warning" },
|
|
21
|
+
danger: { fill: "bg-danger" },
|
|
22
|
+
},
|
|
23
|
+
},
|
|
24
|
+
defaultVariants: {
|
|
25
|
+
color: "primary",
|
|
26
|
+
},
|
|
27
|
+
},
|
|
28
|
+
{
|
|
29
|
+
twMerge: true,
|
|
30
|
+
},
|
|
31
|
+
);
|
|
32
|
+
|
|
33
|
+
type MeterVariants = VariantProps<typeof meterStyles>;
|
|
34
|
+
|
|
35
|
+
export const Meter = Object.assign(
|
|
36
|
+
(props: ComponentProps<typeof KMeter> & MeterVariants) => {
|
|
37
|
+
const [local, variantProps, others] = splitProps(
|
|
38
|
+
props,
|
|
39
|
+
["class"],
|
|
40
|
+
["color"]
|
|
41
|
+
);
|
|
42
|
+
const s = () => meterStyles({ color: variantProps.color });
|
|
43
|
+
|
|
44
|
+
return (
|
|
45
|
+
<KMeter class={s().root({ class: local.class })} {...others}>
|
|
46
|
+
{others.children}
|
|
47
|
+
</KMeter>
|
|
48
|
+
);
|
|
49
|
+
},
|
|
50
|
+
{
|
|
51
|
+
Label: (props: ComponentProps<typeof KMeter.Label>) => {
|
|
52
|
+
const [local, others] = splitProps(props, ["class"]);
|
|
53
|
+
return (
|
|
54
|
+
<KMeter.Label
|
|
55
|
+
class={meterStyles().labelContainer({ class: local.class })}
|
|
56
|
+
{...others}
|
|
57
|
+
/>
|
|
58
|
+
);
|
|
59
|
+
},
|
|
60
|
+
ValueLabel: (props: ComponentProps<typeof KMeter.ValueLabel>) => {
|
|
61
|
+
const [local, others] = splitProps(props, ["class"]);
|
|
62
|
+
return (
|
|
63
|
+
<KMeter.ValueLabel
|
|
64
|
+
class={`text-xs text-slate-500 ${local.class}`}
|
|
65
|
+
{...others}
|
|
66
|
+
/>
|
|
67
|
+
);
|
|
68
|
+
},
|
|
69
|
+
Track: (props: ComponentProps<typeof KMeter.Track>) => {
|
|
70
|
+
const [local, others] = splitProps(props, ["class"]);
|
|
71
|
+
return (
|
|
72
|
+
<KMeter.Track
|
|
73
|
+
class={meterStyles().track({ class: local.class })}
|
|
74
|
+
{...others}
|
|
75
|
+
/>
|
|
76
|
+
);
|
|
77
|
+
},
|
|
78
|
+
Fill: (props: ComponentProps<typeof KMeter.Fill>) => {
|
|
79
|
+
const [local, others] = splitProps(props, ["class"]);
|
|
80
|
+
// 注意:Fill 不需要手动设置宽度,Kobalte 会通过 style 注入百分比
|
|
81
|
+
return (
|
|
82
|
+
<KMeter.Fill
|
|
83
|
+
class={meterStyles().fill({ class: local.class })}
|
|
84
|
+
{...others}
|
|
85
|
+
/>
|
|
86
|
+
);
|
|
87
|
+
},
|
|
88
|
+
}
|
|
89
|
+
);
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import { NavigationMenu as KNavigationMenu } from "@kobalte/core/navigation-menu";
|
|
2
|
+
import { splitProps, type ComponentProps, type JSX, For, Show } from "solid-js";
|
|
3
|
+
import { tv } from "tailwind-variants";
|
|
4
|
+
|
|
5
|
+
// TODO 不显示问题
|
|
6
|
+
|
|
7
|
+
const navStyles = tv(
|
|
8
|
+
{
|
|
9
|
+
slots: {
|
|
10
|
+
root: "relative z-10 flex w-full justify-center antialiased",
|
|
11
|
+
trigger: [
|
|
12
|
+
"group inline-flex h-9 w-max items-center justify-center rounded-md px-4 py-2 text-sm font-medium transition-all",
|
|
13
|
+
"hover:bg-slate-100 hover:text-slate-900 data-[state=open]:bg-slate-100/50",
|
|
14
|
+
"dark:hover:bg-slate-800 dark:hover:text-slate-50",
|
|
15
|
+
],
|
|
16
|
+
content:
|
|
17
|
+
"absolute left-0 top-0 w-full p-2 animate-in fade-in zoom-in-95 duration-200",
|
|
18
|
+
viewport:
|
|
19
|
+
"relative mt-1.5 h-(--kb-navigation-menu-viewport-height) w-(--kb-navigation-menu-viewport-width) origin-[top_center] overflow-hidden rounded-md border bg-white shadow-xl dark:bg-slate-950 dark:border-slate-800 transition-[width,height] duration-300",
|
|
20
|
+
},
|
|
21
|
+
},
|
|
22
|
+
{
|
|
23
|
+
twMerge: true,
|
|
24
|
+
},
|
|
25
|
+
);
|
|
26
|
+
|
|
27
|
+
const { root, trigger, content, viewport } = navStyles();
|
|
28
|
+
|
|
29
|
+
interface NavItem {
|
|
30
|
+
title: string;
|
|
31
|
+
href?: string;
|
|
32
|
+
content?: JSX.Element;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export interface NavigationMenuProps
|
|
36
|
+
extends ComponentProps<typeof KNavigationMenu> {
|
|
37
|
+
items: NavItem[];
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export const NavigationMenu = (props: NavigationMenuProps) => {
|
|
41
|
+
const [local, others] = splitProps(props, ["items", "class"]);
|
|
42
|
+
|
|
43
|
+
return (
|
|
44
|
+
<KNavigationMenu class={root({ class: local.class })} {...others}>
|
|
45
|
+
<For each={local.items}>
|
|
46
|
+
{(item) => (
|
|
47
|
+
<KNavigationMenu.Menu>
|
|
48
|
+
<Show
|
|
49
|
+
when={item.content}
|
|
50
|
+
fallback={
|
|
51
|
+
<KNavigationMenu.Trigger
|
|
52
|
+
as="a"
|
|
53
|
+
href={item.href}
|
|
54
|
+
class={trigger()}
|
|
55
|
+
>
|
|
56
|
+
{item.title}
|
|
57
|
+
</KNavigationMenu.Trigger>
|
|
58
|
+
}
|
|
59
|
+
>
|
|
60
|
+
<KNavigationMenu.Trigger class={trigger()}>
|
|
61
|
+
{item.title}
|
|
62
|
+
<svg
|
|
63
|
+
class="ml-1 h-3 w-3 transition-transform duration-200 group-data-[state=open]:rotate-180"
|
|
64
|
+
fill="none"
|
|
65
|
+
viewBox="0 0 24 24"
|
|
66
|
+
stroke="currentColor"
|
|
67
|
+
>
|
|
68
|
+
<path
|
|
69
|
+
stroke-linecap="round"
|
|
70
|
+
stroke-linejoin="round"
|
|
71
|
+
stroke-width="2"
|
|
72
|
+
d="M19 9l-7 7-7-7"
|
|
73
|
+
/>
|
|
74
|
+
</svg>
|
|
75
|
+
</KNavigationMenu.Trigger>
|
|
76
|
+
<KNavigationMenu.Portal>
|
|
77
|
+
<KNavigationMenu.Content class={content()}>
|
|
78
|
+
{item.content}
|
|
79
|
+
</KNavigationMenu.Content>
|
|
80
|
+
</KNavigationMenu.Portal>
|
|
81
|
+
</Show>
|
|
82
|
+
</KNavigationMenu.Menu>
|
|
83
|
+
)}
|
|
84
|
+
</For>
|
|
85
|
+
<KNavigationMenu.Viewport class={viewport()}>
|
|
86
|
+
<KNavigationMenu.Arrow />
|
|
87
|
+
</KNavigationMenu.Viewport>
|
|
88
|
+
</KNavigationMenu>
|
|
89
|
+
);
|
|
90
|
+
};
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import { NumberField as KNumberField } from "@kobalte/core/number-field";
|
|
2
|
+
import { splitProps, type ComponentProps, Show } from "solid-js";
|
|
3
|
+
import { tv, type VariantProps } from "tailwind-variants";
|
|
4
|
+
import { ChevronUp, ChevronDown } from "lucide-solid";
|
|
5
|
+
|
|
6
|
+
const numberFieldStyles = tv(
|
|
7
|
+
{
|
|
8
|
+
slots: {
|
|
9
|
+
root: "flex flex-col gap-1.5 w-full antialiased",
|
|
10
|
+
label: "text-sm font-medium text-main ml-1",
|
|
11
|
+
container: [
|
|
12
|
+
"relative flex items-center rounded-md border border-slate-200 bg-app transition-shadow shadow-sm",
|
|
13
|
+
"focus-within:ring-2 focus-within:ring-blue-500/20 focus-within:border-blue-500",
|
|
14
|
+
],
|
|
15
|
+
input: "flex-1 bg-transparent px-3 py-2 text-sm outline-none placeholder:text-muted disabled:cursor-not-allowed",
|
|
16
|
+
controls:
|
|
17
|
+
"flex flex-col border-l border-slate-200 dark:border-slate-800",
|
|
18
|
+
stepper: [
|
|
19
|
+
"flex h-1/2 w-8 items-center justify-center transition-colors hover:bg-foreground active:bg-foreground",
|
|
20
|
+
"disabled:opacity-30 disabled:pointer-events-none",
|
|
21
|
+
],
|
|
22
|
+
errorMessage: "text-xs text-danger font-medium ml-1 mt-1",
|
|
23
|
+
},
|
|
24
|
+
},
|
|
25
|
+
{
|
|
26
|
+
twMerge: true,
|
|
27
|
+
},
|
|
28
|
+
);
|
|
29
|
+
|
|
30
|
+
type NumberFieldVariants = VariantProps<typeof numberFieldStyles>;
|
|
31
|
+
|
|
32
|
+
export interface NumberFieldProps
|
|
33
|
+
extends Omit<ComponentProps<typeof KNumberField>, "class">,
|
|
34
|
+
NumberFieldVariants {
|
|
35
|
+
label?: string;
|
|
36
|
+
description?: string;
|
|
37
|
+
class?: string;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export const NumberField = (props: NumberFieldProps) => {
|
|
41
|
+
// 严格处理属性,防止 TS 报错“已声明但未使用”
|
|
42
|
+
const [local, others] = splitProps(props, [
|
|
43
|
+
"label",
|
|
44
|
+
"description",
|
|
45
|
+
"class",
|
|
46
|
+
]);
|
|
47
|
+
const s = numberFieldStyles();
|
|
48
|
+
|
|
49
|
+
return (
|
|
50
|
+
<KNumberField class={s.root({ class: local.class })} {...others}>
|
|
51
|
+
<Show when={local.label}>
|
|
52
|
+
<KNumberField.Label class={s.label()}>
|
|
53
|
+
{local.label}
|
|
54
|
+
</KNumberField.Label>
|
|
55
|
+
</Show>
|
|
56
|
+
|
|
57
|
+
<div class={s.container()}>
|
|
58
|
+
<KNumberField.Input class={s.input()} />
|
|
59
|
+
<div class={s.controls()}>
|
|
60
|
+
<KNumberField.IncrementTrigger class={s.stepper()}>
|
|
61
|
+
<ChevronUp size={14} />
|
|
62
|
+
</KNumberField.IncrementTrigger>
|
|
63
|
+
<KNumberField.DecrementTrigger
|
|
64
|
+
class={s.stepper({
|
|
65
|
+
class: "border-t border-slate-200 dark:border-slate-800",
|
|
66
|
+
})}
|
|
67
|
+
>
|
|
68
|
+
<ChevronDown size={14} />
|
|
69
|
+
</KNumberField.DecrementTrigger>
|
|
70
|
+
</div>
|
|
71
|
+
</div>
|
|
72
|
+
|
|
73
|
+
<Show when={local.description}>
|
|
74
|
+
<KNumberField.Description class="text-xs text-slate-500 ml-1 mt-1" />
|
|
75
|
+
</Show>
|
|
76
|
+
<KNumberField.ErrorMessage class={s.errorMessage()} />
|
|
77
|
+
</KNumberField>
|
|
78
|
+
);
|
|
79
|
+
};
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { Pagination as KPagination } from "@kobalte/core/pagination";
|
|
2
|
+
import { splitProps, type ComponentProps } from "solid-js";
|
|
3
|
+
import { tv } from "tailwind-variants";
|
|
4
|
+
import { ChevronLeft, ChevronRight, Ellipsis } from "lucide-solid";
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
// FIXME 样式修改,
|
|
8
|
+
|
|
9
|
+
const paginationStyles = tv(
|
|
10
|
+
{
|
|
11
|
+
slots: {
|
|
12
|
+
root: "flex w-full justify-center antialiased",
|
|
13
|
+
itemsContainer: "flex items-center gap-1",
|
|
14
|
+
item: [
|
|
15
|
+
"inline-flex h-9 w-9 items-center justify-center rounded-md text-sm font-medium transition-colors text-main",
|
|
16
|
+
"hover:bg-foreground hover:text-muted",
|
|
17
|
+
"data-[current]:bg-foreground data-[current]:text-muted",
|
|
18
|
+
"disabled:pointer-events-none disabled:opacity-50",
|
|
19
|
+
],
|
|
20
|
+
ellipsis: "flex h-9 w-9 items-center justify-center text-slate-400",
|
|
21
|
+
trigger:
|
|
22
|
+
"inline-flex h-9 w-9 items-center justify-center rounded-md border border-light bg-transparent hover:bg-foreground ",
|
|
23
|
+
},
|
|
24
|
+
},
|
|
25
|
+
{
|
|
26
|
+
twMerge: true,
|
|
27
|
+
},
|
|
28
|
+
);
|
|
29
|
+
|
|
30
|
+
const s = paginationStyles();
|
|
31
|
+
|
|
32
|
+
export interface PaginationProps extends ComponentProps<typeof KPagination> {}
|
|
33
|
+
|
|
34
|
+
export const Pagination = (props: PaginationProps) => {
|
|
35
|
+
// 显式提取 count 以满足类型约束,同时清理 others
|
|
36
|
+
const [local, others] = splitProps(props, ["class", "count"]);
|
|
37
|
+
|
|
38
|
+
return (
|
|
39
|
+
<KPagination
|
|
40
|
+
class={s.root({ class: local.class })}
|
|
41
|
+
count={local.count}
|
|
42
|
+
{...others}
|
|
43
|
+
itemComponent={(p) => (
|
|
44
|
+
<KPagination.Item page={p.page} class={s.item()}>
|
|
45
|
+
{p.page}
|
|
46
|
+
</KPagination.Item>
|
|
47
|
+
)}
|
|
48
|
+
ellipsisComponent={() => (
|
|
49
|
+
<KPagination.Ellipsis class={s.ellipsis()}>
|
|
50
|
+
<Ellipsis size={16} />
|
|
51
|
+
</KPagination.Ellipsis>
|
|
52
|
+
)}
|
|
53
|
+
>
|
|
54
|
+
<div class={s.itemsContainer()}>
|
|
55
|
+
<KPagination.Previous class={s.trigger()}>
|
|
56
|
+
<ChevronLeft size={16} />
|
|
57
|
+
</KPagination.Previous>
|
|
58
|
+
|
|
59
|
+
<KPagination.Items />
|
|
60
|
+
|
|
61
|
+
<KPagination.Next class={s.trigger()}>
|
|
62
|
+
<ChevronRight size={16} />
|
|
63
|
+
</KPagination.Next>
|
|
64
|
+
</div>
|
|
65
|
+
</KPagination>
|
|
66
|
+
);
|
|
67
|
+
};
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { Popover as KPopover } from "@kobalte/core/popover";
|
|
2
|
+
import { CrossIcon } from "lucide-solid";
|
|
3
|
+
import { splitProps, type ComponentProps, type JSX } from "solid-js";
|
|
4
|
+
import { tv } from "tailwind-variants";
|
|
5
|
+
|
|
6
|
+
// FIXME 与其他的气泡样式不统一的问题
|
|
7
|
+
// Description,而不是内敛。
|
|
8
|
+
// trigger用内部,而其他放在标签属性
|
|
9
|
+
|
|
10
|
+
const popoverStyles = tv(
|
|
11
|
+
{
|
|
12
|
+
slots: {
|
|
13
|
+
content: [
|
|
14
|
+
"z-50 w-72 rounded-md border border-light bg-app p-4 shadow-md outline-none antialiased text-main",
|
|
15
|
+
"data-[expanded]:animate-in data-[closed]:animate-out",
|
|
16
|
+
],
|
|
17
|
+
arrow: "fill-app stroke-slate-200 dark:stroke-slate-800",
|
|
18
|
+
},
|
|
19
|
+
},
|
|
20
|
+
{
|
|
21
|
+
twMerge: true,
|
|
22
|
+
},
|
|
23
|
+
);
|
|
24
|
+
|
|
25
|
+
const {content, arrow} = popoverStyles();
|
|
26
|
+
|
|
27
|
+
export interface PopoverProps extends ComponentProps<typeof KPopover> {
|
|
28
|
+
trigger: JSX.Element;
|
|
29
|
+
title: string;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export const Popover = (props: PopoverProps) => {
|
|
33
|
+
const [local, others] = splitProps(props, ["trigger", "children", "title"]);
|
|
34
|
+
|
|
35
|
+
return (
|
|
36
|
+
<KPopover {...others}>
|
|
37
|
+
<KPopover.Trigger class="inline-flex">
|
|
38
|
+
{local.trigger}
|
|
39
|
+
</KPopover.Trigger>
|
|
40
|
+
|
|
41
|
+
<KPopover.Portal>
|
|
42
|
+
<KPopover.Content class={content()}>
|
|
43
|
+
<KPopover.Arrow class={arrow()} />
|
|
44
|
+
|
|
45
|
+
<div class="flex">
|
|
46
|
+
<KPopover.Title>{local.title}</KPopover.Title>
|
|
47
|
+
<KPopover.CloseButton>
|
|
48
|
+
<CrossIcon />
|
|
49
|
+
</KPopover.CloseButton>
|
|
50
|
+
</div>
|
|
51
|
+
<KPopover.Description>
|
|
52
|
+
{local.children}
|
|
53
|
+
</KPopover.Description>
|
|
54
|
+
</KPopover.Content>
|
|
55
|
+
</KPopover.Portal>
|
|
56
|
+
</KPopover>
|
|
57
|
+
);
|
|
58
|
+
};
|