property-practice-ui 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (189) hide show
  1. package/.prettierignore +3 -0
  2. package/.prettierrc +4 -0
  3. package/.storybook/main.ts +30 -0
  4. package/.storybook/preview.ts +32 -0
  5. package/.storybook/vitest.setup.ts +6 -0
  6. package/CHANGELOG.md +7 -0
  7. package/dist/index.js +10148 -0
  8. package/dist/index.mjs +10148 -0
  9. package/eslint.config.mjs +4 -0
  10. package/package.json +63 -0
  11. package/postcss.config.js +6 -0
  12. package/src/atoms/ArrowButton/ArrowButton.stories.tsx +52 -0
  13. package/src/atoms/ArrowButton/ArrowButton.tsx +71 -0
  14. package/src/atoms/Button/Button.stories.tsx +45 -0
  15. package/src/atoms/Button/Button.tsx +91 -0
  16. package/src/atoms/CheckboxItem/CheckboxItem.tsx +49 -0
  17. package/src/atoms/Description/Description.tsx +43 -0
  18. package/src/atoms/ExtendedButton/ExtendedButton.stories.tsx +61 -0
  19. package/src/atoms/ExtendedButton/ExtendedButton.tsx +40 -0
  20. package/src/atoms/FeatureItem/FeatureItem.stories.tsx +25 -0
  21. package/src/atoms/FeatureItem/FeatureItem.tsx +90 -0
  22. package/src/atoms/FormContainer/FormContainer.tsx +34 -0
  23. package/src/atoms/Header/Header.stories.tsx +22 -0
  24. package/src/atoms/Header/Header.tsx +53 -0
  25. package/src/atoms/Input/Input.stories.tsx +23 -0
  26. package/src/atoms/Input/Input.tsx +28 -0
  27. package/src/atoms/Label/Label.stories.tsx +28 -0
  28. package/src/atoms/Label/Label.tsx +53 -0
  29. package/src/atoms/Loader/Loader.tsx +49 -0
  30. package/src/atoms/Pill/Pill.stories.tsx +30 -0
  31. package/src/atoms/Pill/Pill.tsx +82 -0
  32. package/src/atoms/RadioItem/RadioItem.stories.tsx +25 -0
  33. package/src/atoms/RadioItem/RadioItem.tsx +54 -0
  34. package/src/atoms/SecondaryInput/SecondaryInput.stories.tsx +30 -0
  35. package/src/atoms/SecondaryInput/SecondaryInput.tsx +125 -0
  36. package/src/atoms/SocialButton/SocialButton.stories.tsx +79 -0
  37. package/src/atoms/SocialButton/SocialButton.tsx +90 -0
  38. package/src/atoms/TermsCheckbox/TermsCheckbox.stories.tsx +62 -0
  39. package/src/atoms/TermsCheckbox/TermsCheckbox.tsx +150 -0
  40. package/src/atoms/Text/Text.stories.tsx +32 -0
  41. package/src/atoms/Text/Text.tsx +49 -0
  42. package/src/atoms/TextButton/TextButton.stories.tsx +77 -0
  43. package/src/atoms/TextButton/TextButton.tsx +78 -0
  44. package/src/atoms/Textarea/Textarea.tsx +36 -0
  45. package/src/atoms/ToggleButton/ToggleButton.stories.tsx +32 -0
  46. package/src/atoms/ToggleButton/ToggleButton.tsx +106 -0
  47. package/src/atoms/index.ts +20 -0
  48. package/src/components/DynamicInput.tsx +54 -0
  49. package/src/components/FileUpload.tsx +123 -0
  50. package/src/components/Filter/Filter.tsx +33 -0
  51. package/src/components/ModeSwitch.tsx +66 -0
  52. package/src/components/NavMenu.tsx +83 -0
  53. package/src/components/SearchBar/Search.stories.tsx +25 -0
  54. package/src/components/SearchBar/Search.tsx +40 -0
  55. package/src/components/SortBy/SortBy.stories.tsx +27 -0
  56. package/src/components/SortBy/SortBy.tsx +45 -0
  57. package/src/components/Spinner.tsx +30 -0
  58. package/src/components/Table/Table.stories.tsx +56 -0
  59. package/src/components/Table/Table.tsx +25 -0
  60. package/src/components/TableInner/TableInner.tsx +27 -0
  61. package/src/components/TableInner/tableInner.stories.tsx +21 -0
  62. package/src/components/TableList.tsx +195 -0
  63. package/src/components/TableRow/TableRow.stories.tsx +55 -0
  64. package/src/components/TableRow/TableRow.tsx +343 -0
  65. package/src/components/Tabs/Tabs.stories.tsx +42 -0
  66. package/src/components/Tabs/Tabs.tsx +56 -0
  67. package/src/components/Toast.tsx +192 -0
  68. package/src/components/TopMenu.tsx +62 -0
  69. package/src/index.ts +20 -0
  70. package/src/molecules/Accordion/Accordion.stories.tsx +54 -0
  71. package/src/molecules/Accordion/Accordion.tsx +45 -0
  72. package/src/molecules/AccordionContent/AccordionContent.tsx +16 -0
  73. package/src/molecules/AccordionHeader/AccordionHeader.stories.tsx +31 -0
  74. package/src/molecules/AccordionHeader/AccordionHeader.tsx +67 -0
  75. package/src/molecules/Address/Address.stories.tsx +116 -0
  76. package/src/molecules/Address/Address.tsx +136 -0
  77. package/src/molecules/CTAContainer/CTAContainer.stories.tsx +67 -0
  78. package/src/molecules/CTAContainer/CTAContainer.tsx +98 -0
  79. package/src/molecules/Checkbox/Checkbox.tsx +60 -0
  80. package/src/molecules/ContentCard/ContentCard.stories.tsx +31 -0
  81. package/src/molecules/ContentCard/ContentCard.tsx +80 -0
  82. package/src/molecules/DocumentAccordionHeader/DocumentAccordionHeader.tsx +50 -0
  83. package/src/molecules/DocumentAccordionRow/DocumentAccordionRow.tsx +66 -0
  84. package/src/molecules/Dropdown/Dropdown.stories.tsx +39 -0
  85. package/src/molecules/Dropdown/Dropdown.tsx +89 -0
  86. package/src/molecules/EmptyState/EmptyState.stories.tsx +26 -0
  87. package/src/molecules/EmptyState/EmptyState.tsx +49 -0
  88. package/src/molecules/FAQAccordion/FAQAccordion.stories.tsx +63 -0
  89. package/src/molecules/FAQAccordion/FAQAccordion.tsx +98 -0
  90. package/src/molecules/FeatureContainer/FeatureContainer.stories.tsx +40 -0
  91. package/src/molecules/FeatureContainer/FeatureContainer.tsx +59 -0
  92. package/src/molecules/FileButton/FileButton.tsx +54 -0
  93. package/src/molecules/Input/Input.stories.tsx +30 -0
  94. package/src/molecules/Input/Input.tsx +31 -0
  95. package/src/molecules/InputContainer/InputContainer.tsx +60 -0
  96. package/src/molecules/JutaBrand/JutaBrand.stories.tsx +43 -0
  97. package/src/molecules/JutaBrand/JutaBrand.tsx +74 -0
  98. package/src/molecules/Modal/Modal.tsx +71 -0
  99. package/src/molecules/OverviewRowItem/OverviewRowItem.stories.tsx +23 -0
  100. package/src/molecules/OverviewRowItem/OverviewRowItem.tsx +39 -0
  101. package/src/molecules/PDFPreviewer/PDFPreviewer.tsx +42 -0
  102. package/src/molecules/PageLayout/PageLayout.tsx +60 -0
  103. package/src/molecules/ProductInfo/ProductInfo.stories.tsx +50 -0
  104. package/src/molecules/ProductInfo/ProductInfo.tsx +90 -0
  105. package/src/molecules/RadioGroup/RadioGroup.stories.tsx +47 -0
  106. package/src/molecules/RadioGroup/RadioGroup.tsx +55 -0
  107. package/src/molecules/RatesChart/RatesChart.stories.tsx +61 -0
  108. package/src/molecules/RatesChart/RatesChart.tsx +185 -0
  109. package/src/molecules/SideNav/SideNav.stories.tsx +64 -0
  110. package/src/molecules/SideNav/SideNav.tsx +140 -0
  111. package/src/molecules/SidePanel/SidePanel.stories.tsx +87 -0
  112. package/src/molecules/SidePanel/SidePanel.tsx +138 -0
  113. package/src/molecules/StepperHeaderTab/StepperHeaderTab.stories.tsx +23 -0
  114. package/src/molecules/StepperHeaderTab/StepperHeaderTab.tsx +43 -0
  115. package/src/molecules/Textarea/Textarea.tsx +29 -0
  116. package/src/molecules/index.ts +23 -0
  117. package/src/organism/ContactForm/ContactForm.stories.tsx +15 -0
  118. package/src/organism/ContactForm/ContactForm.tsx +54 -0
  119. package/src/organism/DocumentListAccordion/DocumentListAccordion.tsx +96 -0
  120. package/src/organism/FeatureCarousel/FeatureCarousel.stories.tsx +81 -0
  121. package/src/organism/FeatureCarousel/FeatureCarousel.tsx +162 -0
  122. package/src/organism/Footer/Footer.stories.tsx +77 -0
  123. package/src/organism/Footer/Footer.tsx +231 -0
  124. package/src/organism/Header/Header.stories.tsx +51 -0
  125. package/src/organism/Header/Header.tsx +76 -0
  126. package/src/organism/OverviewList/OverviewList.stories.tsx +43 -0
  127. package/src/organism/OverviewList/OverviewList.tsx +56 -0
  128. package/src/organism/ToastProvider/ToastProvider.tsx +40 -0
  129. package/src/organism/VersionLabel/VersionLabel.tsx +9 -0
  130. package/src/organism/index.ts +9 -0
  131. package/src/styles/tailwind.css +8 -0
  132. package/src/templates/AboutUs/AboutUs.stories.tsx +60 -0
  133. package/src/templates/AboutUs/AboutUs.tsx +97 -0
  134. package/src/templates/Contact/Contact.stories.tsx +62 -0
  135. package/src/templates/Contact/Contact.tsx +125 -0
  136. package/src/templates/FAQ/FAQ.stories.tsx +82 -0
  137. package/src/templates/FAQ/FAQ.tsx +91 -0
  138. package/src/templates/Features/Features.stories.tsx +94 -0
  139. package/src/templates/Features/Features.tsx +79 -0
  140. package/src/templates/Hero/Hero.stories.tsx +105 -0
  141. package/src/templates/Hero/Hero.tsx +139 -0
  142. package/src/templates/OtherProducts/OtherProducts.stories.tsx +77 -0
  143. package/src/templates/OtherProducts/OtherProducts.tsx +86 -0
  144. package/src/templates/index.ts +7 -0
  145. package/src/tokens/animations.ts +11 -0
  146. package/src/tokens/breakpoints.ts +7 -0
  147. package/src/tokens/colors.stories.tsx +77 -0
  148. package/src/tokens/colors.ts +59 -0
  149. package/src/tokens/radii.ts +6 -0
  150. package/src/tokens/sizes.ts +8 -0
  151. package/src/tokens/spaces.ts +21 -0
  152. package/src/types.ts +20 -0
  153. package/stories/Button.stories.ts +54 -0
  154. package/stories/Button.tsx +41 -0
  155. package/stories/Configure.mdx +364 -0
  156. package/stories/Header.stories.ts +34 -0
  157. package/stories/Header.tsx +71 -0
  158. package/stories/Page.stories.ts +33 -0
  159. package/stories/Page.tsx +91 -0
  160. package/stories/TopMenu.stories.tsx +51 -0
  161. package/stories/assets/accessibility.png +0 -0
  162. package/stories/assets/accessibility.svg +1 -0
  163. package/stories/assets/addon-library.png +0 -0
  164. package/stories/assets/assets.png +0 -0
  165. package/stories/assets/avif-test-image.avif +0 -0
  166. package/stories/assets/context.png +0 -0
  167. package/stories/assets/discord.svg +1 -0
  168. package/stories/assets/docs.png +0 -0
  169. package/stories/assets/figma-plugin.png +0 -0
  170. package/stories/assets/github.svg +1 -0
  171. package/stories/assets/share.png +0 -0
  172. package/stories/assets/styling.png +0 -0
  173. package/stories/assets/testing.png +0 -0
  174. package/stories/assets/theming.png +0 -0
  175. package/stories/assets/tutorials.svg +1 -0
  176. package/stories/assets/youtube.svg +1 -0
  177. package/stories/button.css +30 -0
  178. package/stories/header.css +32 -0
  179. package/stories/page.css +68 -0
  180. package/tailwind.config.js +34 -0
  181. package/tsconfig.json +8 -0
  182. package/types/index.ts +5 -0
  183. package/types/inputAttributes.ts +16 -0
  184. package/types/menuItem.ts +17 -0
  185. package/types/orderType.ts +2 -0
  186. package/types/tableListItem.ts +7 -0
  187. package/types/toast.ts +1 -0
  188. package/vitest.config.ts +37 -0
  189. package/vitest.shims.d.ts +1 -0
