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.
Files changed (96) hide show
  1. package/dist/{src/alert-dialog → alert-dialog}/alert-dialog.d.ts +1 -1
  2. package/dist/{src/badge → badge}/badge.d.ts +2 -2
  3. package/dist/index.css +3 -1
  4. package/dist/index.js +16097 -17258
  5. package/dist/{src/separator → separator}/separator.d.ts +11 -5
  6. package/dist/{src/skeleton → skeleton}/skeleton.d.ts +2 -2
  7. package/dist/{src/slider → slider}/slider.d.ts +12 -0
  8. package/dist/{src/toast → toast}/toast.d.ts +3 -1
  9. package/dist/{src/toggle-button → toggle-button}/toggle-button.d.ts +0 -3
  10. package/package.json +11 -7
  11. package/src/accordion/accordion.tsx +80 -0
  12. package/src/alert/alert.tsx +86 -0
  13. package/src/alert-dialog/alert-dialog.tsx +129 -0
  14. package/src/badge/badge.tsx +49 -0
  15. package/src/breadcrumbs/breadcrumbs.tsx +69 -0
  16. package/src/button/button.tsx +216 -0
  17. package/src/checkbox/checkbox.tsx +63 -0
  18. package/src/collapsible/collapsible.tsx +46 -0
  19. package/src/color-area/color-area.tsx +46 -0
  20. package/src/color-channel-field/color-channel-field.tsx +46 -0
  21. package/src/color-field/color-field.tsx +64 -0
  22. package/src/color-slider/color-slider.tsx +60 -0
  23. package/src/color-swatch/color-swatch.tsx +33 -0
  24. package/src/color-wheel/color-wheel.tsx +50 -0
  25. package/src/combobox/combobox.tsx +97 -0
  26. package/src/context-menu/context-menu.tsx +102 -0
  27. package/src/dialog/dialog.tsx +101 -0
  28. package/src/dropdown-menu/dropdown-menu.tsx +111 -0
  29. package/src/file-field/file-field.tsx +114 -0
  30. package/src/hover-card/hover-card.tsx +61 -0
  31. package/src/image/image.tsx +59 -0
  32. package/src/index.tsx +94 -0
  33. package/src/link/link.tsx +64 -0
  34. package/src/menubar/menubar.tsx +85 -0
  35. package/src/meter/meter.tsx +89 -0
  36. package/src/navigation-menu/navigation-menu.tsx +90 -0
  37. package/src/number-field/number-field.tsx +79 -0
  38. package/src/pagination/pagination.tsx +67 -0
  39. package/src/popover/popover.tsx +58 -0
  40. package/src/progress/progress.tsx +83 -0
  41. package/src/radio-group/radio-group.tsx +94 -0
  42. package/src/rating-group/rating-group.tsx +101 -0
  43. package/src/search/search.tsx +99 -0
  44. package/src/segmented-control/segmented-control.tsx +92 -0
  45. package/src/select/select.tsx +163 -0
  46. package/src/separator/separator.tsx +64 -0
  47. package/src/skeleton/skeleton.tsx +73 -0
  48. package/src/slider/slider.tsx +94 -0
  49. package/src/style/global.css +156 -0
  50. package/src/switch/switch.tsx +104 -0
  51. package/src/tabs/tabs.tsx +73 -0
  52. package/src/text-field/text-field.tsx +97 -0
  53. package/src/time-field/time-field.tsx +103 -0
  54. package/src/toast/toast.tsx +132 -0
  55. package/src/toggle-button/toggle-button.tsx +69 -0
  56. package/src/toggle-group/toggle-group.tsx +85 -0
  57. package/src/tooltip/tooltip.tsx +73 -0
  58. /package/dist/{src/accordion → accordion}/accordion.d.ts +0 -0
  59. /package/dist/{src/alert → alert}/alert.d.ts +0 -0
  60. /package/dist/{src/breadcrumbs → breadcrumbs}/breadcrumbs.d.ts +0 -0
  61. /package/dist/{src/button → button}/button.d.ts +0 -0
  62. /package/dist/{src/checkbox → checkbox}/checkbox.d.ts +0 -0
  63. /package/dist/{src/collapsible → collapsible}/collapsible.d.ts +0 -0
  64. /package/dist/{src/color-area → color-area}/color-area.d.ts +0 -0
  65. /package/dist/{src/color-channel-field → color-channel-field}/color-channel-field.d.ts +0 -0
  66. /package/dist/{src/color-field → color-field}/color-field.d.ts +0 -0
  67. /package/dist/{src/color-slider → color-slider}/color-slider.d.ts +0 -0
  68. /package/dist/{src/color-swatch → color-swatch}/color-swatch.d.ts +0 -0
  69. /package/dist/{src/color-wheel → color-wheel}/color-wheel.d.ts +0 -0
  70. /package/dist/{src/combobox → combobox}/combobox.d.ts +0 -0
  71. /package/dist/{src/context-menu → context-menu}/context-menu.d.ts +0 -0
  72. /package/dist/{src/dialog → dialog}/dialog.d.ts +0 -0
  73. /package/dist/{src/dropdown-menu → dropdown-menu}/dropdown-menu.d.ts +0 -0
  74. /package/dist/{src/file-field → file-field}/file-field.d.ts +0 -0
  75. /package/dist/{src/hover-card → hover-card}/hover-card.d.ts +0 -0
  76. /package/dist/{src/image → image}/image.d.ts +0 -0
  77. /package/dist/{src/index.d.ts → index.d.ts} +0 -0
  78. /package/dist/{src/link → link}/link.d.ts +0 -0
  79. /package/dist/{src/menubar → menubar}/menubar.d.ts +0 -0
  80. /package/dist/{src/meter → meter}/meter.d.ts +0 -0
  81. /package/dist/{src/navigation-menu → navigation-menu}/navigation-menu.d.ts +0 -0
  82. /package/dist/{src/number-field → number-field}/number-field.d.ts +0 -0
  83. /package/dist/{src/pagination → pagination}/pagination.d.ts +0 -0
  84. /package/dist/{src/popover → popover}/popover.d.ts +0 -0
  85. /package/dist/{src/progress → progress}/progress.d.ts +0 -0
  86. /package/dist/{src/radio-group → radio-group}/radio-group.d.ts +0 -0
  87. /package/dist/{src/rating-group → rating-group}/rating-group.d.ts +0 -0
  88. /package/dist/{src/search → search}/search.d.ts +0 -0
  89. /package/dist/{src/segmented-control → segmented-control}/segmented-control.d.ts +0 -0
  90. /package/dist/{src/select → select}/select.d.ts +0 -0
  91. /package/dist/{src/switch → switch}/switch.d.ts +0 -0
  92. /package/dist/{src/tabs → tabs}/tabs.d.ts +0 -0
  93. /package/dist/{src/text-field → text-field}/text-field.d.ts +0 -0
  94. /package/dist/{src/time-field → time-field}/time-field.d.ts +0 -0
  95. /package/dist/{src/toggle-group → toggle-group}/toggle-group.d.ts +0 -0
  96. /package/dist/{src/tooltip → tooltip}/tooltip.d.ts +0 -0
