@algorithm-shift/design-system 1.2.10 → 1.2.12

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 (92) hide show
  1. package/dist/index.css +1 -2314
  2. package/dist/index.css.map +1 -1
  3. package/dist/index.js.map +1 -1
  4. package/package.json +2 -2
  5. package/src/components/Basic/Image/Image.stories.tsx +13 -0
  6. package/src/components/Basic/Image/Image.tsx +52 -0
  7. package/src/components/Basic/Shape/Shape.tsx +16 -0
  8. package/src/components/Basic/Typography/Typography.stories.tsx +18 -0
  9. package/src/components/Basic/Typography/Typography.tsx +31 -0
  10. package/src/components/DataDisplay/Table/Table.stories.tsx +35 -0
  11. package/src/components/DataDisplay/Table/Table.tsx +15 -0
  12. package/src/components/DataDisplay/index.ts +1 -0
  13. package/src/components/Global/SelectDropdown.tsx +61 -0
  14. package/src/components/Global/TinyMceEditor.tsx +81 -0
  15. package/src/components/Inputs/Checkbox/Checkbox.tsx +18 -0
  16. package/src/components/Inputs/DatePicker/DatePicker.tsx +81 -0
  17. package/src/components/Inputs/DateRange/DateRange.tsx +64 -0
  18. package/src/components/Inputs/Dropdown/Dropdown.tsx +62 -0
  19. package/src/components/Inputs/EmailInput/EmailInput.tsx +64 -0
  20. package/src/components/Inputs/FileInput/FileInput.tsx +24 -0
  21. package/src/components/Inputs/MultiCheckbox/MultiCheckbox.tsx +24 -0
  22. package/src/components/Inputs/NumberInput/NumberInput.tsx +66 -0
  23. package/src/components/Inputs/PasswordInput/PasswordInput.tsx +66 -0
  24. package/src/components/Inputs/PhoneInput/PhoneInput.tsx +58 -0
  25. package/src/components/Inputs/RadioInput/RadioInput.tsx +24 -0
  26. package/src/components/Inputs/RichText/RichText.tsx +10 -0
  27. package/src/components/Inputs/SearchInput/SearchInput.tsx +64 -0
  28. package/src/components/Inputs/SwitchToggle/SwitchToggle.tsx +22 -0
  29. package/src/components/Inputs/TextInput/TextInput.tsx +59 -0
  30. package/src/components/Inputs/Textarea/Textarea.tsx +58 -0
  31. package/src/components/Inputs/UrlInput/UrlInput.tsx +66 -0
  32. package/src/components/Layout/Flex.tsx +13 -0
  33. package/src/components/Layout/Grid.tsx +13 -0
  34. package/src/components/Navigation/Logo/Logo.stories.tsx +25 -0
  35. package/src/components/Navigation/Logo/Logo.tsx +33 -0
  36. package/src/components/Navigation/Notification/Notification.stories.tsx +20 -0
  37. package/src/components/Navigation/Notification/Notification.tsx +20 -0
  38. package/src/components/Navigation/Profile/Profile.stories.tsx +20 -0
  39. package/src/components/Navigation/Profile/Profile.tsx +25 -0
  40. package/src/components/Navigation/Spacer/Spacer.stories.tsx +18 -0
  41. package/src/components/Navigation/Spacer/Spacer.tsx +11 -0
  42. package/src/components/Navigation/Stages/Stages.stories.tsx +24 -0
  43. package/src/components/Navigation/Stages/Stages.tsx +49 -0
  44. package/src/components/Navigation/Tabs/Tabs.stories.tsx +38 -0
  45. package/src/components/Navigation/Tabs/Tabs.tsx +72 -0
  46. package/src/components/Navigation/index.ts +6 -0
  47. package/src/components/index.ts +27 -0
  48. package/src/components/ui/button.stories.tsx +24 -0
  49. package/src/components/ui/button.tsx +59 -0
  50. package/src/components/ui/calendar.tsx +211 -0
  51. package/src/components/ui/checkbox.tsx +30 -0
  52. package/src/components/ui/data-table.tsx +138 -0
  53. package/src/components/ui/dropdown-menu.tsx +258 -0
  54. package/src/components/ui/input.tsx +21 -0
  55. package/src/components/ui/label.tsx +22 -0
  56. package/src/components/ui/popover.tsx +46 -0
  57. package/src/components/ui/radio-group.tsx +43 -0
  58. package/src/components/ui/select.tsx +183 -0
  59. package/src/components/ui/switch.tsx +29 -0
  60. package/src/components/ui/table.tsx +121 -0
  61. package/src/components/ui/textarea.tsx +18 -0
  62. package/src/global.css +6 -0
  63. package/src/index.css +119 -0
  64. package/src/index.ts +4 -0
  65. package/src/lib/utils.ts +6 -0
  66. package/src/stories/Button.stories.ts +54 -0
  67. package/src/stories/Button.tsx +35 -0
  68. package/src/stories/Configure.mdx +364 -0
  69. package/src/stories/Header.stories.ts +34 -0
  70. package/src/stories/Header.tsx +54 -0
  71. package/src/stories/Page.stories.ts +33 -0
  72. package/src/stories/Page.tsx +73 -0
  73. package/src/stories/assets/accessibility.png +0 -0
  74. package/src/stories/assets/accessibility.svg +1 -0
  75. package/src/stories/assets/addon-library.png +0 -0
  76. package/src/stories/assets/assets.png +0 -0
  77. package/src/stories/assets/avif-test-image.avif +0 -0
  78. package/src/stories/assets/context.png +0 -0
  79. package/src/stories/assets/discord.svg +1 -0
  80. package/src/stories/assets/docs.png +0 -0
  81. package/src/stories/assets/figma-plugin.png +0 -0
  82. package/src/stories/assets/github.svg +1 -0
  83. package/src/stories/assets/share.png +0 -0
  84. package/src/stories/assets/styling.png +0 -0
  85. package/src/stories/assets/testing.png +0 -0
  86. package/src/stories/assets/theming.png +0 -0
  87. package/src/stories/assets/tutorials.svg +1 -0
  88. package/src/stories/assets/youtube.svg +1 -0
  89. package/src/stories/button.css +30 -0
  90. package/src/stories/header.css +32 -0
  91. package/src/stories/page.css +68 -0
  92. package/src/types/global.d.ts +85 -0