@@ -0,0 +1,90 @@
1
+ import styled from 'styled-components';
2
+ import { colors } from '../../tokens/colors';
3
+
4
+ const variants = ['primary', 'secondary', 'inverse', 'filled'] as const;
5
+ type Variant = (typeof variants)[number];
6
+
7
+ const StyledButton = styled.button<{ variant: Variant }>`
8
+ width: 2.5rem;
9
+ height: 2.5rem;
10
+ display: flex;
11
+ align-items: center;
12
+ justify-content: center;
13
+ border-radius: 4px;
14
+ background-color: ${(props) => {
15
+ switch (props.variant) {
16
+ case 'filled':
17
+ return colors.background.brand;
18
+ case 'primary':
19
+ case 'secondary':
20
+ case 'inverse':
21
+ default:
22
+ return 'transparent';
23
+ }
24
+ }};
25
+ border: 2px solid ${(props) => {
26
+ switch (props.variant) {
27
+ case 'primary':
28
+ return colors.text.brand;
29
+ case 'secondary':
30
+ return colors.text.blue;
31
+ case 'inverse':
32
+ return colors.text.secondary;
33
+ case 'filled':
34
+ return colors.background.brand;
35
+ default:
36
+ return colors.text.brand;
37
+ }
38
+ }};
39
+ color: ${(props) => {
40
+ switch (props.variant) {
41
+ case 'primary':
42
+ return colors.text.brand;
43
+ case 'secondary':
44
+ return colors.text.blue;
45
+ case 'inverse':
46
+ return colors.text.secondary;
47
+ case 'filled':
48
+ return colors.text.secondary;
49
+ default:
50
+ return colors.text.brand;
51
+ }
52
+ }};
53
+ cursor: pointer;
54
+ transition: all 0.2s;
55
+
56
+ &:hover {
57
+ opacity: 0.8;
58
+ }
59
+
60
+ svg {
61
+ width: 1.25rem;
62
+ height: 1.25rem;
63
+ }
64
+ `;
65
+
66
+ interface SocialButtonProps {
67
+ icon: React.ReactNode;
68
+ onClick?: () => void;
69
+ variant?: Variant;
70
+ ariaLabel?: string;
71
+ }
72
+
73
+ export const SocialButton = ({
74
+ icon,
75
+ onClick,
76
+ variant = 'primary',
77
+ ariaLabel,
78
+ }: SocialButtonProps) => {
79
+ return (
80
+ <StyledButton
81
+ onClick={onClick}
82
+ variant={variant}
83
+ aria-label={ariaLabel}
84
+ >
85
+ {icon}
86
+ </StyledButton>
87
+ );
88
+ };
89
+
90
+ SocialButton.variants = variants;
@@ -0,0 +1,62 @@
1
+ import type { Meta, StoryObj } from '@storybook/react-vite';
2
+ import { ComponentProps, useState } from 'react';
3
+ import { TermsCheckbox as Component } from './TermsCheckbox';
4
+
5
+ const meta: Meta = {
6
+ title: 'Atoms/TermsCheckbox',
7
+ component: Component,
8
+ };
9
+
10
+ export default meta;
11
+
12
+ export const TermsCheckbox: StoryObj<Omit<ComponentProps<typeof Component>, 'onClick'>> = {
13
+ render: (args) => {
14
+ const [checked, setChecked] = useState(false);
15
+
16
+ return (
17
+ <Component
18
+ {...args}
19
+ checked={checked}
20
+ onChange={setChecked}
21
+ />
22
+ );
23
+ },
24
+ args: {
25
+ text: "By submitting, I agree to Juta's",
26
+ termsText: 'Terms and Conditions',
27
+ termsUrl: '/terms',
28
+ cookieText: 'Cookie Policy',
29
+ cookieUrl: '/cookie-policy',
30
+
31
+ },
32
+ argTypes: {
33
+ text: { control: 'text' },
34
+ termsText: { control: 'text' },
35
+ termsUrl: { control: 'text' },
36
+ cookieText: { control: 'text' },
37
+ cookieUrl: { control: 'text' },
38
+
39
+ },
40
+ };
41
+
42
+ export const Checked: StoryObj<ComponentProps<typeof Component>> = {
43
+ render: (args) => {
44
+ const [checked, setChecked] = useState(true);
45
+
46
+ return (
47
+ <Component
48
+ {...args}
49
+ checked={checked}
50
+ onChange={setChecked}
51
+ />
52
+ );
53
+ },
54
+ args: {
55
+ text: "By submitting, I agree to Juta's",
56
+ termsText: 'Terms and Conditions',
57
+ termsUrl: '/terms',
58
+ cookieText: 'Cookie Policy',
59
+ cookieUrl: '/cookie-policy',
60
+
61
+ },
62
+ };
@@ -0,0 +1,150 @@
1
+ import styled from 'styled-components';
2
+ import { colors } from '../../tokens/colors';
3
+
4
+ const variants = ['primary', 'secondary', 'subtle'] as const;
5
+ type Variant = (typeof variants)[number];
6
+
7
+ const CheckboxContainer = styled.label`
8
+ display: flex;
9
+ align-items: flex-start;
10
+ gap: 0.75rem;
11
+ cursor: pointer;
12
+ font-size: 0.875rem;
13
+ line-height: 1.5;
14
+ `;
15
+
16
+ const HiddenCheckbox = styled.input.attrs({ type: 'checkbox' })`
17
+ position: absolute;
18
+ opacity: 0;
19
+ cursor: pointer;
20
+ `;
21
+
22
+ const StyledCheckbox = styled.div<{ $checked: boolean; variant: Variant }>`
23
+ width: 1.25rem;
24
+ height: 1.25rem;
25
+ border: 2px solid ${props => {
26
+ if (props.$checked) {
27
+ switch (props.variant) {
28
+ case 'primary':
29
+ return colors.text.brand;
30
+ case 'secondary':
31
+ return colors.text.blue;
32
+ case 'subtle':
33
+ return colors.text.subtle;
34
+ default:
35
+ return colors.text.brand;
36
+ }
37
+ }
38
+ return colors.text.subtle;
39
+ }};
40
+ border-radius: 4px;
41
+ background-color: ${props => {
42
+ if (props.$checked) {
43
+ switch (props.variant) {
44
+ case 'primary':
45
+ return colors.text.brand;
46
+ case 'secondary':
47
+ return colors.text.blue;
48
+ case 'subtle':
49
+ return colors.text.subtle;
50
+ default:
51
+ return colors.text.brand;
52
+ }
53
+ }
54
+ return 'transparent';
55
+ }};
56
+ display: flex;
57
+ align-items: center;
58
+ justify-content: center;
59
+ flex-shrink: 0;
60
+ transition: all 0.2s;
61
+
62
+ &::after {
63
+ content: '✓';
64
+ color: ${colors.text.secondary}; // white checkmark
65
+ font-size: 0.875rem;
66
+ font-weight: bold;
67
+ display: ${props => props.$checked ? 'block' : 'none'};
68
+ }
69
+ `;
70
+
71
+ const Text = styled.span<{ variant: Variant }>`
72
+ color: ${(props) => {
73
+ switch (props.variant) {
74
+ case 'primary':
75
+ return colors.text.primary;
76
+ case 'secondary':
77
+ return colors.text.blue;
78
+ case 'subtle':
79
+ return colors.text.subtle;
80
+ default:
81
+ return colors.text.primary;
82
+ }
83
+ }};
84
+ `;
85
+
86
+ const Link = styled.a<{ variant: Variant }>`
87
+ color: ${(props) => {
88
+ switch (props.variant) {
89
+ case 'primary':
90
+ return colors.text.brand;
91
+ case 'secondary':
92
+ return colors.text.blue;
93
+ case 'subtle':
94
+ return colors.text.subtle;
95
+ default:
96
+ return colors.text.brand;
97
+ }
98
+ }};
99
+ font-weight: 700;
100
+ text-decoration: underline;
101
+ cursor: pointer;
102
+
103
+ &:hover {
104
+ opacity: 0.8;
105
+ }
106
+ `;
107
+
108
+ interface TermsCheckboxProps {
109
+ checked: boolean;
110
+ onChange: (checked: boolean) => void;
111
+ text?: string;
112
+ termsText?: string;
113
+ termsUrl?: string;
114
+ cookieText?: string;
115
+ cookieUrl?: string;
116
+ variant?: Variant;
117
+ }
118
+
119
+ export const TermsCheckbox = ({
120
+ checked,
121
+ onChange,
122
+ text = "By submitting, I agree to Juta's",
123
+ termsText = "Terms and Conditions",
124
+ termsUrl = "/terms",
125
+ cookieText = "Cookie Policy",
126
+ cookieUrl = "/cookie-policy",
127
+ variant = 'primary',
128
+ }: TermsCheckboxProps) => {
129
+ return (
130
+ <CheckboxContainer>
131
+ <HiddenCheckbox
132
+ checked={checked}
133
+ onChange={(e) => onChange(e.target.checked)}
134
+ />
135
+ <StyledCheckbox $checked={checked} variant={variant} />
136
+ <Text variant={variant}>
137
+ {text}{' '}
138
+ <Link href={termsUrl} variant={variant} target="_blank" rel="noopener noreferrer">
139
+ {termsText}
140
+ </Link>
141
+ {' '}and{' '}
142
+ <Link href={cookieUrl} variant={variant} target="_blank" rel="noopener noreferrer">
143
+ {cookieText}
144
+ </Link>
145
+ </Text>
146
+ </CheckboxContainer>
147
+ );
148
+ };
149
+
150
+ TermsCheckbox.variants = variants;
@@ -0,0 +1,32 @@
1
+ import type { Meta, StoryObj } from '@storybook/react-vite';
2
+ import { ComponentProps } from 'react';
3
+ import { colors } from '../../tokens/colors';
4
+ import { Text as Component } from './Text';
5
+
6
+ const meta: Meta = {
7
+ title: 'Atoms/Text',
8
+ component: Component,
9
+ };
10
+
11
+ export default meta;
12
+
13
+ export const Text: StoryObj<ComponentProps<typeof Component>> = {
14
+ args: {
15
+ color: 'active',
16
+ variant: 'sm',
17
+ children: 'Text',
18
+ },
19
+ argTypes: {
20
+ children: {
21
+ control: 'text',
22
+ },
23
+ color: {
24
+ control: 'select',
25
+ options: Object.keys(colors.text),
26
+ },
27
+ variant: {
28
+ control: 'select',
29
+ options: Component.variants,
30
+ },
31
+ },
32
+ };
@@ -0,0 +1,49 @@
1
+ import styled from 'styled-components';
2
+ import { colors } from '../../tokens/colors';
3
+
4
+ const sizes = ['sm', 'md', 'lg'] as const;
5
+
6
+ const variants = {
7
+ sm: {
8
+ fontSize: '14px',
9
+ fontWeight: 500,
10
+ },
11
+ md: {
12
+ fontSize: '16px',
13
+ fontWeight: 500,
14
+ },
15
+ lg: {
16
+ fontSize: '18px',
17
+ fontWeight: 500,
18
+ },
19
+ } as const;
20
+
21
+ type Variant = keyof typeof variants;
22
+
23
+ type Color = keyof typeof colors.text;
24
+
25
+ interface TextProps {
26
+ children: string;
27
+ variant?: Variant;
28
+ color?: Color;
29
+ }
30
+
31
+ const StyledText = styled.h1<{ variant: Variant; color: Color }>`
32
+ color: ${(props) => colors.text[props?.color]};
33
+ font-size: ${(props) => variants[props.variant].fontSize};
34
+ font-weight: ${(props) => variants[props.variant].fontWeight};
35
+ `;
36
+
37
+ export const Text = ({
38
+ children,
39
+ color = 'primary',
40
+ variant = 'md',
41
+ }: TextProps) => {
42
+ return (
43
+ <StyledText color={color} variant={variant}>
44
+ {children}
45
+ </StyledText>
46
+ );
47
+ };
48
+
49
+ Text.variants = sizes;
@@ -0,0 +1,77 @@
1
+ import type { Meta, StoryObj } from '@storybook/react-vite';
2
+ import { ComponentProps } from 'react';
3
+ import { TextButton as Component } from './TextButton';
4
+
5
+ const meta: Meta = {
6
+ title: 'Atoms/TextButton',
7
+ component: Component,
8
+ };
9
+
10
+ export default meta;
11
+
12
+ export const TextButton: StoryObj<Omit<ComponentProps<typeof Component>, 'onClick'>> = {
13
+ args: {
14
+ text: 'Click Me',
15
+ bgVariant: 'brand',
16
+ textVariant: 'secondary',
17
+ uppercase: true,
18
+ bold: false,
19
+ },
20
+ argTypes: {
21
+ text: { control: 'text' },
22
+ bgVariant: {
23
+ control: 'select',
24
+ options: ['primary', 'secondary', 'tertiary', 'subtle', 'blue', 'brand', 'light', 'transparent'],
25
+ },
26
+ textVariant: {
27
+ control: 'select',
28
+ options: ['brand', 'primary', 'secondary', 'tertiary', 'subtle', 'light', 'error', 'blue'],
29
+ },
30
+ uppercase: { control: 'boolean' },
31
+ bold: { control: 'boolean' },
32
+ },
33
+ };
34
+
35
+ export const DarkButton: StoryObj<ComponentProps<typeof Component>> = {
36
+ args: {
37
+ text: 'Dark Button',
38
+ bgVariant: 'brand',
39
+ textVariant: 'secondary',
40
+ },
41
+ };
42
+
43
+ export const LightButton: StoryObj<ComponentProps<typeof Component>> = {
44
+ args: {
45
+ text: 'Light Button',
46
+ bgVariant: 'secondary',
47
+ textVariant: 'primary',
48
+ },
49
+ };
50
+
51
+ export const TealButton: StoryObj<ComponentProps<typeof Component>> = {
52
+ args: {
53
+ text: 'Teal Button',
54
+ bgVariant: 'subtle',
55
+ textVariant: 'secondary',
56
+ },
57
+ };
58
+
59
+ export const TransparentButton: StoryObj<ComponentProps<typeof Component>> = {
60
+ args: {
61
+ text: 'Transparent Button',
62
+ bgVariant: 'transparent',
63
+ textVariant: 'primary',
64
+ },
65
+ };
66
+
67
+ export const AllCombinations: StoryObj = {
68
+ render: () => (
69
+ <div style={{ display: 'flex', flexDirection: 'column', gap: '1rem' }}>
70
+ <Component text="Dark BG + White Text" bgVariant="brand" textVariant="secondary" />
71
+ <Component text="Light BG + Dark Text" bgVariant="secondary" textVariant="primary" />
72
+ <Component text="Teal BG + White Text" bgVariant="subtle" textVariant="secondary" />
73
+ <Component text="Blue BG + White Text" bgVariant="blue" textVariant="secondary" />
74
+ <Component text="Transparent + Dark Text" bgVariant="transparent" textVariant="primary" />
75
+ </div>
76
+ ),
77
+ };
@@ -0,0 +1,78 @@
1
+ import styled from 'styled-components';
2
+ import { colors } from '../../tokens/colors';
3
+
4
+ const bgVariants = ['primary', 'secondary', 'tertiary', 'subtle', 'blue', 'brand', 'light', 'transparent'] as const;
5
+ const textVariants = ['brand', 'primary', 'secondary', 'tertiary', 'subtle', 'light', 'error', 'blue'] as const;
6
+
7
+ type BgVariant = (typeof bgVariants)[number];
8
+ type TextVariant = (typeof textVariants)[number];
9
+
10
+ const StyledContainer = styled.button<{
11
+ as?: 'button' | 'div';
12
+ bgVariant: BgVariant;
13
+ }>`
14
+ padding: 0 1rem;
15
+ height: 2.5rem;
16
+ display: flex;
17
+ align-items: center;
18
+ flex-shrink:0;
19
+ white-space: nowrap;
20
+ background-color: ${(props) => {
21
+ if (props.bgVariant === 'transparent') return 'transparent';
22
+ return colors.background[props.bgVariant];
23
+ }};
24
+ transition: all 0.2s;
25
+ border: none;
26
+ cursor: pointer;
27
+
28
+ &:hover {
29
+ opacity: 0.9;
30
+ }
31
+ `;
32
+
33
+ const StyledText = styled.span<{
34
+ textVariant: TextVariant;
35
+ $uppercase?: boolean;
36
+ $bold?: boolean;
37
+ }>`
38
+ color: ${(props) => colors.text[props.textVariant]};
39
+ font-size: 0.75rem;
40
+ letter-spacing: 0.05em;
41
+ text-transform: ${props => props.$uppercase ? 'uppercase' : 'none'};
42
+ font-weight: ${props => props.$bold ? 700 : 600};
43
+ `;
44
+
45
+ interface TextButtonProps {
46
+ text: string;
47
+ onClick?: () => void;
48
+ asChild?: boolean;
49
+ bgVariant?: BgVariant;
50
+ textVariant?: TextVariant;
51
+ uppercase?: boolean;
52
+ bold?: boolean;
53
+ }
54
+
55
+ export const TextButton = ({
56
+ text,
57
+ onClick,
58
+ asChild = false,
59
+ bgVariant = 'brand',
60
+ textVariant = 'secondary',
61
+ uppercase = true,
62
+ bold = false
63
+ }: TextButtonProps) => {
64
+ return (
65
+ <StyledContainer
66
+ as={asChild ? 'div' : 'button'}
67
+ onClick={onClick}
68
+ bgVariant={bgVariant}
69
+ >
70
+ <StyledText textVariant={textVariant} $uppercase={uppercase} $bold={bold}>
71
+ {text}
72
+ </StyledText>
73
+ </StyledContainer>
74
+ );
75
+ };
76
+
77
+ TextButton.bgVariants = bgVariants;
78
+ TextButton.textVariants = textVariants;
@@ -0,0 +1,36 @@
1
+ import { ChangeEvent } from 'react';
2
+ import styled from 'styled-components';
3
+ import { colors } from '../../tokens/colors';
4
+ import { InputTypes, type BaseInputProps } from '../../types';
5
+
6
+ interface TextareaProps extends Omit<BaseInputProps, 'label'> {
7
+ onChange: (event: ChangeEvent<HTMLTextAreaElement>) => void;
8
+ disabled?: boolean;
9
+ value?: string | number;
10
+ rows?: number;
11
+ cols?: number;
12
+ }
13
+
14
+ const StyledTextarea = styled.textarea`
15
+ display: block;
16
+ width: 100%;
17
+ height: 100%;
18
+ outline: none;
19
+ background-color: transparent;
20
+ color: ${colors.text.subtle};
21
+ font-weight: 600;
22
+ resize: vertical;
23
+ `;
24
+
25
+ export const Textarea = ({
26
+ name,
27
+ onChange,
28
+ rows = 3,
29
+ ...rest
30
+ }: TextareaProps) => {
31
+ return (
32
+ <StyledTextarea name={name} onChange={onChange} rows={rows} {...rest} />
33
+ );
34
+ };
35
+
36
+ Textarea.types = InputTypes;
@@ -0,0 +1,32 @@
1
+ import type { Meta, StoryObj } from '@storybook/react-vite';
2
+ import { ComponentProps, useState } from 'react';
3
+ import { ToggleButton as Component } from './ToggleButton';
4
+
5
+ const meta: Meta = {
6
+ title: 'Atoms/ToggleButton',
7
+ component: Component,
8
+ };
9
+
10
+ export default meta;
11
+
12
+ export const ToggleButton: StoryObj<Omit<ComponentProps<typeof Component>, 'onClick'>> = {
13
+ render: (args) => {
14
+ const [activeOption, setActiveOption] = useState('GENERAL');
15
+
16
+ return (
17
+ <Component
18
+ {...args}
19
+ activeOption={activeOption}
20
+ onChange={setActiveOption}
21
+ />
22
+ );
23
+ },
24
+ args: {
25
+ options: ['GENERAL', 'LEGAL'],
26
+
27
+ },
28
+ argTypes: {
29
+ options: { control: 'object' },
30
+
31
+ },
32
+ };