@fabio.caffarello/react-design-system 1.2.1 → 1.3.1

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 (57) hide show
  1. package/dist/index.cjs +4 -4
  2. package/dist/index.js +696 -246
  3. package/dist/ui/atoms/ErrorMessage/ErrorMessage.d.ts +18 -0
  4. package/dist/ui/atoms/ErrorMessage/ErrorMessage.stories.d.ts +7 -0
  5. package/dist/ui/atoms/ErrorMessage/ErrorMessage.test.d.ts +1 -0
  6. package/dist/ui/atoms/Label/Label.d.ts +20 -0
  7. package/dist/ui/atoms/Label/Label.stories.d.ts +8 -0
  8. package/dist/ui/atoms/Label/Label.test.d.ts +1 -0
  9. package/dist/ui/atoms/NavLink/NavLink.d.ts +20 -0
  10. package/dist/ui/atoms/NavLink/NavLink.stories.d.ts +8 -0
  11. package/dist/ui/atoms/NavLink/NavLink.test.d.ts +1 -0
  12. package/dist/ui/atoms/index.d.ts +3 -0
  13. package/dist/ui/molecules/Breadcrumb/Breadcrumb.d.ts +28 -0
  14. package/dist/ui/molecules/Breadcrumb/Breadcrumb.stories.d.ts +9 -0
  15. package/dist/ui/molecules/Breadcrumb/Breadcrumb.test.d.ts +1 -0
  16. package/dist/ui/molecules/Form/Form.d.ts +24 -0
  17. package/dist/ui/molecules/Form/Form.stories.d.ts +9 -0
  18. package/dist/ui/molecules/Form/Form.test.d.ts +1 -0
  19. package/dist/ui/molecules/Pagination/Pagination.d.ts +28 -0
  20. package/dist/ui/molecules/Pagination/Pagination.stories.d.ts +10 -0
  21. package/dist/ui/molecules/Pagination/Pagination.test.d.ts +1 -0
  22. package/dist/ui/molecules/index.d.ts +4 -0
  23. package/dist/ui/organisms/Modal/Modal.d.ts +25 -0
  24. package/dist/ui/organisms/Modal/Modal.stories.d.ts +9 -0
  25. package/dist/ui/organisms/Modal/Modal.test.d.ts +1 -0
  26. package/dist/ui/organisms/Table/Table.d.ts +35 -0
  27. package/dist/ui/organisms/Table/Table.stories.d.ts +9 -0
  28. package/dist/ui/organisms/Table/Table.test.d.ts +1 -0
  29. package/dist/ui/organisms/index.d.ts +3 -0
  30. package/package.json +1 -1
  31. package/src/ui/atoms/ErrorMessage/ErrorMessage.stories.tsx +81 -0
  32. package/src/ui/atoms/ErrorMessage/ErrorMessage.test.tsx +40 -0
  33. package/src/ui/atoms/ErrorMessage/ErrorMessage.tsx +62 -0
  34. package/src/ui/atoms/Label/Label.stories.tsx +94 -0
  35. package/src/ui/atoms/Label/Label.test.tsx +47 -0
  36. package/src/ui/atoms/Label/Label.tsx +51 -0
  37. package/src/ui/atoms/NavLink/NavLink.stories.tsx +71 -0
  38. package/src/ui/atoms/NavLink/NavLink.test.tsx +44 -0
  39. package/src/ui/atoms/NavLink/NavLink.tsx +63 -0
  40. package/src/ui/atoms/index.ts +6 -0
  41. package/src/ui/molecules/Breadcrumb/Breadcrumb.stories.tsx +75 -0
  42. package/src/ui/molecules/Breadcrumb/Breadcrumb.test.tsx +89 -0
  43. package/src/ui/molecules/Breadcrumb/Breadcrumb.tsx +79 -0
  44. package/src/ui/molecules/Form/Form.stories.tsx +195 -0
  45. package/src/ui/molecules/Form/Form.test.tsx +87 -0
  46. package/src/ui/molecules/Form/Form.tsx +78 -0
  47. package/src/ui/molecules/Pagination/Pagination.stories.tsx +116 -0
  48. package/src/ui/molecules/Pagination/Pagination.test.tsx +112 -0
  49. package/src/ui/molecules/Pagination/Pagination.tsx +170 -0
  50. package/src/ui/molecules/index.ts +7 -0
  51. package/src/ui/organisms/Modal/Modal.stories.tsx +102 -0
  52. package/src/ui/organisms/Modal/Modal.test.tsx +111 -0
  53. package/src/ui/organisms/Modal/Modal.tsx +205 -0
  54. package/src/ui/organisms/Table/Table.stories.tsx +137 -0
  55. package/src/ui/organisms/Table/Table.test.tsx +109 -0
  56. package/src/ui/organisms/Table/Table.tsx +130 -0
  57. package/src/ui/organisms/index.ts +5 -0
