diff --git a/packages/frontend/package.json b/packages/frontend/package.json index 49736684..d1e6e78b 100644 --- a/packages/frontend/package.json +++ b/packages/frontend/package.json @@ -5,6 +5,7 @@ "dependencies": { "@fontsource/inter": "^5.0.16", "@material-tailwind/react": "^2.1.7", + "@radix-ui/react-checkbox": "^1.0.4", "@testing-library/jest-dom": "^5.17.0", "@testing-library/react": "^13.4.0", "@testing-library/user-event": "^13.5.0", diff --git a/packages/frontend/src/components/shared/Checkbox/Checkbox.theme.ts b/packages/frontend/src/components/shared/Checkbox/Checkbox.theme.ts new file mode 100644 index 00000000..e39b66f3 --- /dev/null +++ b/packages/frontend/src/components/shared/Checkbox/Checkbox.theme.ts @@ -0,0 +1,68 @@ +import { tv, type VariantProps } from 'tailwind-variants'; + +export const getCheckboxVariant = tv({ + slots: { + wrapper: ['group', 'flex', 'gap-3'], + indicator: [ + 'grid', + 'place-content-center', + 'text-transparent', + 'group-hover:text-controls-disabled', + 'focus-visible:text-controls-disabled', + 'group-focus-visible:text-controls-disabled', + 'data-[state=checked]:text-elements-on-primary', + 'data-[state=checked]:group-focus-visible:text-elements-on-primary', + 'data-[state=indeterminate]:text-elements-on-primary', + 'data-[state=checked]:data-[disabled]:text-elements-on-disabled-active', + ], + icon: ['w-3', 'h-3', 'stroke-current', 'text-current'], + input: [ + 'h-5', + 'w-5', + 'group', + 'border', + 'border-border-interactive/10', + 'bg-controls-tertiary', + 'rounded-md', + 'transition-all', + 'duration-150', + 'focus-ring', + 'shadow-button', + 'group-hover:border-border-interactive/[0.14]', + 'group-hover:bg-controls-tertiary', + 'data-[state=checked]:bg-controls-primary', + 'data-[state=checked]:hover:bg-controls-primary-hovered', + 'data-[state=checked]:focus-visible:bg-controls-primary-hovered', + 'data-[disabled]:bg-controls-disabled', + 'data-[disabled]:shadow-none', + 'data-[disabled]:hover:border-border-interactive/10', + 'data-[disabled]:cursor-not-allowed', + 'data-[state=checked]:data-[disabled]:bg-controls-disabled-active', + ], + label: [ + 'text-sm', + 'tracking-[-0.006em]', + 'text-elements-high-em', + 'flex', + 'flex-col', + 'gap-1', + 'px-1', + ], + description: ['text-xs', 'text-elements-low-em'], + }, + variants: { + disabled: { + true: { + wrapper: ['cursor-not-allowed'], + indicator: ['group-hover:text-transparent'], + input: [ + 'group-hover:border-border-interactive/[0.14]', + 'group-hover:bg-controls-disabled', + ], + label: ['cursor-not-allowed'], + }, + }, + }, +}); + +export type CheckboxVariants = VariantProps; diff --git a/packages/frontend/src/components/shared/Checkbox/Checkbox.tsx b/packages/frontend/src/components/shared/Checkbox/Checkbox.tsx new file mode 100644 index 00000000..0ba9d825 --- /dev/null +++ b/packages/frontend/src/components/shared/Checkbox/Checkbox.tsx @@ -0,0 +1,76 @@ +import React from 'react'; +import * as CheckboxRadix from '@radix-ui/react-checkbox'; +import { type CheckboxProps as CheckboxRadixProps } from '@radix-ui/react-checkbox'; + +import { getCheckboxVariant, type CheckboxVariants } from './Checkbox.theme'; +import { CheckIcon } from 'components/shared/CustomIcon'; + +interface CheckBoxProps extends CheckboxRadixProps, CheckboxVariants { + /** + * The label of the checkbox. + */ + label?: string; + /** + * The description of the checkbox. + */ + description?: string; +} + +/** + * Checkbox component is used to allow users to select one or more items from a set. + * It is a wrapper around the `@radix-ui/react-checkbox` component. + * + * It accepts all the props from `@radix-ui/react-checkbox` component and the variants from the theme. + * + * It also accepts `label` and `description` props to display the label and description of the checkbox. + * + * @example + * ```tsx + * + * ``` + */ +export const Checkbox = ({ + id, + className, + label, + description, + onCheckedChange, + ...props +}: CheckBoxProps) => { + const { + wrapper: wrapperStyle, + indicator: indicatorStyle, + icon: iconStyle, + input: inputStyle, + label: labelStyle, + description: descriptionStyle, + } = getCheckboxVariant({ + disabled: props?.disabled, + }); + return ( +
+ + + + + + {label && ( + + )} +
+ ); +}; diff --git a/packages/frontend/src/components/shared/Checkbox/index.ts b/packages/frontend/src/components/shared/Checkbox/index.ts new file mode 100644 index 00000000..f5c939fa --- /dev/null +++ b/packages/frontend/src/components/shared/Checkbox/index.ts @@ -0,0 +1 @@ +export * from './Checkbox'; diff --git a/packages/frontend/src/components/shared/CustomIcon/CheckIcon.tsx b/packages/frontend/src/components/shared/CustomIcon/CheckIcon.tsx new file mode 100644 index 00000000..e1096cb1 --- /dev/null +++ b/packages/frontend/src/components/shared/CustomIcon/CheckIcon.tsx @@ -0,0 +1,22 @@ +import React from 'react'; +import { CustomIcon, CustomIconProps } from './CustomIcon'; + +export const CheckIcon = (props: CustomIconProps) => { + return ( + + + + ); +}; diff --git a/packages/frontend/src/components/shared/CustomIcon/index.ts b/packages/frontend/src/components/shared/CustomIcon/index.ts index e4b51032..34b7f485 100644 --- a/packages/frontend/src/components/shared/CustomIcon/index.ts +++ b/packages/frontend/src/components/shared/CustomIcon/index.ts @@ -1,5 +1,6 @@ export * from './PlusIcon'; export * from './CustomIcon'; +export * from './CheckIcon'; export * from './ChevronGrabberHorizontal'; export * from './ChevronLeft'; export * from './ChevronRight'; diff --git a/packages/frontend/src/pages/components/index.tsx b/packages/frontend/src/pages/components/index.tsx index 775acbb1..28b62579 100644 --- a/packages/frontend/src/pages/components/index.tsx +++ b/packages/frontend/src/pages/components/index.tsx @@ -1,5 +1,6 @@ import { Button, ButtonOrLinkProps } from 'components/shared/Button'; import { Calendar } from 'components/shared/Calendar'; +import { Checkbox } from 'components/shared/Checkbox'; import { PlusIcon } from 'components/shared/CustomIcon'; import React, { useState } from 'react'; import { Value } from 'react-calendar/dist/cjs/shared/types'; @@ -77,6 +78,36 @@ const Page = () => {
+ +
+

Checkbox

+
+ {Array.from({ length: 5 }).map((_, index) => ( + + ))} +
+
+ {Array.from({ length: 2 }).map((_, index) => ( + + ))} +
+
+ +
+

Calendar

diff --git a/yarn.lock b/yarn.lock index 8845c973..42d230b9 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1280,7 +1280,7 @@ resolved "https://registry.npmjs.org/@babel/regjsgen/-/regjsgen-0.8.0.tgz" integrity sha512-x/rqGMdzj+fWZvCOYForTghzbtqPDZ5gPwaoNGHdgDfF2QA/XZbCBp4Moo5scrkAMPhB7z26XM/AaHuIJdgauA== -"@babel/runtime@^7.10.4", "@babel/runtime@^7.23.7", "@babel/runtime@^7.3.1": +"@babel/runtime@^7.10.4", "@babel/runtime@^7.13.10", "@babel/runtime@^7.23.7", "@babel/runtime@^7.3.1": version "7.23.9" resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.23.9.tgz#47791a15e4603bb5f905bc0753801cf21d6345f7" integrity sha512-0CX6F+BI2s9dkUqr08KFrAIZgNFj75rdBU/DjCyYLIaV/quFjkk6T+EJ2LkZHyZTbEV4L5p97mNkUsHl2wLFAw== @@ -3277,6 +3277,104 @@ resolved "https://registry.yarnpkg.com/@protobufjs/utf8/-/utf8-1.1.0.tgz#a777360b5b39a1a2e5106f8e858f2fd2d060c570" integrity sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw== +"@radix-ui/primitive@1.0.1": + version "1.0.1" + resolved "https://registry.yarnpkg.com/@radix-ui/primitive/-/primitive-1.0.1.tgz#e46f9958b35d10e9f6dc71c497305c22e3e55dbd" + integrity sha512-yQ8oGX2GVsEYMWGxcovu1uGWPCxV5BFfeeYxqPmuAzUyLT9qmaMXSAhXpb0WrspIeqYzdJpkh2vHModJPgRIaw== + dependencies: + "@babel/runtime" "^7.13.10" + +"@radix-ui/react-checkbox@^1.0.4": + version "1.0.4" + resolved "https://registry.yarnpkg.com/@radix-ui/react-checkbox/-/react-checkbox-1.0.4.tgz#98f22c38d5010dd6df4c5744cac74087e3275f4b" + integrity sha512-CBuGQa52aAYnADZVt/KBQzXrwx6TqnlwtcIPGtVt5JkkzQwMOLJjPukimhfKEr4GQNd43C+djUh5Ikopj8pSLg== + dependencies: + "@babel/runtime" "^7.13.10" + "@radix-ui/primitive" "1.0.1" + "@radix-ui/react-compose-refs" "1.0.1" + "@radix-ui/react-context" "1.0.1" + "@radix-ui/react-presence" "1.0.1" + "@radix-ui/react-primitive" "1.0.3" + "@radix-ui/react-use-controllable-state" "1.0.1" + "@radix-ui/react-use-previous" "1.0.1" + "@radix-ui/react-use-size" "1.0.1" + +"@radix-ui/react-compose-refs@1.0.1": + version "1.0.1" + resolved "https://registry.yarnpkg.com/@radix-ui/react-compose-refs/-/react-compose-refs-1.0.1.tgz#7ed868b66946aa6030e580b1ffca386dd4d21989" + integrity sha512-fDSBgd44FKHa1FRMU59qBMPFcl2PZE+2nmqunj+BWFyYYjnhIDWL2ItDs3rrbJDQOtzt5nIebLCQc4QRfz6LJw== + dependencies: + "@babel/runtime" "^7.13.10" + +"@radix-ui/react-context@1.0.1": + version "1.0.1" + resolved "https://registry.yarnpkg.com/@radix-ui/react-context/-/react-context-1.0.1.tgz#fe46e67c96b240de59187dcb7a1a50ce3e2ec00c" + integrity sha512-ebbrdFoYTcuZ0v4wG5tedGnp9tzcV8awzsxYph7gXUyvnNLuTIcCk1q17JEbnVhXAKG9oX3KtchwiMIAYp9NLg== + dependencies: + "@babel/runtime" "^7.13.10" + +"@radix-ui/react-presence@1.0.1": + version "1.0.1" + resolved "https://registry.yarnpkg.com/@radix-ui/react-presence/-/react-presence-1.0.1.tgz#491990ba913b8e2a5db1b06b203cb24b5cdef9ba" + integrity sha512-UXLW4UAbIY5ZjcvzjfRFo5gxva8QirC9hF7wRE4U5gz+TP0DbRk+//qyuAQ1McDxBt1xNMBTaciFGvEmJvAZCg== + dependencies: + "@babel/runtime" "^7.13.10" + "@radix-ui/react-compose-refs" "1.0.1" + "@radix-ui/react-use-layout-effect" "1.0.1" + +"@radix-ui/react-primitive@1.0.3": + version "1.0.3" + resolved "https://registry.yarnpkg.com/@radix-ui/react-primitive/-/react-primitive-1.0.3.tgz#d49ea0f3f0b2fe3ab1cb5667eb03e8b843b914d0" + integrity sha512-yi58uVyoAcK/Nq1inRY56ZSjKypBNKTa/1mcL8qdl6oJeEaDbOldlzrGn7P6Q3Id5d+SYNGc5AJgc4vGhjs5+g== + dependencies: + "@babel/runtime" "^7.13.10" + "@radix-ui/react-slot" "1.0.2" + +"@radix-ui/react-slot@1.0.2": + version "1.0.2" + resolved "https://registry.yarnpkg.com/@radix-ui/react-slot/-/react-slot-1.0.2.tgz#a9ff4423eade67f501ffb32ec22064bc9d3099ab" + integrity sha512-YeTpuq4deV+6DusvVUW4ivBgnkHwECUu0BiN43L5UCDFgdhsRUWAghhTF5MbvNTPzmiFOx90asDSUjWuCNapwg== + dependencies: + "@babel/runtime" "^7.13.10" + "@radix-ui/react-compose-refs" "1.0.1" + +"@radix-ui/react-use-callback-ref@1.0.1": + version "1.0.1" + resolved "https://registry.yarnpkg.com/@radix-ui/react-use-callback-ref/-/react-use-callback-ref-1.0.1.tgz#f4bb1f27f2023c984e6534317ebc411fc181107a" + integrity sha512-D94LjX4Sp0xJFVaoQOd3OO9k7tpBYNOXdVhkltUbGv2Qb9OXdrg/CpsjlZv7ia14Sylv398LswWBVVu5nqKzAQ== + dependencies: + "@babel/runtime" "^7.13.10" + +"@radix-ui/react-use-controllable-state@1.0.1": + version "1.0.1" + resolved "https://registry.yarnpkg.com/@radix-ui/react-use-controllable-state/-/react-use-controllable-state-1.0.1.tgz#ecd2ced34e6330caf89a82854aa2f77e07440286" + integrity sha512-Svl5GY5FQeN758fWKrjM6Qb7asvXeiZltlT4U2gVfl8Gx5UAv2sMR0LWo8yhsIZh2oQ0eFdZ59aoOOMV7b47VA== + dependencies: + "@babel/runtime" "^7.13.10" + "@radix-ui/react-use-callback-ref" "1.0.1" + +"@radix-ui/react-use-layout-effect@1.0.1": + version "1.0.1" + resolved "https://registry.yarnpkg.com/@radix-ui/react-use-layout-effect/-/react-use-layout-effect-1.0.1.tgz#be8c7bc809b0c8934acf6657b577daf948a75399" + integrity sha512-v/5RegiJWYdoCvMnITBkNNx6bCj20fiaJnWtRkU18yITptraXjffz5Qbn05uOiQnOvi+dbkznkoaMltz1GnszQ== + dependencies: + "@babel/runtime" "^7.13.10" + +"@radix-ui/react-use-previous@1.0.1": + version "1.0.1" + resolved "https://registry.yarnpkg.com/@radix-ui/react-use-previous/-/react-use-previous-1.0.1.tgz#b595c087b07317a4f143696c6a01de43b0d0ec66" + integrity sha512-cV5La9DPwiQ7S0gf/0qiD6YgNqM5Fk97Kdrlc5yBcrF3jyEZQwm7vYFqMo4IfeHgJXsRaMvLABFtd0OVEmZhDw== + dependencies: + "@babel/runtime" "^7.13.10" + +"@radix-ui/react-use-size@1.0.1": + version "1.0.1" + resolved "https://registry.yarnpkg.com/@radix-ui/react-use-size/-/react-use-size-1.0.1.tgz#1c5f5fea940a7d7ade77694bb98116fb49f870b2" + integrity sha512-ibay+VqrgcaI6veAojjofPATwledXiSmX+C0KrBk/xgpX9rBzPV3OsfwlhQdUOFbh+LKQorLYT+xTXW9V8yd0g== + dependencies: + "@babel/runtime" "^7.13.10" + "@radix-ui/react-use-layout-effect" "1.0.1" + "@remix-run/router@1.13.1": version "1.13.1" resolved "https://registry.yarnpkg.com/@remix-run/router/-/router-1.13.1.tgz#07e2a8006f23a3bc898b3f317e0a58cc8076b86e"