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
@@ -0,0 +1,64 @@
1
+ import { Separator as KSeparator } from "@kobalte/core/separator";
2
+ import { splitProps, type ComponentProps } from "solid-js";
3
+ import { tv, type VariantProps } from "tailwind-variants";
4
+
5
+ const separatorStyles = tv(
6
+ {
7
+ base: "bg-foreground shrink-0 transition-colors",
8
+ variants: {
9
+ orientation: {
10
+ horizontal: "h-[1px] w-full my-4",
11
+ vertical: "h-full w-[1px] mx-4",
12
+ },
13
+ thickness: {
14
+ thin: "", // 默认 1px
15
+ medium: "data-[orientation=horizontal]:h-[2px] data-[orientation=vertical]:w-[2px]",
16
+ thick: "data-[orientation=horizontal]:h-[4px] data-[orientation=vertical]:w-[4px] rounded-full",
17
+ },
18
+ variant: {
19
+ default: "bg-foreground",
20
+ primary: "bg-primary",
21
+ success: "bg-success",
22
+ warning: "bg-warning",
23
+ danger: "bg-danger",
24
+ },
25
+ },
26
+ defaultVariants: {
27
+ orientation: "horizontal",
28
+ thickness: "thin",
29
+ variant: "default",
30
+ },
31
+ },
32
+ {
33
+ twMerge: true,
34
+ },
35
+ );
36
+
37
+ type SeparatorVariants = VariantProps<typeof separatorStyles>;
38
+
39
+ export interface SeparatorProps
40
+ extends ComponentProps<typeof KSeparator>,
41
+ SeparatorVariants {
42
+ class?: string;
43
+ }
44
+
45
+ export const Separator = (props: SeparatorProps) => {
46
+ const [local, variantProps, others] = splitProps(
47
+ props,
48
+ ["class"],
49
+ ["orientation", "thickness", "variant"]
50
+ );
51
+
52
+ return (
53
+ <KSeparator
54
+ class={separatorStyles({
55
+ orientation: variantProps.orientation,
56
+ thickness: variantProps.thickness,
57
+ variant: variantProps.variant,
58
+ class: local.class,
59
+ })}
60
+ orientation={variantProps.orientation}
61
+ {...others}
62
+ />
63
+ );
64
+ };
@@ -0,0 +1,73 @@
1
+ import { Skeleton as KSkeleton } from "@kobalte/core/skeleton";
2
+ import { splitProps, type ComponentProps } from "solid-js";
3
+ import { tv, type VariantProps } from "tailwind-variants";
4
+
5
+ const skeletonStyles = tv(
6
+ {
7
+ base: "bg-foreground",
8
+ variants: {
9
+ variant: {
10
+ rect: "rounded-md",
11
+ circle: "rounded-full",
12
+ text: "rounded h-3 w-full",
13
+ },
14
+ animation: {
15
+ pulse: "animate-pulse",
16
+ wave: "relative overflow-hidden before:absolute before:inset-0 before:-translate-x-full before:animate-[wave_2s_linear_infinite] before:bg-gradient-to-r before:from-transparent before:via-white/20 before:to-transparent",
17
+ none: "",
18
+ },
19
+ },
20
+ defaultVariants: {
21
+ variant: "rect",
22
+ animation: "pulse",
23
+ },
24
+ },
25
+ {
26
+ twMerge: true,
27
+ },
28
+ );
29
+
30
+ type SkeletonVariants = VariantProps<typeof skeletonStyles>;
31
+
32
+ // 核心修正:使用 Omit 排除掉冲突的 width 和 height
33
+ export interface SkeletonProps
34
+ extends Omit<
35
+ ComponentProps<typeof KSkeleton>,
36
+ "class" | "width" | "height"
37
+ >,
38
+ SkeletonVariants {
39
+ width?: string | number;
40
+ height?: string | number;
41
+ class?: string;
42
+ }
43
+
44
+ export const Skeleton = (props: SkeletonProps) => {
45
+ // 显式提取这些属性,避免传给 KSkeleton 引起类型或运行时错误
46
+ const [local, variantProps, others] = splitProps(
47
+ props,
48
+ ["class", "width", "height", "style"],
49
+ ["variant", "animation"]
50
+ );
51
+
52
+ const mergedStyle = () => ({
53
+ width:
54
+ typeof local.width === "number" ? `${local.width}px` : local.width,
55
+ height:
56
+ typeof local.height === "number"
57
+ ? `${local.height}px`
58
+ : local.height,
59
+ ...(typeof local.style === "object" ? local.style : {}),
60
+ });
61
+
62
+ return (
63
+ <KSkeleton
64
+ class={skeletonStyles({
65
+ variant: variantProps.variant,
66
+ animation: variantProps.animation,
67
+ class: local.class,
68
+ })}
69
+ style={mergedStyle()}
70
+ {...others}
71
+ />
72
+ );
73
+ };
@@ -0,0 +1,94 @@
1
+ import { Slider as KSlider } from "@kobalte/core/slider";
2
+ import { splitProps, type ComponentProps, For, Show } from "solid-js";
3
+ import { tv, type VariantProps } from "tailwind-variants";
4
+
5
+ // FIXME 点击轨道时报错
6
+
7
+ const sliderStyles = tv(
8
+ {
9
+ slots: {
10
+ root: "relative flex flex-col items-center select-none touch-none w-full gap-2",
11
+ labelWrapper: "flex w-full justify-between items-center",
12
+ label: "text-sm font-medium text-muted",
13
+ value: "text-sm text-muted font-mono",
14
+ track: "relative h-2 w-full grow rounded-full bg-foreground",
15
+ fill: "absolute h-full rounded-full ",
16
+ thumb: [
17
+ "block h-5 w-5 rounded-full border-2 bg-app ring-offset-white transition-colors",
18
+ "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-blue-400 focus-visible:ring-offset-2",
19
+ "disabled:pointer-events-none disabled:opacity-50 hover:scale-110 active:scale-95 transition-transform",
20
+ ],
21
+ },
22
+ variants: {
23
+ variant: {
24
+ default: { fill: "bg-primary", thumb: "border-primary" },
25
+ danger: { fill: "bg-danger", thumb: "border-danger" },
26
+ warning: { fill: "bg-warning", thumb: "border-warning" },
27
+ success: {
28
+ fill: "bg-success",
29
+ thumb: "border-success",
30
+ },
31
+ },
32
+ size: {
33
+ sm: { track: "h-1", thumb: "h-4 w-4" },
34
+ md: { track: "h-2", thumb: "h-5 w-5" },
35
+ lg: { track: "h-3", thumb: "h-6 w-6" },
36
+ },
37
+ },
38
+ defaultVariants: {
39
+ variant: "default",
40
+ size: "md",
41
+ },
42
+ },
43
+ {
44
+ twMerge: true,
45
+ },
46
+ );
47
+
48
+ type SliderVariants = VariantProps<typeof sliderStyles>;
49
+
50
+ export interface SliderProps
51
+ extends Omit<ComponentProps<typeof KSlider>, "class">,
52
+ SliderVariants {
53
+ label?: string;
54
+ showValue?: boolean;
55
+ class?: string;
56
+ }
57
+
58
+ export const Slider = (props: SliderProps) => {
59
+ const [local, variantProps, others] = splitProps(
60
+ props,
61
+ ["label", "showValue", "class"],
62
+ ["variant", "size"]
63
+ );
64
+
65
+ const styles = sliderStyles(variantProps);
66
+
67
+ return (
68
+ <KSlider class={styles.root({ class: local.class })} {...others}>
69
+ <Show when={local.label || local.showValue}>
70
+ <div class={styles.labelWrapper()}>
71
+ <Show when={local.label}>
72
+ <KSlider.Label class={styles.label()}>
73
+ {local.label}
74
+ </KSlider.Label>
75
+ </Show>
76
+ <Show when={local.showValue}>
77
+ <KSlider.ValueLabel class={styles.value()} />
78
+ </Show>
79
+ </div>
80
+ </Show>
81
+
82
+ <KSlider.Track class={styles.track()}>
83
+ <KSlider.Fill class={styles.fill()} />
84
+ <For each={others.value ?? [others.defaultValue]}>
85
+ {() => (
86
+ <KSlider.Thumb class={styles.thumb()}>
87
+ <KSlider.Input />
88
+ </KSlider.Thumb>
89
+ )}
90
+ </For>
91
+ </KSlider.Track>
92
+ </KSlider>
93
+ );
94
+ };
@@ -0,0 +1,156 @@
1
+ @import "tailwindcss";
2
+
3
+ @layer theme {
4
+ :root {
5
+ --primary: var(--color-blue-600);
6
+ --success: var(--color-green-600);
7
+ --warning: var(--color-orange-600);
8
+ --danger: var(--color-red-600);
9
+
10
+ --app-bg: var(--color-white); /* 应用背景色 */
11
+ --app-bg-reversal: var(--color-zinc-900); /* 应用反转背景色 */
12
+ --app-foreground: var(--color-zinc-100); /* 应用前景色 */
13
+
14
+
15
+ --app-text-main: var(--color-zinc-950); /* 应用主文字色 */
16
+ --app-text-muted: var(--color-zinc-600); /* 应用次级文字色*/
17
+ --app-border: var(--color-zinc-500); /* 应用边框色*/
18
+ --app-border-light: var(--color-zinc-300); /* 应用浅边框色 */
19
+ --app-ring: var(--color-zinc-300);
20
+ --app-text-reversal: var(--color-zinc-100); /* 应用反转文字色 */
21
+ }
22
+
23
+ [data-theme="dark"] {
24
+ --app-text-reversal: var(--color-zinc-950);
25
+ --app-bg-reversal: var(--color-zinc-50);
26
+ --app-bg: var(--color-zinc-950);
27
+ --app-text-main: var(--color-zinc-50);
28
+ --app-text-muted: var(--color-zinc-400);
29
+ --app-ring: var(--color-zinc-600);
30
+ --app-foreground: var(--color-zinc-900);
31
+ }
32
+
33
+ [data-theme="coffee"] {
34
+ --app-bg: #2c2420;
35
+ --app-text-main: #f3e5d8;
36
+ --app-ring: #8b5e3c;
37
+ }
38
+
39
+ @keyframes accordion-down {
40
+ from {
41
+ height: 0;
42
+ }
43
+ to {
44
+ height: var(--kb-accordion-content-height);
45
+ }
46
+ }
47
+
48
+ @keyframes accordion-up {
49
+ from {
50
+ height: var(--kb-accordion-content-height);
51
+ }
52
+ to {
53
+ height: 0;
54
+ }
55
+ }
56
+
57
+ @keyframes fade-in {
58
+ from {
59
+ opacity: 0;
60
+ }
61
+ to {
62
+ opacity: 1;
63
+ }
64
+ }
65
+
66
+ @keyframes fade-out {
67
+ from {
68
+ opacity: 1;
69
+ }
70
+ to {
71
+ opacity: 0;
72
+ }
73
+ }
74
+
75
+ @keyframes collapsible-down {
76
+ from {
77
+ height: 0;
78
+ }
79
+ to {
80
+ height: var(--kb-collapsible-content-height);
81
+ }
82
+ }
83
+
84
+ @keyframes collapsible-up {
85
+ from {
86
+ height: var(--kb-collapsible-content-height);
87
+ }
88
+ to {
89
+ height: 0;
90
+ }
91
+ }
92
+
93
+ @keyframes slide-in {
94
+ from {
95
+ transform: translateX(calc(100% + var(--viewport-padding)));
96
+ }
97
+ to {
98
+ transform: translateX(0);
99
+ }
100
+ }
101
+
102
+ @keyframes hide {
103
+ from {
104
+ opacity: 1;
105
+ }
106
+ to {
107
+ opacity: 0;
108
+ }
109
+ }
110
+
111
+ @keyframes swipe-out {
112
+ from {
113
+ transform: translateX(var(--kb-toast-swipe-end-x));
114
+ }
115
+ to {
116
+ transform: translateX(calc(100% + var(--viewport-padding)));
117
+ }
118
+ }
119
+ }
120
+
121
+ /* --- 2. 注册到 Tailwind 主题系统 --- */
122
+ @theme {
123
+ --color-primary: var(--primary);
124
+ --color-success: var(--success);
125
+ --color-warning: var(--warning);
126
+ --color-danger: var(--danger);
127
+
128
+ --color-app: var(--app-bg);
129
+ --color-foreground: var(--app-foreground);
130
+ --color-reversal-bg: var(--app-bg-reversal);
131
+ --color-main: var(--app-text-main);
132
+ --color-muted: var(--app-text-muted);
133
+ --color-reversal: var(--app-text-reversal);
134
+ --color-base: var(--app-border);
135
+ --color-light: var(--app-border-light);
136
+ --radius-app: 0.75rem;
137
+
138
+ /* 注册动画到主题 */
139
+ --animate-accordion-down: accordion-down 0.2s ease-out;
140
+ --animate-accordion-up: accordion-up 0.2s ease-out;
141
+
142
+ --animate-in: fade-in 0.2s ease-in;
143
+ --animate-out: fade-out 0.2s ease-out forwards;
144
+
145
+ --animate-collapsible-down: collapsible-down 0.2s ease-out;
146
+ --animate-collapsible-up: collapsible-up 0.2s ease-out;
147
+
148
+ --animate-slide-in: slide-in 150ms cubic-bezier(0.16, 1, 0.3, 1);
149
+ --animate-hide: hide 100ms ease-in;
150
+ --animate-swipe-out: swipe-out 100ms ease-out;
151
+
152
+ --viewport-padding: 16px;
153
+ }
154
+
155
+ /* --- 3. 暗色主题变体 --- */
156
+ @custom-variant dark (&:where([data-theme="dark"], [data-theme="dark"] *));
@@ -0,0 +1,104 @@
1
+ import { Switch as KSwitch } from "@kobalte/core/switch";
2
+ import { splitProps, type ComponentProps, Show } from "solid-js";
3
+ import { tv, type VariantProps } from "tailwind-variants";
4
+
5
+ const switchStyles = tv(
6
+ {
7
+ slots: {
8
+ root: "inline-flex items-center gap-2 group",
9
+ control: [
10
+ "inline-flex h-6 w-11 shrink-0 cursor-pointer items-center rounded-full border-2 border-transparent transition-colors",
11
+ "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-blue-primary focus-visible:ring-offset-2",
12
+ "disabled:cursor-not-allowed disabled:opacity-50",
13
+ "bg-foreground data-[checked]:bg-primary",
14
+ ],
15
+ thumb: [
16
+ "pointer-events-none block h-5 w-5 rounded-full bg-app shadow-lg ring-0 transition-transform",
17
+ "data-[checked]:translate-x-5 translate-x-0",
18
+ ],
19
+ label: "text-sm font-medium leading-none group-data-[disabled]:opacity-70",
20
+ description: "text-xs text-muted",
21
+ },
22
+ variants: {
23
+ size: {
24
+ sm: {
25
+ control: "h-5 w-9",
26
+ thumb: "h-4 w-4 data-[checked]:translate-x-4",
27
+ },
28
+ md: {
29
+ control: "h-6 w-11",
30
+ thumb: "h-5 w-5 data-[checked]:translate-x-5",
31
+ },
32
+ lg: {
33
+ control: "h-7 w-13",
34
+ thumb: "h-6 w-6 data-[checked]:translate-x-6",
35
+ },
36
+ },
37
+ variant: {
38
+ primary: {
39
+ control:
40
+ "data-[checked]:bg-primary",
41
+ },
42
+ success: {
43
+ control:
44
+ "data-[checked]:bg-success",
45
+ },
46
+ danger: {
47
+ control:
48
+ "data-[checked]:bg-danger",
49
+ },
50
+ },
51
+ },
52
+ defaultVariants: {
53
+ size: "md",
54
+ variant: "primary",
55
+ },
56
+ },
57
+ {
58
+ twMerge: true,
59
+ },
60
+ );
61
+
62
+ type SwitchVariants = VariantProps<typeof switchStyles>;
63
+
64
+ export interface SwitchProps
65
+ extends Omit<ComponentProps<typeof KSwitch>, "class">,
66
+ SwitchVariants {
67
+ label?: string;
68
+ description?: string;
69
+ class?: string;
70
+ }
71
+
72
+ export const Switch = (props: SwitchProps) => {
73
+ const [local, variantProps, others] = splitProps(
74
+ props,
75
+ ["label", "description", "class"],
76
+ ["size", "variant"]
77
+ );
78
+
79
+ const styles = switchStyles(variantProps);
80
+
81
+ return (
82
+ <KSwitch class={styles.root({ class: local.class })} {...others}>
83
+ <KSwitch.Input />
84
+ <KSwitch.Control class={styles.control()}>
85
+ <KSwitch.Thumb class={styles.thumb()} />
86
+ </KSwitch.Control>
87
+
88
+ <Show when={local.label || local.description}>
89
+ <div class="flex flex-col gap-0.5">
90
+ <Show when={local.label}>
91
+ <KSwitch.Label class={styles.label()}>
92
+ {local.label}
93
+ </KSwitch.Label>
94
+ </Show>
95
+ <Show when={local.description}>
96
+ <KSwitch.Description class={styles.description()}>
97
+ {local.description}
98
+ </KSwitch.Description>
99
+ </Show>
100
+ </div>
101
+ </Show>
102
+ </KSwitch>
103
+ );
104
+ };
@@ -0,0 +1,73 @@
1
+ import { Tabs as KTabs } from "@kobalte/core/tabs";
2
+ import { splitProps, type JSX, For } from "solid-js";
3
+ import { tv } from "tailwind-variants";
4
+
5
+ const tabsStyles = tv(
6
+ {
7
+ slots: {
8
+ root: "flex flex-col w-full",
9
+ list: "relative flex items-center border-b border-base",
10
+ trigger: [
11
+ "relative flex h-9 items-center justify-center px-4 text-sm font-medium transition-colors outline-none select-none cursor-pointer",
12
+ "text-muted hover:text-muted/80 ",
13
+ "data-[selected]:text-main",
14
+ ],
15
+ indicator:
16
+ "absolute bottom-[-1px] h-0.5 bg-reversal-bg transition-all duration-200",
17
+ content:
18
+ "mt-4 text-sm text-main focus-visible:outline-none",
19
+ },
20
+ },
21
+ {
22
+ twMerge: true,
23
+ },
24
+ );
25
+
26
+ const { root, list, trigger, indicator, content } = tabsStyles();
27
+
28
+ export type TabItem = {
29
+ value: string;
30
+ label: string | JSX.Element;
31
+ content: JSX.Element;
32
+ disabled?: boolean;
33
+ };
34
+
35
+ interface TabsProps {
36
+ items: TabItem[];
37
+ defaultValue?: string;
38
+ value?: string;
39
+ onValueChange?: (value: string) => void;
40
+ orientation?: "horizontal" | "vertical";
41
+ class?: string;
42
+ }
43
+
44
+ export const Tabs = (props: TabsProps) => {
45
+ const [local, others] = splitProps(props, ["items", "class"]);
46
+
47
+ return (
48
+ <KTabs class={root({ class: local.class })} {...others}>
49
+ <KTabs.List class={list()}>
50
+ <For each={local.items}>
51
+ {(item) => (
52
+ <KTabs.Trigger
53
+ class={trigger()}
54
+ value={item.value}
55
+ disabled={item.disabled}
56
+ >
57
+ {item.label}
58
+ </KTabs.Trigger>
59
+ )}
60
+ </For>
61
+ <KTabs.Indicator class={indicator()} />
62
+ </KTabs.List>
63
+
64
+ <For each={local.items}>
65
+ {(item) => (
66
+ <KTabs.Content class={content()} value={item.value}>
67
+ {item.content}
68
+ </KTabs.Content>
69
+ )}
70
+ </For>
71
+ </KTabs>
72
+ );
73
+ };
@@ -0,0 +1,97 @@
1
+ import { TextField as KTextField } from "@kobalte/core/text-field";
2
+ import { splitProps, type ComponentProps, Show } from "solid-js";
3
+ import { tv, type VariantProps } from "tailwind-variants";
4
+
5
+ const textFieldStyles = tv(
6
+ {
7
+ slots: {
8
+ root: "flex flex-col gap-1.5 w-full",
9
+ label: "text-sm font-medium text-muted peer-disabled:cursor-not-allowed peer-disabled:opacity-70",
10
+ input: [
11
+ "flex h-10 w-full rounded-md border border-light bg-app px-3 py-2 text-sm transition-shadow text-main",
12
+ "ring-offset-white file:border-0 file:bg-transparent file:text-sm file:font-medium",
13
+ "placeholder:text-muted/40 focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-primary",
14
+ "disabled:cursor-not-allowed disabled:opacity-50",
15
+ "data-[invalid]:border-danger data-[invalid]:focus-visible:ring-danger",
16
+ ],
17
+ description: "text-xs text-muted",
18
+ errorMessage:
19
+ "text-xs text-danger animate-in fade-in-50 slide-in-from-top-1",
20
+ },
21
+ variants: {
22
+ size: {
23
+ sm: { input: "h-8 px-2 text-xs" },
24
+ md: { input: "h-10 px-3 text-sm" },
25
+ lg: { input: "h-12 px-4 text-base" },
26
+ },
27
+ },
28
+ defaultVariants: {
29
+ size: "md",
30
+ },
31
+ },
32
+ {
33
+ twMerge: true,
34
+ },
35
+ );
36
+
37
+ type TextFieldVariants = VariantProps<typeof textFieldStyles>;
38
+
39
+ export interface TextFieldProps
40
+ extends Omit<ComponentProps<typeof KTextField>, "class">,
41
+ TextFieldVariants {
42
+ label?: string;
43
+ description?: string;
44
+ errorMessage?: string;
45
+ placeholder?: string;
46
+ type?: string;
47
+ class?: string;
48
+ }
49
+
50
+ export const TextField = (props: TextFieldProps) => {
51
+ const [local, variantProps, others] = splitProps(
52
+ props,
53
+ [
54
+ "label",
55
+ "description",
56
+ "errorMessage",
57
+ "placeholder",
58
+ "type",
59
+ "class",
60
+ ],
61
+ ["size"]
62
+ );
63
+
64
+ const styles = textFieldStyles(variantProps);
65
+
66
+ return (
67
+ <KTextField
68
+ class={styles.root({ class: local.class })}
69
+ validationState={local.errorMessage ? "invalid" : "valid"}
70
+ {...others}
71
+ >
72
+ <Show when={local.label}>
73
+ <KTextField.Label class={styles.label()}>
74
+ {local.label}
75
+ </KTextField.Label>
76
+ </Show>
77
+
78
+ <KTextField.Input
79
+ class={styles.input()}
80
+ type={local.type}
81
+ placeholder={local.placeholder}
82
+ />
83
+
84
+ <Show when={local.description}>
85
+ <KTextField.Description class={styles.description()}>
86
+ {local.description}
87
+ </KTextField.Description>
88
+ </Show>
89
+
90
+ <Show when={local.errorMessage}>
91
+ <KTextField.ErrorMessage class={styles.errorMessage()}>
92
+ {local.errorMessage}
93
+ </KTextField.ErrorMessage>
94
+ </Show>
95
+ </KTextField>
96
+ );
97
+ };