@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.
Files changed (99) hide show
  1. package/dist/cjs/bundle.css +227 -16
  2. package/dist/cjs/bundle.js +3 -3
  3. package/dist/cjs/bundle.js.map +1 -1
  4. package/dist/cjs/types/components/ActionButton/ActionButton.d.ts +20 -0
  5. package/dist/cjs/types/components/ActionButton/ActionButton.stories.d.ts +311 -0
  6. package/dist/cjs/types/components/ActionButton/ActionButton.styles.d.ts +6 -0
  7. package/dist/cjs/types/components/Avatar/Avatar.d.ts +32 -0
  8. package/dist/cjs/types/components/Avatar/Avatar.stories.d.ts +64 -0
  9. package/dist/cjs/types/components/Avatar/Avatar.styles.d.ts +4 -0
  10. package/dist/cjs/types/components/Avatar/AvatarBase.d.ts +6 -0
  11. package/dist/cjs/types/components/Avatar/AvatarGroup.d.ts +11 -0
  12. package/dist/cjs/types/components/Avatar/AvatarGroup.stories.d.ts +31 -0
  13. package/dist/cjs/types/components/Input/Input.d.ts +21 -4
  14. package/dist/cjs/types/components/Input/Input.stories.d.ts +340 -22
  15. package/dist/cjs/types/components/Input/Input.styles.d.ts +9 -0
  16. package/dist/cjs/types/components/Label/Label.d.ts +6 -1
  17. package/dist/cjs/types/components/Label/Label.stories.d.ts +10 -1
  18. package/dist/cjs/types/components/Label/Label.styles.d.ts +6 -0
  19. package/dist/cjs/types/components/Navbar/Navbar.d.ts +12 -0
  20. package/dist/cjs/types/components/Navbar/Navbar.stories.d.ts +35 -0
  21. package/dist/cjs/types/components/Search/Search.d.ts +2 -0
  22. package/dist/cjs/types/components/Search/Search.stories.d.ts +21 -0
  23. package/dist/cjs/types/components/ThemeToggle.d.ts +2 -0
  24. package/dist/components/ActionButton/ActionButton.js +38 -0
  25. package/dist/components/ActionButton/ActionButton.stories.js +45 -0
  26. package/dist/components/ActionButton/ActionButton.styles.js +71 -0
  27. package/dist/components/Avatar/Avatar.js +22 -0
  28. package/dist/components/Avatar/Avatar.stories.js +47 -0
  29. package/dist/components/Avatar/Avatar.styles.js +23 -0
  30. package/dist/components/Avatar/AvatarBase.js +43 -0
  31. package/dist/components/Avatar/AvatarGroup.js +21 -0
  32. package/dist/components/Avatar/AvatarGroup.stories.js +47 -0
  33. package/dist/components/Button/Button.styles.js +6 -6
  34. package/dist/components/Dropdown/Dropdown.js +39 -2
  35. package/dist/components/Dropdown/Dropdown.stories.js +29 -4
  36. package/dist/components/Input/Input.js +5 -4
  37. package/dist/components/Input/Input.stories.js +2 -4
  38. package/dist/components/Input/Input.styles.js +45 -0
  39. package/dist/components/Label/Label.js +7 -3
  40. package/dist/components/Label/Label.styles.js +57 -0
  41. package/dist/components/Navbar/Navbar.js +9 -0
  42. package/dist/components/Navbar/Navbar.stories.js +41 -0
  43. package/dist/components/Search/Search.js +19 -0
  44. package/dist/components/Search/Search.stories.js +36 -0
  45. package/dist/components/Text/Text.js +2 -1
  46. package/dist/components/ThemeToggle.js +17 -0
  47. package/dist/esm/bundle.css +227 -16
  48. package/dist/esm/bundle.js +3 -3
  49. package/dist/esm/bundle.js.map +1 -1
  50. package/dist/esm/types/components/ActionButton/ActionButton.d.ts +20 -0
  51. package/dist/esm/types/components/ActionButton/ActionButton.stories.d.ts +311 -0
  52. package/dist/esm/types/components/ActionButton/ActionButton.styles.d.ts +6 -0
  53. package/dist/esm/types/components/Avatar/Avatar.d.ts +32 -0
  54. package/dist/esm/types/components/Avatar/Avatar.stories.d.ts +64 -0
  55. package/dist/esm/types/components/Avatar/Avatar.styles.d.ts +4 -0
  56. package/dist/esm/types/components/Avatar/AvatarBase.d.ts +6 -0
  57. package/dist/esm/types/components/Avatar/AvatarGroup.d.ts +11 -0
  58. package/dist/esm/types/components/Avatar/AvatarGroup.stories.d.ts +31 -0
  59. package/dist/esm/types/components/Input/Input.d.ts +21 -4
  60. package/dist/esm/types/components/Input/Input.stories.d.ts +340 -22
  61. package/dist/esm/types/components/Input/Input.styles.d.ts +9 -0
  62. package/dist/esm/types/components/Label/Label.d.ts +6 -1
  63. package/dist/esm/types/components/Label/Label.stories.d.ts +10 -1
  64. package/dist/esm/types/components/Label/Label.styles.d.ts +6 -0
  65. package/dist/esm/types/components/Navbar/Navbar.d.ts +12 -0
  66. package/dist/esm/types/components/Navbar/Navbar.stories.d.ts +35 -0
  67. package/dist/esm/types/components/Search/Search.d.ts +2 -0
  68. package/dist/esm/types/components/Search/Search.stories.d.ts +21 -0
  69. package/dist/esm/types/components/ThemeToggle.d.ts +2 -0
  70. package/dist/index.d.ts +22 -10
  71. package/dist/src/theme/global.css +290 -21
  72. package/dist/theme/global.css +11 -0
  73. package/dist/theme/presets/colors.js +28 -0
  74. package/package.json +2 -1
  75. package/src/components/ActionButton/ActionButton.stories.tsx +176 -0
  76. package/src/components/ActionButton/ActionButton.styles.ts +79 -0
  77. package/src/components/ActionButton/ActionButton.tsx +42 -0
  78. package/src/components/Avatar/Avatar.stories.tsx +107 -0
  79. package/src/components/Avatar/Avatar.styles.ts +28 -0
  80. package/src/components/Avatar/Avatar.tsx +88 -0
  81. package/src/components/Avatar/AvatarBase.tsx +50 -0
  82. package/src/components/Avatar/AvatarGroup.stories.tsx +77 -0
  83. package/src/components/Avatar/AvatarGroup.tsx +55 -0
  84. package/src/components/Button/Button.styles.ts +6 -6
  85. package/src/components/Dropdown/Dropdown.stories.tsx +25 -3
  86. package/src/components/Dropdown/Dropdown.tsx +61 -2
  87. package/src/components/Input/Input.stories.tsx +8 -6
  88. package/src/components/Input/Input.styles.tsx +51 -0
  89. package/src/components/Input/Input.tsx +30 -6
  90. package/src/components/Label/Label.styles.ts +61 -0
  91. package/src/components/Label/Label.tsx +13 -7
  92. package/src/components/Navbar/Navbar.stories.tsx +86 -0
  93. package/src/components/Navbar/Navbar.tsx +56 -0
  94. package/src/components/Search/Search.stories.tsx +44 -0
  95. package/src/components/Search/Search.tsx +25 -0
  96. package/src/components/Text/Text.tsx +2 -1
  97. package/src/components/ThemeToggle.tsx +19 -0
  98. package/src/theme/global.css +11 -0
  99. 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
- variant: "solid",
61
- disabled: true,
62
- color: "secondary",
63
- class: "text-white",
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={() => setIsFocused(true)}
174
- onBlur={() => setIsFocused(false)}
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 w-full">
36
- <Input type="email" placeholder="Email" />
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 StoryObj;
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 * as React from "react";
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 interface InputProps
6
- extends React.InputHTMLAttributes<HTMLInputElement> {}
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 = React.forwardRef<HTMLInputElement, InputProps>(
9
- ({ className, type, ...props }, ref) => {
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
- "flex h-10 w-full rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50",
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 { cva, type VariantProps } from "class-variance-authority";
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 labelVariants>
13
+ VariantProps<typeof labelVariant>
17
14
  >(({ className, ...props }, ref) => (
18
15
  <LabelPrimitive.Root
19
16
  ref={ref}
20
- className={cn(labelVariants(), className)}
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} ${className}`}
53
+ className={cn(`typography-${variant} text-${color}`, className)}
53
54
  style={style}
54
55
  >
55
56
  {children}