takeat-design-system-ui-kit 0.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (224) hide show
  1. package/.storybook/main.ts +17 -0
  2. package/.storybook/preview.tsx +41 -0
  3. package/README.md +50 -0
  4. package/cli/create-story.js +65 -0
  5. package/eslint.config.js +26 -0
  6. package/index.html +13 -0
  7. package/package.json +66 -0
  8. package/public/vite.svg +1 -0
  9. package/src/App.css +42 -0
  10. package/src/App.tsx +7 -0
  11. package/src/LibraryProvider.tsx +17 -0
  12. package/src/assets/Spinner.svg +3 -0
  13. package/src/assets/icons/addCircleFilled.svg +8 -0
  14. package/src/assets/icons/arrowDown.svg +8 -0
  15. package/src/assets/icons/arrowDropDown.svg +8 -0
  16. package/src/assets/icons/arrowDropUp.svg +8 -0
  17. package/src/assets/icons/arrowUp.svg +8 -0
  18. package/src/assets/icons/barGraph.svg +8 -0
  19. package/src/assets/icons/bell.svg +8 -0
  20. package/src/assets/icons/bellFilled.svg +8 -0
  21. package/src/assets/icons/bellNotification.svg +8 -0
  22. package/src/assets/icons/bellNotificationFilled.svg +8 -0
  23. package/src/assets/icons/bill.svg +8 -0
  24. package/src/assets/icons/billFilled.svg +8 -0
  25. package/src/assets/icons/bookOpen.svg +8 -0
  26. package/src/assets/icons/bookOpenFilled.svg +8 -0
  27. package/src/assets/icons/bullhorn.svg +3 -0
  28. package/src/assets/icons/cached.svg +8 -0
  29. package/src/assets/icons/calendar.svg +8 -0
  30. package/src/assets/icons/calendarCheck.svg +8 -0
  31. package/src/assets/icons/calendarCheckFilled.svg +8 -0
  32. package/src/assets/icons/calendarFilled.svg +8 -0
  33. package/src/assets/icons/cashier.svg +35 -0
  34. package/src/assets/icons/cashierFilled.svg +6 -0
  35. package/src/assets/icons/chat.svg +8 -0
  36. package/src/assets/icons/chatFilled.svg +8 -0
  37. package/src/assets/icons/check.svg +8 -0
  38. package/src/assets/icons/checkbox.svg +8 -0
  39. package/src/assets/icons/checkboxChecked.svg +8 -0
  40. package/src/assets/icons/checkboxCheckedFilled.svg +11 -0
  41. package/src/assets/icons/chevronDown.svg +3 -0
  42. package/src/assets/icons/chevronLeft.svg +3 -0
  43. package/src/assets/icons/chevronRight.svg +3 -0
  44. package/src/assets/icons/chevronUp.svg +3 -0
  45. package/src/assets/icons/clipboardCheck.svg +8 -0
  46. package/src/assets/icons/clipboardCheckFilled.svg +8 -0
  47. package/src/assets/icons/clock.svg +8 -0
  48. package/src/assets/icons/close.svg +8 -0
  49. package/src/assets/icons/closeCircle.svg +8 -0
  50. package/src/assets/icons/closeCircleFilled.svg +8 -0
  51. package/src/assets/icons/cloud.svg +8 -0
  52. package/src/assets/icons/cloudFilled.svg +8 -0
  53. package/src/assets/icons/copy.svg +4 -0
  54. package/src/assets/icons/copyFilled.svg +4 -0
  55. package/src/assets/icons/deleteFilled.svg +8 -0
  56. package/src/assets/icons/dollarSign.svg +8 -0
  57. package/src/assets/icons/download.svg +8 -0
  58. package/src/assets/icons/exchange.svg +8 -0
  59. package/src/assets/icons/exclamation.svg +8 -0
  60. package/src/assets/icons/externalLink.svg +4 -0
  61. package/src/assets/icons/eye.svg +3 -0
  62. package/src/assets/icons/eyeFilled.svg +3 -0
  63. package/src/assets/icons/eyeSlash.svg +8 -0
  64. package/src/assets/icons/eyeSlashFilled.svg +8 -0
  65. package/src/assets/icons/filterList.svg +10 -0
  66. package/src/assets/icons/folderOpen.svg +8 -0
  67. package/src/assets/icons/folderOpenFilled.svg +8 -0
  68. package/src/assets/icons/hand.svg +8 -0
  69. package/src/assets/icons/handFilled.svg +8 -0
  70. package/src/assets/icons/helpFilled.svg +8 -0
  71. package/src/assets/icons/home.svg +8 -0
  72. package/src/assets/icons/homeFilled.svg +9 -0
  73. package/src/assets/icons/idCard.svg +8 -0
  74. package/src/assets/icons/idCardFilled.svg +8 -0
  75. package/src/assets/icons/info.svg +8 -0
  76. package/src/assets/icons/infoFilled.svg +8 -0
  77. package/src/assets/icons/instagram.svg +5 -0
  78. package/src/assets/icons/like.svg +3 -0
  79. package/src/assets/icons/likeFilled.svg +4 -0
  80. package/src/assets/icons/loading.svg +17 -0
  81. package/src/assets/icons/logout.svg +4 -0
  82. package/src/assets/icons/mail.svg +8 -0
  83. package/src/assets/icons/mailFilled.svg +8 -0
  84. package/src/assets/icons/manager.svg +4 -0
  85. package/src/assets/icons/menu.svg +8 -0
  86. package/src/assets/icons/menuCircles.svg +8 -0
  87. package/src/assets/icons/minus.svg +8 -0
  88. package/src/assets/icons/minusCircle.svg +8 -0
  89. package/src/assets/icons/minusCircleFilled.svg +8 -0
  90. package/src/assets/icons/money.svg +8 -0
  91. package/src/assets/icons/moneyCircle.svg +8 -0
  92. package/src/assets/icons/moneyFilled.svg +8 -0
  93. package/src/assets/icons/motorcycle.svg +3 -0
  94. package/src/assets/icons/pencil.svg +3 -0
  95. package/src/assets/icons/pencilFilled.svg +4 -0
  96. package/src/assets/icons/percent.svg +8 -0
  97. package/src/assets/icons/phone.svg +8 -0
  98. package/src/assets/icons/phoneFilled.svg +8 -0
  99. package/src/assets/icons/piggyBank.svg +8 -0
  100. package/src/assets/icons/piggyBankFilled.svg +8 -0
  101. package/src/assets/icons/playCircle.svg +8 -0
  102. package/src/assets/icons/playCircleFilled.svg +8 -0
  103. package/src/assets/icons/playSquare.svg +8 -0
  104. package/src/assets/icons/playSquareFilled.svg +8 -0
  105. package/src/assets/icons/plus.svg +8 -0
  106. package/src/assets/icons/plusCircle.svg +8 -0
  107. package/src/assets/icons/power.svg +8 -0
  108. package/src/assets/icons/printer.svg +8 -0
  109. package/src/assets/icons/printerFilled.svg +8 -0
  110. package/src/assets/icons/qrCode.svg +8 -0
  111. package/src/assets/icons/question.svg +8 -0
  112. package/src/assets/icons/radioButton.svg +8 -0
  113. package/src/assets/icons/radioButtonChecked.svg +8 -0
  114. package/src/assets/icons/refresh.svg +8 -0
  115. package/src/assets/icons/scheduleFilled.svg +8 -0
  116. package/src/assets/icons/search.svg +8 -0
  117. package/src/assets/icons/settings.svg +4 -0
  118. package/src/assets/icons/settingsFilled.svg +3 -0
  119. package/src/assets/icons/star.svg +8 -0
  120. package/src/assets/icons/starFilled.svg +8 -0
  121. package/src/assets/icons/store.svg +8 -0
  122. package/src/assets/icons/storeFilled.svg +8 -0
  123. package/src/assets/icons/takeatIcon.svg +6 -0
  124. package/src/assets/icons/takeatIconFilled.svg +6 -0
  125. package/src/assets/icons/ticket.svg +8 -0
  126. package/src/assets/icons/ticketFilled.svg +8 -0
  127. package/src/assets/icons/trash.svg +8 -0
  128. package/src/assets/icons/trendingDown.svg +8 -0
  129. package/src/assets/icons/trendingUp.svg +8 -0
  130. package/src/assets/icons/user.svg +8 -0
  131. package/src/assets/icons/userAdd.svg +8 -0
  132. package/src/assets/icons/userAddFilled.svg +8 -0
  133. package/src/assets/icons/userCircle.svg +8 -0
  134. package/src/assets/icons/userCircleFilled.svg +8 -0
  135. package/src/assets/icons/userFilled.svg +8 -0
  136. package/src/assets/icons/utensils.svg +8 -0
  137. package/src/assets/icons/waiter.svg +3 -0
  138. package/src/assets/icons/warning.svg +8 -0
  139. package/src/assets/icons/warningFilled.svg +8 -0
  140. package/src/assets/icons/whatsapp.svg +10 -0
  141. package/src/assets/icons/whatsappFilled.svg +10 -0
  142. package/src/components/Accordion/Accordion.stories.tsx +19 -0
  143. package/src/components/Accordion/index.tsx +8 -0
  144. package/src/components/Accordion/styles.ts +1 -0
  145. package/src/components/Badge/Badge.stories.tsx +21 -0
  146. package/src/components/Badge/index.tsx +8 -0
  147. package/src/components/Badge/styles.ts +1 -0
  148. package/src/components/Button/Button.stories.tsx +186 -0
  149. package/src/components/Button/index.tsx +71 -0
  150. package/src/components/Button/styles.ts +216 -0
  151. package/src/components/Calendar/Calendar.stories.tsx +69 -0
  152. package/src/components/Calendar/CalendarComponents/index.tsx +214 -0
  153. package/src/components/Calendar/CalendarComponents/styles.ts +46 -0
  154. package/src/components/Calendar/index.tsx +290 -0
  155. package/src/components/Calendar/styles.ts +203 -0
  156. package/src/components/Divider/Divider.stories.tsx +57 -0
  157. package/src/components/Divider/index.tsx +22 -0
  158. package/src/components/Divider/styles.ts +25 -0
  159. package/src/components/FormItens/Checkbox/Checkbox.stories.tsx +50 -0
  160. package/src/components/FormItens/Checkbox/index.tsx +34 -0
  161. package/src/components/FormItens/Checkbox/styles.ts +96 -0
  162. package/src/components/FormItens/Input/Input.stories.tsx +138 -0
  163. package/src/components/FormItens/Input/index.tsx +72 -0
  164. package/src/components/FormItens/Input/styles.ts +136 -0
  165. package/src/components/FormItens/Radio/Radio.stories.tsx +76 -0
  166. package/src/components/FormItens/Radio/index.tsx +35 -0
  167. package/src/components/FormItens/Radio/styles.ts +112 -0
  168. package/src/components/FormItens/Select/Select.stories.tsx +83 -0
  169. package/src/components/FormItens/Select/index.tsx +117 -0
  170. package/src/components/FormItens/Select/styles.ts +149 -0
  171. package/src/components/FormItens/Switch/Switch.stories.tsx +127 -0
  172. package/src/components/FormItens/Switch/index.tsx +59 -0
  173. package/src/components/FormItens/Switch/styles.ts +123 -0
  174. package/src/components/Icon/Icon.stories.tsx +87 -0
  175. package/src/components/Icon/index.tsx +24 -0
  176. package/src/components/Icon/styles.ts +36 -0
  177. package/src/components/Layouts/ColumnsGrid/ColumnsGrid.stories.tsx +66 -0
  178. package/src/components/Layouts/ColumnsGrid/index.tsx +35 -0
  179. package/src/components/Layouts/ColumnsGrid/styles.ts +21 -0
  180. package/src/components/Layouts/Grid/Grid.stories.tsx +61 -0
  181. package/src/components/Layouts/Grid/index.tsx +42 -0
  182. package/src/components/Layouts/Grid/styles.ts +16 -0
  183. package/src/components/Layouts/GridArea/GridArea.stories.tsx +64 -0
  184. package/src/components/Layouts/GridArea/index.tsx +51 -0
  185. package/src/components/Layouts/GridArea/styles.ts +12 -0
  186. package/src/components/Layouts/ResponsiveGrid/ResponsiveGrid.stories.tsx +71 -0
  187. package/src/components/Layouts/ResponsiveGrid/index.tsx +34 -0
  188. package/src/components/Layouts/ResponsiveGrid/styles.ts +19 -0
  189. package/src/components/MockComponent/index.tsx +9 -0
  190. package/src/components/MockComponent/styles.ts +14 -0
  191. package/src/components/Modal/Modal.stories.tsx +75 -0
  192. package/src/components/Modal/index.tsx +81 -0
  193. package/src/components/Modal/styles.ts +75 -0
  194. package/src/components/NotificationBanner/NotificationBanner.stories.tsx +49 -0
  195. package/src/components/NotificationBanner/index.tsx +54 -0
  196. package/src/components/NotificationBanner/styles.ts +48 -0
  197. package/src/components/SingleTab/SingleTab.stories.tsx +50 -0
  198. package/src/components/SingleTab/index.tsx +36 -0
  199. package/src/components/SingleTab/styles.ts +110 -0
  200. package/src/components/Spinner/Spinner.stories.tsx +20 -0
  201. package/src/components/Spinner/index.tsx +14 -0
  202. package/src/components/Spinner/styles.ts +31 -0
  203. package/src/components/StoriesComponents/index.tsx +0 -0
  204. package/src/components/StoriesComponents/styles.ts +17 -0
  205. package/src/components/TabGroup/TabGroup.stories.tsx +64 -0
  206. package/src/components/TabGroup/index.tsx +75 -0
  207. package/src/components/TabGroup/styles.ts +7 -0
  208. package/src/components/Tooltip/Tooltip.stories.tsx +78 -0
  209. package/src/components/Tooltip/index.tsx +38 -0
  210. package/src/index.css +68 -0
  211. package/src/index.ts +19 -0
  212. package/src/main.tsx +10 -0
  213. package/src/styled.d.ts +6 -0
  214. package/src/svg.d.ts +9 -0
  215. package/src/utils/GlobalStyle.ts +47 -0
  216. package/src/utils/consts.ts +241 -0
  217. package/src/utils/functions.ts +327 -0
  218. package/src/utils/globalTypes.ts +8 -0
  219. package/src/utils/icons.tsx +15 -0
  220. package/src/vite-env.d.ts +1 -0
  221. package/tsconfig.app.json +24 -0
  222. package/tsconfig.json +7 -0
  223. package/tsconfig.node.json +22 -0
  224. package/vite.config.ts +8 -0
