@damarkuncoro/ui-library
v0.0.4
Published
A strict Meta-Architecture compliant UI library focusing on Separation of Concerns, Zero Hardcoding, and Contract-Driven Development.
Readme
@damarkuncoro/ui-library
A strict Meta-Architecture compliant UI library focusing on Separation of Concerns, Zero Hardcoding, and Contract-Driven Development.
Features
- Meta Architecture: Strict separation between Logic (Base) and Visuals (Skin).
- Contract-Driven: All component APIs and Visual Styles are defined by rigid Contracts.
- Zero Hardcoding: Every visual value (color, spacing, size) is derived from Design Tokens or Contracts.
- Multi-Skin Support: Comes with Tailwind CSS skin by default, but supports framework-agnostic implementations.
- TypeScript First: Built with strict type safety and
as constassertions. - Tailwind v3 & v4 Support: Compatible with both Tailwind CSS v3 and v4.
Installation
pnpm add @damarkuncoro/ui-librarySetup
1. Theme Provider
Wrap your application with ThemeProvider to inject design tokens (CSS Variables).
import { ThemeProvider } from '@damarkuncoro/ui-library';
function App() {
return (
<ThemeProvider>
<YourApp />
</ThemeProvider>
);
}2. Tailwind Configuration
Configure Tailwind to use the library's preset and CSS variables.
For Tailwind v3:
// tailwind.config.js
const { preset, content } = require('@damarkuncoro/ui-library/tailwind/v3');
module.exports = {
content: [
'./src/**/*.{js,jsx,ts,tsx}',
...content(),
],
theme: {
extend: preset.theme.extend,
},
presets: [preset],
};For Tailwind v4:
// tailwind.config.js
import { preset } from '@damarkuncoro/ui-library/tailwind/v4';
export default {
presets: [preset],
};3. Import CSS Variables
Import the contract fallback CSS to ensure design tokens are available:
/* index.css */
@import '@damarkuncoro/ui-library/styles/contract-fallback.css';Usage
Button
The Button component supports multiple variants, sizes, and states.
import { Button } from '@damarkuncoro/ui-library';
// Standard usage (Tailwind Skin)
<Button variant="primary" size="md" onClick={() => console.log('Clicked')}>
Click Me
</Button>
// With Icons
<Button leftIcon={<span>👈</span>} variant="outline">
Go Back
</Button>
// Loading State
<Button isLoading variant="primary">
Processing...
</Button>
// Disabled State
<Button disabled variant="secondary">
Disabled
</Button>Button Variants
primary- Primary action buttonsecondary- Secondary action buttonoutline- Outlined buttonghost- Ghost button (no background)danger- Destructive action button
Button Sizes
sm- Small buttonmd- Medium button (default)lg- Large button
Button Props
| Prop | Type | Default | Description |
|------|------|----------|-------------|
| children | ReactNode | - | Button content (required) |
| variant | ButtonVariant | 'primary' | Visual style variant |
| size | ButtonSize | 'md' | Button size |
| isLoading | boolean | false | Show loading spinner |
| leftIcon | ReactNode | - | Icon before text |
| rightIcon | ReactNode | - | Icon after text |
| disabled | boolean | false | Disable button |
| onClick | function | - | Click handler |
Input
The Input component supports multiple variants, sizes, icons, and validation states.
import { Input } from '@damarkuncoro/ui-library';
// Standard usage
<Input
placeholder="Enter your name"
variant="outline"
onChange={(e) => console.log(e.target.value)}
/>
// With Icons
<Input
placeholder="Search..."
leftIcon={<span>🔍</span>}
variant="filled"
/>
// Invalid State
<Input
placeholder="Email"
isInvalid={true}
variant="outline"
/>
// Disabled State
<Input
placeholder="Read only"
disabled
variant="flushed"
/>Input Variants
outline- Outlined input (default)filled- Filled background inputflushed- Bottom border only input
Input Sizes
sm- Small inputmd- Medium input (default)lg- Large input
Input Props
| Prop | Type | Default | Description |
|------|------|----------|-------------|
| placeholder | string | - | Placeholder text |
| variant | InputVariant | 'outline' | Visual style variant |
| size | InputSize | 'md' | Input size |
| isInvalid | boolean | false | Show error state |
| leftIcon | ReactNode | - | Icon before input |
| rightIcon | ReactNode | - | Icon after input |
| disabled | boolean | false | Disable input |
| readOnly | boolean | false | Make input read-only |
| onChange | function | - | Change handler |
| inputClassName | string | - | Custom class for input element |
| wrapperStyle | CSSProperties | - | Custom inline styles for wrapper |
Native Skin
For projects not using Tailwind CSS, use the native skin components:
import { ButtonNative, InputNative } from '@damarkuncoro/ui-library';
<ButtonNative variant="primary">Native Button</ButtonNative>
<InputNative placeholder="Native Input" />Customization
1. Theming (Easy)
You can override default design tokens (colors, etc.) by passing a themeOverrides prop to ThemeProvider.
const myBrandTheme = {
light: {
'--color-primary-main': '#ff4757', // Change primary color to Red
'--color-primary-hover': '#ff6b81',
},
dark: {
'--color-primary-main': '#ff6b81',
}
};
function App() {
return (
<ThemeProvider themeOverrides={myBrandTheme}>
<Button variant="primary">Branded Button</Button>
</ThemeProvider>
);
}2. Custom Skins (Advanced)
If you need complete control over visual implementation (e.g., using a different CSS framework like Emotion or Styled Components), you can build your own Skin on top of our Base components.
This library follows a strict dependency rule:
- Contracts: JSON/TS definitions of Logic (Props) and Visuals (Tokens).
- Base UI: Functional components (Logic, ARIA, DOM). Depends only on Logic Contracts.
- Skins: Visual implementations. Depend on Base UI + Visual Contracts.
To create your own skin:
- Import
ButtonBaseandbuttonSkinContractDef. - Create a wrapper that styles
ButtonBaseusing values frombuttonSkinContractDef. - Pass styles via
classNameorstyleprop.
import { ButtonBase, buttonSkinContractDef } from '@damarkuncoro/ui-library';
import styled from 'styled-components'; // Example
// 1. Read values from Contract (Single Source of Truth)
const { variants } = buttonSkinContractDef;
// 2. Build your Styled Component
const MyStyledButton = styled(ButtonBase)`
background-color: ${variants.primary.backgroundColor};
color: ${variants.primary.color};
/* ... map other contract values ... */
`;
// 3. Use it!
<MyStyledButton variant="primary">Custom Skin</MyStyledButton>Available Exports
Components
Button- Tailwind-styled button componentButtonNative- Native-styled button componentInput- Tailwind-styled input componentInputNative- Native-styled input component
Theme
ThemeProvider- Theme provider componentuseTheme- Theme hook
Contracts
buttonContractDef- Button logic contractbuttonSkinContractDef- Button visual contractinputContractDef- Input logic contractinputSkinContractDef- Input visual contract
Base Components
ButtonBase- Button logic componentInputBase- Input logic component
Example Components
ButtonVariantExamples- Button variant examplesButtonSizeExamples- Button size examplesButtonIconExamples- Button icon examplesButtonStateExamples- Button state examplesButtonCombinedExamples- Button combined examplesButtonNativeSkinExamples- Button native skin examplesButtonAccessibilityExamples- Button accessibility examplesInputVariantExamples- Input variant examplesInputSizeExamples- Input size examplesInputIconExamples- Input icon examplesInputStateExamples- Input state examplesInputCombinedExamples- Input combined examples
License
MIT
Author
Damar Kuncoro