@@ -13,10 +13,12 @@ declare const separatorStyles: import('tailwind-variants').TVReturnType<{
13
13
  };
14
14
  variant: {
15
15
  default: string;
16
- muted: string;
17
16
  primary: string;
17
+ success: string;
18
+ warning: string;
19
+ danger: string;
18
20
  };
19
- }, undefined, "bg-slate-200 dark:bg-slate-800 shrink-0 transition-colors", {
21
+ }, undefined, "bg-foreground shrink-0 transition-colors", {
20
22
  orientation: {
21
23
  horizontal: string;
22
24
  vertical: string;
@@ -28,8 +30,10 @@ declare const separatorStyles: import('tailwind-variants').TVReturnType<{
28
30
  };
29
31
  variant: {
30
32
  default: string;
31
- muted: string;
32
33
  primary: string;
34
+ success: string;
35
+ warning: string;
36
+ danger: string;
33
37
  };
34
38
  }, undefined, import('tailwind-variants').TVReturnType<{
35
39
  orientation: {
@@ -43,10 +47,12 @@ declare const separatorStyles: import('tailwind-variants').TVReturnType<{
43
47
  };
44
48
  variant: {
45
49
  default: string;
46
- muted: string;
47
50
  primary: string;
51
+ success: string;
52
+ warning: string;
53
+ danger: string;
48
54
  };
49
- }, undefined, "bg-slate-200 dark:bg-slate-800 shrink-0 transition-colors", unknown, unknown, undefined>>;
55
+ }, undefined, "bg-foreground shrink-0 transition-colors", unknown, unknown, undefined>>;
50
56
  type SeparatorVariants = VariantProps<typeof separatorStyles>;
51
57
  export interface SeparatorProps extends ComponentProps<typeof KSeparator>, SeparatorVariants {
52
58
  class?: string;
@@ -12,7 +12,7 @@ declare const skeletonStyles: import('tailwind-variants').TVReturnType<{
12
12
  wave: string;
13
13
  none: string;
14
14
  };
15
- }, undefined, "bg-slate-200 dark:bg-slate-800", {
15
+ }, undefined, "bg-foreground", {
16
16
  variant: {
17
17
  rect: string;
18
18
  circle: string;
@@ -34,7 +34,7 @@ declare const skeletonStyles: import('tailwind-variants').TVReturnType<{
34
34
  wave: string;
35
35
  none: string;
36
36
  };
37
- }, undefined, "bg-slate-200 dark:bg-slate-800", unknown, unknown, undefined>>;
37
+ }, undefined, "bg-foreground", unknown, unknown, undefined>>;
38
38
  type SkeletonVariants = VariantProps<typeof skeletonStyles>;
39
39
  export interface SkeletonProps extends Omit<ComponentProps<typeof KSkeleton>, "class" | "width" | "height">, SkeletonVariants {
40
40
  width?: string | number;
@@ -11,6 +11,10 @@ declare const sliderStyles: import('tailwind-variants').TVReturnType<{
11
11
  fill: string;
12
12
  thumb: string;
13
13
  };
14
+ warning: {
15
+ fill: string;
16
+ thumb: string;
17
+ };
14
18
  success: {
15
19
  fill: string;
16
20
  thumb: string;
@@ -48,6 +52,10 @@ declare const sliderStyles: import('tailwind-variants').TVReturnType<{
48
52
  fill: string;
49
53
  thumb: string;
50
54
  };
55
+ warning: {
56
+ fill: string;
57
+ thumb: string;
58
+ };
51
59
  success: {
52
60
  fill: string;
53
61
  thumb: string;
@@ -85,6 +93,10 @@ declare const sliderStyles: import('tailwind-variants').TVReturnType<{
85
93
  fill: string;
86
94
  thumb: string;
87
95
  };
96
+ warning: {
97
+ fill: string;
98
+ thumb: string;
99
+ };
88
100
  success: {
89
101
  fill: string;
90
102
  thumb: string;
@@ -87,5 +87,7 @@ export interface ToastProps extends Omit<ComponentProps<typeof KToast>, "class">
87
87
  class?: string;
88
88
  }
89
89
  export declare const ToastProvider: (props: ParentProps) => import("solid-js").JSX.Element;
90
- export declare const showToast: (props: Omit<ToastProps, "toastId">) => number;
90
+ export declare const showToast: (props: Omit<ToastProps, "toastId">) => number | {
91
+ toastId: () => string;
92
+ };
91
93
  export {};
@@ -5,7 +5,6 @@ declare const toggleStyles: import('tailwind-variants').TVReturnType<{
5
5
  variant: {
6
6
  solid: string;
7
7
  outline: string;
8
- ghost: string;
9
8
  };
10
9
  size: {
11
10
  sm: string;
@@ -17,7 +16,6 @@ declare const toggleStyles: import('tailwind-variants').TVReturnType<{
17
16
  variant: {
18
17
  solid: string;
19
18
  outline: string;
20
- ghost: string;
21
19
  };
22
20
  size: {
23
21
  sm: string;
@@ -29,7 +27,6 @@ declare const toggleStyles: import('tailwind-variants').TVReturnType<{
29
27
  variant: {
30
28
  solid: string;
31
29
  outline: string;
32
- ghost: string;
33
30
  };
34
31
  size: {
35
32
  sm: string;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "solid-element-ui",
3
- "version": "0.2.4",
3
+ "version": "0.2.6",
4
4
  "type": "module",
5
5
  "license": "MIT",
6
6
  "author": "sanguogege",
@@ -25,6 +25,7 @@
25
25
  },
26
26
  "files": [
27
27
  "dist",
28
+ "src",
28
29
  "README.md"
29
30
  ],
30
31
  "main": "./dist/index.js",
@@ -34,23 +35,26 @@
34
35
  ".": {
35
36
  "types": "./dist/index.d.ts",
36
37
  "solid": "./src/index.tsx",
37
- "import": "./dist/index.js",
38
+ "import": {
39
+ "node": "./dist/index.js",
40
+ "default": "./dist/index.js"
41
+ },
42
+ "browser": "./dist/index.js",
38
43
  "default": "./dist/index.js"
39
44
  },
40
- "./styles": "./src/index.css",
41
- "./index.css": "./dist/index.css"
45
+ "./index.css": "./dist/global.css"
42
46
  },
43
47
  "source": "./src/index.tsx",
44
48
  "scripts": {
45
49
  "build": "tsc -b && vite build"
46
50
  },
47
51
  "peerDependencies": {
48
- "solid-js": "^1.9.10"
52
+ "solid-js": "^1.9.11"
49
53
  },
50
54
  "dependencies": {
51
55
  "@kobalte/core": "^0.13.11",
52
- "lucide-solid": "^0.562.0",
53
- "tailwind-merge": "^3.4.0",
56
+ "lucide-solid": "^0.577.0",
57
+ "tailwind-merge": "^3.5.0",
54
58
  "tailwind-variants": "^3.2.2"
55
59
  },
56
60
  "devDependencies": {
@@ -0,0 +1,80 @@
1
+ import {
2
+ Accordion as KAccordion,
3
+ type AccordionRootProps,
4
+ } from "@kobalte/core/accordion";
5
+ import { For, type JSX, splitProps } from "solid-js";
6
+ import { ChevronDown } from "lucide-solid";
7
+ import { tv, type VariantProps } from "tailwind-variants";
8
+
9
+ // 1. 定义样式
10
+ const accordionStyles = tv(
11
+ {
12
+ slots: {
13
+ root: "w-full divide-y divide-base border border-base rounded-lg overflow-hidden",
14
+ item: "group",
15
+ header: "flex",
16
+ trigger: [
17
+ "flex flex-1 items-center justify-between cursor-pointer py-4 px-4 text-md font-medium transition-all ",
18
+ "bg-foreground hover:bg-foreground/80",
19
+ ],
20
+ content: [
21
+ "overflow-hidden text-md transition-all bg-transparent text-main",
22
+ "data-[expanded]:animate-accordion-down data-[closed]:animate-accordion-up",
23
+ ],
24
+ contentInner: "pb-4 pt-2 px-4",
25
+ icon: "h-4 w-4 transition-transform duration-200 group-data-[expanded]:rotate-180",
26
+ },
27
+ },
28
+ {
29
+ twMerge: true,
30
+ },
31
+ );
32
+
33
+ const { root, item, header, trigger, content, contentInner, icon } =
34
+ accordionStyles();
35
+
36
+ // 2. 类型定义
37
+ export interface AccordionItem {
38
+ value: string;
39
+ title: JSX.Element;
40
+ content: JSX.Element;
41
+ disabled?: boolean;
42
+ }
43
+
44
+ interface AccordionProps
45
+ extends AccordionRootProps, VariantProps<typeof accordionStyles> {
46
+ items: AccordionItem[];
47
+ class?: string;
48
+ }
49
+
50
+ export const Accordion = (props: AccordionProps) => {
51
+ const [local, others] = splitProps(props, ["items", "class"]);
52
+
53
+ return (
54
+ <KAccordion class={root({ class: local.class })} {...others}>
55
+ <For each={local.items}>
56
+ {(itemData) => (
57
+ <KAccordion.Item
58
+ value={itemData.value}
59
+ disabled={itemData.disabled}
60
+ class={item()}
61
+ >
62
+ <KAccordion.Header class={header()}>
63
+ <KAccordion.Trigger class={trigger()}>
64
+ {itemData.title}
65
+ <ChevronDown
66
+ class={icon()}
67
+ aria-hidden="true"
68
+ />
69
+ </KAccordion.Trigger>
70
+ </KAccordion.Header>
71
+
72
+ <KAccordion.Content class={content()}>
73
+ <div class={contentInner()}>{itemData.content}</div>
74
+ </KAccordion.Content>
75
+ </KAccordion.Item>
76
+ )}
77
+ </For>
78
+ </KAccordion>
79
+ );
80
+ };
@@ -0,0 +1,86 @@
1
+ import { Alert as KAlert } from "@kobalte/core/alert";
2
+ import { splitProps, type JSX, type ComponentProps } from "solid-js";
3
+ import { tv, type VariantProps } from "tailwind-variants";
4
+ import { Info, CircleAlert, CircleCheck, CircleX } from "lucide-solid";
5
+
6
+ const alertStyles = tv(
7
+ {
8
+ slots: {
9
+ root: "relative w-full rounded-lg border p-4 flex gap-3 antialiased text-main",
10
+ content: "flex flex-col gap-1 text-left",
11
+ title: "font-semibold leading-none tracking-tight",
12
+ children: "text-md leading-relaxed opacity-90",
13
+ icon: "shrink-0",
14
+ },
15
+ variants: {
16
+ variant: {
17
+ info: {
18
+ root: "bg-primary/20 border-primary/80",
19
+ icon: "text-primary",
20
+ },
21
+ success: {
22
+ root: "bg-success/20 border-success/80 ",
23
+ icon: "text-success",
24
+ },
25
+ warning: {
26
+ root: "bg-warning/20 border-warning/80 ",
27
+ icon: "text-warning",
28
+ },
29
+ danger: {
30
+ root: "bg-danger/20 border-danger/80 ",
31
+ icon: "text-danger",
32
+ },
33
+ },
34
+ },
35
+ defaultVariants: {
36
+ variant: "info",
37
+ },
38
+ },
39
+ {
40
+ twMerge: true,
41
+ },
42
+ );
43
+
44
+ type AlertVariants = VariantProps<typeof alertStyles>;
45
+
46
+ export interface AlertProps
47
+ extends ComponentProps<typeof KAlert>, AlertVariants {
48
+ title?: string;
49
+ icon?: boolean | JSX.Element;
50
+ }
51
+
52
+ const iconMap = {
53
+ info: Info,
54
+ success: CircleCheck,
55
+ warning: CircleAlert,
56
+ danger: CircleX,
57
+ };
58
+
59
+ export const Alert = (props: AlertProps) => {
60
+ const [local, variantProps, others] = splitProps(
61
+ props,
62
+ ["title", "icon", "children", "class"],
63
+ ["variant"],
64
+ );
65
+
66
+ const { root, content, title, children, icon } = alertStyles(variantProps);
67
+
68
+ const RenderedIcon = () => {
69
+ if (local.icon === false) return null;
70
+ if (typeof local.icon === "object") return local.icon;
71
+
72
+ const Icon = iconMap[variantProps.variant || "info"];
73
+ return <Icon size={18} class={icon()} />;
74
+ };
75
+
76
+ // 5. 渲染组件
77
+ return (
78
+ <KAlert class={`${root()} ${local.class || ""}`.trim()} {...others}>
79
+ <RenderedIcon />
80
+ <div class={content()}>
81
+ {local.title && <h5 class={title()}>{local.title}</h5>}
82
+ <div class={children()}>{local.children}</div>
83
+ </div>
84
+ </KAlert>
85
+ );
86
+ };
@@ -0,0 +1,129 @@
1
+ import { AlertDialog as KAlertDialog } from "@kobalte/core/alert-dialog";
2
+ import {
3
+ splitProps,
4
+ type JSX,
5
+ type ComponentProps,
6
+ createSignal,
7
+ } from "solid-js";
8
+ import { tv } from "tailwind-variants";
9
+ import { X } from "lucide-solid";
10
+ import { Button } from "../button/button";
11
+
12
+ const alertDialogStyles = tv(
13
+ {
14
+ slots: {
15
+ overlay: [
16
+ "fixed inset-0 z-50 bg-black/50 backdrop-blur-sm",
17
+ " data-[expanded]:animate-in data-[closed]:animate-out ",
18
+ ],
19
+ content: [
20
+ "fixed left-1/2 top-1/2 z-50 w-full max-w-md -translate-x-1/2 -translate-y-1/2 rounded-xl bg-app p-4 shadow-xl ",
21
+ "data-[expanded]:animate-in data-[closed]:animate-out",
22
+ ],
23
+ header: "flex align-center justify-between",
24
+ title: "text-lg font-semibold text-main ",
25
+ description: "text-sm py-2 text-main",
26
+ footer: "mt-6 flex flex-row justify-end gap-3",
27
+ closeButton:
28
+ "rounded-sm opacity-70 text-main transition-opacity hover:opacity-100 focus:outline-none",
29
+ },
30
+ },
31
+ {
32
+ twMerge: true,
33
+ },
34
+ );
35
+
36
+ const { overlay, content, header, title, description, footer, closeButton } =
37
+ alertDialogStyles();
38
+
39
+ interface AlertDialogProps extends ComponentProps<typeof KAlertDialog> {
40
+ trigger: JSX.Element;
41
+ title: string;
42
+ description?: string;
43
+ action?: JSX.Element;
44
+ cancel?: JSX.Element;
45
+ onConfirm?: () => void | Promise<void>;
46
+ }
47
+
48
+ export const AlertDialog = (props: AlertDialogProps) => {
49
+ // 使用受控模式
50
+ const [isOpen, setIsOpen] = createSignal(false);
51
+ const [loading, setLoading] = createSignal(false);
52
+
53
+ const [local, others] = splitProps(props, [
54
+ "trigger",
55
+ "title",
56
+ "description",
57
+ "action",
58
+ "cancel",
59
+ "onConfirm",
60
+ ]);
61
+
62
+ const handleConfirm = async (e: MouseEvent) => {
63
+ // 阻止默认行为和冒泡,确保点击不会误触发 Kobalte 的内部关闭逻辑
64
+ e.preventDefault();
65
+ e.stopPropagation();
66
+
67
+ if (local.onConfirm) {
68
+ setLoading(true);
69
+ try {
70
+ await local.onConfirm();
71
+ // 只有逻辑成功执行后,才手动关闭
72
+ setIsOpen(false);
73
+ } catch (error) {
74
+ console.error("确认操作失败:", error);
75
+ // 报错时不关闭,让用户留在页面
76
+ } finally {
77
+ setLoading(false);
78
+ }
79
+ } else {
80
+ setIsOpen(false);
81
+ }
82
+ };
83
+
84
+ return (
85
+ <KAlertDialog {...others} open={isOpen()} onOpenChange={setIsOpen}>
86
+ <div onClick={() => setIsOpen(true)} class="inline-block">
87
+ {local.trigger}
88
+ </div>
89
+
90
+ <KAlertDialog.Portal>
91
+ <KAlertDialog.Overlay class={overlay()} />
92
+ <KAlertDialog.Content class={content()}>
93
+ <div class={header()}>
94
+ <KAlertDialog.Title class={title()}>
95
+ {local.title}
96
+ </KAlertDialog.Title>
97
+ {/* 这里使用 CloseButton 是正确的,因为它专门负责“取消/关闭” */}
98
+ <KAlertDialog.CloseButton class={closeButton()}>
99
+ <X size={18} />
100
+ </KAlertDialog.CloseButton>
101
+ </div>
102
+
103
+ <div class="mt-2">
104
+ {local.description && (
105
+ <KAlertDialog.Description class={description()}>
106
+ {local.description}
107
+ </KAlertDialog.Description>
108
+ )}
109
+ </div>
110
+
111
+ <div class={footer()}>
112
+ <KAlertDialog.CloseButton>
113
+ {local.cancel || (
114
+ <Button variant="outline">取消</Button>
115
+ )}
116
+ </KAlertDialog.CloseButton>
117
+ <div onClick={handleConfirm}>
118
+ {local.action || (
119
+ <Button color="primary" loading={loading()}>
120
+ 确认
121
+ </Button>
122
+ )}
123
+ </div>
124
+ </div>
125
+ </KAlertDialog.Content>
126
+ </KAlertDialog.Portal>
127
+ </KAlertDialog>
128
+ );
129
+ };
@@ -0,0 +1,49 @@
1
+ import { Badge as KBadge } from "@kobalte/core/badge";
2
+ import { splitProps, type ComponentProps } from "solid-js";
3
+ import { tv, type VariantProps } from "tailwind-variants";
4
+
5
+ const badgeStyles = tv(
6
+ {
7
+ base: "inline-flex items-center rounded-full border border-transparent px-2.5 py-0.5 text-xs font-semibold transition-colors focus:outline-none",
8
+ variants: {
9
+ variant: {
10
+ default: " bg-reversal-bg text-reversal",
11
+ secondary:
12
+ "bg-foreground text-muted",
13
+ outline: "text-main border-light",
14
+ success:
15
+ "bg-success/20 text-success ",
16
+ danger: "bg-danger/20 text-danger",
17
+ },
18
+ },
19
+ defaultVariants: {
20
+ variant: "default",
21
+ },
22
+ },
23
+ {
24
+ twMerge: true,
25
+ },
26
+ );
27
+
28
+ type BadgeVariants = VariantProps<typeof badgeStyles>;
29
+
30
+ export interface BadgeProps
31
+ extends ComponentProps<typeof KBadge>, BadgeVariants {}
32
+
33
+ export const Badge = (props: BadgeProps) => {
34
+ const [local, variantProps, others] = splitProps(
35
+ props,
36
+ ["class"],
37
+ ["variant"],
38
+ );
39
+
40
+ return (
41
+ <KBadge
42
+ class={badgeStyles({
43
+ variant: variantProps.variant,
44
+ class: local.class,
45
+ })}
46
+ {...others}
47
+ />
48
+ );
49
+ };
@@ -0,0 +1,69 @@
1
+ import { Breadcrumbs as KBreadcrumbs } from "@kobalte/core/breadcrumbs";
2
+ import { For, type JSX, splitProps, type ComponentProps } from "solid-js";
3
+ import { tv } from "tailwind-variants";
4
+ import { ChevronRight } from "lucide-solid";
5
+
6
+ // TODO 1. 定义样式
7
+ // 2. icon 支持自定义
8
+
9
+ const breadcrumbStyles = tv(
10
+ {
11
+ slots: {
12
+ root: "flex w-full justify-start items-center gap-2",
13
+ link: "text-md transition-colors text-main data-[current]:text-main/50 data-[disabled]:pointer-events-none no-underline",
14
+ separator: "flex h-4 w-4 items-center justify-center text-main/80",
15
+ },
16
+ },
17
+ {
18
+ twMerge: true,
19
+ },
20
+ );
21
+
22
+ const { root, link, separator } = breadcrumbStyles();
23
+
24
+ export interface BreadcrumbItem {
25
+ title: JSX.Element;
26
+ href?: string;
27
+ current?: boolean;
28
+ disabled?: boolean;
29
+ }
30
+
31
+ interface BreadcrumbsProps extends ComponentProps<typeof KBreadcrumbs> {
32
+ items: BreadcrumbItem[];
33
+ separatorIcon?: JSX.Element;
34
+ }
35
+
36
+ export const Breadcrumbs = (props: BreadcrumbsProps) => {
37
+ const [local, others] = splitProps(props, [
38
+ "items",
39
+ "separatorIcon",
40
+ "class",
41
+ ]);
42
+
43
+ return (
44
+ <KBreadcrumbs class={root()} {...others}>
45
+ <For each={local.items}>
46
+ {(breadcrumb, index) => (
47
+ <>
48
+ <KBreadcrumbs.Link
49
+ href={breadcrumb.href}
50
+ current={breadcrumb.current}
51
+ disabled={breadcrumb.disabled}
52
+ class={link({ class: local.class })}
53
+ >
54
+ {breadcrumb.title}
55
+ </KBreadcrumbs.Link>
56
+
57
+ {index() < local.items.length - 1 && (
58
+ <span aria-hidden="true" class={separator()}>
59
+ {local.separatorIcon || (
60
+ <ChevronRight size={16} />
61
+ )}
62
+ </span>
63
+ )}
64
+ </>
65
+ )}
66
+ </For>
67
+ </KBreadcrumbs>
68
+ );
69
+ };