@@ -0,0 +1,18 @@
1
+ import type { HTMLAttributes } from "react";
2
+ interface Props extends HTMLAttributes<HTMLDivElement> {
3
+ message: string;
4
+ id?: string;
5
+ }
6
+ /**
7
+ * ErrorMessage Component
8
+ *
9
+ * A component for displaying validation error messages.
10
+ * Follows Atomic Design principles as an Atom component.
11
+ *
12
+ * @example
13
+ * ```tsx
14
+ * <ErrorMessage message="This field is required" id="email-error" />
15
+ * ```
16
+ */
17
+ export default function ErrorMessage({ message, id, className, ...props }: Props): import("react/jsx-runtime").JSX.Element;
18
+ export {};
@@ -0,0 +1,7 @@
1
+ import type { Meta, StoryObj } from "@storybook/react";
2
+ import ErrorMessage from "./ErrorMessage";
3
+ declare const meta: Meta<typeof ErrorMessage>;
4
+ export declare const Default: StoryObj<typeof ErrorMessage>;
5
+ export declare const WithInput: StoryObj<typeof ErrorMessage>;
6
+ export declare const MultipleErrors: StoryObj<typeof ErrorMessage>;
7
+ export default meta;
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,20 @@
1
+ import type { LabelHTMLAttributes } from "react";
2
+ interface Props extends LabelHTMLAttributes<HTMLLabelElement> {
3
+ variant?: "default" | "required" | "optional";
4
+ children: React.ReactNode;
5
+ }
6
+ /**
7
+ * Label Component
8
+ *
9
+ * A styled label component for form inputs.
10
+ * Follows Atomic Design principles as an Atom component.
11
+ *
12
+ * @example
13
+ * ```tsx
14
+ * <Label htmlFor="email" variant="required">
15
+ * Email Address
16
+ * </Label>
17
+ * ```
18
+ */
19
+ export default function Label({ variant, className, children, ...props }: Props): import("react/jsx-runtime").JSX.Element;
20
+ export {};
@@ -0,0 +1,8 @@
1
+ import type { Meta, StoryObj } from "@storybook/react";
2
+ import Label from "./Label";
3
+ declare const meta: Meta<typeof Label>;
4
+ export declare const Default: StoryObj<typeof Label>;
5
+ export declare const Required: StoryObj<typeof Label>;
6
+ export declare const Optional: StoryObj<typeof Label>;
7
+ export declare const WithInput: StoryObj<typeof Label>;
8
+ export default meta;
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,20 @@
1
+ import type { AnchorHTMLAttributes } from "react";
2
+ interface Props extends AnchorHTMLAttributes<HTMLAnchorElement> {
3
+ variant?: "default" | "active" | "disabled";
4
+ children: React.ReactNode;
5
+ }
6
+ /**
7
+ * NavLink Component
8
+ *
9
+ * A navigation link component with active and disabled states.
10
+ * Follows Atomic Design principles as an Atom component.
11
+ *
12
+ * @example
13
+ * ```tsx
14
+ * <NavLink href="/dashboard" variant="active">
15
+ * Dashboard
16
+ * </NavLink>
17
+ * ```
18
+ */
19
+ export default function NavLink({ variant, className, children, ...props }: Props): import("react/jsx-runtime").JSX.Element;
20
+ export {};
@@ -0,0 +1,8 @@
1
+ import type { Meta, StoryObj } from "@storybook/react";
2
+ import NavLink from "./NavLink";
3
+ declare const meta: Meta<typeof NavLink>;
4
+ export declare const Default: StoryObj<typeof NavLink>;
5
+ export declare const Active: StoryObj<typeof NavLink>;
6
+ export declare const Disabled: StoryObj<typeof NavLink>;
7
+ export declare const NavigationBar: StoryObj<typeof NavLink>;
8
+ export default meta;
@@ -0,0 +1 @@
1
+ export {};
@@ -6,3 +6,6 @@ export { default as BoxWrapper } from "./BoxWrapper/BoxWrapper";
6
6
  export { default as Badge } from "./Badge/Badge";
