globalfy-design-system 0.2.8 → 0.4.0

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 (106) hide show
  1. package/package.json +14 -1
  2. package/.babelrc +0 -7
  3. package/.eslintrc.cjs +0 -20
  4. package/.husky/commit-msg +0 -4
  5. package/.husky/pre-commit +0 -4
  6. package/.lintstagedrc +0 -4
  7. package/.nvmrc +0 -1
  8. package/.prettierrc +0 -3
  9. package/.storybook/main.ts +0 -20
  10. package/.storybook/preview-head.html +0 -6
  11. package/.storybook/preview.ts +0 -17
  12. package/CODEOWNERS +0 -1
  13. package/bitbucket-pipelines.yml +0 -42
  14. package/commitlint.config.cjs +0 -1
  15. package/components.json +0 -16
  16. package/index.html +0 -13
  17. package/jest.config.js +0 -9
  18. package/postcss.config.js +0 -6
  19. package/public/vite.svg +0 -1
  20. package/src/assets/fonts/satoshi/Satoshi-Black.ttf +0 -0
  21. package/src/assets/fonts/satoshi/Satoshi-Black.woff +0 -0
  22. package/src/assets/fonts/satoshi/Satoshi-Black.woff2 +0 -0
  23. package/src/assets/fonts/satoshi/Satoshi-Bold.ttf +0 -0
  24. package/src/assets/fonts/satoshi/Satoshi-Bold.woff +0 -0
  25. package/src/assets/fonts/satoshi/Satoshi-Bold.woff2 +0 -0
  26. package/src/assets/fonts/satoshi/Satoshi-Medium.ttf +0 -0
  27. package/src/assets/fonts/satoshi/Satoshi-Medium.woff +0 -0
  28. package/src/assets/fonts/satoshi/Satoshi-Medium.woff2 +0 -0
  29. package/src/assets/fonts/satoshi/Satoshi-Regular.ttf +0 -0
  30. package/src/assets/fonts/satoshi/Satoshi-Regular.woff +0 -0
  31. package/src/assets/fonts/satoshi/Satoshi-Regular.woff2 +0 -0
  32. package/src/assets/fonts/satoshi/satoshi.css +0 -43
  33. package/src/components/atoms/Avatar/Avatar.stories.tsx +0 -26
  34. package/src/components/atoms/Avatar/Avatar.test.tsx +0 -19
  35. package/src/components/atoms/Avatar/Avatar.tsx +0 -46
  36. package/src/components/atoms/Avatar/Avatar.types.ts +0 -7
  37. package/src/components/atoms/Avatar/index.ts +0 -2
  38. package/src/components/atoms/Checkbox/Checkbox.stories.tsx +0 -19
  39. package/src/components/atoms/Checkbox/Checkbox.test.tsx +0 -12
  40. package/src/components/atoms/Checkbox/Checkbox.tsx +0 -20
  41. package/src/components/atoms/Checkbox/index.ts +0 -1
  42. package/src/components/atoms/FieldMessage/FieldMessage.stories.tsx +0 -20
  43. package/src/components/atoms/FieldMessage/FieldMessage.test.tsx +0 -14
  44. package/src/components/atoms/FieldMessage/FieldMessage.tsx +0 -6
  45. package/src/components/atoms/FieldMessage/FieldMessage.type.ts +0 -3
  46. package/src/components/atoms/FieldMessage/index.ts +0 -2
  47. package/src/components/atoms/Flag/Flag.stories.tsx +0 -34
  48. package/src/components/atoms/Flag/Flag.tsx +0 -35
  49. package/src/components/atoms/Flag/Flag.types.ts +0 -6
  50. package/src/components/atoms/Flag/images/bra.svg +0 -8
  51. package/src/components/atoms/Flag/images/esp.svg +0 -6
  52. package/src/components/atoms/Flag/images/usa.svg +0 -9
  53. package/src/components/atoms/Flag/index.ts +0 -2
  54. package/src/components/atoms/Icon/Icon.stories.tsx +0 -32
  55. package/src/components/atoms/Icon/Icon.tsx +0 -6
  56. package/src/components/atoms/Icon/assets/fonts/icomoon.eot +0 -0
  57. package/src/components/atoms/Icon/assets/fonts/icomoon.svg +0 -21
  58. package/src/components/atoms/Icon/assets/fonts/icomoon.ttf +0 -0
  59. package/src/components/atoms/Icon/assets/fonts/icomoon.woff +0 -0
  60. package/src/components/atoms/Icon/assets/selection.json +0 -285
  61. package/src/components/atoms/Icon/assets/style.css +0 -60
  62. package/src/components/atoms/Icon/icon.types.ts +0 -17
  63. package/src/components/atoms/Icon/index.ts +0 -2
  64. package/src/components/atoms/Logo/Logo.stories.tsx +0 -20
  65. package/src/components/atoms/Logo/Logo.test.tsx +0 -11
  66. package/src/components/atoms/Logo/Logo.tsx +0 -12
  67. package/src/components/atoms/Logo/Logo.types.ts +0 -3
  68. package/src/components/atoms/Logo/images/globalfy_desktop.svg +0 -9
  69. package/src/components/atoms/Logo/images/globalfy_mobile.svg +0 -3
  70. package/src/components/atoms/Logo/index.ts +0 -2
  71. package/src/components/atoms/RadioGroup/RadioGroup.stories.tsx +0 -21
  72. package/src/components/atoms/RadioGroup/RadioGroup.test.tsx +0 -47
  73. package/src/components/atoms/RadioGroup/RadioGroup.tsx +0 -26
  74. package/src/components/atoms/RadioGroup/RadioGroup.types.ts +0 -12
  75. package/src/components/atoms/RadioGroup/index.ts +0 -1
  76. package/src/components/atoms/Switch/Switch.stories.tsx +0 -18
  77. package/src/components/atoms/Switch/Switch.test.tsx +0 -12
  78. package/src/components/atoms/Switch/Switch.tsx +0 -32
  79. package/src/components/atoms/Switch/Switch.types.ts +0 -3
  80. package/src/components/atoms/Switch/index.ts +0 -2
  81. package/src/components/atoms/Typography/Typography.stories.tsx +0 -18
  82. package/src/components/atoms/Typography/Typography.test.tsx +0 -10
  83. package/src/components/atoms/Typography/Typography.tsx +0 -37
  84. package/src/components/atoms/Typography/Typography.types.ts +0 -7
  85. package/src/components/atoms/Typography/index.ts +0 -2
  86. package/src/components/atoms/index.ts +0 -9
  87. package/src/components/index.ts +0 -1
  88. package/src/global.css +0 -76
  89. package/src/main.ts +0 -1
  90. package/src/shadcn/components/ui/avatar.tsx +0 -48
  91. package/src/shadcn/components/ui/button.tsx +0 -55
  92. package/src/shadcn/components/ui/checkbox.tsx +0 -28
  93. package/src/shadcn/components/ui/form.tsx +0 -177
  94. package/src/shadcn/components/ui/label.tsx +0 -23
  95. package/src/shadcn/components/ui/radio-group.tsx +0 -44
  96. package/src/shadcn/components/ui/switch.tsx +0 -27
  97. package/src/shadcn/utils.ts +0 -6
  98. package/src/utils/reactHookForm/FormWrapper.tsx +0 -12
  99. package/src/utils/tailwind/classNames.ts +0 -4
  100. package/src/vite-env.d.ts +0 -1
  101. package/tailwind.config.js +0 -98
  102. package/testSetup.ts +0 -1
  103. package/tsconfig.json +0 -32
  104. package/tsconfig.node.json +0 -10
  105. package/vite.config.ts +0 -23
  106. package/yarn.lock +0 -10726
