Overview
The library is built with TypeScript in strict mode , providing comprehensive type safety and excellent IDE autocomplete. All components are fully typed with exported interfaces and props.
TypeScript Configuration
The library uses strict TypeScript settings for maximum type safety:
{
"compilerOptions" : {
"target" : "es6" ,
"esModuleInterop" : true ,
"forceConsistentCasingInFileNames" : true ,
"strict" : true , // Strict mode enabled
"skipLibCheck" : true ,
"jsx" : "react-jsx" ,
"module" : "ESNext" ,
"declaration" : true , // Generate .d.ts files
"sourceMap" : true ,
"outDir" : "dist" ,
"moduleResolution" : "node" ,
"allowSyntheticDefaultImports" : true ,
"emitDeclarationOnly" : true ,
"resolveJsonModule" : true ,
"lib" : [ "dom" , "dom.iterable" , "esnext" ],
"allowJs" : true ,
"noFallthroughCasesInSwitch" : true ,
"isolatedModules" : true ,
"baseUrl" : "." ,
"paths" : {
"@components/*" : [ "src/components/*" ],
"@constants/*" : [ "src/constants/*" ],
"@assets/*" : [ "src/assets/*" ]
}
},
"include" : [ "src/**/*" ],
"exclude" : [ "src/**/*.stories.tsx" , "src/**/*.stories.ts" ]
}
Story files (.stories.tsx) are excluded from the TypeScript build but are still type-checked during development.
Path Aliases
The library uses TypeScript path aliases for clean, maintainable imports across the codebase.
Available Aliases
Maps to src/components/* - Use for importing components
Maps to src/constants/* - Use for importing constants like Color and ColorV2
Maps to src/assets/* - Use for importing static assets like Lottie animations
Usage Examples
Cross-Directory Imports (Correct)
Same-Directory Imports (Correct)
Avoid Relative Paths (Wrong)
// ✅ CORRECT: Use path aliases for cross-directory imports
import Text from "@components/Text/Text" ;
import Color from "@constants/Color" ;
import ColorV2 from "@constants/ColorV2" ;
import loadingAnimation from "@assets/animations/button-loading.json" ;
import checkAnimation from "@assets/animations/button-check.json" ;
Real-World Example
From ButtonPrimary.tsx:
import React , { ComponentPropsWithoutRef , useEffect , useState } from "react" ;
import styled from "styled-components" ;
import { Player } from "@lottiefiles/react-lottie-player" ;
// Path aliases for cross-directory imports
import AnimationCheck from "@assets/animations/button-check.json" ;
import AnimationLoading from "@assets/animations/button-loading.json" ;
import Text from "@components/Text/Text" ;
import Color from "@constants/Color" ;
const ButtonPrimary = styled . button <{
$size ?: "small" | "normal" ;
$loading ?: boolean ;
$success ?: boolean ;
}> `
background-color: ${ ( props ) =>
props . $success ? Color . status . color . success : Color . background . primary } ;
// ... rest of styles
` ;
Benefits
Location Independent Imports work the same regardless of where the file is located in the project
Refactor Friendly Moving files doesn’t break imports that use path aliases
Better Readability Clear indication of where imports come from (components, constants, or assets)
IDE Autocomplete Enhanced TypeScript and IDE support for import suggestions
Component Type Definitions
All components export comprehensive TypeScript interfaces with JSDoc comments.
import { ComponentPropsWithoutRef } from "react" ;
/**
* Button component with multiple visual variants and built-in loading/success states.
*
* @example
* ```tsx
* <Button design="primary" loading={isLoading}>
* Submit
* </Button>
* ```
*/
export interface ButtonProps extends ComponentPropsWithoutRef < "button" > {
/** Visual variant: `primary` for main actions, `secondary` for less emphasis */
design ?: "primary" | "secondary" | "text" | "image" | "call-to-action" ;
/** Button size: `normal` (default) or `small` for compact layouts */
size ?: "small" | "normal" ;
icon ?: React . ReactElement ;
iconPosition ?: "left" | "right" ;
/** Shows animated loading spinner (Lottie animation) */
loading ?: boolean ;
disabled ?: boolean ;
/** Triggers success animation (Lottie checkmark) */
success ?: boolean ;
/** Delay in milliseconds before showing loading animation */
animationDelay ?: number ;
/** Duration in milliseconds for success animation before callback */
animationTime ?: number ;
/** Time in seconds to display countdown on button */
countdown ?: number ;
/** Callback fired when success animation completes */
onSuccess ?: ( success : boolean ) => void ;
/** Callback fired when countdown reaches zero */
onCountdownEnd ?: () => void ;
}
Extending ComponentPropsWithoutRef<"button"> ensures all standard HTML button attributes are supported with proper types.
Text Component Types
/**
* Unified typography component that renders headers (h1-h6, d1),
* paragraphs (p, p2, c1, c2, o1, o2), or button text (b1, b2, b3).
* Automatically chooses the correct semantic HTML element based on the `type` prop.
*
* @example
* ```tsx
* <Text type="h1" weight="bold">Page Title</Text>
* <Text type="p" color={ColorV2.text.neutralMedium}>Body text</Text>
* <Text type="b1">Button text</Text>
* ```
*/
export type TextProps = HeaderProps | ParagraphProps | ButtonProps ;
Variant Component Types
Variant implementations define their own interfaces:
export interface Props extends ComponentPropsWithoutRef < "button" > {
size ?: "small" | "normal" ;
icon ?: React . ReactElement ;
iconPosition ?: "left" | "right" ;
loading ?: boolean ;
success ?: boolean ;
animationDelay ?: number ;
animationTime ?: number ;
countdown ?: number ;
onSuccess ?: ( success : boolean ) => void ;
onCountdownEnd ?: () => void ;
}
Styled Components with TypeScript
Typing Styled Components
Use TypeScript generics to type styled-components:
import styled from "styled-components" ;
const ButtonPrimary = styled . button <{
$size ?: "small" | "normal" ;
$loading ?: boolean ;
$countdown ?: boolean ;
$success ?: boolean ;
}> `
height: ${ ( props ) => ( props . $size === "small" ? "40px" : "56px" ) } ;
background-color: ${ ( props ) =>
props . $success ? Color . status . color . success : Color . background . primary } ;
cursor: ${ ( props ) =>
props . disabled || props . $loading || props . $countdown
? "default"
: "pointer" } ;
` ;
Always use transient props (prefixed with $) for props that should not be passed to the DOM element.
Composing Styled Components
When extending other components, specify types:
import Text from "@components/Text/Text" ;
const Label = styled ( Text ) < {
$size? : "small" | "normal" ;
$icon : boolean ;
} > `
display: flex;
align-items: center;
gap: 6px;
font-size: ${ ( props ) => ( props . $size === "small" ? "14px" : "15px" ) } ;
margin-left: ${ ( props ) => ( props . $icon ? "6px" : "0" ) } ;
` ;
Type Imports from Library
Consumers can import types from the library:
import { ButtonProps } from "@adoptaunabuelo/react-components" ;
import type { ComponentPropsWithoutRef } from "react" ;
interface MyCustomButtonProps extends ButtonProps {
customProp ?: string ;
}
const MyButton : React . FC < MyCustomButtonProps > = ( props ) => {
return < Button { ... props } /> ;
};
Generic Type Patterns
ComponentPropsWithoutRef
Use ComponentPropsWithoutRef to inherit all standard HTML element props:
import { ComponentPropsWithoutRef } from "react" ;
// Inherits all button props (onClick, disabled, type, etc.)
export interface ButtonProps extends ComponentPropsWithoutRef < "button" > {
design ?: "primary" | "secondary" ;
loading ?: boolean ;
}
// Inherits all input props (value, onChange, placeholder, etc.)
export interface InputProps extends ComponentPropsWithoutRef < "input" > {
error ?: string ;
label ?: string ;
}
Union Types
Use union types for variant discrimination:
export type TextProps = HeaderProps | ParagraphProps | ButtonProps ;
type ButtonDesign = "primary" | "secondary" | "text" | "image" | "call-to-action" ;
type ButtonSize = "small" | "normal" ;
Optional Props
Use ? for optional properties:
export interface ButtonProps {
design ?: "primary" | "secondary" ; // Optional, defaults in component
size ?: "small" | "normal" ; // Optional, defaults in component
loading ?: boolean ; // Optional, defaults to false
icon ?: React . ReactElement ; // Optional
onClick ?: ( e : React . MouseEvent < HTMLButtonElement >) => void ; // Optional callback
}
JSON Module Types
The library imports JSON files (like Lottie animations) with proper typing:
import AnimationCheck from "@assets/animations/button-check.json" ;
import AnimationLoading from "@assets/animations/button-loading.json" ;
// TypeScript resolves JSON files thanks to "resolveJsonModule": true
Build Output
The build process generates TypeScript declarations:
dist/
├── esm/ # ESM modules
│ ├── components/
│ ├── constants/
│ └── ...
└── index.d.ts # Type declarations
Consumers get full TypeScript support when importing from the library:
import { Button , Text , Color , ColorV2 } from "@adoptaunabuelo/react-components" ;
// IDE provides full autocomplete and type checking ✨
Best Practices
Use Path Aliases Consistently
// ✅ Good - consistent use of aliases
import Text from "@components/Text/Text" ;
import Color from "@constants/Color" ;
// ❌ Bad - mixing aliases and relative paths
import Text from "../../Text/Text" ;
import Color from "@constants/Color" ;
Document Props with JSDoc
export interface ButtonProps {
/** Visual variant: `primary` for main actions, `secondary` for less emphasis */
design ?: "primary" | "secondary" ;
/** Shows animated loading spinner (Lottie animation) */
loading ?: boolean ;
}
Use Transient Props in Styled Components
// ✅ Good - transient props don't leak to DOM
const Button = styled . button <{ $loading : boolean }> `
opacity: ${ p => p . $loading ? 0.5 : 1 } ;
` ;
// ❌ Bad - causes React warnings
const Button = styled . button <{ loading : boolean }> `
opacity: ${ p => p . loading ? 0.5 : 1 } ;
` ;
Extend Standard HTML Props
import { ComponentPropsWithoutRef } from "react" ;
// Inherits all standard button attributes automatically
export interface ButtonProps extends ComponentPropsWithoutRef < "button" > {
design ?: "primary" | "secondary" ;
}
Component Architecture Learn about the variant router pattern and export structure
Styling Guide Understand styled-components and color constants