@@ -0,0 +1,25 @@
1
+ 'use client';
2
+
3
+ import { ProfileProps } from "@/types/global";
4
+
5
+ const Profile = ({ profileType, showName, userName, className, style }: ProfileProps) => {
6
+ return (
7
+ <div className={className} style={style}>
8
+ <div className='flex gap-2 items-center justify-between w-30 cursor-pointer'>
9
+ {showName && (
10
+ <h4 className='text-[#000000] dark:text-[#fff] text-[13px] font-[500] mb-0'>{userName}</h4>
11
+ )}
12
+ {profileType === 'avatar' ? (
13
+ <img
14
+ src='https://builder.development.algorithmshift.ai/images/toolset/profile.svg' alt="auto" width={24} height={24}
15
+ />
16
+ ) : (
17
+ <div className='w-6 h-6 bg-[#12715b] rounded-full text-[#fff] text-center text-[11px] flex items-center justify-center'>A</div>
18
+ )}
19
+
20
+ </div>
21
+ </div>
22
+ );
23
+ };
24
+
25
+ export default Profile;
@@ -0,0 +1,18 @@
1
+ import type { Meta, StoryObj } from '@storybook/react-webpack5';
2
+
3
+ import Spacer from './Spacer';
4
+
5
+ const meta = {
6
+ component: Spacer,
7
+ tags: ['autodocs'],
8
+ } satisfies Meta<typeof Spacer>;
9
+
10
+ export default meta;
11
+
12
+ type Story = StoryObj<typeof meta>;
13
+
14
+ export const Default: Story = {
15
+ args: {
16
+ className: 'mt-[20px] mb-[20px] border-[1px] border-[#E0E0E0] border-solid group relative w-full',
17
+ },
18
+ };
@@ -0,0 +1,11 @@
1
+ 'use client';
2
+
3
+ import { ElementProps } from "@/types/global";
4
+
5
+ const Spacer = ({ className, style }: ElementProps) => {
6
+ return (
7
+ <div className={`${className}`} style={style} />
8
+ );
9
+ };
10
+
11
+ export default Spacer;
@@ -0,0 +1,24 @@
1
+ import type { Meta, StoryObj } from '@storybook/react-webpack5';
2
+
3
+ import Stages from './Stages';
4
+
5
+ const meta = {
6
+ component: Stages,
7
+ tags: ['autodocs'],
8
+ } satisfies Meta<typeof Stages>;
9
+
10
+ export default meta;
11
+
12
+ type Story = StoryObj<typeof meta>;
13
+
14
+ export const Default: Story = {
15
+ args: {
16
+ stages: [
17
+ { id: 1, header: 'Stage 1', isActive: true },
18
+ { id: 2, header: 'Stage 2', isActive: false },
19
+ { id: 3, header: 'Stage 3', isActive: false },
20
+ ],
21
+ isShowBtn: true,
22
+ buttonText: 'Next',
23
+ },
24
+ };
@@ -0,0 +1,49 @@
1
+ 'use client';
2
+
3
+ import { StagesProps } from '@/types/global';
4
+ import React from 'react';
5
+
6
+ const StagesComponent = ({ stages, isShowBtn, buttonText, className, style }: StagesProps) => {
7
+
8
+ return (
9
+ <div className={className} style={style}>
10
+ <div className="flex items-center justify-between bg-gray-50 p-2 rounded-lg border border-gray-200 w-full">
11
+ <div className="flex items-center">
12
+ <button className="p-2 hover:bg-gray-100 rounded">
13
+ <svg className="w-4 h-4 text-gray-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
14
+ <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M19 9l-7 7-7-7" />
15
+ </svg>
16
+ </button>
17
+ </div>
18
+
19
+ <div className="flex items-center flex-1 px-2">
20
+ {stages?.length > 0 && stages?.map((stage: any, index: number) => (
21
+ <React.Fragment key={stage.id}>
22
+ <button
23
+ className={`
24
+ min-w-[120px] px-4 py-2 rounded-full text-sm font-medium transition-colors duration-200 whitespace-nowrap ${stage.isActive ? 'bg-[#034486] text-white shadow-md' : 'bg-white text-gray-700 hover:bg-gray-100 border border-gray-200'}`}
25
+ >
26
+ {stage.header}
27
+ </button>
28
+
29
+ {index < stages.length - 1 && (
30
+ <div className="flex-shrink-0 w-3 h-px bg-gray-300"></div>
31
+ )}
32
+ </React.Fragment>
33
+ ))}
34
+ </div>
35
+
36
+ {isShowBtn && (
37
+ <div className="flex items-center">
38
+ <button className="bg-[#034486] text-white px-6 py-2 rounded-lg text-sm font-medium transition-colors duration-200 shadow-sm">
39
+ {buttonText}
40
+ </button>
41
+ </div>
42
+ )}
43
+
44
+ </div>
45
+ </div>
46
+ );
47
+ };
48
+
49
+ export default StagesComponent;
@@ -0,0 +1,38 @@
1
+ import type { Meta, StoryObj } from '@storybook/react-webpack5';
2
+
3
+ import Tabs from './Tabs';
4
+
5
+ const meta = {
6
+ component: Tabs,
7
+ tags: ['autodocs'],
8
+ } satisfies Meta<typeof Tabs>;
9
+
10
+ export default meta;
11
+
12
+ type Story = StoryObj<typeof meta>;
13
+
14
+ export const Default: Story = {
15
+ args: {
16
+ tabs: [
17
+ { header: 'Home', isActive: true },
18
+ { header: 'Profile' },
19
+ {
20
+ header: 'Settings',
21
+ isDropDown: true,
22
+ children: [
23
+ { id: 1, header: 'Account' },
24
+ { id: 2, header: 'Privacy' },
25
+ { id: 3, header: 'Notifications' },
26
+ ],
27
+ },
28
+ { header: 'Help' },
29
+ ],
30
+ className: 'flex col-span-12 col-start-1 items-center h-50 visible bg-[#12715b] p-auto pr-[10px] pt-[10px] pb-[10px] pl-[10px] sm:flex sm:grid-cols-12 sm:col-span-12 sm:col-start-1 sm:items-center sm:h-50 sm:visible sm:bg-[#12715b] sm:p-auto sm:pr-[10px] sm:pt-[10px] sm:pb-[10px] sm:pl-[10px] md:flex md:grid-cols-12 md:col-span-12 md:col-start-1 md:items-center md:h-50 md:visible md:bg-[#12715b] md:p-auto md:pr-[10px] md:pt-[10px] md:pb-[10px] md:pl-[10px] group relative w-full transition-opacity duration:300 pointer-events-none grid-cols-12',
31
+ style: {
32
+ 'height': '50px',
33
+ 'width': 'auto',
34
+ 'backgroundColor': 'rgb(18, 113, 91)',
35
+ 'pointerEvents': 'none',
36
+ }
37
+ },
38
+ };
@@ -0,0 +1,72 @@
1
+ 'use client';
2
+
3
+ import { ChevronDown } from 'lucide-react';
4
+
5
+ import {
6
+ DropdownMenu,
7
+ DropdownMenuContent,
8
+ DropdownMenuItem,
9
+ DropdownMenuTrigger,
10
+ } from '@/components/ui/dropdown-menu';
11
+ import { TabsProps } from '@/types/global';
12
+
13
+
14
+ const Tabs = ({ tabs, className, style }: TabsProps) => {
15
+ const rawTabs = Array.isArray(tabs) ? tabs : [];
16
+ const baseClasses =
17
+ 'text-[12px] text-[#E9E9E9] p-2 text-center rounded-md transition-colors border-none outline-none focus:outline-none focus:ring-0 focus:ring-offset-0 cursor-pointer select-none ';
18
+ const activeClasses = 'bg-white/10 text-white';
19
+ const hoverClasses = 'hover:bg-white/5';
20
+
21
+ return (
22
+ <div className={className} style={style}>
23
+ {rawTabs.map((tab: any, index: number) => {
24
+ const finalClasses = [
25
+ baseClasses,
26
+ tab.isActive ? activeClasses : hoverClasses,
27
+ tab.className || '',
28
+ ].join(' ');
29
+
30
+ const hasDropdown = Array.isArray(tab.children) && tab.children.length > 0 && tab.isDropDown;
31
+
32
+ if (hasDropdown) {
33
+ return (
34
+ <DropdownMenu key={index}>
35
+ <DropdownMenuTrigger
36
+ className={`${finalClasses} inline-flex items-center gap-1`}
37
+ >
38
+ {tab.header}
39
+ <ChevronDown className="h-4 w-4 opacity-80" />
40
+ </DropdownMenuTrigger>
41
+
42
+ <DropdownMenuContent
43
+ align="start"
44
+ sideOffset={6}
45
+ className="z-50 min-w-[160px] rounded-md border border-gray-200 bg-white p-1 shadow-lg"
46
+ >
47
+ {tab.children.map((item: any) => (
48
+ <DropdownMenuItem
49
+ key={item.id}
50
+ asChild
51
+ className="cursor-pointer rounded-sm px-3 py-2 text-[12px] text-gray-800 hover:bg-gray-100 focus:bg-gray-100"
52
+ >
53
+ {item.header}
54
+ </DropdownMenuItem>
55
+ ))}
56
+ </DropdownMenuContent>
57
+ </DropdownMenu>
58
+ );
59
+ }
60
+
61
+ return (
62
+ <div key={index} className={finalClasses} style={{ backgroundColor: 'transparent', border: 'none', ...tab.style }} role="button" tabIndex={0}>
63
+ {tab.header}
64
+ </div>
65
+ );
66
+ })}
67
+
68
+ </div>
69
+ );
70
+ };
71
+
72
+ export default Tabs;
@@ -0,0 +1,6 @@
1
+ export { default as Tabs } from './Tabs/Tabs';
2
+ export { default as Stages } from './Stages/Stages';
3
+ export { default as Spacer } from './Spacer/Spacer';
4
+ export { default as Profile } from './Profile/Profile';
5
+ export { default as Notification } from './Notification/Notification';
6
+ export { default as Logo } from './Logo/Logo';
@@ -0,0 +1,27 @@
1
+ export * from './ui/button'
2
+
3
+ export { default as FlexLayout } from './Layout/Flex'
4
+ export { default as GridLayout } from './Layout/Grid'
5
+
6
+ export { default as Typography } from './Basic/Typography/Typography'
7
+ export { default as Shape } from './Basic/Shape/Shape'
8
+ export { default as Image } from './Basic/Image/Image'
9
+ export * from './Inputs/TextInput/TextInput'
10
+ export * from './Inputs/NumberInput/NumberInput'
11
+ export * from './Inputs/EmailInput/EmailInput'
12
+ export * from './Inputs/PasswordInput/PasswordInput'
13
+ export * from './Inputs/Textarea/Textarea'
14
+ export * from './Inputs/UrlInput/UrlInput'
15
+ export * from './Inputs/Checkbox/Checkbox'
16
+ export * from './Inputs/RadioInput/RadioInput'
17
+ export * from './Inputs/MultiCheckbox/MultiCheckbox'
18
+ export { default as RichText } from './Inputs/RichText/RichText'
19
+ export * from './Inputs/Dropdown/Dropdown'
20
+ export * from './Inputs/SwitchToggle/SwitchToggle'
21
+ export * from './Inputs/PhoneInput/PhoneInput'
22
+ export * from './Inputs/SearchInput/SearchInput'
23
+ export * from './Inputs/FileInput/FileInput'
24
+ export { default as DatePicker } from './Inputs/DatePicker/DatePicker'
25
+ export { default as DateRange } from './Inputs/DateRange/DateRange'
26
+ export { Table } from './DataDisplay';
27
+ export { Stages, Tabs, Spacer, Profile, Notification, Logo } from './Navigation';
@@ -0,0 +1,24 @@
1
+ import type { Meta, StoryObj } from '@storybook/react-webpack5';
2
+
3
+ import { Button } from './button';
4
+
5
+ const meta = {
6
+ component: Button,
7
+ tags: ['autodocs'],
8
+ } satisfies Meta<typeof Button>;
9
+
10
+ export default meta;
11
+
12
+ type Story = StoryObj<typeof meta>;
13
+
14
+ export const Default: Story = { args: { children: "Default" } };
15
+
16
+ export const Outline: Story = { args: { variant: "outline", children: "Outline" } };
17
+
18
+ export const Destructive: Story = { args: { variant: "destructive", children: "Destructive" } };
19
+
20
+ export const Secondary: Story = { args: { variant: "secondary", children: "Secondary" } };
21
+
22
+ export const Ghost: Story = { args: { variant: "ghost", children: "Ghost" } };
23
+
24
+ export const Link: Story = { args: { variant: "link", children: "Link" } };
@@ -0,0 +1,59 @@
1
+ import * as React from "react"
2
+ import { Slot } from "@radix-ui/react-slot"
3
+ import { cva, type VariantProps } from "class-variance-authority"
4
+
5
+ import { cn } from "@/lib/utils"
6
+
7
+ const buttonVariants = cva(
8
+ "inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-all disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-4 shrink-0 [&_svg]:shrink-0 outline-none focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px] aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive",
9
+ {
10
+ variants: {
11
+ variant: {
12
+ default:
13
+ "bg-primary text-primary-foreground shadow-xs hover:bg-primary/90",
14
+ destructive:
15
+ "bg-destructive text-white shadow-xs hover:bg-destructive/90 focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40 dark:bg-destructive/60",
16
+ outline:
17
+ "border bg-background shadow-xs hover:bg-accent hover:text-accent-foreground dark:bg-input/30 dark:border-input dark:hover:bg-input/50",
18
+ secondary:
19
+ "bg-secondary text-secondary-foreground shadow-xs hover:bg-secondary/80",
20
+ ghost:
21
+ "hover:bg-accent hover:text-accent-foreground dark:hover:bg-accent/50",
22
+ link: "text-primary underline-offset-4 hover:underline",
23
+ },
24
+ size: {
25
+ default: "h-9 px-4 py-2 has-[>svg]:px-3",
26
+ sm: "h-8 rounded-md gap-1.5 px-3 has-[>svg]:px-2.5",
27
+ lg: "h-10 rounded-md px-6 has-[>svg]:px-4",
28
+ icon: "size-9",
29
+ },
30
+ },
31
+ defaultVariants: {
32
+ variant: "default",
33
+ size: "default",
34
+ },
35
+ }
36
+ )
37
+
38
+ function Button({
39
+ className,
40
+ variant,
41
+ size,
42
+ asChild = false,
43
+ ...props
44
+ }: React.ComponentProps<"button"> &
45
+ VariantProps<typeof buttonVariants> & {
46
+ asChild?: boolean
47
+ }) {
48
+ const Comp = asChild ? Slot : "button"
49
+
50
+ return (
51
+ <Comp
52
+ data-slot="button"
53
+ className={cn(buttonVariants({ variant, size, className }))}
54
+ {...props}
55
+ />
56
+ )
57
+ }
58
+
59
+ export { Button, buttonVariants }
@@ -0,0 +1,211 @@
1
+ import * as React from "react"
2
+ import {
3
+ ChevronDownIcon,
4
+ ChevronLeftIcon,
5
+ ChevronRightIcon,
6
+ } from "lucide-react"
7
+ import { DayButton, DayPicker, getDefaultClassNames } from "react-day-picker"
8
+
9
+ import { cn } from "@/lib/utils"
10
+ import { Button, buttonVariants } from "@/components/ui/button"
11
+
12
+ function Calendar({
13
+ className,
14
+ classNames,
15
+ showOutsideDays = true,
16
+ captionLayout = "label",
17
+ buttonVariant = "ghost",
18
+ formatters,
19
+ components,
20
+ ...props
21
+ }: React.ComponentProps<typeof DayPicker> & {
22
+ buttonVariant?: React.ComponentProps<typeof Button>["variant"]
23
+ }) {
24
+ const defaultClassNames = getDefaultClassNames()
25
+
26
+ return (
27
+ <DayPicker
28
+ showOutsideDays={showOutsideDays}
29
+ className={cn(
30
+ "bg-background group/calendar p-3 [--cell-size:--spacing(8)] [[data-slot=card-content]_&]:bg-transparent [[data-slot=popover-content]_&]:bg-transparent",
31
+ String.raw`rtl:**:[.rdp-button\_next>svg]:rotate-180`,
32
+ String.raw`rtl:**:[.rdp-button\_previous>svg]:rotate-180`,
33
+ className
34
+ )}
35
+ captionLayout={captionLayout}
36
+ formatters={{
37
+ formatMonthDropdown: (date) =>
38
+ date.toLocaleString("default", { month: "short" }),
39
+ ...formatters,
40
+ }}
41
+ classNames={{
42
+ root: cn("w-fit", defaultClassNames.root),
43
+ months: cn(
44
+ "flex gap-4 flex-col md:flex-row relative",
45
+ defaultClassNames.months
46
+ ),
47
+ month: cn("flex flex-col w-full gap-4", defaultClassNames.month),
48
+ nav: cn(
49
+ "flex items-center gap-1 w-full absolute top-0 inset-x-0 justify-between",
50
+ defaultClassNames.nav
51
+ ),
52
+ button_previous: cn(
53
+ buttonVariants({ variant: buttonVariant }),
54
+ "size-(--cell-size) aria-disabled:opacity-50 p-0 select-none",
55
+ defaultClassNames.button_previous
56
+ ),
57
+ button_next: cn(
58
+ buttonVariants({ variant: buttonVariant }),
59
+ "size-(--cell-size) aria-disabled:opacity-50 p-0 select-none",
60
+ defaultClassNames.button_next
61
+ ),
62
+ month_caption: cn(
63
+ "flex items-center justify-center h-(--cell-size) w-full px-(--cell-size)",
64
+ defaultClassNames.month_caption
65
+ ),
66
+ dropdowns: cn(
67
+ "w-full flex items-center text-sm font-medium justify-center h-(--cell-size) gap-1.5",
68
+ defaultClassNames.dropdowns
69
+ ),
70
+ dropdown_root: cn(
71
+ "relative has-focus:border-ring border border-input shadow-xs has-focus:ring-ring/50 has-focus:ring-[3px] rounded-md",
72
+ defaultClassNames.dropdown_root
73
+ ),
74
+ dropdown: cn(
75
+ "absolute bg-popover inset-0 opacity-0",
76
+ defaultClassNames.dropdown
77
+ ),
78
+ caption_label: cn(
79
+ "select-none font-medium",
80
+ captionLayout === "label"
81
+ ? "text-sm"
82
+ : "rounded-md pl-2 pr-1 flex items-center gap-1 text-sm h-8 [&>svg]:text-muted-foreground [&>svg]:size-3.5",
83
+ defaultClassNames.caption_label
84
+ ),
85
+ table: "w-full border-collapse",
86
+ weekdays: cn("flex", defaultClassNames.weekdays),
87
+ weekday: cn(
88
+ "text-muted-foreground rounded-md flex-1 font-normal text-[0.8rem] select-none",
89
+ defaultClassNames.weekday
90
+ ),
91
+ week: cn("flex w-full mt-2", defaultClassNames.week),
92
+ week_number_header: cn(
93
+ "select-none w-(--cell-size)",
94
+ defaultClassNames.week_number_header
95
+ ),
96
+ week_number: cn(
97
+ "text-[0.8rem] select-none text-muted-foreground",
98
+ defaultClassNames.week_number
99
+ ),
100
+ day: cn(
101
+ "relative w-full h-full p-0 text-center [&:first-child[data-selected=true]_button]:rounded-l-md [&:last-child[data-selected=true]_button]:rounded-r-md group/day aspect-square select-none",
102
+ defaultClassNames.day
103
+ ),
104
+ range_start: cn(
105
+ "rounded-l-md bg-accent",
106
+ defaultClassNames.range_start
107
+ ),
108
+ range_middle: cn("rounded-none", defaultClassNames.range_middle),
109
+ range_end: cn("rounded-r-md bg-accent", defaultClassNames.range_end),
110
+ today: cn(
111
+ "bg-accent text-accent-foreground rounded-md data-[selected=true]:rounded-none",
112
+ defaultClassNames.today
113
+ ),
114
+ outside: cn(
115
+ "text-muted-foreground aria-selected:text-muted-foreground",
116
+ defaultClassNames.outside
117
+ ),
118
+ disabled: cn(
119
+ "text-muted-foreground opacity-50",
120
+ defaultClassNames.disabled
121
+ ),
122
+ hidden: cn("invisible", defaultClassNames.hidden),
123
+ ...classNames,
124
+ }}
125
+ components={{
126
+ Root: ({ className, rootRef, ...props }) => {
127
+ return (
128
+ <div
129
+ data-slot="calendar"
130
+ ref={rootRef}
131
+ className={cn(className)}
132
+ {...props}
133
+ />
134
+ )
135
+ },
136
+ Chevron: ({ className, orientation, ...props }) => {
137
+ if (orientation === "left") {
138
+ return (
139
+ <ChevronLeftIcon className={cn("size-4", className)} {...props} />
140
+ )
141
+ }
142
+
143
+ if (orientation === "right") {
144
+ return (
145
+ <ChevronRightIcon
146
+ className={cn("size-4", className)}
147
+ {...props}
148
+ />
149
+ )
150
+ }
151
+
152
+ return (
153
+ <ChevronDownIcon className={cn("size-4", className)} {...props} />
154
+ )
155
+ },
156
+ DayButton: CalendarDayButton,
157
+ WeekNumber: ({ children, ...props }) => {
158
+ return (
159
+ <td {...props}>
160
+ <div className="flex size-(--cell-size) items-center justify-center text-center">
161
+ {children}
162
+ </div>
163
+ </td>
164
+ )
165
+ },
166
+ ...components,
167
+ }}
168
+ {...props}
169
+ />
170
+ )
171
+ }
172
+
173
+ function CalendarDayButton({
174
+ className,
175
+ day,
176
+ modifiers,
177
+ ...props
178
+ }: React.ComponentProps<typeof DayButton>) {
179
+ const defaultClassNames = getDefaultClassNames()
180
+
181
+ const ref = React.useRef<HTMLButtonElement>(null)
182
+ React.useEffect(() => {
183
+ if (modifiers.focused) ref.current?.focus()
184
+ }, [modifiers.focused])
185
+
186
+ return (
187
+ <Button
188
+ ref={ref}
189
+ variant="ghost"
190
+ size="icon"
191
+ data-day={day.date.toLocaleDateString()}
192
+ data-selected-single={
193
+ modifiers.selected &&
194
+ !modifiers.range_start &&
195
+ !modifiers.range_end &&
196
+ !modifiers.range_middle
197
+ }
198
+ data-range-start={modifiers.range_start}
199
+ data-range-end={modifiers.range_end}
200
+ data-range-middle={modifiers.range_middle}
201
+ className={cn(
202
+ "data-[selected-single=true]:bg-primary data-[selected-single=true]:text-primary-foreground data-[range-middle=true]:bg-accent data-[range-middle=true]:text-accent-foreground data-[range-start=true]:bg-primary data-[range-start=true]:text-primary-foreground data-[range-end=true]:bg-primary data-[range-end=true]:text-primary-foreground group-data-[focused=true]/day:border-ring group-data-[focused=true]/day:ring-ring/50 dark:hover:text-accent-foreground flex aspect-square size-auto w-full min-w-(--cell-size) flex-col gap-1 leading-none font-normal group-data-[focused=true]/day:relative group-data-[focused=true]/day:z-10 group-data-[focused=true]/day:ring-[3px] data-[range-end=true]:rounded-md data-[range-end=true]:rounded-r-md data-[range-middle=true]:rounded-none data-[range-start=true]:rounded-md data-[range-start=true]:rounded-l-md [&>span]:text-xs [&>span]:opacity-70",
203
+ defaultClassNames.day,
204
+ className
205
+ )}
206
+ {...props}
207
+ />
208
+ )
209
+ }
210
+
211
+ export { Calendar, CalendarDayButton }
@@ -0,0 +1,30 @@
1
+ import * as React from "react"
2
+ import * as CheckboxPrimitive from "@radix-ui/react-checkbox"
3
+ import { CheckIcon } from "lucide-react"
4
+
5
+ import { cn } from "@/lib/utils"
6
+
7
+ function Checkbox({
8
+ className,
9
+ ...props
10
+ }: React.ComponentProps<typeof CheckboxPrimitive.Root>) {
11
+ return (
12
+ <CheckboxPrimitive.Root
13
+ data-slot="checkbox"
14
+ className={cn(
15
+ "peer border-input dark:bg-input/30 data-[state=checked]:bg-primary data-[state=checked]:text-primary-foreground dark:data-[state=checked]:bg-primary data-[state=checked]:border-primary focus-visible:border-ring focus-visible:ring-ring/50 aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive size-4 shrink-0 rounded-[4px] border shadow-xs transition-shadow outline-none focus-visible:ring-[3px] disabled:cursor-not-allowed disabled:opacity-50",
16
+ className
17
+ )}
18
+ {...props}
19
+ >
20
+ <CheckboxPrimitive.Indicator
21
+ data-slot="checkbox-indicator"
22
+ className="flex items-center justify-center text-current transition-none"
23
+ >
24
+ <CheckIcon className="size-3.5" />
25
+ </CheckboxPrimitive.Indicator>
26
+ </CheckboxPrimitive.Root>
27
+ )
28
+ }
29
+
30
+ export { Checkbox }