@rovula/ui 0.0.12 → 0.0.14
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/cjs/bundle.css +227 -16
- package/dist/cjs/bundle.js +3 -3
- package/dist/cjs/bundle.js.map +1 -1
- package/dist/cjs/types/components/ActionButton/ActionButton.d.ts +20 -0
- package/dist/cjs/types/components/ActionButton/ActionButton.stories.d.ts +311 -0
- package/dist/cjs/types/components/ActionButton/ActionButton.styles.d.ts +6 -0
- package/dist/cjs/types/components/Avatar/Avatar.d.ts +32 -0
- package/dist/cjs/types/components/Avatar/Avatar.stories.d.ts +64 -0
- package/dist/cjs/types/components/Avatar/Avatar.styles.d.ts +4 -0
- package/dist/cjs/types/components/Avatar/AvatarBase.d.ts +6 -0
- package/dist/cjs/types/components/Avatar/AvatarGroup.d.ts +11 -0
- package/dist/cjs/types/components/Avatar/AvatarGroup.stories.d.ts +31 -0
- package/dist/cjs/types/components/Input/Input.d.ts +21 -4
- package/dist/cjs/types/components/Input/Input.stories.d.ts +340 -22
- package/dist/cjs/types/components/Input/Input.styles.d.ts +9 -0
- package/dist/cjs/types/components/Label/Label.d.ts +6 -1
- package/dist/cjs/types/components/Label/Label.stories.d.ts +10 -1
- package/dist/cjs/types/components/Label/Label.styles.d.ts +6 -0
- package/dist/cjs/types/components/Navbar/Navbar.d.ts +12 -0
- package/dist/cjs/types/components/Navbar/Navbar.stories.d.ts +35 -0
- package/dist/cjs/types/components/Search/Search.d.ts +2 -0
- package/dist/cjs/types/components/Search/Search.stories.d.ts +21 -0
- package/dist/cjs/types/components/ThemeToggle.d.ts +2 -0
- package/dist/components/ActionButton/ActionButton.js +38 -0
- package/dist/components/ActionButton/ActionButton.stories.js +45 -0
- package/dist/components/ActionButton/ActionButton.styles.js +71 -0
- package/dist/components/Avatar/Avatar.js +22 -0
- package/dist/components/Avatar/Avatar.stories.js +47 -0
- package/dist/components/Avatar/Avatar.styles.js +23 -0
- package/dist/components/Avatar/AvatarBase.js +43 -0
- package/dist/components/Avatar/AvatarGroup.js +21 -0
- package/dist/components/Avatar/AvatarGroup.stories.js +47 -0
- package/dist/components/Button/Button.styles.js +6 -6
- package/dist/components/Dropdown/Dropdown.js +39 -2
- package/dist/components/Dropdown/Dropdown.stories.js +29 -4
- package/dist/components/Input/Input.js +5 -4
- package/dist/components/Input/Input.stories.js +2 -4
- package/dist/components/Input/Input.styles.js +45 -0
- package/dist/components/Label/Label.js +7 -3
- package/dist/components/Label/Label.styles.js +57 -0
- package/dist/components/Navbar/Navbar.js +9 -0
- package/dist/components/Navbar/Navbar.stories.js +41 -0
- package/dist/components/Search/Search.js +19 -0
- package/dist/components/Search/Search.stories.js +36 -0
- package/dist/components/Text/Text.js +2 -1
- package/dist/components/ThemeToggle.js +17 -0
- package/dist/esm/bundle.css +227 -16
- package/dist/esm/bundle.js +3 -3
- package/dist/esm/bundle.js.map +1 -1
- package/dist/esm/types/components/ActionButton/ActionButton.d.ts +20 -0
- package/dist/esm/types/components/ActionButton/ActionButton.stories.d.ts +311 -0
- package/dist/esm/types/components/ActionButton/ActionButton.styles.d.ts +6 -0
- package/dist/esm/types/components/Avatar/Avatar.d.ts +32 -0
- package/dist/esm/types/components/Avatar/Avatar.stories.d.ts +64 -0
- package/dist/esm/types/components/Avatar/Avatar.styles.d.ts +4 -0
- package/dist/esm/types/components/Avatar/AvatarBase.d.ts +6 -0
- package/dist/esm/types/components/Avatar/AvatarGroup.d.ts +11 -0
- package/dist/esm/types/components/Avatar/AvatarGroup.stories.d.ts +31 -0
- package/dist/esm/types/components/Input/Input.d.ts +21 -4
- package/dist/esm/types/components/Input/Input.stories.d.ts +340 -22
- package/dist/esm/types/components/Input/Input.styles.d.ts +9 -0
- package/dist/esm/types/components/Label/Label.d.ts +6 -1
- package/dist/esm/types/components/Label/Label.stories.d.ts +10 -1
- package/dist/esm/types/components/Label/Label.styles.d.ts +6 -0
- package/dist/esm/types/components/Navbar/Navbar.d.ts +12 -0
- package/dist/esm/types/components/Navbar/Navbar.stories.d.ts +35 -0
- package/dist/esm/types/components/Search/Search.d.ts +2 -0
- package/dist/esm/types/components/Search/Search.stories.d.ts +21 -0
- package/dist/esm/types/components/ThemeToggle.d.ts +2 -0
- package/dist/index.d.ts +22 -10
- package/dist/src/theme/global.css +290 -21
- package/dist/theme/global.css +11 -0
- package/dist/theme/presets/colors.js +28 -0
- package/package.json +2 -1
- package/src/components/ActionButton/ActionButton.stories.tsx +176 -0
- package/src/components/ActionButton/ActionButton.styles.ts +79 -0
- package/src/components/ActionButton/ActionButton.tsx +42 -0
- package/src/components/Avatar/Avatar.stories.tsx +107 -0
- package/src/components/Avatar/Avatar.styles.ts +28 -0
- package/src/components/Avatar/Avatar.tsx +88 -0
- package/src/components/Avatar/AvatarBase.tsx +50 -0
- package/src/components/Avatar/AvatarGroup.stories.tsx +77 -0
- package/src/components/Avatar/AvatarGroup.tsx +55 -0
- package/src/components/Button/Button.styles.ts +6 -6
- package/src/components/Dropdown/Dropdown.stories.tsx +25 -3
- package/src/components/Dropdown/Dropdown.tsx +61 -2
- package/src/components/Input/Input.stories.tsx +8 -6
- package/src/components/Input/Input.styles.tsx +51 -0
- package/src/components/Input/Input.tsx +30 -6
- package/src/components/Label/Label.styles.ts +61 -0
- package/src/components/Label/Label.tsx +13 -7
- package/src/components/Navbar/Navbar.stories.tsx +86 -0
- package/src/components/Navbar/Navbar.tsx +56 -0
- package/src/components/Search/Search.stories.tsx +44 -0
- package/src/components/Search/Search.tsx +25 -0
- package/src/components/Text/Text.tsx +2 -1
- package/src/components/ThemeToggle.tsx +19 -0
- package/src/theme/global.css +11 -0
- package/src/theme/presets/colors.js +28 -0
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import React, { Children, FC, ReactNode, cloneElement } from "react";
|
|
4
|
+
import Avatar from "./Avatar";
|
|
5
|
+
|
|
6
|
+
export type AvatarGroupProps = {
|
|
7
|
+
maxDisplay?: number;
|
|
8
|
+
borderWidth?: number;
|
|
9
|
+
borderColor?: string;
|
|
10
|
+
remainingText?: string;
|
|
11
|
+
children?: ReactNode;
|
|
12
|
+
remainingAvatar?: ReactNode;
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
const AvatarGroup: FC<AvatarGroupProps> = ({
|
|
16
|
+
borderWidth = 2,
|
|
17
|
+
borderColor = "white",
|
|
18
|
+
maxDisplay = 4,
|
|
19
|
+
children,
|
|
20
|
+
remainingText,
|
|
21
|
+
remainingAvatar,
|
|
22
|
+
}) => {
|
|
23
|
+
const avatars = Children.toArray(children);
|
|
24
|
+
const displayAvatars = avatars.slice(0, maxDisplay);
|
|
25
|
+
const remainingCount = Math.max(0, avatars.length - maxDisplay);
|
|
26
|
+
|
|
27
|
+
const remainingComp =
|
|
28
|
+
remainingAvatar ||
|
|
29
|
+
cloneElement(displayAvatars[0] as React.ReactElement, {
|
|
30
|
+
style: { borderWidth, borderColor },
|
|
31
|
+
className: "relative z-0",
|
|
32
|
+
children: remainingText || `+${remainingCount}`,
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
return (
|
|
36
|
+
<div className="flex items-center -space-x-2">
|
|
37
|
+
{displayAvatars.map((avatar, index) => {
|
|
38
|
+
return (
|
|
39
|
+
<div
|
|
40
|
+
key={index}
|
|
41
|
+
className="relative"
|
|
42
|
+
style={{ zIndex: avatars.length - index }}
|
|
43
|
+
>
|
|
44
|
+
{cloneElement(avatar as React.ReactElement, {
|
|
45
|
+
style: { borderWidth, borderColor },
|
|
46
|
+
})}
|
|
47
|
+
</div>
|
|
48
|
+
);
|
|
49
|
+
})}
|
|
50
|
+
{remainingCount > 0 && remainingComp}
|
|
51
|
+
</div>
|
|
52
|
+
);
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
export default AvatarGroup;
|
|
@@ -56,12 +56,12 @@ export const buttonVariants = cva(
|
|
|
56
56
|
color: "secondary",
|
|
57
57
|
class: "text-secondary-foreground",
|
|
58
58
|
},
|
|
59
|
-
{
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
},
|
|
59
|
+
// {
|
|
60
|
+
// variant: "solid",
|
|
61
|
+
// disabled: true,
|
|
62
|
+
// color: "secondary",
|
|
63
|
+
// class: "text-white",
|
|
64
|
+
// },
|
|
65
65
|
{
|
|
66
66
|
variant: "solid",
|
|
67
67
|
color: "tertiary",
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import React, { useRef } from "react";
|
|
1
|
+
import React, { useRef, useState } from "react";
|
|
2
2
|
import type { Meta, StoryObj } from "@storybook/react";
|
|
3
3
|
import Dropdown, { Options } from "./Dropdown";
|
|
4
4
|
import Button from "../Button/Button";
|
|
@@ -53,15 +53,37 @@ export const Default = {
|
|
|
53
53
|
const DropdownWithRef = (props: any) => {
|
|
54
54
|
const inputRef = useRef<HTMLInputElement | null>(null);
|
|
55
55
|
|
|
56
|
+
const [options, setOptions] = useState(customOptions);
|
|
57
|
+
const [value, setValue] = useState<Options>({
|
|
58
|
+
label: "",
|
|
59
|
+
value: "",
|
|
60
|
+
});
|
|
61
|
+
const [text, setText] = useState("");
|
|
62
|
+
|
|
56
63
|
return (
|
|
57
64
|
<Dropdown
|
|
58
65
|
id="1"
|
|
59
66
|
size="lg"
|
|
60
67
|
{...props}
|
|
68
|
+
value={value}
|
|
69
|
+
options={options}
|
|
61
70
|
ref={inputRef}
|
|
62
71
|
labelClassName="peer-focus:bg-red-500"
|
|
72
|
+
onSelect={setValue}
|
|
73
|
+
onChangeText={(e) => setText(e.target.value)}
|
|
63
74
|
onKeyDown={(e) => {
|
|
64
75
|
if (e.code === "Enter") {
|
|
76
|
+
setOptions((options) => [
|
|
77
|
+
...options,
|
|
78
|
+
{
|
|
79
|
+
label: text,
|
|
80
|
+
value: text,
|
|
81
|
+
},
|
|
82
|
+
]);
|
|
83
|
+
setValue({
|
|
84
|
+
label: text,
|
|
85
|
+
value: text,
|
|
86
|
+
});
|
|
65
87
|
inputRef.current?.blur?.();
|
|
66
88
|
}
|
|
67
89
|
}}
|
|
@@ -83,7 +105,7 @@ export const WithRef = {
|
|
|
83
105
|
};
|
|
84
106
|
return (
|
|
85
107
|
<div className="flex flex-row gap-4 w-full">
|
|
86
|
-
<DropdownWithRef id="1" size="lg" options={options} {...args}
|
|
108
|
+
<DropdownWithRef id="1" size="lg" options={options} {...args} />
|
|
87
109
|
</div>
|
|
88
110
|
);
|
|
89
111
|
},
|
|
@@ -126,7 +148,7 @@ export const CustomOption = {
|
|
|
126
148
|
};
|
|
127
149
|
return (
|
|
128
150
|
<div className="flex flex-row gap-4 w-full">
|
|
129
|
-
<DropdownWithRef id="1" size="lg" options={options} {...args}
|
|
151
|
+
<DropdownWithRef id="1" size="lg" options={options} {...args} />
|
|
130
152
|
</div>
|
|
131
153
|
);
|
|
132
154
|
},
|
|
@@ -5,6 +5,7 @@ import React, {
|
|
|
5
5
|
useCallback,
|
|
6
6
|
useEffect,
|
|
7
7
|
useMemo,
|
|
8
|
+
useRef,
|
|
8
9
|
useState,
|
|
9
10
|
} from "react";
|
|
10
11
|
|
|
@@ -80,6 +81,7 @@ const Dropdown = forwardRef<HTMLInputElement, DropdownProps>(
|
|
|
80
81
|
Options | null | undefined
|
|
81
82
|
>(null);
|
|
82
83
|
const [textValue, setTextValue] = useState("");
|
|
84
|
+
const keyCode = useRef("");
|
|
83
85
|
|
|
84
86
|
useEffect(() => {
|
|
85
87
|
if (value && !selectedOption) {
|
|
@@ -147,6 +149,62 @@ const Dropdown = forwardRef<HTMLInputElement, DropdownProps>(
|
|
|
147
149
|
</ul>
|
|
148
150
|
);
|
|
149
151
|
|
|
152
|
+
const handleOnFocus = useCallback(
|
|
153
|
+
(e: React.FocusEvent<HTMLInputElement, Element>) => {
|
|
154
|
+
setIsFocused(true);
|
|
155
|
+
props?.onFocus?.(e);
|
|
156
|
+
},
|
|
157
|
+
[props?.onFocus]
|
|
158
|
+
);
|
|
159
|
+
|
|
160
|
+
const clearMismatchValue = useCallback(
|
|
161
|
+
(e: React.FocusEvent<HTMLInputElement, Element>) => {
|
|
162
|
+
const matchSelectedValue = optionsFiltered.find(
|
|
163
|
+
(opt) =>
|
|
164
|
+
opt.value === e.target?.value || opt.label === e.target?.value
|
|
165
|
+
);
|
|
166
|
+
const isMatchSelectedValue = !!matchSelectedValue;
|
|
167
|
+
|
|
168
|
+
let option = matchSelectedValue || {
|
|
169
|
+
value: "",
|
|
170
|
+
label: "",
|
|
171
|
+
};
|
|
172
|
+
|
|
173
|
+
if (!isMatchSelectedValue && textValue) {
|
|
174
|
+
option = {
|
|
175
|
+
value: "",
|
|
176
|
+
label: "",
|
|
177
|
+
};
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
if (keyCode.current === "Enter") {
|
|
181
|
+
return;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
setSelectedOption(option);
|
|
185
|
+
setTextValue(option.label);
|
|
186
|
+
onSelect?.(option);
|
|
187
|
+
},
|
|
188
|
+
[optionsFiltered, textValue]
|
|
189
|
+
);
|
|
190
|
+
|
|
191
|
+
const handleOnBlur = useCallback(
|
|
192
|
+
(e: React.FocusEvent<HTMLInputElement, Element>) => {
|
|
193
|
+
setIsFocused(false);
|
|
194
|
+
clearMismatchValue(e);
|
|
195
|
+
props?.onBlur?.(e);
|
|
196
|
+
},
|
|
197
|
+
[props?.onBlur]
|
|
198
|
+
);
|
|
199
|
+
|
|
200
|
+
const handleOnKeyDown = useCallback(
|
|
201
|
+
(e: React.KeyboardEvent<HTMLInputElement>) => {
|
|
202
|
+
keyCode.current = e.code;
|
|
203
|
+
props?.onKeyDown?.(e);
|
|
204
|
+
},
|
|
205
|
+
[props?.onKeyDown]
|
|
206
|
+
);
|
|
207
|
+
|
|
150
208
|
return (
|
|
151
209
|
<div className={`relative ${fullwidth ? "w-full" : ""}`}>
|
|
152
210
|
<TextInput
|
|
@@ -170,8 +228,9 @@ const Dropdown = forwardRef<HTMLInputElement, DropdownProps>(
|
|
|
170
228
|
hasClearIcon={false}
|
|
171
229
|
size={size}
|
|
172
230
|
className={customInputVariant({ size })}
|
|
173
|
-
onFocus={
|
|
174
|
-
onBlur={
|
|
231
|
+
onFocus={handleOnFocus}
|
|
232
|
+
onBlur={handleOnBlur}
|
|
233
|
+
onKeyDown={handleOnKeyDown}
|
|
175
234
|
endIcon={
|
|
176
235
|
<div className={iconWrapperVariant({ size })}>
|
|
177
236
|
<ChevronDownIcon
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import React from "react";
|
|
2
2
|
import type { Meta, StoryObj } from "@storybook/react";
|
|
3
|
-
import { Input } from "./Input";
|
|
3
|
+
import { Input, InputProps } from "./Input";
|
|
4
4
|
|
|
5
5
|
const meta = {
|
|
6
6
|
title: "Components/Input",
|
|
@@ -20,10 +20,10 @@ const meta = {
|
|
|
20
20
|
|
|
21
21
|
export default meta;
|
|
22
22
|
|
|
23
|
+
type Story = StoryObj<typeof meta>;
|
|
24
|
+
|
|
23
25
|
export const Default = {
|
|
24
26
|
args: {
|
|
25
|
-
// label: "Lorem Ipsum",
|
|
26
|
-
// value: "Lorem Ipsum",
|
|
27
27
|
// fullwidth: true,
|
|
28
28
|
},
|
|
29
29
|
render: (args) => {
|
|
@@ -32,9 +32,11 @@ export const Default = {
|
|
|
32
32
|
...args,
|
|
33
33
|
};
|
|
34
34
|
return (
|
|
35
|
-
<div className="flex flex-row gap-4
|
|
36
|
-
<Input
|
|
35
|
+
<div className="flex flex-row gap-4">
|
|
36
|
+
<Input id="1" size="lg" placeholder="Email" {...args} />
|
|
37
|
+
<Input id="2" size="md" placeholder="Email" {...args} />
|
|
38
|
+
<Input id="3" size="sm" placeholder="Email" {...args} />
|
|
37
39
|
</div>
|
|
38
40
|
);
|
|
39
41
|
},
|
|
40
|
-
} satisfies
|
|
42
|
+
} satisfies Story;
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { cva } from "class-variance-authority";
|
|
2
|
+
|
|
3
|
+
export const inputVariants = cva(
|
|
4
|
+
[
|
|
5
|
+
"border-0 outline-none",
|
|
6
|
+
"p-1 flex w-auto h-fit box-border",
|
|
7
|
+
"peer text-black",
|
|
8
|
+
],
|
|
9
|
+
{
|
|
10
|
+
variants: {
|
|
11
|
+
size: {
|
|
12
|
+
sm: "p-2 px-3 typography-small1",
|
|
13
|
+
md: "py-2 px-3 typography-subtitile4",
|
|
14
|
+
lg: "p-4 typography-subtitile1",
|
|
15
|
+
},
|
|
16
|
+
rounded: {
|
|
17
|
+
none: "rounded-none",
|
|
18
|
+
normal: "rounded-xl",
|
|
19
|
+
full: "rounded-full",
|
|
20
|
+
},
|
|
21
|
+
variant: {
|
|
22
|
+
flat: "",
|
|
23
|
+
outline:
|
|
24
|
+
"ring-1 ring-inset ring-input-stroke hover:ring-input-active focus:ring-1 focus:ring-inset focus:ring-input-stroke-active",
|
|
25
|
+
underline:
|
|
26
|
+
"border-b-2 border-input-stroke transition-colors hover:border-input-stroke-active focus:border-input-stroke",
|
|
27
|
+
},
|
|
28
|
+
hiddenPlaceholder: {
|
|
29
|
+
true: "placeholder:text-transparent",
|
|
30
|
+
},
|
|
31
|
+
fullwidth: {
|
|
32
|
+
true: "w-full",
|
|
33
|
+
},
|
|
34
|
+
disabled: {
|
|
35
|
+
true: "text-input-text-disabled ring-input-stroke-disabled placeholder:text-input-text-disabled",
|
|
36
|
+
},
|
|
37
|
+
error: {
|
|
38
|
+
true: "ring-error focus:ring-error",
|
|
39
|
+
},
|
|
40
|
+
},
|
|
41
|
+
defaultVariants: {
|
|
42
|
+
size: "md",
|
|
43
|
+
variant: "outline",
|
|
44
|
+
rounded: "normal",
|
|
45
|
+
fullwidth: false,
|
|
46
|
+
disabled: false,
|
|
47
|
+
error: false,
|
|
48
|
+
hiddenPlaceholder: true,
|
|
49
|
+
},
|
|
50
|
+
}
|
|
51
|
+
);
|
|
@@ -1,20 +1,44 @@
|
|
|
1
|
-
import
|
|
1
|
+
import React, { InputHTMLAttributes, forwardRef } from "react";
|
|
2
2
|
|
|
3
3
|
import { cn } from "@/utils/cn";
|
|
4
|
+
import { inputVariants } from "./Input.styles";
|
|
4
5
|
|
|
5
|
-
export
|
|
6
|
-
|
|
6
|
+
export type InputProps = {
|
|
7
|
+
size?: "sm" | "md" | "lg";
|
|
8
|
+
rounded?: "none" | "normal" | "full";
|
|
9
|
+
variant?: "flat" | "outline" | "underline";
|
|
10
|
+
fullwidth?: boolean;
|
|
11
|
+
disabled?: boolean;
|
|
12
|
+
error?: boolean;
|
|
13
|
+
hiddenPlaceholder?: boolean;
|
|
14
|
+
className?: string;
|
|
15
|
+
} & Omit<InputHTMLAttributes<HTMLInputElement>, "size">;
|
|
7
16
|
|
|
8
|
-
const Input =
|
|
9
|
-
(
|
|
17
|
+
const Input = forwardRef<HTMLInputElement, InputProps>(
|
|
18
|
+
(
|
|
19
|
+
{
|
|
20
|
+
className,
|
|
21
|
+
type = "text",
|
|
22
|
+
size = "md",
|
|
23
|
+
variant = "outline",
|
|
24
|
+
fullwidth = false,
|
|
25
|
+
disabled = false,
|
|
26
|
+
error = false,
|
|
27
|
+
required = false,
|
|
28
|
+
hiddenPlaceholder = false,
|
|
29
|
+
...props
|
|
30
|
+
},
|
|
31
|
+
ref
|
|
32
|
+
) => {
|
|
10
33
|
return (
|
|
11
34
|
<input
|
|
12
35
|
type={type}
|
|
13
36
|
className={cn(
|
|
14
|
-
|
|
37
|
+
inputVariants({ size, variant, fullwidth, error, hiddenPlaceholder }),
|
|
15
38
|
className
|
|
16
39
|
)}
|
|
17
40
|
ref={ref}
|
|
41
|
+
disabled={disabled}
|
|
18
42
|
{...props}
|
|
19
43
|
/>
|
|
20
44
|
);
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { cva } from "class-variance-authority";
|
|
2
|
+
|
|
3
|
+
export const labelVariant = cva(
|
|
4
|
+
[
|
|
5
|
+
"block duration-450 transition-all px-[2px] text-input-text peer-focus:text-input-text-active",
|
|
6
|
+
],
|
|
7
|
+
{
|
|
8
|
+
variants: {
|
|
9
|
+
size: {
|
|
10
|
+
sm: "typography-small1",
|
|
11
|
+
md: "typography-subtitile4",
|
|
12
|
+
lg: "typography-subtitile1",
|
|
13
|
+
},
|
|
14
|
+
disabled: {
|
|
15
|
+
true: "text-input-text-disabled ring-input-stroke-disabled placeholder:text-input-text-disabled peer-disabled:cursor-not-allowed",
|
|
16
|
+
},
|
|
17
|
+
error: {
|
|
18
|
+
true: "ring-error",
|
|
19
|
+
},
|
|
20
|
+
isFloatable: {
|
|
21
|
+
true: "absolute peer-focus:text-input-text-active peer-focus:bg-input-label-background",
|
|
22
|
+
false: "",
|
|
23
|
+
},
|
|
24
|
+
},
|
|
25
|
+
compoundVariants: [
|
|
26
|
+
{
|
|
27
|
+
size: "sm",
|
|
28
|
+
isFloatable: true,
|
|
29
|
+
className: [
|
|
30
|
+
"left-3 -top-1.5 typography-label2 bg-input-label-background",
|
|
31
|
+
"peer-placeholder-shown:top-2 peer-placeholder-shown:typography-small1 peer-placeholder-shown:bg-transparent",
|
|
32
|
+
"peer-focus:-top-1.5 peer-focus:typography-label2",
|
|
33
|
+
],
|
|
34
|
+
},
|
|
35
|
+
{
|
|
36
|
+
size: "md",
|
|
37
|
+
isFloatable: true,
|
|
38
|
+
className: [
|
|
39
|
+
"left-3 -top-1.5 typography-label1 bg-input-label-background",
|
|
40
|
+
"peer-placeholder-shown:top-2 peer-placeholder-shown:typography-subtitile4 peer-placeholder-shown:bg-transparent",
|
|
41
|
+
"peer-focus:-top-1.5 peer-focus:typography-label1",
|
|
42
|
+
],
|
|
43
|
+
},
|
|
44
|
+
{
|
|
45
|
+
size: "lg",
|
|
46
|
+
isFloatable: true,
|
|
47
|
+
className: [
|
|
48
|
+
"left-4 -top-1.5 typography-label1 bg-input-label-background",
|
|
49
|
+
"peer-placeholder-shown:top-4 peer-placeholder-shown:typography-subtitile1 peer-placeholder-shown:bg-transparent",
|
|
50
|
+
"peer-focus:-top-1.5 peer-focus:typography-label1",
|
|
51
|
+
],
|
|
52
|
+
},
|
|
53
|
+
],
|
|
54
|
+
defaultVariants: {
|
|
55
|
+
size: "md",
|
|
56
|
+
disabled: false,
|
|
57
|
+
error: false,
|
|
58
|
+
isFloatable: false,
|
|
59
|
+
},
|
|
60
|
+
}
|
|
61
|
+
);
|
|
@@ -2,25 +2,31 @@
|
|
|
2
2
|
|
|
3
3
|
import * as React from "react";
|
|
4
4
|
import * as LabelPrimitive from "@radix-ui/react-label";
|
|
5
|
-
import {
|
|
5
|
+
import { type VariantProps } from "class-variance-authority";
|
|
6
6
|
|
|
7
7
|
import { cn } from "@/utils/cn";
|
|
8
|
-
|
|
9
|
-
const labelVariants = cva(
|
|
10
|
-
"typography-label1 peer-disabled:cursor-not-allowed peer-disabled:opacity-70"
|
|
11
|
-
);
|
|
8
|
+
import { labelVariant } from "./Label.styles";
|
|
12
9
|
|
|
13
10
|
const Label = React.forwardRef<
|
|
14
11
|
React.ElementRef<typeof LabelPrimitive.Root>,
|
|
15
12
|
React.ComponentPropsWithoutRef<typeof LabelPrimitive.Root> &
|
|
16
|
-
VariantProps<typeof
|
|
13
|
+
VariantProps<typeof labelVariant>
|
|
17
14
|
>(({ className, ...props }, ref) => (
|
|
18
15
|
<LabelPrimitive.Root
|
|
19
16
|
ref={ref}
|
|
20
|
-
className={cn(
|
|
17
|
+
className={cn(
|
|
18
|
+
labelVariant({
|
|
19
|
+
size: props.size,
|
|
20
|
+
disabled: props.disabled,
|
|
21
|
+
error: props.error,
|
|
22
|
+
isFloatable: props.isFloatable,
|
|
23
|
+
}),
|
|
24
|
+
className
|
|
25
|
+
)}
|
|
21
26
|
{...props}
|
|
22
27
|
/>
|
|
23
28
|
));
|
|
29
|
+
|
|
24
30
|
Label.displayName = LabelPrimitive.Root.displayName;
|
|
25
31
|
|
|
26
32
|
export { Label };
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import type { Meta, StoryObj } from "@storybook/react";
|
|
3
|
+
|
|
4
|
+
import { Checkbox } from "../Checkbox/Checkbox";
|
|
5
|
+
import Navbar from "./Navbar";
|
|
6
|
+
|
|
7
|
+
const meta = {
|
|
8
|
+
title: "Components/Navbar",
|
|
9
|
+
component: Navbar,
|
|
10
|
+
tags: ["autodocs"],
|
|
11
|
+
parameters: {
|
|
12
|
+
layout: "fullscreen",
|
|
13
|
+
},
|
|
14
|
+
decorators: [
|
|
15
|
+
(Story) => (
|
|
16
|
+
<div className="p-5 w-full h-screen">
|
|
17
|
+
<Story />
|
|
18
|
+
</div>
|
|
19
|
+
),
|
|
20
|
+
],
|
|
21
|
+
} satisfies Meta<typeof Navbar>;
|
|
22
|
+
|
|
23
|
+
export default meta;
|
|
24
|
+
|
|
25
|
+
export const Default = {
|
|
26
|
+
args: {},
|
|
27
|
+
render: (args) => {
|
|
28
|
+
console.log("args ", args);
|
|
29
|
+
const props: typeof args = {
|
|
30
|
+
...args,
|
|
31
|
+
};
|
|
32
|
+
return (
|
|
33
|
+
<div className="flex flex-row gap-4 w-full">
|
|
34
|
+
<Navbar
|
|
35
|
+
leftNav={
|
|
36
|
+
<ul className="flex gap-2">
|
|
37
|
+
<li>link 1</li>
|
|
38
|
+
<li>link 2</li>
|
|
39
|
+
<li>link 3</li>
|
|
40
|
+
</ul>
|
|
41
|
+
}
|
|
42
|
+
center={<>Center text</>}
|
|
43
|
+
rightNav={
|
|
44
|
+
<ul className="flex gap-2">
|
|
45
|
+
<li>sss 1</li>
|
|
46
|
+
<li>ddd 2</li>
|
|
47
|
+
<li>vvvv 3</li>
|
|
48
|
+
</ul>
|
|
49
|
+
}
|
|
50
|
+
/>
|
|
51
|
+
</div>
|
|
52
|
+
);
|
|
53
|
+
},
|
|
54
|
+
} satisfies StoryObj;
|
|
55
|
+
|
|
56
|
+
export const Custom = {
|
|
57
|
+
args: {},
|
|
58
|
+
render: (args) => {
|
|
59
|
+
console.log("args ", args);
|
|
60
|
+
const props: typeof args = {
|
|
61
|
+
...args,
|
|
62
|
+
};
|
|
63
|
+
return (
|
|
64
|
+
<div className="flex flex-row gap-4 w-full">
|
|
65
|
+
<Navbar
|
|
66
|
+
className="px-8"
|
|
67
|
+
leftNav={
|
|
68
|
+
<ul className="flex gap-2">
|
|
69
|
+
<li>link 1</li>
|
|
70
|
+
<li>link 2</li>
|
|
71
|
+
<li>link 3</li>
|
|
72
|
+
</ul>
|
|
73
|
+
}
|
|
74
|
+
center={<>Center text</>}
|
|
75
|
+
rightNav={
|
|
76
|
+
<ul className="flex gap-2">
|
|
77
|
+
<li>sss 1</li>
|
|
78
|
+
<li>ddd 2</li>
|
|
79
|
+
<li>vvvv 3</li>
|
|
80
|
+
</ul>
|
|
81
|
+
}
|
|
82
|
+
/>
|
|
83
|
+
</div>
|
|
84
|
+
);
|
|
85
|
+
},
|
|
86
|
+
} satisfies StoryObj;
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { cn } from "@/utils/cn";
|
|
2
|
+
import React, { FC, ReactNode } from "react";
|
|
3
|
+
|
|
4
|
+
type NavbarProps = {
|
|
5
|
+
position?: "static" | "sticky";
|
|
6
|
+
children?: ReactNode;
|
|
7
|
+
leftNav?: ReactNode;
|
|
8
|
+
rightNav?: ReactNode;
|
|
9
|
+
center?: ReactNode;
|
|
10
|
+
container?: boolean;
|
|
11
|
+
className?: string;
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
const Navbar: FC<NavbarProps> = ({
|
|
15
|
+
children,
|
|
16
|
+
className,
|
|
17
|
+
center,
|
|
18
|
+
leftNav,
|
|
19
|
+
rightNav,
|
|
20
|
+
position,
|
|
21
|
+
container = false,
|
|
22
|
+
}) => {
|
|
23
|
+
return (
|
|
24
|
+
<header
|
|
25
|
+
className={cn(
|
|
26
|
+
"w-full px-4 py-6 h-[var(--navbar-height)] box-border overflow-hidden typography-subtitile2 border-solid border-b-2 bg-[rgb(var(--navbar-bg-color))] text-[rgb(var(--navbar-text-color))] border-b-[rgb(var(--navbar-border-color))]",
|
|
27
|
+
{ position },
|
|
28
|
+
className
|
|
29
|
+
)}
|
|
30
|
+
>
|
|
31
|
+
<div
|
|
32
|
+
className={cn("mx-auto flex h-full justify-between items-center", {
|
|
33
|
+
container,
|
|
34
|
+
})}
|
|
35
|
+
>
|
|
36
|
+
{children || (
|
|
37
|
+
<>
|
|
38
|
+
<nav className="flex w-1/2 gap-x-[var(--navbar-gap)] text-xl">
|
|
39
|
+
{leftNav}
|
|
40
|
+
</nav>
|
|
41
|
+
|
|
42
|
+
<div className="flex flex-shrink-0 flex-wrap justify-center">
|
|
43
|
+
{center}
|
|
44
|
+
</div>
|
|
45
|
+
|
|
46
|
+
<nav className="flex w-1/2 justify-end gap-x-[var(--navbar-gap)] text-xl">
|
|
47
|
+
{rightNav}
|
|
48
|
+
</nav>
|
|
49
|
+
</>
|
|
50
|
+
)}
|
|
51
|
+
</div>
|
|
52
|
+
</header>
|
|
53
|
+
);
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
export default Navbar;
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import type { Meta, StoryObj } from "@storybook/react";
|
|
3
|
+
import { Search } from "./Search";
|
|
4
|
+
import { error } from "console";
|
|
5
|
+
|
|
6
|
+
const meta = {
|
|
7
|
+
title: "Components/Search",
|
|
8
|
+
component: Search,
|
|
9
|
+
tags: ["autodocs"],
|
|
10
|
+
parameters: {
|
|
11
|
+
layout: "fullscreen",
|
|
12
|
+
},
|
|
13
|
+
decorators: [
|
|
14
|
+
(Story) => (
|
|
15
|
+
<div className="p-5 flex w-full">
|
|
16
|
+
<Story />
|
|
17
|
+
</div>
|
|
18
|
+
),
|
|
19
|
+
],
|
|
20
|
+
} satisfies Meta<typeof Search>;
|
|
21
|
+
|
|
22
|
+
export default meta;
|
|
23
|
+
|
|
24
|
+
type Story = StoryObj<typeof meta>;
|
|
25
|
+
|
|
26
|
+
export const Default = {
|
|
27
|
+
args: {
|
|
28
|
+
error: false,
|
|
29
|
+
// fullwidth: true,
|
|
30
|
+
},
|
|
31
|
+
render: (args) => {
|
|
32
|
+
console.log("args ", args);
|
|
33
|
+
const props: typeof args = {
|
|
34
|
+
...args,
|
|
35
|
+
};
|
|
36
|
+
return (
|
|
37
|
+
<div className="flex flex-row gap-4">
|
|
38
|
+
<Search id="1" size="lg" placeholder="Search" {...args} />
|
|
39
|
+
<Search id="2" size="md" placeholder="Search" {...args} />
|
|
40
|
+
<Search id="3" size="sm" placeholder="Search" {...args} />
|
|
41
|
+
</div>
|
|
42
|
+
);
|
|
43
|
+
},
|
|
44
|
+
} satisfies Story;
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { Input } from "../Input/Input";
|
|
3
|
+
import { Label } from "../Label/Label";
|
|
4
|
+
|
|
5
|
+
type SearchProps = {};
|
|
6
|
+
|
|
7
|
+
function Search(props: any) {
|
|
8
|
+
return (
|
|
9
|
+
<div className=" relative">
|
|
10
|
+
<Input {...props} hiddenPlaceholder />
|
|
11
|
+
<Label
|
|
12
|
+
htmlFor={props.id}
|
|
13
|
+
size={props.size}
|
|
14
|
+
disabled={props.disabled}
|
|
15
|
+
error={props.error}
|
|
16
|
+
className={props.labelClassname ?? ""}
|
|
17
|
+
isFloatable={true}
|
|
18
|
+
>
|
|
19
|
+
Search
|
|
20
|
+
</Label>
|
|
21
|
+
</div>
|
|
22
|
+
);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export { Search };
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { cn } from "@/utils/cn";
|
|
1
2
|
import React, { FC, forwardRef } from "react";
|
|
2
3
|
|
|
3
4
|
export type TextProps = {
|
|
@@ -49,7 +50,7 @@ const Text = forwardRef<TextProps["tag"], TextProps>(
|
|
|
49
50
|
}) => {
|
|
50
51
|
return (
|
|
51
52
|
<Tag
|
|
52
|
-
className={`typography-${variant} text-${color}
|
|
53
|
+
className={cn(`typography-${variant} text-${color}`, className)}
|
|
53
54
|
style={style}
|
|
54
55
|
>
|
|
55
56
|
{children}
|