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,4 @@
1
+ import { config } from '@repo/eslint-config/react-internal';
2
+
3
+ /** @type {import("eslint").Linter.Config} */
4
+ export default config;
package/package.json ADDED
@@ -0,0 +1,63 @@
1
+ {
2
+ "name": "property-practice-ui",
3
+ "version": "0.0.1",
4
+ "description": "",
5
+ "private": false,
6
+ "exports": {
7
+ ".": "./src/index.ts",
8
+ "./types": "./types/index.ts",
9
+ "./atoms": "./src/atoms/index.ts",
10
+ "./molecules": "./src/molecules/index.ts"
11
+ },
12
+ "keywords": [
13
+ "storybook",
14
+ "react",
15
+ "ui",
16
+ "components",
17
+ "design system",
18
+ "tailwindcss",
19
+ "typescript"
20
+ ],
21
+ "author": "Property Practice",
22
+ "devDependencies": {
23
+ "@chromatic-com/storybook": "^4.0.1",
24
+ "@storybook/addon-a11y": "^9.0.16",
25
+ "@storybook/addon-docs": "^9.0.16",
26
+ "@storybook/addon-onboarding": "^9.0.16",
27
+ "@storybook/addon-vitest": "^9.0.16",
28
+ "@storybook/react-vite": "^9.0.16",
29
+ "@types/react": "^19.1.8",
30
+ "@types/react-dom": "^19.1.6",
31
+ "@vitest/browser": "^3.2.4",
32
+ "@vitest/coverage-v8": "^3.2.4",
33
+ "autoprefixer": "^10.4.21",
34
+ "playwright": "^1.53.2",
35
+ "postcss": "^8.5.6",
36
+ "prettier": "3.6.2",
37
+ "react": "^18.0.0",
38
+ "react-dom": "^18.0.0",
39
+ "storybook": "^9.0.16",
40
+ "tailwindcss": "^3.4.17",
41
+ "tsconfig-paths": "^4.2.0",
42
+ "typescript": "^5.8.3",
43
+ "vitest": "^3.2.4"
44
+ },
45
+ "dependencies": {
46
+ "axios": "^1.12.2",
47
+ "framer-motion": "^12.23.2",
48
+ "next": "15.3.6",
49
+ "react-hook-form": "^7.62.0",
50
+ "react-icons": "^5.5.0",
51
+ "styled-components": "^6.1.19",
52
+ "tailwind-variants": "^1.0.0",
53
+ "@heroicons/react": "^2.2.0",
54
+ "tailwind-merge": "^3.3.1"
55
+ },
56
+ "scripts": {
57
+ "storybook": "storybook dev -p 6006",
58
+ "build-storybook": "storybook build",
59
+ "test": "jest",
60
+ "format": "prettier --write \"**/*.@(js|jsx|mjs|ts|tsx)\"",
61
+ "lint": ""
62
+ }
63
+ }
@@ -0,0 +1,6 @@
1
+ module.exports = {
2
+ plugins: {
3
+ tailwindcss: {},
4
+ autoprefixer: {},
5
+ },
6
+ };
@@ -0,0 +1,52 @@
1
+ import type { Meta, StoryObj } from '@storybook/react-vite';
2
+ import { ComponentProps } from 'react';
3
+ import { ArrowButton as Component } from './ArrowButton';
4
+
5
+ const meta: Meta = {
6
+ title: 'Atoms/ArrowButton',
7
+ component: Component,
8
+ };
9
+
10
+ export default meta;
11
+
12
+ export const ArrowButton: StoryObj<Omit<ComponentProps<typeof Component>, 'onClick'>> = {
13
+ args: {
14
+ variant: 'brand',
15
+ asChild: false,
16
+ },
17
+ argTypes: {
18
+ variant: {
19
+ control: 'select',
20
+ options: ['brand', 'teal', 'blue'],
21
+ },
22
+ asChild: { control: 'boolean' },
23
+ },
24
+ };
25
+
26
+ export const BrandVariant: StoryObj<ComponentProps<typeof Component>> = {
27
+ args: {
28
+ variant: 'brand',
29
+ },
30
+ };
31
+
32
+ export const TealVariant: StoryObj<ComponentProps<typeof Component>> = {
33
+ args: {
34
+ variant: 'teal',
35
+ },
36
+ };
37
+
38
+ export const BlueVariant: StoryObj<ComponentProps<typeof Component>> = {
39
+ args: {
40
+ variant: 'blue',
41
+ },
42
+ };
43
+
44
+ export const AllVariants: StoryObj = {
45
+ render: () => (
46
+ <div style={{ display: 'flex', gap: '1rem', alignItems: 'center' }}>
47
+ <Component variant="brand" />
48
+ <Component variant="teal" />
49
+ <Component variant="blue" />
50
+ </div>
51
+ ),
52
+ };
@@ -0,0 +1,71 @@
1
+ import { HiArrowUpRight } from 'react-icons/hi2';
2
+ import styled from 'styled-components';
3
+ import { colors } from '../../tokens/colors';
4
+
5
+ const variants = ['brand', 'teal', 'blue'] as const;
6
+ type Variant = (typeof variants)[number];
7
+
8
+ const StyledContainer = styled.button<{
9
+ as?: 'button' | 'div';
10
+ variant: Variant;
11
+ }>`
12
+ padding: 0.75rem;
13
+ ${props => props.as === 'button' ? `
14
+ width: 2.5rem;
15
+ height: 2.5rem;
16
+ ` : ''}
17
+ flex-shrink: 0;
18
+ background-color: ${(props) => {
19
+ switch (props.variant) {
20
+ case 'brand':
21
+ return colors.background.brand;
22
+ case 'teal':
23
+ return colors.background.subtle;
24
+ case 'blue':
25
+ return colors.background.blue;
26
+ default:
27
+ return colors.background.brand;
28
+ }
29
+ }};
30
+ transition: all 0.2s;
31
+ border: none;
32
+ cursor: pointer;
33
+ display: flex;
34
+ align-items: center;
35
+ justify-content: center;
36
+
37
+ &:hover svg {
38
+ transform: rotate(45deg);
39
+ }
40
+ `;
41
+
42
+ const StyledIcon = styled(HiArrowUpRight)`
43
+ width: 1rem;
44
+ height: 1rem;
45
+ color: ${colors.text.secondary};
46
+ transition: transform 0.2s;
47
+ `;
48
+
49
+ interface ButtonProps {
50
+ onClick?: () => void;
51
+ asChild?: boolean;
52
+ variant?: Variant;
53
+ }
54
+
55
+ export const ArrowButton = ({
56
+ onClick,
57
+ asChild = false,
58
+ variant = 'brand'
59
+ }: ButtonProps) => {
60
+ return (
61
+ <StyledContainer
62
+ as={asChild ? 'div' : 'button'}
63
+ onClick={onClick}
64
+ variant={variant}
65
+ >
66
+ <StyledIcon aria-hidden />
67
+ </StyledContainer>
68
+ );
69
+ };
70
+
71
+ ArrowButton.variants = variants;
@@ -0,0 +1,45 @@
1
+ import type { Meta, StoryObj } from '@storybook/react-vite';
2
+ import { ComponentProps } from 'react';
3
+ import { FaPlus } from 'react-icons/fa';
4
+ import { Button as Component } from './Button';
5
+
6
+ const meta: Meta = {
7
+ title: 'Atoms/Button',
8
+ component: Component,
9
+ };
10
+
11
+ export default meta;
12
+
13
+ export const Button: StoryObj<
14
+ Pick<ComponentProps<typeof Component>, 'text' | 'type' | 'disabled'>
15
+ > = {
16
+ args: {
17
+ text: 'Submit',
18
+ disabled: false,
19
+ },
20
+ argTypes: {
21
+ text: {
22
+ control: 'text',
23
+ },
24
+ type: {
25
+ control: 'select',
26
+ options: Component.types,
27
+ },
28
+ disabled: {
29
+ control: 'boolean',
30
+ },
31
+ },
32
+ render: (args) => {
33
+ return (
34
+ <div style={{ display: 'flex', flexDirection: 'column', gap: '24px' }}>
35
+ <Component disabled={args.disabled} text={args.text} type={args.type} />
36
+ <Component
37
+ disabled={args.disabled}
38
+ text={args.text}
39
+ type={args.type}
40
+ icon={<FaPlus fontSize="12px" />}
41
+ />
42
+ </div>
43
+ );
44
+ },
45
+ };
@@ -0,0 +1,91 @@
1
+ import { ReactElement } from 'react';
2
+ import styled from 'styled-components';
3
+ import { colors } from '../../tokens/colors';
4
+ import { radii } from '../../tokens/radii';
5
+ import { spaces } from '../../tokens/spaces';
6
+ import { Loader } from '../Loader/Loader';
7
+
8
+ const ButtonTypes = ['submit', 'reset', 'button'] as const;
9
+
10
+ type ButtonType = (typeof ButtonTypes)[number];
11
+
12
+ const variants = ['dark', 'light'] as const;
13
+
14
+ type Variant = (typeof variants)[number];
15
+
16
+ interface ButtonProps {
17
+ onClick?: () => void;
18
+ text?: string;
19
+ type?: ButtonType;
20
+ disabled?: boolean;
21
+ icon?: ReactElement;
22
+ variant?: Variant;
23
+ isLoading?: boolean;
24
+ }
25
+
26
+ const StyledButton = styled.button<{ variant: Variant }>`
27
+ padding: ${spaces[2]} ${spaces[4]};
28
+ background-color: ${(props) =>
29
+ props.variant === 'light'
30
+ ? colors.button.primary
31
+ : colors.button.secondary};
32
+ border-radius: ${radii.lg};
33
+ color: ${(props) =>
34
+ props.variant === 'light' ? colors.text.primary : colors.text.secondary};
35
+ display: flex;
36
+ align-items: center;
37
+ justify-content: center;
38
+ gap: ${spaces[2]};
39
+ max-height: 34px;
40
+
41
+ &:hover {
42
+ background-color: ${colors.button.hover};
43
+ cursor: pointer;
44
+ }
45
+
46
+ &:active {
47
+ background-color: ${colors.button.active};
48
+ color: ${colors.text.secondary};
49
+ }
50
+
51
+ &:disabled {
52
+ background-color: ${colors.button.primary};
53
+ cursor: not-allowed;
54
+ color: ${colors.text.primary};
55
+ }
56
+ `;
57
+
58
+ const ButtonText = styled.span`
59
+ font-size: 12px;
60
+ font-weight: 700;
61
+ `;
62
+
63
+ export const Button = ({
64
+ onClick,
65
+ text,
66
+ type = 'button',
67
+ disabled,
68
+ icon = undefined,
69
+ variant = 'light',
70
+ isLoading,
71
+ }: ButtonProps) => {
72
+ return (
73
+ <StyledButton
74
+ type={type}
75
+ onClick={onClick}
76
+ disabled={disabled || isLoading}
77
+ variant={variant}
78
+ >
79
+ {!isLoading ? (
80
+ <>
81
+ {typeof icon !== 'undefined' && icon}
82
+ <ButtonText>{text}</ButtonText>
83
+ </>
84
+ ) : (
85
+ <Loader size="20px" />
86
+ )}
87
+ </StyledButton>
88
+ );
89
+ };
90
+
91
+ Button.types = ButtonTypes;
@@ -0,0 +1,49 @@
1
+ import styled from 'styled-components';
2
+ import { colors } from '../../tokens/colors';
3
+ import { radii } from '../../tokens/radii';
4
+ import { sizes } from '../../tokens/sizes';
5
+ import { spaces } from '../../tokens/spaces';
6
+
7
+ interface CheckboxItemProps<T> {
8
+ value: T;
9
+ label: string;
10
+ checked: boolean;
11
+ onClick: () => void;
12
+ }
13
+
14
+ const CheckboxWrapper = styled.label`
15
+ display: flex;
16
+ align-items: center;
17
+ gap: ${spaces[2]};
18
+ cursor: pointer;
19
+ font-size: 16px;
20
+ color: ${colors.text.subtle};
21
+ `;
22
+
23
+ const HiddenCheckbox = styled.input.attrs({ type: 'checkbox' })`
24
+ display: none;
25
+ `;
26
+
27
+ const StyledCheckbox = styled.span<{ checked: boolean }>`
28
+ width: ${sizes.lg};
29
+ height: ${sizes.lg};
30
+ border: 1.5px solid ${colors.background.tertiary};
31
+ border-radius: ${radii.md};
32
+ background-color: ${({ checked }) =>
33
+ checked ? colors.background.tertiary : 'transparent'};
34
+ transition: all 0.2s ease-in-out;
35
+ `;
36
+
37
+ export const CheckboxItem = <T extends string | number | boolean>({
38
+ label,
39
+ onClick,
40
+ checked,
41
+ }: CheckboxItemProps<T>) => {
42
+ return (
43
+ <CheckboxWrapper onClick={onClick}>
44
+ <HiddenCheckbox checked={checked} readOnly />
45
+ <StyledCheckbox checked={checked} />
46
+ {label}
47
+ </CheckboxWrapper>
48
+ );
49
+ };
@@ -0,0 +1,43 @@
1
+ import styled from 'styled-components';
2
+ import { colors } from '../../tokens/colors';
3
+
4
+ const variants = ['primary', 'secondary', 'subtle', 'error'] as const;
5
+ type Variant = (typeof variants)[number];
6
+
7
+ interface DescriptionProps {
8
+ children: string;
9
+ variant?: Variant;
10
+ }
11
+
12
+ const StyledDescription = styled.p<{ variant: Variant }>`
13
+ margin: 0;
14
+ font-size: 1rem;
15
+ line-height: 1.6;
16
+ color: ${(props) => {
17
+ switch (props.variant) {
18
+ case 'primary':
19
+ return colors.text.primary;
20
+ case 'secondary':
21
+ return colors.text.secondary;
22
+ case 'subtle':
23
+ return colors.text.subtle;
24
+ case 'error':
25
+ return colors.text.error;
26
+ default:
27
+ return colors.text.primary;
28
+ }
29
+ }};
30
+ `;
31
+
32
+ export const Description = ({
33
+ children,
34
+ variant = 'primary',
35
+ }: DescriptionProps) => {
36
+ return (
37
+ <StyledDescription variant={variant}>
38
+ {children}
39
+ </StyledDescription>
40
+ );
41
+ };
42
+
43
+ Description.variants = variants;
@@ -0,0 +1,61 @@
1
+ import type { Meta, StoryObj } from '@storybook/react-vite';
2
+ import { ComponentProps } from 'react';
3
+ import { ExtendedButton as Component } from './ExtendedButton';
4
+
5
+ const meta: Meta = {
6
+ title: 'Atoms/ExtendedButton',
7
+ component: Component,
8
+ };
9
+
10
+ export default meta;
11
+
12
+ export const ExtendedButton: StoryObj<Omit<ComponentProps<typeof Component>, 'onClick'>> = {
13
+ args: {
14
+ text: 'Register For Free',
15
+ arrowVariant: 'teal',
16
+ textBgVariant: 'brand',
17
+ textVariant: 'secondary',
18
+ },
19
+ argTypes: {
20
+ text: { control: 'text' },
21
+ arrowVariant: {
22
+ control: 'select',
23
+ options: ['brand', 'teal', 'blue'],
24
+ },
25
+ textBgVariant: {
26
+ control: 'select',
27
+ options: ['primary', 'secondary', 'tertiary', 'subtle', 'blue', 'brand', 'light', 'transparent'],
28
+ },
29
+ textVariant: {
30
+ control: 'select',
31
+ options: ['brand', 'primary', 'secondary', 'tertiary', 'subtle', 'light', 'error', 'blue'],
32
+ },
33
+ },
34
+ };
35
+
36
+ export const TealArrowDarkBg: StoryObj<ComponentProps<typeof Component>> = {
37
+ args: {
38
+ text: 'Register For Free',
39
+ arrowVariant: 'teal',
40
+ textBgVariant: 'brand',
41
+ textVariant: 'secondary',
42
+ },
43
+ };
44
+
45
+ export const BlueArrowLightBg: StoryObj<ComponentProps<typeof Component>> = {
46
+ args: {
47
+ text: 'Learn More',
48
+ arrowVariant: 'blue',
49
+ textBgVariant: 'secondary',
50
+ textVariant: 'primary',
51
+ },
52
+ };
53
+
54
+ export const BrandArrowTealBg: StoryObj<ComponentProps<typeof Component>> = {
55
+ args: {
56
+ text: 'Get Started',
57
+ arrowVariant: 'brand',
58
+ textBgVariant: 'subtle',
59
+ textVariant: 'secondary',
60
+ },
61
+ };
@@ -0,0 +1,40 @@
1
+ import styled from 'styled-components';
2
+ import { ArrowButton, TextButton } from "..";
3
+
4
+ const StyledButton = styled.button`
5
+ display: flex;
6
+ align-items: center;
7
+ height: 2.5rem;
8
+ border: none;
9
+ cursor: pointer;
10
+ transition: opacity 0.2s;
11
+ padding: 0;
12
+ background: transparent;
13
+
14
+ &:hover {
15
+ opacity: 0.9;
16
+ }
17
+ `;
18
+
19
+ interface ExtendedButtonProps {
20
+ text: string;
21
+ onClick?: () => void;
22
+ arrowVariant?: 'brand' | 'teal' | 'blue';
23
+ textBgVariant?: 'primary' | 'secondary' | 'tertiary' | 'subtle' | 'blue' | 'brand' | 'light' | 'transparent';
24
+ textVariant?: 'brand' | 'primary' | 'secondary' | 'tertiary' | 'subtle' | 'light' | 'error' | 'blue';
25
+ }
26
+
27
+ export const ExtendedButton = ({
28
+ text,
29
+ onClick,
30
+ arrowVariant = 'teal',
31
+ textBgVariant = 'brand',
32
+ textVariant = 'secondary',
33
+ }: ExtendedButtonProps) => {
34
+ return (
35
+ <StyledButton onClick={onClick}>
36
+ <ArrowButton asChild variant={arrowVariant} />
37
+ <TextButton asChild text={text} bgVariant={textBgVariant} textVariant={textVariant} uppercase={false} />
38
+ </StyledButton>
39
+ );
40
+ };
@@ -0,0 +1,25 @@
1
+ import type { Meta, StoryObj } from '@storybook/react-vite';
2
+ import { ComponentProps } from 'react';
3
+ import { GiMolecule } from "react-icons/gi";
4
+ import { FeatureItem as Component } from './FeatureItem';
5
+
6
+ const meta: Meta = {
7
+ title: 'Atoms/FeatureItem',
8
+ component: Component,
9
+ };
10
+
11
+ export default meta;
12
+
13
+ export const FeatureItem: StoryObj<Omit<ComponentProps<typeof Component>, 'onClick'>> = {
14
+ args: {
15
+ thumbnail: <GiMolecule size={24} color="#0d9488" />,
16
+ title: 'End-to-End Process Issuing',
17
+ description: 'Litigator manages the full issuing process for you.',
18
+
19
+ },
20
+ argTypes: {
21
+ title: { control: 'text' },
22
+ description: { control: 'text' },
23
+
24
+ },
25
+ };
@@ -0,0 +1,90 @@
1
+ import styled from 'styled-components';
2
+ import { colors } from '../../tokens/colors';
3
+
4
+ type TextColor = keyof typeof colors.text;
5
+ type BackgroundColor = keyof typeof colors.background;
6
+
7
+ const Container = styled.div`
8
+ display: flex;
9
+ gap: 1rem;
10
+ background-color: transparent;
11
+ `;
12
+
13
+ const ThumbnailWrapper = styled.div<{ $size?: string; thumbnailBgColor: BackgroundColor }>`
14
+ width: ${props => props.$size || '3rem'};
15
+ height: ${props => props.$size || '3rem'};
16
+ border-radius: 50%;
17
+ background-color: ${props => colors.background[props.thumbnailBgColor]};
18
+ display: flex;
19
+ align-items: center;
20
+ justify-content: center;
21
+ flex-shrink: 0;
22
+ `;
23
+
24
+ const Content = styled.div`
25
+ display: flex;
26
+ flex-direction: column;
27
+ gap: 0.25rem;
28
+ `;
29
+
30
+ const Title = styled.h3<{ titleColor: TextColor }>`
31
+ margin: 0;
32
+ font-size: 1rem;
33
+ font-weight: 600;
34
+ color: ${props => colors.text[props.titleColor]};
35
+ `;
36
+
37
+ const Description = styled.p<{ descriptionColor: TextColor }>`
38
+ margin: 0;
39
+ font-size: 0.875rem;
40
+ line-height: 1.5;
41
+ color: ${props => colors.text[props.descriptionColor]};
42
+ `;
43
+
44
+ interface FeatureItemProps {
45
+ thumbnail: React.ReactNode;
46
+ title: string;
47
+ description: string;
48
+ thumbnailSize?: string;
49
+ thumbnailBgColor?: BackgroundColor;
50
+ titleColor?: TextColor;
51
+ descriptionVariant?: 'primary' | 'secondary' | 'subtle' | 'error';
52
+ }
53
+
54
+ export const FeatureItem = ({
55
+ thumbnail,
56
+ title,
57
+ description,
58
+ thumbnailSize,
59
+ thumbnailBgColor = 'brand',
60
+ titleColor = 'primary',
61
+ descriptionVariant = 'subtle',
62
+ }: FeatureItemProps) => {
63
+ // Map descriptionVariant to text color
64
+ const getDescriptionColor = (): TextColor => {
65
+ switch (descriptionVariant) {
66
+ case 'primary':
67
+ return 'primary';
68
+ case 'secondary':
69
+ return 'secondary';
70
+ case 'subtle':
71
+ return 'subtle';
72
+ case 'error':
73
+ return 'error';
74
+ default:
75
+ return 'subtle';
76
+ }
77
+ };
78
+
79
+ return (
80
+ <Container>
81
+ <ThumbnailWrapper $size={thumbnailSize} thumbnailBgColor={thumbnailBgColor}>
82
+ {thumbnail}
83
+ </ThumbnailWrapper>
84
+ <Content>
85
+ <Title titleColor={titleColor}>{title}</Title>
86
+ <Description descriptionColor={getDescriptionColor()}>{description}</Description>
87
+ </Content>
88
+ </Container>
89
+ );
90
+ };
@@ -0,0 +1,34 @@
1
+ import { ReactNode } from 'react';
2
+ import styled from 'styled-components';
3
+ import { breakpoints } from '../../tokens/breakpoints';
4
+ import { spaces } from '../../tokens/spaces';
5
+
6
+ type Space = keyof typeof spaces;
7
+
8
+ interface FormContainerProps {
9
+ children: ReactNode;
10
+ space?: Space;
11
+ }
12
+
13
+ const Container = styled.div`
14
+ width: 100%;
15
+ display: flex;
16
+ justify-content: center;
17
+ `;
18
+
19
+ const InnerContainer = styled.div<{ space: Space }>`
20
+ display: flex;
21
+ flex-direction: column;
22
+ padding: ${spaces[4]};
23
+ width: 100%;
24
+ max-width: ${breakpoints.lg};
25
+ gap: ${(props) => spaces[props.space]};
26
+ `;
27
+
28
+ export const FormContainer = ({ children, space = 4 }: FormContainerProps) => {
29
+ return (
30
+ <Container>
31
+ <InnerContainer space={space}>{children}</InnerContainer>
32
+ </Container>
33
+ );
34
+ };