@@ -1,47 +0,0 @@
1
- import { render } from "@testing-library/react";
2
- import { RadioGroup } from "./RadioGroup";
3
-
4
- describe("RadioGroup Component", () => {
5
- const options = [
6
- { value: "value1", id: "id1", label: "Label1" },
7
- { value: "value2", id: "id2", label: "Label2" }
8
- ];
9
-
10
- test("should render the correct radio inputs and labels", () => {
11
- const { getAllByRole, getByText } = render(
12
- <RadioGroup options={options} />
13
- );
14
- const radios = getAllByRole("radio");
15
- expect(radios.length).toBe(options.length);
16
-
17
- options.forEach((option) => {
18
- expect(getByText(option.label)).toBeInTheDocument();
19
- const labelOne = getByText("Label1");
20
- const labelTwo = getByText("Label2");
21
- expect(labelOne).toBeInTheDocument();
22
- expect(labelTwo).toBeInTheDocument();
23
- });
24
- });
25
-
26
- test("should render a radio group component with label on the left", () => {
27
- const oneOption = [{ value: "value2", id: "id2", label: "Label2" }];
28
- const { getByRole } = render(
29
- <RadioGroup options={oneOption} labelPosition="left" />
30
- );
31
- const radioGroupItem = getByRole("radio");
32
- expect(radioGroupItem).toBeInTheDocument();
33
- expect(radioGroupItem.nextSibling).toBeNull();
34
- expect(radioGroupItem.previousSibling).not.toBeNull();
35
- });
36
-
37
- test("should render a radio group component with label on the right", () => {
38
- const oneOption = [{ value: "value2", id: "id2", label: "Label2" }];
39
- const { getByRole } = render(
40
- <RadioGroup options={oneOption} labelPosition="right" />
41
- );
42
- const radioGroupItem = getByRole("radio");
43
- expect(radioGroupItem).toBeInTheDocument();
44
- expect(radioGroupItem.nextSibling).not.toBeNull();
45
- expect(radioGroupItem.previousSibling).toBeNull();
46
- });
47
- });
@@ -1,26 +0,0 @@
1
- import {
2
- RadioGroup as SCNRadioGroup,
3
- RadioGroupItem as SCNRadioGroupItem
4
- } from "@/shadcn/components/ui/radio-group";
5
- import { RadioGroupProps } from "./RadioGroup.types";
6
-
7
- export const RadioGroup = ({
8
- options,
9
- labelPosition = "right"
10
- }: RadioGroupProps) => {
11
- return (
12
- <SCNRadioGroup>
13
- {options.map((option) => (
14
- <div key={option.value} className="flex gap-2 items-center">
15
- {labelPosition === "left" && option.label}
16
- <SCNRadioGroupItem
17
- value={option.value}
18
- id={option.id}
19
- className="flex items-center justify-center h-5 w-5 border-globalfy-grey900 text-globalfy-white data-[state=checked]:bg-globalfy-primaryGreen data-[state=checked]:border-globalfy-primaryGreen"
20
- />
21
- {labelPosition === "right" && option.label}
22
- </div>
23
- ))}
24
- </SCNRadioGroup>
25
- );
26
- };
@@ -1,12 +0,0 @@
1
- import { ReactNode } from "react";
2
-
3
- export type RadioGroupOption = {
4
- label: ReactNode;
5
- value: string;
6
- id: string;
7
- };
8
-
9
- export type RadioGroupProps = {
10
- options: RadioGroupOption[];
11
- labelPosition?: "left" | "right";
12
- };
@@ -1 +0,0 @@
1
- export * from "./RadioGroup";
@@ -1,18 +0,0 @@
1
- import { Meta, StoryObj } from "@storybook/react";
2
- import { Switch } from "./Switch";
3
-
4
- const meta = {
5
- title: "Components/Atoms/Switch",
6
- component: Switch,
7
- tags: ["autodocs"]
8
- } satisfies Meta<typeof Switch>;
9
-
10
- export default meta;
11
-
12
- type Story = StoryObj<typeof meta>;
13
-
14
- export const Default: Story = {
15
- args: {
16
- variant: "regular"
17
- }
18
- };
@@ -1,12 +0,0 @@
1
- import { render } from "@testing-library/react";
2
-
3
- import { Switch } from "./Switch";
4
-
5
- describe("Switch Component", () => {
6
- test("should render a switch component", async () => {
7
- const { getByRole } = await render(<Switch />);
8
- const switchTest = getByRole("switch");
9
-
10
- expect(switchTest).toBeTruthy();
11
- });
12
- });
@@ -1,32 +0,0 @@
1
- import * as React from "react";
2
- import * as SwitchPrimitives from "@radix-ui/react-switch";
3
- import { SwitchProps } from "./Switch.types";
4
- import { cva } from "class-variance-authority";
5
- import { classNames } from "@/utils/tailwind/classNames";
6
- import { Switch as SCNSwitch } from "@/shadcn/components/ui/switch";
7
-
8
- export const Switch = React.forwardRef<
9
- React.ElementRef<typeof SwitchPrimitives.Root>,
10
- React.ComponentPropsWithoutRef<typeof SwitchPrimitives.Root> & SwitchProps
11
- >(({ className, variant, ...props }, ref) => {
12
- const variants = cva(
13
- "data-[state=checked]:bg-globalfy-primaryGreen data-[state=unchecked]:bg-globalfy-grey600",
14
- {
15
- variants: {
16
- variant: {
17
- regular: "",
18
- large:
19
- "h-[64px] w-[116px] [&>*]:h-[48px] [&>*]:w-[48px] [&>*]:data-[state=checked]:translate-x-14 [&>*]:data-[state=unchecked]:translate-x-2"
20
- }
21
- }
22
- }
23
- );
24
-
25
- return (
26
- <SCNSwitch
27
- className={classNames(className, variants({ variant }))}
28
- {...props}
29
- ref={ref}
30
- />
31
- );
32
- });
@@ -1,3 +0,0 @@
1
- export type SwitchProps = {
2
- variant?: "regular" | "large";
3
- };
@@ -1,2 +0,0 @@
1
- export * from "./Switch";
2
- export * from "./Switch.types";
@@ -1,18 +0,0 @@
1
- import { Meta, StoryObj } from "@storybook/react";
2
- import { Typography } from ".";
3
-
4
- const meta = {
5
- title: "Components/Atoms/Typography",
6
- component: Typography,
7
- tags: ["autodocs"]
8
- } satisfies Meta<typeof Typography>;
9
-
10
- export default meta;
11
-
12
- type Story = StoryObj<typeof meta>;
13
-
14
- export const Playground: Story = {
15
- args: {
16
- children: "Typography"
17
- }
18
- };
@@ -1,10 +0,0 @@
1
- import { render, screen } from "@testing-library/react";
2
-
3
- import { Typography } from "./Typography";
4
-
5
- describe("Typography Component", () => {
6
- test("should render the provided children", async () => {
7
- render(<Typography>Typography</Typography>);
8
- expect(screen.getByText("Typography")).toBeTruthy();
9
- });
10
- });
@@ -1,37 +0,0 @@
1
- import { cva } from "class-variance-authority";
2
- import { TypographyProps } from "./Typography.types";
3
- import { classNames } from "@/utils/tailwind/classNames";
4
-
5
- export const Typography = ({
6
- children,
7
- className,
8
- font = "satoshi",
9
- weight = "regular",
10
- ...props
11
- }: TypographyProps) => {
12
- const typographyVariants = cva("", {
13
- variants: {
14
- font: {
15
- satoshi: "font-satoshi",
16
- livvic: "font-livvic"
17
- },
18
- weight: {
19
- light: "font-light",
20
- regular: "font-normal",
21
- medium: "font-medium",
22
- semibold: "font-semibold",
23
- bold: "font-bold",
24
- black: "font-black"
25
- }
26
- }
27
- });
28
-
29
- return (
30
- <p
31
- {...props}
32
- className={classNames(className, typographyVariants({ font, weight }))}
33
- >
34
- {children}
35
- </p>
36
- );
37
- };
@@ -1,7 +0,0 @@
1
- import { HTMLAttributes } from "react";
2
-
3
- export type TypographyProps = {
4
- children: React.ReactNode;
5
- font?: "satoshi" | "livvic";
6
- weight?: "light" | "regular" | "medium" | "semibold" | "bold" | "black";
7
- } & HTMLAttributes<HTMLParagraphElement>;
@@ -1,2 +0,0 @@
1
- export * from "./Typography";
2
- export * from "./Typography.types";
@@ -1,9 +0,0 @@
1
- export * from "./Logo";
2
- export * from "./FieldMessage";
3
- export * from "./Typography";
4
- export * from "./Flag";
5
- export * from "./Icon";
6
- export * from "./Switch";
7
- export * from "./Checkbox";
8
- export * from "./Avatar";
9
- export * from "./RadioGroup";
@@ -1 +0,0 @@
1
- export * from "./atoms";
package/src/global.css DELETED
@@ -1,76 +0,0 @@
1
- @tailwind base;
2
- @tailwind components;
3
- @tailwind utilities;
4
-
5
- @layer base {
6
- :root {
7
- --background: 0 0% 100%;
8
- --foreground: 222.2 84% 4.9%;
9
-
10
- --card: 0 0% 100%;
11
- --card-foreground: 222.2 84% 4.9%;
12
-
13
- --popover: 0 0% 100%;
14
- --popover-foreground: 222.2 84% 4.9%;
15
-
16
- --primary: 222.2 47.4% 11.2%;
17
- --primary-foreground: 210 40% 98%;
18
-
19
- --secondary: 210 40% 96.1%;
20
- --secondary-foreground: 222.2 47.4% 11.2%;
21
-
22
- --muted: 210 40% 96.1%;
23
- --muted-foreground: 215.4 16.3% 46.9%;
24
-
25
- --accent: 210 40% 96.1%;
26
- --accent-foreground: 222.2 47.4% 11.2%;
27
-
28
- --destructive: 0 84.2% 60.2%;
29
- --destructive-foreground: 210 40% 98%;
30
-
31
- --border: 214.3 31.8% 91.4%;
32
- --input: 214.3 31.8% 91.4%;
33
- --ring: 222.2 84% 4.9%;
34
-
35
- --radius: 0.5rem;
36
- }
37
-
38
- .dark {
39
- --background: 222.2 84% 4.9%;
40
- --foreground: 210 40% 98%;
41
-
42
- --card: 222.2 84% 4.9%;
43
- --card-foreground: 210 40% 98%;
44
-
45
- --popover: 222.2 84% 4.9%;
46
- --popover-foreground: 210 40% 98%;
47
-
48
- --primary: 210 40% 98%;
49
- --primary-foreground: 222.2 47.4% 11.2%;
50
-
51
- --secondary: 217.2 32.6% 17.5%;
52
- --secondary-foreground: 210 40% 98%;
53
-
54
- --muted: 217.2 32.6% 17.5%;
55
- --muted-foreground: 215 20.2% 65.1%;
56
-
57
- --accent: 217.2 32.6% 17.5%;
58
- --accent-foreground: 210 40% 98%;
59
-
60
- --destructive: 0 62.8% 30.6%;
61
- --destructive-foreground: 210 40% 98%;
62
-
63
- --border: 217.2 32.6% 17.5%;
64
- --input: 217.2 32.6% 17.5%;
65
- --ring: 212.7 26.8% 83.9%;
66
- }
67
- }
68
-
69
- @layer base {
70
- * {
71
- @apply border-border;
72
- }
73
- body {
74
- @apply bg-background text-foreground;
75
- }
76
- }
package/src/main.ts DELETED
@@ -1 +0,0 @@
1
- export * from "./components";
@@ -1,48 +0,0 @@
1
- import * as React from "react";
2
- import * as AvatarPrimitive from "@radix-ui/react-avatar";
3
-
4
- import { cn } from "@/shadcn/utils";
5
-
6
- const Avatar = React.forwardRef<
7
- React.ElementRef<typeof AvatarPrimitive.Root>,
8
- React.ComponentPropsWithoutRef<typeof AvatarPrimitive.Root>
9
- >(({ className, ...props }, ref) => (
10
- <AvatarPrimitive.Root
11
- ref={ref}
12
- className={cn(
13
- "relative flex h-10 w-10 shrink-0 overflow-hidden rounded-full",
14
- className
15
- )}
16
- {...props}
17
- />
18
- ));
19
- Avatar.displayName = AvatarPrimitive.Root.displayName;
20
-
21
- const AvatarImage = React.forwardRef<
22
- React.ElementRef<typeof AvatarPrimitive.Image>,
23
- React.ComponentPropsWithoutRef<typeof AvatarPrimitive.Image>
24
- >(({ className, ...props }, ref) => (
25
- <AvatarPrimitive.Image
26
- ref={ref}
27
- className={cn("aspect-square h-full w-full", className)}
28
- {...props}
29
- />
30
- ));
31
- AvatarImage.displayName = AvatarPrimitive.Image.displayName;
32
-
33
- const AvatarFallback = React.forwardRef<
34
- React.ElementRef<typeof AvatarPrimitive.Fallback>,
35
- React.ComponentPropsWithoutRef<typeof AvatarPrimitive.Fallback>
36
- >(({ className, ...props }, ref) => (
37
- <AvatarPrimitive.Fallback
38
- ref={ref}
39
- className={cn(
40
- "flex h-full w-full items-center justify-center rounded-full bg-muted",
41
- className
42
- )}
43
- {...props}
44
- />
45
- ));
46
- AvatarFallback.displayName = AvatarPrimitive.Fallback.displayName;
47
-
48
- export { Avatar, AvatarImage, AvatarFallback };
@@ -1,55 +0,0 @@
1
- import * as React from "react";
2
- import { Slot } from "@radix-ui/react-slot";
3
- import { cva, type VariantProps } from "class-variance-authority";
4
- import { cn } from "@/shadcn/utils";
5
-
6
- const buttonVariants = cva(
7
- "inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50",
8
- {
9
- variants: {
10
- variant: {
11
- default: "bg-primary text-primary-foreground hover:bg-primary/90",
12
- destructive:
13
- "bg-destructive text-destructive-foreground hover:bg-destructive/90",
14
- outline:
15
- "border border-input bg-background hover:bg-accent hover:text-accent-foreground",
16
- secondary:
17
- "bg-secondary text-secondary-foreground hover:bg-secondary/80",
18
- ghost: "hover:bg-accent hover:text-accent-foreground",
19
- link: "text-primary underline-offset-4 hover:underline"
20
- },
21
- size: {
22
- default: "h-10 px-4 py-2",
23
- sm: "h-9 rounded-md px-3",
24
- lg: "h-11 rounded-md px-8",
25
- icon: "h-10 w-10"
26
- }
27
- },
28
- defaultVariants: {
29
- variant: "default",
30
- size: "default"
31
- }
32
- }
33
- );
34
-
35
- export interface ButtonProps
36
- extends React.ButtonHTMLAttributes<HTMLButtonElement>,
37
- VariantProps<typeof buttonVariants> {
38
- asChild?: boolean;
39
- }
40
-
41
- const Button = React.forwardRef<HTMLButtonElement, ButtonProps>(
42
- ({ className, variant, size, asChild = false, ...props }, ref) => {
43
- const Comp = asChild ? Slot : "button";
44
- return (
45
- <Comp
46
- className={cn(buttonVariants({ variant, size, className }))}
47
- ref={ref}
48
- {...props}
49
- />
50
- );
51
- }
52
- );
53
- Button.displayName = "Button";
54
-
55
- export { Button, buttonVariants };
@@ -1,28 +0,0 @@
1
- import * as React from "react";
2
- import * as CheckboxPrimitive from "@radix-ui/react-checkbox";
3
- import { Check } from "lucide-react";
4
-
5
- import { cn } from "@/shadcn/utils";
6
-
7
- const Checkbox = React.forwardRef<
8
- React.ElementRef<typeof CheckboxPrimitive.Root>,
9
- React.ComponentPropsWithoutRef<typeof CheckboxPrimitive.Root>
10
- >(({ className, ...props }, ref) => (
11
- <CheckboxPrimitive.Root
12
- ref={ref}
13
- className={cn(
14
- "peer h-4 w-4 shrink-0 rounded-sm border border-primary ring-offset-background focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 data-[state=checked]:bg-primary data-[state=checked]:text-primary-foreground",
15
- className
16
- )}
17
- {...props}
18
- >
19
- <CheckboxPrimitive.Indicator
20
- className={cn("flex items-center justify-center text-current")}
21
- >
22
- <Check strokeWidth={4} className="h-4 w-4" />
23
- </CheckboxPrimitive.Indicator>
24
- </CheckboxPrimitive.Root>
25
- ));
26
- Checkbox.displayName = CheckboxPrimitive.Root.displayName;
27
-
28
- export { Checkbox };
@@ -1,177 +0,0 @@
1
- import * as React from "react";
2
- import * as LabelPrimitive from "@radix-ui/react-label";
3
- import { Slot } from "@radix-ui/react-slot";
4
- import {
5
- Controller,
6
- ControllerProps,
7
- FieldPath,
8
- FieldValues,
9
- FormProvider,
10
- useFormContext
11
- } from "react-hook-form";
12
-
13
- import { Label } from "@/shadcn/components/ui/label";
14
- import { cn } from "@/shadcn/utils";
15
-
16
- const Form = FormProvider;
17
-
18
- type FormFieldContextValue<
19
- TFieldValues extends FieldValues = FieldValues,
20
- TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>
21
- > = {
22
- name: TName;
23
- };
24
-
25
- const FormFieldContext = React.createContext<FormFieldContextValue>(
26
- {} as FormFieldContextValue
27
- );
28
-
29
- const FormField = <
30
- TFieldValues extends FieldValues = FieldValues,
31
- TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>
32
- >({
33
- ...props
34
- }: ControllerProps<TFieldValues, TName>) => {
35
- return (
36
- <FormFieldContext.Provider value={{ name: props.name }}>
37
- <Controller {...props} />
38
- </FormFieldContext.Provider>
39
- );
40
- };
41
-
42
- const useFormField = () => {
43
- const fieldContext = React.useContext(FormFieldContext);
44
- const itemContext = React.useContext(FormItemContext);
45
- const { getFieldState, formState } = useFormContext();
46
-
47
- const fieldState = getFieldState(fieldContext.name, formState);
48
-
49
- if (!fieldContext) {
50
- throw new Error("useFormField should be used within <FormField>");
51
- }
52
-
53
- const { id } = itemContext;
54
-
55
- return {
56
- id,
57
- name: fieldContext.name,
58
- formItemId: `${id}-form-item`,
59
- formDescriptionId: `${id}-form-item-description`,
60
- formMessageId: `${id}-form-item-message`,
61
- ...fieldState
62
- };
63
- };
64
-
65
- type FormItemContextValue = {
66
- id: string;
67
- };
68
-
69
- const FormItemContext = React.createContext<FormItemContextValue>(
70
- {} as FormItemContextValue
71
- );
72
-
73
- const FormItem = React.forwardRef<
74
- HTMLDivElement,
75
- React.HTMLAttributes<HTMLDivElement>
76
- >(({ className, ...props }, ref) => {
77
- const id = React.useId();
78
-
79
- return (
80
- <FormItemContext.Provider value={{ id }}>
81
- <div ref={ref} className={cn("space-y-2", className)} {...props} />
82
- </FormItemContext.Provider>
83
- );
84
- });
85
- FormItem.displayName = "FormItem";
86
-
87
- const FormLabel = React.forwardRef<
88
- React.ElementRef<typeof LabelPrimitive.Root>,
89
- React.ComponentPropsWithoutRef<typeof LabelPrimitive.Root>
90
- >(({ className, ...props }, ref) => {
91
- const { error, formItemId } = useFormField();
92
-
93
- return (
94
- <Label
95
- ref={ref}
96
- className={cn(error && "text-destructive", className)}
97
- htmlFor={formItemId}
98
- {...props}
99
- />
100
- );
101
- });
102
- FormLabel.displayName = "FormLabel";
103
-
104
- const FormControl = React.forwardRef<
105
- React.ElementRef<typeof Slot>,
106
- React.ComponentPropsWithoutRef<typeof Slot>
107
- >(({ ...props }, ref) => {
108
- const { error, formItemId, formDescriptionId, formMessageId } =
109
- useFormField();
110
-
111
- return (
112
- <Slot
113
- ref={ref}
114
- id={formItemId}
115
- aria-describedby={
116
- !error
117
- ? `${formDescriptionId}`
118
- : `${formDescriptionId} ${formMessageId}`
119
- }
120
- aria-invalid={!!error}
121
- {...props}
122
- />
123
- );
124
- });
125
- FormControl.displayName = "FormControl";
126
-
127
- const FormDescription = React.forwardRef<
128
- HTMLParagraphElement,
129
- React.HTMLAttributes<HTMLParagraphElement>
130
- >(({ className, ...props }, ref) => {
131
- const { formDescriptionId } = useFormField();
132
-
133
- return (
134
- <p
135
- ref={ref}
136
- id={formDescriptionId}
137
- className={cn("text-sm text-muted-foreground", className)}
138
- {...props}
139
- />
140
- );
141
- });
142
- FormDescription.displayName = "FormDescription";
143
-
144
- const FormMessage = React.forwardRef<
145
- HTMLParagraphElement,
146
- React.HTMLAttributes<HTMLParagraphElement>
147
- >(({ className, children, ...props }, ref) => {
148
- const { error, formMessageId } = useFormField();
149
- const body = error ? String(error?.message) : children;
150
-
151
- if (!body) {
152
- return null;
153
- }
154
-
155
- return (
156
- <p
157
- ref={ref}
158
- id={formMessageId}
159
- className={cn("text-sm font-medium text-destructive", className)}
160
- {...props}
161
- >
162
- {body}
163
- </p>
164
- );
165
- });
166
- FormMessage.displayName = "FormMessage";
167
-
168
- export {
169
- useFormField,
170
- Form,
171
- FormItem,
172
- FormLabel,
173
- FormControl,
174
- FormDescription,
175
- FormMessage,
176
- FormField
177
- };
@@ -1,23 +0,0 @@
1
- import * as React from "react";
2
- import * as LabelPrimitive from "@radix-ui/react-label";
3
- import { cva, type VariantProps } from "class-variance-authority";
4
- import { cn } from "@/shadcn/utils";
5
-
6
- const labelVariants = cva(
7
- "text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70"
8
- );
9
-
10
- const Label = React.forwardRef<
11
- React.ElementRef<typeof LabelPrimitive.Root>,
12
- React.ComponentPropsWithoutRef<typeof LabelPrimitive.Root> &
13
- VariantProps<typeof labelVariants>
14
- >(({ className, ...props }, ref) => (
15
- <LabelPrimitive.Root
16
- ref={ref}
17
- className={cn(labelVariants(), className)}
18
- {...props}
19
- />
20
- ));
21
- Label.displayName = LabelPrimitive.Root.displayName;
22
-
23
- export { Label };