7
7
  export { default as Select } from "./Select/Select";
8
8
  export { default as Textarea } from "./Textarea/Textarea";
9
+ export { default as Label } from "./Label/Label";
10
+ export { default as ErrorMessage } from "./ErrorMessage/ErrorMessage";
11
+ export { default as NavLink } from "./NavLink/NavLink";
@@ -0,0 +1,28 @@
1
+ import type { HTMLAttributes } from "react";
2
+ export interface BreadcrumbItem {
3
+ label: string;
4
+ href?: string;
5
+ }
6
+ interface Props extends HTMLAttributes<HTMLElement> {
7
+ items: BreadcrumbItem[];
8
+ separator?: string;
9
+ }
10
+ /**
11
+ * Breadcrumb Component
12
+ *
13
+ * A breadcrumb navigation component for hierarchical navigation.
14
+ * Follows Atomic Design principles as a Molecule component.
15
+ *
16
+ * @example
17
+ * ```tsx
18
+ * <Breadcrumb
19
+ * items={[
20
+ * { label: "Home", href: "/" },
21
+ * { label: "Epics", href: "/epics" },
22
+ * { label: "Epic Details" }
23
+ * ]}
24
+ * />
25
+ * ```
26
+ */
27
+ export default function Breadcrumb({ items, separator, className, ...props }: Props): import("react/jsx-runtime").JSX.Element;
28
+ export {};
@@ -0,0 +1,9 @@
1
+ import type { Meta, StoryObj } from "@storybook/react";
2
+ import Breadcrumb from "./Breadcrumb";
3
+ declare const meta: Meta<typeof Breadcrumb>;
4
+ export declare const Default: StoryObj<typeof Breadcrumb>;
5
+ export declare const TwoLevels: StoryObj<typeof Breadcrumb>;
6
+ export declare const ThreeLevels: StoryObj<typeof Breadcrumb>;
7
+ export declare const CustomSeparator: StoryObj<typeof Breadcrumb>;
8
+ export declare const SingleItem: StoryObj<typeof Breadcrumb>;
9
+ export default meta;
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,24 @@
1
+ import type { FormHTMLAttributes, ReactNode } from "react";
2
+ interface Props extends FormHTMLAttributes<HTMLFormElement> {
3
+ children: ReactNode;
4
+ onSubmit?: (e: React.FormEvent<HTMLFormElement>) => void;
5
+ loading?: boolean;
6
+ error?: string | null;
7
+ success?: string | null;
8
+ }
9
+ /**
10
+ * Form Component
11
+ *
12
+ * A wrapper component for forms with validation states and layout.
13
+ * Follows Atomic Design principles as a Molecule component.
14
+ *
15
+ * @example
16
+ * ```tsx
17
+ * <Form onSubmit={handleSubmit} loading={isSubmitting}>
18
+ * <Input name="email" />
19
+ * <Button type="submit">Submit</Button>
20
+ * </Form>
21
+ * ```
22
+ */
23
+ export default function Form({ children, onSubmit, loading, error, success, className, ...props }: Props): import("react/jsx-runtime").JSX.Element;
24
+ export {};
@@ -0,0 +1,9 @@
1
+ import type { Meta, StoryObj } from "@storybook/react";
2
+ import Form from "./Form";
3
+ declare const meta: Meta<typeof Form>;
4
+ export declare const Default: StoryObj<typeof Form>;
5
+ export declare const WithError: StoryObj<typeof Form>;
6
+ export declare const WithSuccess: StoryObj<typeof Form>;
7
+ export declare const Loading: StoryObj<typeof Form>;
8
+ export declare const CompleteForm: StoryObj<typeof Form>;
9
+ export default meta;
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,28 @@
1
+ import type { HTMLAttributes } from "react";
2
+ interface Props extends HTMLAttributes<HTMLDivElement> {
3
+ currentPage: number;
4
+ totalPages: number;
5
+ onPageChange: (page: number) => void;
6
+ totalItems?: number;
7
+ itemsPerPage?: number;
8
+ showPageInfo?: boolean;
9
+ }
10
+ /**
11
+ * Pagination Component
12
+ *
13
+ * A pagination component for navigating through pages of data.
14
+ * Follows Atomic Design principles as a Molecule component.
15
+ *
16
+ * @example
17
+ * ```tsx
18
+ * <Pagination
19
+ * currentPage={1}
20
+ * totalPages={10}
21
+ * onPageChange={(page) => setPage(page)}
22
+ * totalItems={100}
23
+ * itemsPerPage={10}
24
+ * />
25
+ * ```
26
+ */
27
+ export default function Pagination({ currentPage, totalPages, onPageChange, totalItems, itemsPerPage, showPageInfo, className, ...props }: Props): import("react/jsx-runtime").JSX.Element;
28
+ export {};
@@ -0,0 +1,10 @@
1
+ import type { Meta, StoryObj } from "@storybook/react";
2
+ import Pagination from "./Pagination";
3
+ declare const meta: Meta<typeof Pagination>;
4
+ export declare const Default: StoryObj<typeof Pagination>;
5
+ export declare const FirstPage: StoryObj<typeof Pagination>;
6
+ export declare const MiddlePage: StoryObj<typeof Pagination>;
7
+ export declare const LastPage: StoryObj<typeof Pagination>;
8
+ export declare const FewPages: StoryObj<typeof Pagination>;
9
+ export declare const WithoutPageInfo: StoryObj<typeof Pagination>;
10
+ export default meta;
@@ -0,0 +1 @@
1
+ export {};
@@ -1,2 +1,6 @@
1
1
  export { default as InputWithLabel } from "./InputWithLabel/InputWithLabel";
