@axzydev/axzy_ui_system 1.2.1 → 1.2.2
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/index.css +82 -1
- package/dist/index.css.map +1 -1
- package/package.json +2 -2
- package/src/App.tsx +354 -0
- package/src/assets/logo.png +0 -0
- package/src/assets/react.svg +1 -0
- package/src/components/alert/alert.props.ts +13 -0
- package/src/components/alert/alert.stories.tsx +41 -0
- package/src/components/alert/alert.tsx +53 -0
- package/src/components/avatar/avatar.props.ts +14 -0
- package/src/components/avatar/avatar.stories.tsx +46 -0
- package/src/components/avatar/avatar.tsx +53 -0
- package/src/components/badget/badget.props.ts +12 -0
- package/src/components/badget/badget.stories.tsx +76 -0
- package/src/components/badget/badget.tsx +61 -0
- package/src/components/breadcrumbs/breadcrumbs.props.ts +13 -0
- package/src/components/breadcrumbs/breadcrumbs.stories.tsx +21 -0
- package/src/components/breadcrumbs/breadcrumbs.tsx +34 -0
- package/src/components/button/button.props.ts +18 -0
- package/src/components/button/button.stories.tsx +174 -0
- package/src/components/button/button.tsx +117 -0
- package/src/components/calendar/calendar.props.ts +33 -0
- package/src/components/calendar/calendar.stories.tsx +91 -0
- package/src/components/calendar/calendar.tsx +608 -0
- package/src/components/calendar/index.ts +3 -0
- package/src/components/card/card.props.ts +13 -0
- package/src/components/card/card.stories.tsx +58 -0
- package/src/components/card/card.tsx +79 -0
- package/src/components/checkbox/checkbox.props.ts +11 -0
- package/src/components/checkbox/checkbox.stories.tsx +54 -0
- package/src/components/checkbox/checkbox.tsx +52 -0
- package/src/components/confirm-dialog/confirm-dialog.props.ts +14 -0
- package/src/components/confirm-dialog/confirm-dialog.stories.tsx +33 -0
- package/src/components/confirm-dialog/confirm-dialog.tsx +45 -0
- package/src/components/data-table/ITDataTable.stories.tsx +213 -0
- package/src/components/data-table/dataTable.props.ts +69 -0
- package/src/components/data-table/dataTable.tsx +313 -0
- package/src/components/date-picker/date-picker.props.ts +30 -0
- package/src/components/date-picker/date-picker.stories.tsx +90 -0
- package/src/components/date-picker/datePicker.tsx +307 -0
- package/src/components/dialog/dialog.props.ts +9 -0
- package/src/components/dialog/dialog.stories.tsx +80 -0
- package/src/components/dialog/dialog.tsx +88 -0
- package/src/components/divider/divider.props.ts +8 -0
- package/src/components/divider/divider.stories.tsx +34 -0
- package/src/components/divider/divider.tsx +21 -0
- package/src/components/drawer/drawer.props.ts +14 -0
- package/src/components/drawer/drawer.stories.tsx +41 -0
- package/src/components/drawer/drawer.tsx +53 -0
- package/src/components/dropfile/dropfile.stories.tsx +75 -0
- package/src/components/dropfile/dropfile.tsx +407 -0
- package/src/components/empty-state/empty-state.props.ts +9 -0
- package/src/components/empty-state/empty-state.stories.tsx +20 -0
- package/src/components/empty-state/empty-state.tsx +21 -0
- package/src/components/flex/flex.props.ts +22 -0
- package/src/components/flex/flex.stories.tsx +71 -0
- package/src/components/flex/flex.tsx +79 -0
- package/src/components/form-builder/fieldRenderer.tsx +218 -0
- package/src/components/form-builder/formBuilder.context.tsx +70 -0
- package/src/components/form-builder/formBuilder.props.ts +43 -0
- package/src/components/form-builder/formBuilder.stories.tsx +317 -0
- package/src/components/form-builder/formBuilder.tsx +186 -0
- package/src/components/form-builder/useFormBuilder.ts +80 -0
- package/src/components/form-header/form-header.props.ts +5 -0
- package/src/components/form-header/form-header.tsx +38 -0
- package/src/components/grid/grid.props.ts +17 -0
- package/src/components/grid/grid.stories.tsx +72 -0
- package/src/components/grid/grid.tsx +69 -0
- package/src/components/image/image.props.ts +7 -0
- package/src/components/image/image.tsx +38 -0
- package/src/components/input/input.props.ts +49 -0
- package/src/components/input/input.stories.tsx +115 -0
- package/src/components/input/input.tsx +615 -0
- package/src/components/layout/layout.props.ts +10 -0
- package/src/components/layout/layout.stories.tsx +114 -0
- package/src/components/layout/layout.tsx +80 -0
- package/src/components/loader/loader.props.ts +8 -0
- package/src/components/loader/loader.stories.tsx +105 -0
- package/src/components/loader/loader.tsx +108 -0
- package/src/components/navbar/navbar.props.ts +37 -0
- package/src/components/navbar/navbar.tsx +328 -0
- package/src/components/page/page.props.ts +19 -0
- package/src/components/page/page.stories.tsx +98 -0
- package/src/components/page/page.tsx +90 -0
- package/src/components/page-header/page-header.props.ts +11 -0
- package/src/components/page-header/page-header.stories.tsx +61 -0
- package/src/components/page-header/page-header.tsx +62 -0
- package/src/components/pagination/pagination.props.ts +53 -0
- package/src/components/pagination/pagination.stories.tsx +111 -0
- package/src/components/pagination/pagination.tsx +241 -0
- package/src/components/popover/popover.props.ts +12 -0
- package/src/components/popover/popover.stories.tsx +25 -0
- package/src/components/popover/popover.tsx +45 -0
- package/src/components/progress/progress.props.ts +12 -0
- package/src/components/progress/progress.stories.tsx +40 -0
- package/src/components/progress/progress.tsx +52 -0
- package/src/components/radio/radio.props.ts +16 -0
- package/src/components/radio/radio.stories.tsx +50 -0
- package/src/components/radio/radio.tsx +58 -0
- package/src/components/search-select/index.ts +2 -0
- package/src/components/search-select/search-select.props.ts +46 -0
- package/src/components/search-select/search-select.stories.tsx +129 -0
- package/src/components/search-select/search-select.tsx +229 -0
- package/src/components/searchTable/components/EditableCell.tsx +149 -0
- package/src/components/searchTable/components/PaginationControls.tsx +86 -0
- package/src/components/searchTable/components/PaginationInfo.tsx +20 -0
- package/src/components/searchTable/components/SearchAndSortBar.tsx +53 -0
- package/src/components/searchTable/components/SearchInput.tsx +33 -0
- package/src/components/searchTable/components/SortButton.tsx +50 -0
- package/src/components/searchTable/components/TableEmptyState.tsx +22 -0
- package/src/components/searchTable/components/TableHeader.tsx +35 -0
- package/src/components/searchTable/components/TableHeaderCell.tsx +43 -0
- package/src/components/searchTable/components/TableRow.tsx +144 -0
- package/src/components/searchTable/searchTable.props.ts +56 -0
- package/src/components/searchTable/searchTable.tsx +187 -0
- package/src/components/segmented-control/segmented-control.props.ts +18 -0
- package/src/components/segmented-control/segmented-control.stories.tsx +63 -0
- package/src/components/segmented-control/segmented-control.tsx +52 -0
- package/src/components/select/select.props.ts +25 -0
- package/src/components/select/select.stories.tsx +86 -0
- package/src/components/select/select.tsx +150 -0
- package/src/components/sidebar/sidebar.props.ts +28 -0
- package/src/components/sidebar/sidebar.stories.tsx +117 -0
- package/src/components/sidebar/sidebar.tsx +313 -0
- package/src/components/skeleton/skeleton.props.ts +12 -0
- package/src/components/skeleton/skeleton.stories.tsx +30 -0
- package/src/components/skeleton/skeleton.tsx +45 -0
- package/src/components/slide/slide.props.ts +45 -0
- package/src/components/slide/slide.stories.tsx +121 -0
- package/src/components/slide/slide.tsx +109 -0
- package/src/components/slider/slider.props.ts +10 -0
- package/src/components/slider/slider.stories.tsx +30 -0
- package/src/components/slider/slider.tsx +49 -0
- package/src/components/stack/stack.props.ts +19 -0
- package/src/components/stack/stack.stories.tsx +79 -0
- package/src/components/stack/stack.tsx +79 -0
- package/src/components/stat-card/stat-card.props.ts +13 -0
- package/src/components/stat-card/stat-card.stories.tsx +41 -0
- package/src/components/stat-card/stat-card.tsx +44 -0
- package/src/components/stepper/stepper.css +26 -0
- package/src/components/stepper/stepper.props.ts +29 -0
- package/src/components/stepper/stepper.stories.tsx +155 -0
- package/src/components/stepper/stepper.tsx +227 -0
- package/src/components/table/table.props.ts +43 -0
- package/src/components/table/table.stories.tsx +189 -0
- package/src/components/table/table.tsx +376 -0
- package/src/components/tabs/tabs.props.ts +18 -0
- package/src/components/tabs/tabs.stories.tsx +32 -0
- package/src/components/tabs/tabs.tsx +74 -0
- package/src/components/text/text.props.ts +9 -0
- package/src/components/text/text.tsx +20 -0
- package/src/components/textarea/textarea.props.ts +15 -0
- package/src/components/textarea/textarea.stories.tsx +27 -0
- package/src/components/textarea/textarea.tsx +55 -0
- package/src/components/theme-provider/themeProvider.props.ts +28 -0
- package/src/components/theme-provider/themeProvider.tsx +1854 -0
- package/src/components/time-picker/timePicker.props.ts +16 -0
- package/src/components/time-picker/timePicker.stories.tsx +131 -0
- package/src/components/time-picker/timePicker.tsx +317 -0
- package/src/components/toast/toast.css +32 -0
- package/src/components/toast/toast.props.ts +13 -0
- package/src/components/toast/toast.stories.tsx +138 -0
- package/src/components/toast/toast.tsx +87 -0
- package/src/components/tooltip/tooltip.props.ts +11 -0
- package/src/components/tooltip/tooltip.stories.tsx +20 -0
- package/src/components/tooltip/tooltip.tsx +55 -0
- package/src/components/topbar/topbar.props.ts +21 -0
- package/src/components/topbar/topbar.stories.tsx +80 -0
- package/src/components/topbar/topbar.tsx +205 -0
- package/src/components/triple-filter/tripleFilter.props.ts +15 -0
- package/src/components/triple-filter/tripleFilter.stories.tsx +32 -0
- package/src/components/triple-filter/tripleFilter.tsx +50 -0
- package/src/hooks/useClickOutside.ts +21 -0
- package/src/hooks/useDebouncedSearch.ts +55 -0
- package/src/hooks/useEditableRow.ts +157 -0
- package/src/hooks/useTableState.ts +122 -0
- package/src/index.css +168 -0
- package/src/index.ts +165 -0
- package/src/main.tsx +9 -0
- package/src/showcases/DataShowcases.tsx +260 -0
- package/src/showcases/FeedbackShowcases.tsx +268 -0
- package/src/showcases/FormShowcases.tsx +1159 -0
- package/src/showcases/HomeShowcase.tsx +324 -0
- package/src/showcases/LayoutPrimitivesShowcases.tsx +569 -0
- package/src/showcases/NavigationShowcases.tsx +193 -0
- package/src/showcases/PageShowcases.tsx +207 -0
- package/src/showcases/ShowcaseLayout.tsx +139 -0
- package/src/showcases/StructureShowcases.tsx +152 -0
- package/src/types/badget.types.ts +37 -0
- package/src/types/button.types.ts +16 -0
- package/src/types/colors.types.ts +3 -0
- package/src/types/field.types.ts +103 -0
- package/src/types/formik.types.ts +15 -0
- package/src/types/input.types.ts +14 -0
- package/src/types/loader.types.ts +9 -0
- package/src/types/sizes.types.ts +1 -0
- package/src/types/table.types.ts +15 -0
- package/src/types/toast.types.ts +8 -0
- package/src/types/yup.types.ts +11 -0
- package/src/utils/color.utils.ts +99 -0
- package/src/utils/styles.ts +120 -0
- package/src/utils/table.utils.ts +10 -0
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import type { Meta, StoryObj } from "@storybook/react";
|
|
2
|
+
import ITAvatar from "./avatar";
|
|
3
|
+
import { FaCircle } from "react-icons/fa";
|
|
4
|
+
|
|
5
|
+
const meta: Meta<typeof ITAvatar> = {
|
|
6
|
+
title: "Components/Data Display/ITAvatar",
|
|
7
|
+
component: ITAvatar,
|
|
8
|
+
tags: ["autodocs"],
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
export default meta;
|
|
12
|
+
type Story = StoryObj<typeof ITAvatar>;
|
|
13
|
+
|
|
14
|
+
export const WithImage: Story = {
|
|
15
|
+
args: {
|
|
16
|
+
src: "https://i.pravatar.cc/150?u=test",
|
|
17
|
+
alt: "User",
|
|
18
|
+
size: "md",
|
|
19
|
+
},
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
export const WithInitials: Story = {
|
|
23
|
+
args: {
|
|
24
|
+
initials: "JD",
|
|
25
|
+
size: "md",
|
|
26
|
+
color: "bg-primary-500",
|
|
27
|
+
},
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
export const WithBadge: Story = {
|
|
31
|
+
args: {
|
|
32
|
+
initials: "AG",
|
|
33
|
+
size: "lg",
|
|
34
|
+
badge: <FaCircle className="text-emerald-500 text-[10px]" />,
|
|
35
|
+
},
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
export const Sizes: Story = {
|
|
39
|
+
render: () => (
|
|
40
|
+
<div className="flex items-end gap-4">
|
|
41
|
+
{(["xs", "sm", "md", "lg", "xl"] as const).map((s) => (
|
|
42
|
+
<ITAvatar key={s} initials="A" size={s} />
|
|
43
|
+
))}
|
|
44
|
+
</div>
|
|
45
|
+
),
|
|
46
|
+
};
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import clsx from "clsx";
|
|
2
|
+
import { ITAvatarProps, AvatarSize } from "./avatar.props";
|
|
3
|
+
import ITText from "@/components/text/text";
|
|
4
|
+
|
|
5
|
+
const sizeMap: Record<AvatarSize, { container: string; text: string }> = {
|
|
6
|
+
xs: { container: "w-6 h-6", text: "text-[10px]" },
|
|
7
|
+
sm: { container: "w-8 h-8", text: "text-xs" },
|
|
8
|
+
md: { container: "w-10 h-10", text: "text-sm" },
|
|
9
|
+
lg: { container: "w-12 h-12", text: "text-base" },
|
|
10
|
+
xl: { container: "w-16 h-16", text: "text-xl" },
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
export default function ITAvatar({
|
|
14
|
+
src,
|
|
15
|
+
alt = "",
|
|
16
|
+
initials,
|
|
17
|
+
size = "md",
|
|
18
|
+
color = "bg-primary-500",
|
|
19
|
+
className,
|
|
20
|
+
badge,
|
|
21
|
+
onClick,
|
|
22
|
+
}: ITAvatarProps) {
|
|
23
|
+
const { container, text } = sizeMap[size];
|
|
24
|
+
|
|
25
|
+
return (
|
|
26
|
+
<div
|
|
27
|
+
className={clsx("relative inline-flex items-center justify-center rounded-full flex-shrink-0", container, className)}
|
|
28
|
+
onClick={onClick}
|
|
29
|
+
role={onClick ? "button" : undefined}
|
|
30
|
+
tabIndex={onClick ? 0 : undefined}
|
|
31
|
+
>
|
|
32
|
+
{src ? (
|
|
33
|
+
<img
|
|
34
|
+
src={src}
|
|
35
|
+
alt={alt}
|
|
36
|
+
className="w-full h-full rounded-full object-cover"
|
|
37
|
+
onError={(e) => {
|
|
38
|
+
e.currentTarget.style.display = "none";
|
|
39
|
+
}}
|
|
40
|
+
/>
|
|
41
|
+
) : (
|
|
42
|
+
<div className={clsx("w-full h-full rounded-full flex items-center justify-center text-white font-semibold", text, color)}>
|
|
43
|
+
<ITText as="span">{initials || alt.charAt(0).toUpperCase() || "?"}</ITText>
|
|
44
|
+
</div>
|
|
45
|
+
)}
|
|
46
|
+
{badge && (
|
|
47
|
+
<div className="absolute -bottom-0.5 -right-0.5">
|
|
48
|
+
{badge}
|
|
49
|
+
</div>
|
|
50
|
+
)}
|
|
51
|
+
</div>
|
|
52
|
+
);
|
|
53
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { badgeVariants } from "@/types/badget.types";
|
|
2
|
+
import { ColorsTypes } from "@/types/colors.types";
|
|
3
|
+
import { SizesTypes } from "@/types/sizes.types";
|
|
4
|
+
|
|
5
|
+
export interface ITBadgetProps {
|
|
6
|
+
label?: string;
|
|
7
|
+
children?: React.ReactNode;
|
|
8
|
+
color?: ColorsTypes;
|
|
9
|
+
size?: SizesTypes;
|
|
10
|
+
variant?: keyof typeof badgeVariants;
|
|
11
|
+
className?: string;
|
|
12
|
+
}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import type { Meta, StoryObj } from '@storybook/react';
|
|
2
|
+
import ITBadget from './badget';
|
|
3
|
+
|
|
4
|
+
const meta = {
|
|
5
|
+
title: 'Components/Data Display/ITBadge',
|
|
6
|
+
component: ITBadget,
|
|
7
|
+
parameters: {
|
|
8
|
+
layout: 'centered',
|
|
9
|
+
},
|
|
10
|
+
tags: ['autodocs'],
|
|
11
|
+
argTypes: {
|
|
12
|
+
color: {
|
|
13
|
+
control: 'select',
|
|
14
|
+
options: ['primary', 'secondary', 'success', 'danger', 'warning', 'purple', 'info'],
|
|
15
|
+
},
|
|
16
|
+
variant: {
|
|
17
|
+
control: 'select',
|
|
18
|
+
options: ['filled', 'outlined'],
|
|
19
|
+
},
|
|
20
|
+
size: {
|
|
21
|
+
control: 'select',
|
|
22
|
+
options: ['small', 'medium', 'large'],
|
|
23
|
+
},
|
|
24
|
+
},
|
|
25
|
+
} satisfies Meta<typeof ITBadget>;
|
|
26
|
+
|
|
27
|
+
export default meta;
|
|
28
|
+
type Story = StoryObj<typeof meta>;
|
|
29
|
+
|
|
30
|
+
// 1. Filled (Default)
|
|
31
|
+
export const Filled: Story = {
|
|
32
|
+
args: {
|
|
33
|
+
label: 'Filled Badge',
|
|
34
|
+
color: 'primary',
|
|
35
|
+
variant: 'filled',
|
|
36
|
+
},
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
// 2. Outlined
|
|
40
|
+
export const Outlined: Story = {
|
|
41
|
+
args: {
|
|
42
|
+
label: 'Outlined Badge',
|
|
43
|
+
color: 'primary',
|
|
44
|
+
variant: 'outlined',
|
|
45
|
+
},
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
// 3. All Combinations (Matrix)
|
|
49
|
+
export const AllCombinations: Story = {
|
|
50
|
+
render: (args) => {
|
|
51
|
+
const colors = ['primary', 'secondary', 'success', 'danger', 'warning', 'purple', 'info'];
|
|
52
|
+
const variants = ['filled', 'outlined'];
|
|
53
|
+
|
|
54
|
+
return (
|
|
55
|
+
<div className="flex flex-col gap-8">
|
|
56
|
+
{variants.map((variant) => (
|
|
57
|
+
<div key={variant} className="flex flex-col gap-2">
|
|
58
|
+
<h3 className="text-sm font-bold uppercase text-gray-400">{variant}</h3>
|
|
59
|
+
<div className="flex flex-wrap gap-4 items-center">
|
|
60
|
+
{colors.map((color) => (
|
|
61
|
+
<ITBadget
|
|
62
|
+
key={`${variant}-${color}`}
|
|
63
|
+
{...args}
|
|
64
|
+
color={color as any}
|
|
65
|
+
variant={variant as any}
|
|
66
|
+
label={color.charAt(0).toUpperCase() + color.slice(1)}
|
|
67
|
+
/>
|
|
68
|
+
))}
|
|
69
|
+
</div>
|
|
70
|
+
</div>
|
|
71
|
+
))}
|
|
72
|
+
</div>
|
|
73
|
+
);
|
|
74
|
+
},
|
|
75
|
+
args: {},
|
|
76
|
+
};
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
// components/ITBadge.tsx
|
|
2
|
+
import clsx from "clsx";
|
|
3
|
+
import { ITBadgetProps } from "./badget.props";
|
|
4
|
+
import {
|
|
5
|
+
badgeSizes,
|
|
6
|
+
} from "@/types/badget.types";
|
|
7
|
+
import { theme } from "@/theme/theme";
|
|
8
|
+
import ITText from "@/components/text/text";
|
|
9
|
+
|
|
10
|
+
export default function ITBadget({
|
|
11
|
+
children,
|
|
12
|
+
label,
|
|
13
|
+
color = "primary",
|
|
14
|
+
size = "medium",
|
|
15
|
+
variant = "filled",
|
|
16
|
+
className,
|
|
17
|
+
}: ITBadgetProps) {
|
|
18
|
+
// Access theme configuration
|
|
19
|
+
const themeBadge = (theme as any).badge || {};
|
|
20
|
+
const config = themeBadge[color] || themeBadge.primary || {};
|
|
21
|
+
|
|
22
|
+
const getStyle = () => {
|
|
23
|
+
const style: React.CSSProperties = {
|
|
24
|
+
fontSize: config.fontSize,
|
|
25
|
+
fontWeight: config.fontWeight,
|
|
26
|
+
padding: config.padding,
|
|
27
|
+
borderRadius: config.borderRadius, // '9999px' in theme
|
|
28
|
+
borderWidth: '1px', // Default border width for consistency
|
|
29
|
+
borderStyle: 'solid',
|
|
30
|
+
borderColor: 'transparent', // Default transparent
|
|
31
|
+
transition: 'all 0.2s',
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
if (variant === "filled") {
|
|
35
|
+
style.backgroundColor = config.backgroundColor;
|
|
36
|
+
style.color = config.color;
|
|
37
|
+
style.borderColor = config.borderColor || 'transparent'; // Some filled badges might have subtle borders
|
|
38
|
+
} else if (variant === "outlined") {
|
|
39
|
+
style.backgroundColor = "transparent";
|
|
40
|
+
// Use the dark text color for both text and border to ensure high contrast
|
|
41
|
+
style.color = config.color;
|
|
42
|
+
style.borderColor = config.color;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
return style;
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
return (
|
|
49
|
+
<span
|
|
50
|
+
className={clsx(
|
|
51
|
+
"inline-flex items-center justify-center",
|
|
52
|
+
// Fallback size if theme doesn't have it (though theme does have it for primary)
|
|
53
|
+
!config.padding ? badgeSizes[size] : "",
|
|
54
|
+
className
|
|
55
|
+
)}
|
|
56
|
+
style={getStyle()}
|
|
57
|
+
>
|
|
58
|
+
{children || <ITText as="span" className={clsx("font-semibold")}>{label}</ITText>}
|
|
59
|
+
</span>
|
|
60
|
+
);
|
|
61
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { ReactNode } from "react";
|
|
2
|
+
|
|
3
|
+
export interface ITBreadcrumbItem {
|
|
4
|
+
label: string;
|
|
5
|
+
href?: string;
|
|
6
|
+
onClick?: () => void;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export interface ITBreadcrumbsProps {
|
|
10
|
+
items: ITBreadcrumbItem[];
|
|
11
|
+
separator?: ReactNode;
|
|
12
|
+
className?: string;
|
|
13
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { Meta, StoryObj } from "@storybook/react";
|
|
2
|
+
import ITBreadcrumbs from "./breadcrumbs";
|
|
3
|
+
|
|
4
|
+
const meta: Meta<typeof ITBreadcrumbs> = {
|
|
5
|
+
title: "Components/Navigation/ITBreadcrumbs",
|
|
6
|
+
component: ITBreadcrumbs,
|
|
7
|
+
tags: ["autodocs"],
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
export default meta;
|
|
11
|
+
type Story = StoryObj<typeof ITBreadcrumbs>;
|
|
12
|
+
|
|
13
|
+
export const Default: Story = {
|
|
14
|
+
args: {
|
|
15
|
+
items: [
|
|
16
|
+
{ label: "Inicio", href: "#" },
|
|
17
|
+
{ label: "Usuarios", href: "#" },
|
|
18
|
+
{ label: "Editar Perfil" },
|
|
19
|
+
],
|
|
20
|
+
},
|
|
21
|
+
};
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import clsx from "clsx";
|
|
2
|
+
import { ITBreadcrumbsProps } from "./breadcrumbs.props";
|
|
3
|
+
import { FaChevronRight } from "react-icons/fa";
|
|
4
|
+
import ITText from "@/components/text/text";
|
|
5
|
+
|
|
6
|
+
export default function ITBreadcrumbs({
|
|
7
|
+
items,
|
|
8
|
+
separator = <FaChevronRight size={10} />,
|
|
9
|
+
className,
|
|
10
|
+
}: ITBreadcrumbsProps) {
|
|
11
|
+
return (
|
|
12
|
+
<nav className={clsx("flex items-center gap-1.5 text-sm", className)} aria-label="Breadcrumb">
|
|
13
|
+
{items.map((item, i) => {
|
|
14
|
+
const isLast = i === items.length - 1;
|
|
15
|
+
return (
|
|
16
|
+
<span key={i} className="flex items-center gap-1.5">
|
|
17
|
+
{i > 0 && <span className="text-slate-300 dark:text-slate-600">{separator}</span>}
|
|
18
|
+
{isLast ? (
|
|
19
|
+
<ITText as="span" className="text-slate-800 dark:text-white font-semibold">{item.label}</ITText>
|
|
20
|
+
) : item.href ? (
|
|
21
|
+
<a href={item.href} className="text-slate-500 dark:text-slate-400 hover:text-slate-700 dark:hover:text-slate-200 transition-colors">
|
|
22
|
+
<ITText as="span">{item.label}</ITText>
|
|
23
|
+
</a>
|
|
24
|
+
) : (
|
|
25
|
+
<button onClick={item.onClick} className="text-slate-500 dark:text-slate-400 hover:text-slate-700 dark:hover:text-slate-200 transition-colors">
|
|
26
|
+
<ITText as="span">{item.label}</ITText>
|
|
27
|
+
</button>
|
|
28
|
+
)}
|
|
29
|
+
</span>
|
|
30
|
+
);
|
|
31
|
+
})}
|
|
32
|
+
</nav>
|
|
33
|
+
);
|
|
34
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { buttonVariants } from "@/types/button.types";
|
|
2
|
+
import { ColorsTypes } from "@app/types/colors.types";
|
|
3
|
+
import { SizesTypes } from "@app/types/sizes.types";
|
|
4
|
+
|
|
5
|
+
export interface ITButtonProps {
|
|
6
|
+
label?: string
|
|
7
|
+
children?: React.ReactNode;
|
|
8
|
+
icon?: React.ReactNode;
|
|
9
|
+
onClick?: () => void;
|
|
10
|
+
color?: ColorsTypes;
|
|
11
|
+
size?: SizesTypes;
|
|
12
|
+
variant?: keyof typeof buttonVariants;
|
|
13
|
+
disabled?: boolean;
|
|
14
|
+
className?: string;
|
|
15
|
+
type?: "submit" | "reset" | "button" | undefined;
|
|
16
|
+
ariaLabel?: string;
|
|
17
|
+
title?: string;
|
|
18
|
+
}
|
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
import type { Meta, StoryObj } from '@storybook/react';
|
|
2
|
+
import ITButton from './button';
|
|
3
|
+
|
|
4
|
+
const meta = {
|
|
5
|
+
title: 'Components/Actions/ITButton',
|
|
6
|
+
component: ITButton,
|
|
7
|
+
parameters: {
|
|
8
|
+
layout: 'centered',
|
|
9
|
+
},
|
|
10
|
+
tags: ['autodocs'],
|
|
11
|
+
argTypes: {
|
|
12
|
+
color: {
|
|
13
|
+
control: 'select',
|
|
14
|
+
options: ['primary', 'secondary', 'success', 'danger', 'warning', 'purple', 'info'],
|
|
15
|
+
description: 'The semantic color of the button',
|
|
16
|
+
},
|
|
17
|
+
variant: {
|
|
18
|
+
control: 'select',
|
|
19
|
+
options: ['filled', 'outlined', 'raised', 'rounded', 'text', 'raised-text', 'icon-only', 'link'],
|
|
20
|
+
description: 'The visual style variant',
|
|
21
|
+
},
|
|
22
|
+
size: {
|
|
23
|
+
control: 'select',
|
|
24
|
+
options: ['small', 'medium', 'large'],
|
|
25
|
+
description: 'Button size (padding/font)',
|
|
26
|
+
},
|
|
27
|
+
label: { control: 'text' },
|
|
28
|
+
disabled: { control: 'boolean' },
|
|
29
|
+
},
|
|
30
|
+
} satisfies Meta<typeof ITButton>;
|
|
31
|
+
|
|
32
|
+
export default meta;
|
|
33
|
+
type Story = StoryObj<typeof meta>;
|
|
34
|
+
|
|
35
|
+
// 1. Filled (Default)
|
|
36
|
+
export const Filled: Story = {
|
|
37
|
+
args: {
|
|
38
|
+
label: 'Filled Button',
|
|
39
|
+
color: 'primary',
|
|
40
|
+
variant: 'filled',
|
|
41
|
+
},
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
// 2. Outlined
|
|
45
|
+
export const Outlined: Story = {
|
|
46
|
+
args: {
|
|
47
|
+
label: 'Outlined Button',
|
|
48
|
+
color: 'primary',
|
|
49
|
+
variant: 'outlined',
|
|
50
|
+
},
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
// 3. Raised (Shadow)
|
|
54
|
+
export const Raised: Story = {
|
|
55
|
+
args: {
|
|
56
|
+
label: 'Raised Button',
|
|
57
|
+
color: 'primary',
|
|
58
|
+
variant: 'raised',
|
|
59
|
+
},
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
// 4. Rounded (Pill)
|
|
63
|
+
export const Rounded: Story = {
|
|
64
|
+
args: {
|
|
65
|
+
label: 'Rounded Button',
|
|
66
|
+
color: 'success',
|
|
67
|
+
variant: 'rounded',
|
|
68
|
+
},
|
|
69
|
+
};
|
|
70
|
+
|
|
71
|
+
// 5. Text (Ghost)
|
|
72
|
+
export const Text: Story = {
|
|
73
|
+
args: {
|
|
74
|
+
label: 'Text Button',
|
|
75
|
+
color: 'info',
|
|
76
|
+
variant: 'text',
|
|
77
|
+
},
|
|
78
|
+
};
|
|
79
|
+
|
|
80
|
+
// 6. Raised Text (Elevated White)
|
|
81
|
+
export const RaisedText: Story = {
|
|
82
|
+
args: {
|
|
83
|
+
label: 'Raised Text',
|
|
84
|
+
color: 'warning',
|
|
85
|
+
variant: 'raised-text',
|
|
86
|
+
},
|
|
87
|
+
};
|
|
88
|
+
|
|
89
|
+
// 7. With Icon (icon prop + label)
|
|
90
|
+
export const WithIcon: Story = {
|
|
91
|
+
args: {
|
|
92
|
+
label: 'Guardar',
|
|
93
|
+
color: 'primary',
|
|
94
|
+
variant: 'filled',
|
|
95
|
+
icon: <span style={{ fontSize: '1em' }}>💾</span>,
|
|
96
|
+
},
|
|
97
|
+
};
|
|
98
|
+
|
|
99
|
+
// 8. Icon Only
|
|
100
|
+
export const IconOnly: Story = {
|
|
101
|
+
args: {
|
|
102
|
+
color: 'danger',
|
|
103
|
+
variant: 'icon-only',
|
|
104
|
+
children: <span style={{ fontSize: '1.2em' }}>★</span>,
|
|
105
|
+
ariaLabel: 'Favorite',
|
|
106
|
+
},
|
|
107
|
+
};
|
|
108
|
+
|
|
109
|
+
// 8. Link
|
|
110
|
+
export const Link: Story = {
|
|
111
|
+
args: {
|
|
112
|
+
label: 'Link Button',
|
|
113
|
+
color: 'primary',
|
|
114
|
+
variant: 'link',
|
|
115
|
+
},
|
|
116
|
+
};
|
|
117
|
+
|
|
118
|
+
// 9. All Colors Showcase (Kitchen Sink for colors)
|
|
119
|
+
export const AllColors: Story = {
|
|
120
|
+
render: (args) => (
|
|
121
|
+
<div className="flex flex-wrap gap-4">
|
|
122
|
+
{['primary', 'secondary', 'success', 'danger', 'warning', 'purple', 'info'].map((color) => (
|
|
123
|
+
<ITButton key={color} {...args} color={color as any} label={color.charAt(0).toUpperCase() + color.slice(1)} />
|
|
124
|
+
))}
|
|
125
|
+
</div>
|
|
126
|
+
),
|
|
127
|
+
args: {
|
|
128
|
+
variant: 'filled',
|
|
129
|
+
},
|
|
130
|
+
};
|
|
131
|
+
|
|
132
|
+
// 9. Disabled
|
|
133
|
+
export const Disabled: Story = {
|
|
134
|
+
args: {
|
|
135
|
+
label: 'Disabled Button',
|
|
136
|
+
disabled: true,
|
|
137
|
+
color: 'primary',
|
|
138
|
+
variant: 'filled',
|
|
139
|
+
},
|
|
140
|
+
};
|
|
141
|
+
|
|
142
|
+
// 10. All Combinations (Matrix)
|
|
143
|
+
export const AllCombinations: Story = {
|
|
144
|
+
render: (args) => {
|
|
145
|
+
const colors = ['primary', 'secondary', 'success', 'danger', 'warning', 'purple', 'info'];
|
|
146
|
+
const variants = ['filled', 'outlined', 'raised', 'rounded', 'text', 'raised-text', 'icon-only', 'link'];
|
|
147
|
+
|
|
148
|
+
return (
|
|
149
|
+
<div className="flex flex-col gap-8">
|
|
150
|
+
{variants.map((variant) => (
|
|
151
|
+
<div key={variant} className="flex flex-col gap-2">
|
|
152
|
+
<h3 className="text-sm font-bold uppercase text-gray-400">{variant}</h3>
|
|
153
|
+
<div className="flex flex-wrap gap-4 items-center">
|
|
154
|
+
{colors.map((color) => (
|
|
155
|
+
<ITButton
|
|
156
|
+
key={`${variant}-${color}`}
|
|
157
|
+
{...args}
|
|
158
|
+
color={color as any}
|
|
159
|
+
variant={variant as any}
|
|
160
|
+
label={variant === 'icon-only' ? undefined : (color.charAt(0).toUpperCase() + color.slice(1))}
|
|
161
|
+
ariaLabel={variant === 'icon-only' ? color : undefined}
|
|
162
|
+
>
|
|
163
|
+
{variant === 'icon-only' ? <span style={{ fontSize: '1.2em' }}>★</span> : undefined}
|
|
164
|
+
</ITButton>
|
|
165
|
+
))}
|
|
166
|
+
</div>
|
|
167
|
+
</div>
|
|
168
|
+
))}
|
|
169
|
+
</div>
|
|
170
|
+
);
|
|
171
|
+
},
|
|
172
|
+
args: {},
|
|
173
|
+
};
|
|
174
|
+
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
import {
|
|
2
|
+
buttonSizes,
|
|
3
|
+
buttonVariants,
|
|
4
|
+
} from "@app/types/button.types";
|
|
5
|
+
import clsx from "clsx";
|
|
6
|
+
import { useState } from "react";
|
|
7
|
+
import { theme } from "@/theme/theme";
|
|
8
|
+
import { ITButtonProps } from "./button.props";
|
|
9
|
+
import ITText from "@/components/text/text";
|
|
10
|
+
|
|
11
|
+
export default function ITButton({
|
|
12
|
+
children,
|
|
13
|
+
label,
|
|
14
|
+
icon,
|
|
15
|
+
onClick,
|
|
16
|
+
type = "button",
|
|
17
|
+
color = "primary",
|
|
18
|
+
size = "medium",
|
|
19
|
+
disabled = false,
|
|
20
|
+
className,
|
|
21
|
+
variant = "filled",
|
|
22
|
+
ariaLabel,
|
|
23
|
+
title,
|
|
24
|
+
}: ITButtonProps) {
|
|
25
|
+
const [isHovered, setIsHovered] = useState(false);
|
|
26
|
+
const [isFocused, setIsFocused] = useState(false);
|
|
27
|
+
|
|
28
|
+
// Get specific button config from theme
|
|
29
|
+
const themeBtn = theme.button as any;
|
|
30
|
+
const themeConfig = themeBtn[color] || themeBtn.primary;
|
|
31
|
+
|
|
32
|
+
// Determine if the button should look "filled" (solid bg) or "outlined/text" (transparent/white bg)
|
|
33
|
+
const isSolid = ["filled", "raised", "rounded", "icon-only"].includes(variant || "filled");
|
|
34
|
+
const isOutlined = variant === "outlined";
|
|
35
|
+
const isText = variant === "text" || variant === "link";
|
|
36
|
+
const isRaisedText = variant === "raised-text";
|
|
37
|
+
|
|
38
|
+
const getStyle = () => {
|
|
39
|
+
// if (disabled) return {}; // Removed to allow styles to render with opacity
|
|
40
|
+
|
|
41
|
+
const mainColor = themeConfig.backgroundColor; // The vibrant color
|
|
42
|
+
const textColor = themeConfig.color; // Usually white for filled
|
|
43
|
+
|
|
44
|
+
let style: React.CSSProperties = {
|
|
45
|
+
// fontSize: themeConfig.fontSize, // Removed to allow size prop to control font size
|
|
46
|
+
fontWeight: themeConfig.fontWeight,
|
|
47
|
+
// padding: themeConfig.padding, // Removed to allow size prop to control padding
|
|
48
|
+
borderRadius: themeConfig.borderRadius, // Default from theme
|
|
49
|
+
transition: themeConfig.transition || 'all 0.2s',
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
if (variant === "rounded") {
|
|
53
|
+
style.borderRadius = "9999px";
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
if (variant === "icon-only") {
|
|
57
|
+
style.padding = "0.5rem"; // Square padding override
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
if (isSolid) {
|
|
61
|
+
style.backgroundColor = (isHovered && !disabled) ? themeConfig.hover : mainColor;
|
|
62
|
+
style.color = textColor;
|
|
63
|
+
} else if (isOutlined) {
|
|
64
|
+
style.backgroundColor = "transparent";
|
|
65
|
+
style.color = mainColor;
|
|
66
|
+
style.borderColor = mainColor;
|
|
67
|
+
if (isHovered && !disabled) {
|
|
68
|
+
style.backgroundColor = `${mainColor}10`; // 10% opacity
|
|
69
|
+
}
|
|
70
|
+
} else if (isText) {
|
|
71
|
+
style.backgroundColor = (isHovered && !disabled) ? `${mainColor}10` : "transparent";
|
|
72
|
+
style.color = mainColor;
|
|
73
|
+
} else if (isRaisedText) {
|
|
74
|
+
style.backgroundColor = "var(--card-bg, #ffffff)";
|
|
75
|
+
style.color = mainColor;
|
|
76
|
+
if (isHovered && !disabled) style.backgroundColor = "var(--card-header-bg, #f8fafc)";
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
// Apply focus style from theme (box-shadow ring)
|
|
80
|
+
if (isFocused && themeConfig.focus && !disabled) {
|
|
81
|
+
style.boxShadow = themeConfig.focus;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
return style;
|
|
85
|
+
};
|
|
86
|
+
|
|
87
|
+
return (
|
|
88
|
+
<button
|
|
89
|
+
type={type}
|
|
90
|
+
className={clsx(
|
|
91
|
+
"focus:outline-none", // Removed focus:ring-2 focus:ring-offset-2 to use theme style
|
|
92
|
+
// Apply variant base styles (border, shadow, rounded-full)
|
|
93
|
+
buttonVariants[variant || "filled"],
|
|
94
|
+
// Apply size classes (padding/font-size)
|
|
95
|
+
buttonSizes[size],
|
|
96
|
+
className,
|
|
97
|
+
{ "opacity-50 cursor-not-allowed": disabled }
|
|
98
|
+
)}
|
|
99
|
+
style={getStyle()}
|
|
100
|
+
onMouseEnter={() => setIsHovered(true)}
|
|
101
|
+
onMouseLeave={() => setIsHovered(false)}
|
|
102
|
+
onFocus={() => setIsFocused(true)}
|
|
103
|
+
onBlur={() => setIsFocused(false)}
|
|
104
|
+
onClick={onClick}
|
|
105
|
+
disabled={disabled}
|
|
106
|
+
aria-label={ariaLabel || label}
|
|
107
|
+
title={title || ariaLabel || label}
|
|
108
|
+
>
|
|
109
|
+
{children || (
|
|
110
|
+
<span className={clsx("inline-flex items-center gap-1.5 font-semibold", { "opacity-50": disabled })}>
|
|
111
|
+
{icon && <span className="flex-shrink-0">{icon}</span>}
|
|
112
|
+
<ITText as="span">{label}</ITText>
|
|
113
|
+
</span>
|
|
114
|
+
)}
|
|
115
|
+
</button>
|
|
116
|
+
);
|
|
117
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { ColorsTypes } from "@/types/colors.types";
|
|
2
|
+
|
|
3
|
+
export interface CalendarEvent {
|
|
4
|
+
id: string;
|
|
5
|
+
title: string;
|
|
6
|
+
start: Date | string; // Date object or ISO string
|
|
7
|
+
end: Date | string;
|
|
8
|
+
color?: string; // Hex or tailwind class
|
|
9
|
+
data?: any; // Extra data for callbacks
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export interface ITCalendarProps {
|
|
13
|
+
// Scheduler Props
|
|
14
|
+
events?: CalendarEvent[];
|
|
15
|
+
mode?: 'week' | 'day' | 'month'; // 'month' for picker
|
|
16
|
+
onEventClick?: (event: CalendarEvent) => void;
|
|
17
|
+
onSlotClick?: (date: Date) => void;
|
|
18
|
+
onSlotHover?: (date: Date) => void;
|
|
19
|
+
onSelectRange?: (start: Date, end: Date) => void;
|
|
20
|
+
|
|
21
|
+
// Picker Props (Legacy/DatePicker support)
|
|
22
|
+
value?: Date;
|
|
23
|
+
onChange?: (date: Date) => void;
|
|
24
|
+
selectionMode?: 'single' | 'range';
|
|
25
|
+
startDate?: Date;
|
|
26
|
+
endDate?: Date;
|
|
27
|
+
minDate?: Date;
|
|
28
|
+
maxDate?: Date;
|
|
29
|
+
|
|
30
|
+
className?: string;
|
|
31
|
+
disabled?: boolean;
|
|
32
|
+
variant?: ColorsTypes;
|
|
33
|
+
}
|