@@ -0,0 +1,83 @@
1
+ import { Meta, StoryObj } from "@storybook/react";
2
+ import { Select } from ".";
3
+
4
+ const meta: Meta<typeof Select> = {
5
+ component: Select,
6
+ title: "Design System/Select",
7
+ argTypes: {
8
+ options: {
9
+ description:
10
+ "Array de opções do select no padrão: `{ value: any, label: string }`",
11
+ },
12
+ isMulti: {
13
+ control: {
14
+ type: "boolean",
15
+ },
16
+ },
17
+ isClearable: {
18
+ control: {
19
+ type: "boolean",
20
+ },
21
+ },
22
+ isSearchable: {
23
+ control: {
24
+ type: "boolean",
25
+ },
26
+ },
27
+ register: {
28
+ description:
29
+ 'Usado para integrar ao React Hook Form. Exemplo: `register("name", { required: "Campo obrigatório" })`',
30
+ control: {
31
+ disable: true,
32
+ },
33
+ },
34
+ name: {
35
+ description:
36
+ "Para integrar ao React Hook Form, o select requer que seja definido um 'name' igual ao que é passado para o register",
37
+ control: {
38
+ type: "text",
39
+ },
40
+ },
41
+ control: {
42
+ description:
43
+ "Para integrar ao React Hook Form, o select requer que seja definido um 'control' que é fornecido pelo useForm() do React Hook Form",
44
+ control: {
45
+ disable: true,
46
+ },
47
+ },
48
+ error: {
49
+ control: {
50
+ type: "text",
51
+ },
52
+ },
53
+ info: {
54
+ control: {
55
+ type: "text",
56
+ },
57
+ },
58
+ },
59
+ args: {
60
+ label: "Teste select",
61
+ isLoading: false,
62
+ isDisabled: false,
63
+ options: [
64
+ { value: "chocolate", label: "Chocolate" },
65
+ { value: "strawberry", label: "Strawberry" },
66
+ { value: "vanilla", label: "Vanilla" },
67
+ ],
68
+ info: "Informação adicional",
69
+ error: "",
70
+ isMulti: false,
71
+ isSearchable: false,
72
+ isClearable: false,
73
+ name: "teste",
74
+ },
75
+ };
76
+
77
+ export default meta;
78
+
79
+ type Story = StoryObj<typeof Select>;
80
+
81
+ export const Example: Story = {
82
+ args: {},
83
+ };
@@ -0,0 +1,117 @@
1
+ import ReactSelect, { Props as ReactSelectProps } from "react-select";
2
+ import { AdditionalInfo, SelectWrapper } from "./styles";
3
+ import { Controller, UseFormRegisterReturn } from "react-hook-form";
4
+ import React from "react";
5
+ import { Icon } from "../../Icon";
6
+ import { Spinner } from "../../Spinner";
7
+ import { useTheme } from "styled-components";
8
+
9
+ interface Option {
10
+ label: string;
11
+ value: any;
12
+ }
13
+
14
+ interface CustomSelectProps extends ReactSelectProps<Option, false> {
15
+ name?: string;
16
+ label?: string;
17
+ register?: UseFormRegisterReturn;
18
+ control?: any;
19
+ error?: string;
20
+ info?: React.ReactNode | string;
21
+ isLoading?: boolean;
22
+ }
23
+
24
+ const RawSelect = ({
25
+ label,
26
+ error,
27
+ control,
28
+ info,
29
+ isDisabled,
30
+ isLoading,
31
+ ...props
32
+ }: CustomSelectProps) => {
33
+ const theme = useTheme();
34
+
35
+ return (
36
+ <SelectWrapper disabled={isDisabled || isLoading} hasError={!!error}>
37
+ {label}
38
+ <ReactSelect
39
+ components={{
40
+ DropdownIndicator: () => {
41
+ if (isLoading) {
42
+ return (
43
+ <Spinner
44
+ color={theme.colors.neutral.light}
45
+ size={16}
46
+ style={{ marginRight: 8 }}
47
+ />
48
+ );
49
+ }
50
+ return (
51
+ <Icon
52
+ className="custom-dropdown-icon"
53
+ icon="chevronDown"
54
+ size={28}
55
+ />
56
+ );
57
+ },
58
+ }}
59
+ isDisabled={isDisabled || isLoading}
60
+ classNamePrefix="react-select"
61
+ noOptionsMessage={() => "Nada encontrado"}
62
+ {...props}
63
+ />
64
+ {(!!control || !!error || !!info) && (
65
+ <AdditionalInfo
66
+ className="additional-info"
67
+ disabled={isDisabled || isLoading}
68
+ isError={!!error}
69
+ >
70
+ {error || info}
71
+ </AdditionalInfo>
72
+ )}
73
+ </SelectWrapper>
74
+ );
75
+ };
76
+
77
+ export const Select = ({
78
+ name,
79
+ label,
80
+ register,
81
+ control,
82
+ error,
83
+ info,
84
+ isLoading,
85
+ ...props
86
+ }: CustomSelectProps) => {
87
+ return control ? (
88
+ <Controller
89
+ name={name || ""}
90
+ control={control}
91
+ render={({ field }) => {
92
+ return (
93
+ <RawSelect
94
+ label={label}
95
+ error={error}
96
+ info={info}
97
+ control={control}
98
+ isLoading={isLoading}
99
+ isDisabled={props.isDisabled}
100
+ {...props}
101
+ {...field}
102
+ />
103
+ );
104
+ }}
105
+ />
106
+ ) : (
107
+ <RawSelect
108
+ label={label}
109
+ error={error}
110
+ info={info}
111
+ control={control}
112
+ isLoading={isLoading}
113
+ isDisabled={props.isDisabled}
114
+ {...props}
115
+ />
116
+ );
117
+ };
@@ -0,0 +1,149 @@
1
+ import styled from "styled-components";
2
+
3
+ interface SelectWrapperProps {
4
+ hasError?: boolean;
5
+ disabled?: boolean;
6
+ }
7
+
8
+ export const SelectWrapper = styled.label<SelectWrapperProps>`
9
+ display: flex;
10
+ flex-direction: column;
11
+ gap: 4px;
12
+ font-size: 16px;
13
+ font-style: normal;
14
+ font-weight: 600;
15
+ line-height: 24px;
16
+ letter-spacing: 0.15px;
17
+ color: ${({ theme, disabled }) =>
18
+ disabled ? theme.colors.neutral.light : theme.colors.neutral.dark};
19
+ width: fit-content;
20
+
21
+ .custom-dropdown-icon {
22
+ fill: ${({ theme, disabled }) =>
23
+ disabled ? theme.colors.neutral.light : theme.colors.neutral.dark};
24
+
25
+ padding-right: 8px;
26
+ }
27
+
28
+ .react-select__control {
29
+ border-radius: ${({ theme }) => theme.radius.m};
30
+ border-color: ${({ theme, hasError }) =>
31
+ hasError ? theme.colors.red.default : theme.colors.neutral.dark};
32
+ color: ${({ theme }) => theme.colors.neutral.dark};
33
+ font-size: 14px;
34
+ font-style: normal;
35
+ font-weight: 400;
36
+ line-height: 20px;
37
+ letter-spacing: 0.1px;
38
+ cursor: pointer;
39
+ }
40
+
41
+ [class$="-control"]:hover {
42
+ border-color: ${({ theme }) => theme.colors.neutral.dark};
43
+ }
44
+
45
+ .react-select__control--is-focused {
46
+ outline: none;
47
+ border-color: ${({ theme }) => theme.colors.blue.dark};
48
+ box-shadow: none;
49
+ }
50
+
51
+ .react-select__control--is-disabled {
52
+ background-color: transparent;
53
+ border-color: ${({ theme }) => theme.colors.neutral.light};
54
+ color: ${({ theme }) => theme.colors.neutral.light};
55
+
56
+ .react-select__placeholder {
57
+ color: ${({ theme }) => theme.colors.neutral.light};
58
+ }
59
+ }
60
+
61
+ .react-select__indicator-separator {
62
+ display: none;
63
+ }
64
+
65
+ .react-select__menu {
66
+ border-radius: ${({ theme }) => theme.radius.m};
67
+ padding: ${({ theme }) => theme.spacing.xs};
68
+ border-color: transparent;
69
+ box-shadow: ${({ theme }) => theme.shadows.default};
70
+ }
71
+
72
+ .react-select__menu-list {
73
+ padding: 0;
74
+ }
75
+
76
+ .react-select__option {
77
+ padding: ${({ theme }) => theme.spacing.xs};
78
+ border-radius: ${({ theme }) => theme.radius.s};
79
+ color: ${({ theme }) => theme.colors.neutral.dark};
80
+ font-family: ${({ theme }) => theme.typography.family.default};
81
+ font-size: 14px;
82
+ font-style: normal;
83
+ font-weight: 400;
84
+ line-height: 20px;
85
+ letter-spacing: 0.014px;
86
+ transition: all 0.3s;
87
+ cursor: pointer;
88
+
89
+ &:hover {
90
+ background-color: ${({ theme }) => theme.colors.neutral.lighter};
91
+ }
92
+ }
93
+
94
+ .react-select__option--is-focused {
95
+ background-color: transparent;
96
+ }
97
+
98
+ .react-select__option--is-selected {
99
+ background-color: ${({ theme }) => theme.colors.primary.lightest};
100
+ color: ${({ theme }) => theme.colors.neutral.darker};
101
+ }
102
+
103
+ .react-select__multi-value {
104
+ border-radius: ${({ theme }) => theme.radius.s};
105
+ background-color: ${({ theme }) => theme.colors.neutral.lighter};
106
+ }
107
+
108
+ .react-select__multi-value__label {
109
+ padding: ${({ theme }) => theme.spacing.xxs};
110
+ }
111
+
112
+ .react-select__multi-value__remove:hover {
113
+ background-color: ${({ theme }) => theme.colors.red.lightest};
114
+
115
+ svg {
116
+ fill: ${({ theme }) => theme.colors.red.default};
117
+ }
118
+ }
119
+
120
+ .react-select__menu-notice {
121
+ color: ${({ theme }) => theme.colors.neutral.default};
122
+ font-family: ${({ theme }) => theme.typography.family.default};
123
+ font-size: 14px;
124
+ font-style: normal;
125
+ font-weight: 400;
126
+ line-height: 20px;
127
+ letter-spacing: 0.014px;
128
+ }
129
+ `;
130
+
131
+ interface AdditionalInfo {
132
+ isError?: boolean;
133
+ disabled?: boolean;
134
+ }
135
+
136
+ export const AdditionalInfo = styled.div<AdditionalInfo>`
137
+ color: ${({ theme, isError, disabled }) =>
138
+ isError
139
+ ? theme.colors.primary.default
140
+ : disabled
141
+ ? theme.colors.neutral.light
142
+ : theme.colors.neutral.dark};
143
+ font-size: 12px;
144
+ font-style: normal;
145
+ font-weight: 400;
146
+ line-height: 16px;
147
+ height: 16px;
148
+ letter-spacing: 0.4px;
149
+ `;
@@ -0,0 +1,127 @@
1
+ import { Meta, StoryObj } from "@storybook/react";
2
+ import { Switch } from ".";
3
+ import { Subtitle } from "../../StoriesComponents/styles";
4
+
5
+ const meta: Meta<typeof Switch> = {
6
+ title: "Design System/Switch",
7
+ component: Switch,
8
+ parameters: {
9
+ componentSubtitle: (
10
+ <Subtitle>
11
+ Um Switch é um componente de interface que permite ao usuário alternar
12
+ entre dois estados mutuamente exclusivos, como ligar ou desligar uma
13
+ funcionalidade.
14
+ <br />
15
+ <br /> Esses controles são mais adequados para{" "}
16
+ <b>ações imediatas e contextuais</b>, onde o efeito da mudança de estado
17
+ é percebido instantaneamente. É ideal para ajustes simples e rápidos,
18
+ <b> sem necessidade de confirmação adicional.</b>
19
+ </Subtitle>
20
+ ),
21
+ },
22
+ argTypes: {
23
+ label: {
24
+ control: {
25
+ type: "text",
26
+ },
27
+ },
28
+ labelPosition: {
29
+ control: {
30
+ type: "inline-radio",
31
+ options: ["left", "right", "top", "bottom"],
32
+ },
33
+ },
34
+ customColor: {
35
+ description: "Cor customizada do switch ativo (hexadecimal)",
36
+ control: {
37
+ type: "color",
38
+ },
39
+ },
40
+ isLoading: {
41
+ control: {
42
+ type: "boolean",
43
+ },
44
+ },
45
+ checked: {
46
+ description: "Valor do switch caso precise ter estado controlado",
47
+ control: {
48
+ type: "boolean",
49
+ },
50
+ },
51
+ onChange: {
52
+ description:
53
+ "Função de callback para quando o switch for alterado. Retorna um ChangeEvent. Exemplo: `onChange={(e) => console.log(e.target.checked)}`",
54
+ action: "changed",
55
+ },
56
+ register: {
57
+ description:
58
+ 'Usado para integrar ao React Hook Form. Exemplo: `register("name", { required: "Campo obrigatório" })`',
59
+ control: {
60
+ disable: true,
61
+ },
62
+ },
63
+ },
64
+
65
+ args: {
66
+ label: "Switch",
67
+ labelPosition: "right",
68
+ disabled: false,
69
+ isLoading: false,
70
+ customColor: undefined,
71
+ },
72
+ };
73
+
74
+ export default meta;
75
+
76
+ type Story = StoryObj<typeof Switch>;
77
+
78
+ export const Example: Story = {
79
+ name: "Exemplo",
80
+ };
81
+
82
+ export const List: Story = {
83
+ name: "Lista de todos os estados",
84
+ render: () => {
85
+ return (
86
+ <div style={{ display: "flex", flexDirection: "column", gap: 8 }}>
87
+ <Switch label="Marcado" checked />
88
+ <Switch label="Marcado e desabilitado" disabled checked />
89
+ <Switch label="Desmarcado" checked={false} />
90
+ <Switch label="Desmarcado e desabilitado" disabled />
91
+ </div>
92
+ );
93
+ },
94
+ // Disable all controls
95
+ argTypes: {
96
+ label: {
97
+ table: {
98
+ disable: true,
99
+ },
100
+ },
101
+ checked: {
102
+ table: {
103
+ disable: true,
104
+ },
105
+ },
106
+ disabled: {
107
+ table: {
108
+ disable: true,
109
+ },
110
+ },
111
+ isLoading: {
112
+ table: {
113
+ disable: true,
114
+ },
115
+ },
116
+ labelPosition: {
117
+ table: {
118
+ disable: true,
119
+ },
120
+ },
121
+ customColor: {
122
+ table: {
123
+ disable: true,
124
+ },
125
+ },
126
+ },
127
+ };
@@ -0,0 +1,59 @@
1
+ import { UseFormRegisterReturn } from "react-hook-form";
2
+ import { generateColorVariants } from "../../../utils/functions";
3
+ import { SwitchArea, SwitchLabel } from "./styles";
4
+ import { forwardRef, useMemo } from "react";
5
+ import { LABEL_POSITIONS } from "../../../utils/consts";
6
+ import { Spinner } from "../../Spinner";
7
+ import { useTheme } from "styled-components";
8
+
9
+ interface SwitchProps extends React.InputHTMLAttributes<HTMLInputElement> {
10
+ label?: string | React.ReactNode;
11
+ labelPosition?: keyof typeof LABEL_POSITIONS;
12
+ customColor?: string;
13
+ isLoading?: boolean;
14
+ register?: UseFormRegisterReturn;
15
+ }
16
+
17
+ export const Switch = forwardRef(function Switch(
18
+ {
19
+ label,
20
+ labelPosition = "right",
21
+ customColor,
22
+ isLoading,
23
+ register,
24
+ ...props
25
+ }: SwitchProps,
26
+ ref: React.Ref<HTMLInputElement>
27
+ ) {
28
+ const theme = useTheme();
29
+ const colorVariants = customColor
30
+ ? useMemo(() => generateColorVariants(customColor), [customColor])
31
+ : undefined;
32
+
33
+ return (
34
+ <SwitchLabel labelPosition={labelPosition}>
35
+ <input
36
+ ref={ref}
37
+ type="checkbox"
38
+ {...props}
39
+ disabled={isLoading || props.disabled}
40
+ {...register}
41
+ />
42
+ {label && <span>{label}</span>}
43
+ <SwitchArea colorVariants={colorVariants} isLoading={isLoading}>
44
+ <Spinner
45
+ size={10}
46
+ color={theme.colors.neutral.lighter}
47
+ style={{
48
+ position: "absolute",
49
+ left: 14,
50
+ top: 4,
51
+ transition: "all 0.3s cubic-bezier(0.65, 0, 0.35, 1)",
52
+ zIndex: 1,
53
+ opacity: isLoading ? 1 : 0,
54
+ }}
55
+ />
56
+ </SwitchArea>
57
+ </SwitchLabel>
58
+ );
59
+ });
@@ -0,0 +1,123 @@
1
+ import styled from "styled-components";
2
+ import { LABEL_POSITIONS, spacing } from "../../../utils/consts";
3
+ import { ColorVariants } from "../../../utils/globalTypes";
4
+
5
+ interface SwitchLabelProps {
6
+ labelPosition: keyof typeof LABEL_POSITIONS;
7
+ }
8
+
9
+ export const SwitchLabel = styled.label<SwitchLabelProps>`
10
+ display: flex;
11
+ gap: ${spacing.xs};
12
+ align-items: center;
13
+ justify-content: center;
14
+ width: fit-content;
15
+ flex-direction: ${({ labelPosition }) => LABEL_POSITIONS[labelPosition]};
16
+ border-radius: ${spacing.xxs};
17
+ cursor: pointer;
18
+ user-select: none;
19
+
20
+ input {
21
+ opacity: 0;
22
+ width: 0;
23
+ height: 0;
24
+ position: absolute;
25
+ }
26
+
27
+ &:has(> input[type="checkbox"]:focus-visible) {
28
+ outline: 1px solid black;
29
+ outline-offset: 2px;
30
+ }
31
+
32
+ span {
33
+ color: ${({ theme }) => theme.colors.neutral.darker};
34
+ font-family: Poppins;
35
+ font-size: 14px;
36
+ font-style: normal;
37
+ font-weight: 500;
38
+ line-height: 20px; /* 142.857% */
39
+ letter-spacing: 0.1px;
40
+ transition: all 0.3s;
41
+ }
42
+
43
+ &:has(> input[type="checkbox"]:disabled) {
44
+ cursor: default;
45
+
46
+ span {
47
+ color: ${({ theme }) => theme.colors.neutral.light};
48
+ }
49
+ }
50
+ `;
51
+
52
+ interface SwitchAreaProps {
53
+ isLoading?: boolean;
54
+ colorVariants?: ColorVariants;
55
+ }
56
+
57
+ export const SwitchArea = styled.div<SwitchAreaProps>`
58
+ flex-shrink: 0;
59
+ position: relative;
60
+ width: 40px;
61
+ height: 20px;
62
+ border-radius: 20px;
63
+ transition: all 0.3s;
64
+ background-color: ${({ theme }) => theme.colors.neutral.default};
65
+ border: 1px solid transparent;
66
+
67
+ label:hover > & {
68
+ background-color: ${({ theme }) => theme.colors.neutral.dark};
69
+ }
70
+
71
+ // Switch button
72
+ &::after {
73
+ content: "";
74
+ position: absolute;
75
+ width: 14px;
76
+ height: 14px;
77
+ border-radius: 50%;
78
+ background-color: white;
79
+ transition: all 0.3s;
80
+ top: 2px;
81
+ left: ${({ isLoading }: SwitchAreaProps) => (isLoading ? "12px" : "2px")};
82
+ }
83
+
84
+ // Checked
85
+ input[type="checkbox"]:checked ~ & {
86
+ background-color: ${({ colorVariants, theme }) =>
87
+ colorVariants?.default || theme.colors.green.default};
88
+
89
+ label:hover > & {
90
+ background-color: ${({ colorVariants, theme }) =>
91
+ colorVariants?.dark || theme.colors.green.dark};
92
+ }
93
+
94
+ &::after {
95
+ left: ${({ isLoading }: SwitchAreaProps) =>
96
+ isLoading ? "12px" : "22px"};
97
+ }
98
+ }
99
+
100
+ // Disabled
101
+ input[type="checkbox"]:disabled ~ & {
102
+ background-color: #fff;
103
+ border-color: ${({ theme }) => theme.colors.neutral.light};
104
+
105
+ &::after {
106
+ background-color: ${({ theme }) => theme.colors.neutral.light};
107
+ }
108
+ }
109
+
110
+ //Disabled and checked
111
+ input[type="checkbox"]:disabled:checked ~ & {
112
+ background-color: ${({ theme }) => theme.colors.neutral.lighter};
113
+ border-color: transparent;
114
+
115
+ label:hover > & {
116
+ background-color: ${({ theme }) => theme.colors.neutral.lighter};
117
+ }
118
+
119
+ &::after {
120
+ background-color: ${({ theme }) => theme.colors.neutral.light};
121
+ }
122
+ }
123
+ `;