2
2
  export { default as Card } from "./Card/Card";
3
+ export { default as Form } from "./Form/Form";
4
+ export { default as Breadcrumb } from "./Breadcrumb/Breadcrumb";
5
+ export type { BreadcrumbItem } from "./Breadcrumb/Breadcrumb";
6
+ export { default as Pagination } from "./Pagination/Pagination";
@@ -0,0 +1,25 @@
1
+ import type { HTMLAttributes, ReactNode } from "react";
2
+ interface Props extends HTMLAttributes<HTMLDivElement> {
3
+ isOpen: boolean;
4
+ onClose: () => void;
5
+ title?: string;
6
+ children: ReactNode;
7
+ variant?: "default" | "large" | "fullscreen";
8
+ showCloseButton?: boolean;
9
+ footer?: ReactNode;
10
+ }
11
+ /**
12
+ * Modal Component
13
+ *
14
+ * A modal/dialog component with overlay, portal rendering, and accessibility.
15
+ * Follows Atomic Design principles as an Organism component.
16
+ *
17
+ * @example
18
+ * ```tsx
19
+ * <Modal isOpen={isOpen} onClose={handleClose} title="Confirm Action">
20
+ * <p>Are you sure?</p>
21
+ * </Modal>
22
+ * ```
23
+ */
24
+ export default function Modal({ isOpen, onClose, title, children, variant, showCloseButton, footer, className, ...props }: Props): import("react/jsx-runtime").JSX.Element | null;
25
+ export {};
@@ -0,0 +1,9 @@
1
+ import type { Meta, StoryObj } from "@storybook/react";
2
+ import Modal from "./Modal";
3
+ declare const meta: Meta<typeof Modal>;
4
+ export declare const Default: StoryObj<typeof Modal>;
5
+ export declare const WithFooter: StoryObj<typeof Modal>;
6
+ export declare const Large: StoryObj<typeof Modal>;
7
+ export declare const WithoutTitle: StoryObj<typeof Modal>;
8
+ export declare const WithoutCloseButton: StoryObj<typeof Modal>;
9
+ export default meta;
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,35 @@
1
+ import type { HTMLAttributes, ReactNode } from "react";
2
+ export interface TableColumn<T = any> {
3
+ key: string;
4
+ label: string;
5
+ render?: (value: any, row: T) => ReactNode;
6
+ sortable?: boolean;
7
+ }
8
+ interface Props<T = any> extends HTMLAttributes<HTMLTableElement> {
9
+ columns: TableColumn<T>[];
10
+ data: T[];
11
+ loading?: boolean;
12
+ onSort?: (columnKey: string, direction: 'asc' | 'desc') => void;
13
+ sortColumn?: string;
14
+ sortDirection?: 'asc' | 'desc';
15
+ emptyMessage?: string;
16
+ }
17
+ /**
18
+ * Table Component
19
+ *
20
+ * A table component with sorting, loading states, and responsive design.
21
+ * Follows Atomic Design principles as an Organism component.
22
+ *
23
+ * @example
24
+ * ```tsx
25
+ * <Table
26
+ * columns={[
27
+ * { key: 'name', label: 'Name', sortable: true },
28
+ * { key: 'status', label: 'Status' }
29
+ * ]}
30
+ * data={items}
31
+ * />
32
+ * ```
33
+ */
34
+ export default function Table<T = any>({ columns, data, loading, onSort, sortColumn, sortDirection, emptyMessage, className, ...props }: Props<T>): import("react/jsx-runtime").JSX.Element;
35
+ export {};
@@ -0,0 +1,9 @@
1
+ import type { Meta, StoryObj } from "@storybook/react";
2
+ import Table from "./Table";
3
+ declare const meta: Meta<typeof Table>;
4
+ export declare const Default: StoryObj<typeof Table>;
5
+ export declare const WithSorting: StoryObj<typeof Table>;
6
+ export declare const WithCustomRendering: StoryObj<typeof Table>;
7
+ export declare const Loading: StoryObj<typeof Table>;
8
+ export declare const Empty: StoryObj<typeof Table>;
9
+ export default meta;
@@ -0,0 +1 @@
1
+ export {};
@@ -1 +1,4 @@
1
1
  export { default as LoginBox } from "./LoginBox/LoginBox";
2
+ export { default as Modal } from "./Modal/Modal";
3
+ export { default as Table } from "./Table/Table";
4
+ export type { TableColumn } from "./Table/Table";
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@fabio.caffarello/react-design-system",
3
3
  "private": false,
4
- "version": "1.2.1",
4
+ "version": "1.3.1",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
7
7
  "module": "dist/index.js",
@@ -0,0 +1,81 @@
1
+ import type { Meta, StoryObj } from "@storybook/react";
2
+ import ErrorMessage from "./ErrorMessage";
3
+ import { Input, Label } from "../../atoms";
4
+
5
+ const meta: Meta<typeof ErrorMessage> = {
6
+ title: "UI/Atoms/ErrorMessage",
7
+ component: ErrorMessage,
8
+ parameters: {
9
+ docs: {
10
+ description: {
11
+ component: "A component for displaying validation error messages. Accessible with role='alert'.",
12
+ },
13
+ },
14
+ },
15
+ argTypes: {
16
+ message: {
17
+ control: "text",
18
+ description: "Error message to display",
19
+ },
20
+ id: {
21
+ control: "text",
22
+ description: "ID for accessibility (should match aria-describedby on input)",
23
+ },
24
+ },
25
+ };
26
+
27
+ export const Default: StoryObj<typeof ErrorMessage> = {
28
+ args: {
29
+ message: "This field is required",
30
+ },
31
+ };
32
+
33
+ export const WithInput: StoryObj<typeof ErrorMessage> = {
34
+ render: () => (
35
+ <div className="space-y-2 max-w-md">
36
+ <Label htmlFor="email" variant="required">
37
+ Email Address
38
+ </Label>
39
+ <Input
40
+ id="email"
41
+ type="email"
42
+ placeholder="Enter email..."
43
+ aria-invalid="true"
44
+ aria-describedby="email-error"
45
+ />
46
+ <ErrorMessage message="Please enter a valid email address" id="email-error" />
47
+ </div>
48
+ ),
49
+ };
50
+
51
+ export const MultipleErrors: StoryObj<typeof ErrorMessage> = {
52
+ render: () => (
53
+ <div className="space-y-4 max-w-md">
54
+ <div className="space-y-2">
55
+ <Label htmlFor="name" variant="required">
56
+ Name
57
+ </Label>
58
+ <Input
59
+ id="name"
60
+ aria-invalid="true"
61
+ aria-describedby="name-error"
62
+ />
63
+ <ErrorMessage message="Name must be at least 3 characters" id="name-error" />
64
+ </div>
65
+ <div className="space-y-2">
66
+ <Label htmlFor="password" variant="required">
67
+ Password
68
+ </Label>
69
+ <Input
70
+ id="password"
71
+ type="password"
72
+ aria-invalid="true"
73
+ aria-describedby="password-error"
74
+ />
75
+ <ErrorMessage message="Password must be at least 8 characters" id="password-error" />
76
+ </div>
77
+ </div>
78
+ ),
79
+ };
80
+
81
+ export default meta;
@@ -0,0 +1,40 @@
1
+ import { describe, it, expect } from "vitest";
2
+ import { render, screen } from "@testing-library/react";
3
+ import ErrorMessage from "./ErrorMessage";
4
+
5
+ describe("ErrorMessage", () => {
6
+ it("renders error message", () => {
7
+ render(<ErrorMessage message="This field is required" />);
8
+ expect(screen.getByText("This field is required")).toBeInTheDocument();
9
+ });
10
+
11
+ it("has alert role", () => {
12
+ render(<ErrorMessage message="Error message" />);
13
+ const error = screen.getByRole("alert");
14
+ expect(error).toBeInTheDocument();
15
+ });
16
+
17
+ it("has aria-live attribute", () => {
18
+ const { container } = render(<ErrorMessage message="Error message" />);
19
+ const error = container.querySelector('[role="alert"]');
20
+ expect(error).toHaveAttribute("aria-live", "polite");
21
+ });
22
+
23
+ it("applies custom id", () => {
24
+ render(<ErrorMessage message="Error message" id="custom-error-id" />);
25
+ const error = screen.getByRole("alert");
26
+ expect(error).toHaveAttribute("id", "custom-error-id");
27
+ });
28
+
29
+ it("displays error icon", () => {
30
+ const { container } = render(<ErrorMessage message="Error message" />);
31
+ const svg = container.querySelector("svg");
32
+ expect(svg).toBeInTheDocument();
33
+ });
34
+
35
+ it("applies custom className", () => {
36
+ const { container } = render(<ErrorMessage message="Error" className="custom-class" />);
37
+ const error = container.querySelector('[role="alert"]');
38
+ expect(error).toHaveClass("custom-class");
39
+ });
40
+ });
@@ -0,0 +1,62 @@
1
+ import type { HTMLAttributes } from "react";
2
+
3
+ interface Props extends HTMLAttributes<HTMLDivElement> {
4
+ message: string;
5
+ id?: string;
6
+ }
7
+
8
+ /**
9
+ * ErrorMessage Component
10
+ *
11
+ * A component for displaying validation error messages.
12
+ * Follows Atomic Design principles as an Atom component.
13
+ *
14
+ * @example
15
+ * ```tsx
16
+ * <ErrorMessage message="This field is required" id="email-error" />
17
+ * ```
18
+ */
19
+ export default function ErrorMessage({
20
+ message,
21
+ id,
22
+ className = "",
23
+ ...props
24
+ }: Props) {
25
+ const baseClasses = [
26
+ "mt-1",
27
+ "text-sm",
28
+ "text-red-600",
29
+ "flex",
30
+ "items-center",
31
+ "gap-1",
32
+ ];
33
+
34
+ const classes = [
35
+ ...baseClasses,
36
+ className,
37
+ ].filter(Boolean).join(" ");
38
+
39
+ return (
40
+ <div
41
+ role="alert"
42
+ id={id}
43
+ className={classes}
44
+ aria-live="polite"
45
+ {...props}
46
+ >
47
+ <svg
48
+ className="h-4 w-4 flex-shrink-0"
49
+ fill="currentColor"
50
+ viewBox="0 0 20 20"
51
+ aria-hidden="true"
52
+ >
53
+ <path
54
+ fillRule="evenodd"
55
+ d="M10 18a8 8 0 100-16 8 8 0 000 16zM8.707 7.293a1 1 0 00-1.414 1.414L8.586 10l-1.293 1.293a1 1 0 101.414 1.414L10 11.414l1.293 1.293a1 1 0 001.414-1.414L11.414 10l1.293-1.293a1 1 0 00-1.414-1.414L10 8.586 8.707 7.293z"
56
+ clipRule="evenodd"
57
+ />
58
+ </svg>
59
+ <span>{message}</span>
60
+ </div>
61
+ );
62
+ }
@@ -0,0 +1,94 @@
1
+ import type { Meta, StoryObj } from "@storybook/react";
2
+ import Label from "./Label";
3
+ import { Input } from "../../atoms";
4
+
5
+ const meta: Meta<typeof Label> = {
6
+ title: "UI/Atoms/Label",
7
+ component: Label,
8
+ parameters: {
9
+ docs: {
10
+ description: {
11
+ component: "A styled label component for form inputs. Supports required and optional variants.",
12
+ },
13
+ },
14
+ },
15
+ argTypes: {
16
+ variant: {
17
+ control: "select",
18
+ options: ["default", "required", "optional"],
19
+ description: "Visual variant of the label",
20
+ },
21
+ htmlFor: {
22
+ control: "text",
23
+ description: "ID of the associated input element",
24
+ },
25
+ },
26
+ };
27
+
28
+ export const Default: StoryObj<typeof Label> = {
29
+ args: {
30
+ children: "Email Address",
31
+ htmlFor: "email",
32
+ },
33
+ render: (args) => (
34
+ <div className="space-y-2">
35
+ <Label {...args} />
36
+ <Input id="email" placeholder="Enter email..." />
37
+ </div>
38
+ ),
39
+ };
40
+
41
+ export const Required: StoryObj<typeof Label> = {
42
+ args: {
43
+ children: "Email Address",
44
+ htmlFor: "email-required",
45
+ variant: "required",
46
+ },
47
+ render: (args) => (
48
+ <div className="space-y-2">
49
+ <Label {...args} />
50
+ <Input id="email-required" placeholder="Enter email..." required />
51
+ </div>
52
+ ),
53
+ };
54
+
55
+ export const Optional: StoryObj<typeof Label> = {
56
+ args: {
57
+ children: "Middle Name",
58
+ htmlFor: "middle-name",
59
+ variant: "optional",
60
+ },
61
+ render: (args) => (
62
+ <div className="space-y-2">
63
+ <Label {...args} />
64
+ <Input id="middle-name" placeholder="Enter middle name..." />
65
+ </div>
66
+ ),
67
+ };
68
+
69
+ export const WithInput: StoryObj<typeof Label> = {
70
+ render: () => (
71
+ <div className="space-y-4 max-w-md">
72
+ <div className="space-y-2">
73
+ <Label htmlFor="name" variant="required">
74
+ Full Name
75
+ </Label>
76
+ <Input id="name" placeholder="Enter your name..." />
77
+ </div>
78
+ <div className="space-y-2">
79
+ <Label htmlFor="email" variant="required">
80
+ Email
81
+ </Label>
82
+ <Input id="email" type="email" placeholder="Enter your email..." />
83
+ </div>
84
+ <div className="space-y-2">
85
+ <Label htmlFor="phone" variant="optional">
86
+ Phone Number
87
+ </Label>
88
+ <Input id="phone" type="tel" placeholder="Enter your phone..." />
89
+ </div>
90
+ </div>
91
+ ),
92
+ };
93
+
94
+ export default meta;