From eea543408989ba6a0b3c86d53dad44391ba12060 Mon Sep 17 00:00:00 2001 From: IamLRBA Date: Mon, 8 Dec 2025 10:59:34 +0300 Subject: [PATCH 1/2] feat(tokens): add comprehensive design tokens package Introduce @ode/tokens package with complete design token system for unified ODE design system. Includes base tokens (colors, typography, spacing, borders, shadows, motion, z-index, opacity), semantic tokens, component tokens, layout tokens, and accessibility tokens. Related: #29 --- packages/tokens/.gitignore | 19 + packages/tokens/.npmignore | 16 + packages/tokens/CONTRIBUTING.md | 332 ++++++++++ .../tokens/DESIGN_TOKENS_SPECIFICATION.md | 435 +++++++++++++ packages/tokens/EXAMPLES.md | 573 ++++++++++++++++++ packages/tokens/QUICK_START.md | 89 +++ packages/tokens/README.md | 208 +++++++ packages/tokens/SETUP_COMPLETE.md | 78 +++ packages/tokens/config.json | 57 ++ packages/tokens/package.json | 36 ++ packages/tokens/src/tokens/_tokensHeader.js | 12 + .../src/tokens/accessibility/contrast.json | 9 + .../src/tokens/accessibility/focus.json | 9 + .../tokens/accessibility/touch-targets.json | 8 + packages/tokens/src/tokens/base/borders.json | 20 + packages/tokens/src/tokens/base/colors.json | 45 ++ packages/tokens/src/tokens/base/motion.json | 16 + packages/tokens/src/tokens/base/opacity.json | 16 + .../src/tokens/base/shadows-react-native.json | 28 + packages/tokens/src/tokens/base/shadows.json | 12 + packages/tokens/src/tokens/base/spacing.json | 17 + .../tokens/src/tokens/base/typography.json | 50 ++ packages/tokens/src/tokens/base/z-index.json | 15 + .../tokens/src/tokens/components/icons.json | 33 + .../tokens/src/tokens/layout/breakpoints.json | 10 + .../tokens/src/tokens/layout/containers.json | 10 + packages/tokens/src/tokens/layout/grid.json | 9 + .../tokens/src/tokens/semantic/colors.json | 27 + packages/tokens/style-dictionary.config.js | 24 + 29 files changed, 2213 insertions(+) create mode 100644 packages/tokens/.gitignore create mode 100644 packages/tokens/.npmignore create mode 100644 packages/tokens/CONTRIBUTING.md create mode 100644 packages/tokens/DESIGN_TOKENS_SPECIFICATION.md create mode 100644 packages/tokens/EXAMPLES.md create mode 100644 packages/tokens/QUICK_START.md create mode 100644 packages/tokens/README.md create mode 100644 packages/tokens/SETUP_COMPLETE.md create mode 100644 packages/tokens/config.json create mode 100644 packages/tokens/package.json create mode 100644 packages/tokens/src/tokens/_tokensHeader.js create mode 100644 packages/tokens/src/tokens/accessibility/contrast.json create mode 100644 packages/tokens/src/tokens/accessibility/focus.json create mode 100644 packages/tokens/src/tokens/accessibility/touch-targets.json create mode 100644 packages/tokens/src/tokens/base/borders.json create mode 100644 packages/tokens/src/tokens/base/colors.json create mode 100644 packages/tokens/src/tokens/base/motion.json create mode 100644 packages/tokens/src/tokens/base/opacity.json create mode 100644 packages/tokens/src/tokens/base/shadows-react-native.json create mode 100644 packages/tokens/src/tokens/base/shadows.json create mode 100644 packages/tokens/src/tokens/base/spacing.json create mode 100644 packages/tokens/src/tokens/base/typography.json create mode 100644 packages/tokens/src/tokens/base/z-index.json create mode 100644 packages/tokens/src/tokens/components/icons.json create mode 100644 packages/tokens/src/tokens/layout/breakpoints.json create mode 100644 packages/tokens/src/tokens/layout/containers.json create mode 100644 packages/tokens/src/tokens/layout/grid.json create mode 100644 packages/tokens/src/tokens/semantic/colors.json create mode 100644 packages/tokens/style-dictionary.config.js diff --git a/packages/tokens/.gitignore b/packages/tokens/.gitignore new file mode 100644 index 000000000..5d86f9d0f --- /dev/null +++ b/packages/tokens/.gitignore @@ -0,0 +1,19 @@ +# Dependencies +node_modules/ + +# Build outputs +dist/ + +# Logs +*.log +npm-debug.log* + +# OS files +.DS_Store +Thumbs.db + +# IDE +.vscode/ +.idea/ +*.swp +*.swo diff --git a/packages/tokens/.npmignore b/packages/tokens/.npmignore new file mode 100644 index 000000000..12ef8ca52 --- /dev/null +++ b/packages/tokens/.npmignore @@ -0,0 +1,16 @@ +# Source files (not needed in npm package) +src/ +config.json +style-dictionary.config.js + +# Development files +*.md +!README.md + +# Git files +.gitignore +.git/ + +# Build files (will be generated) +node_modules/ + diff --git a/packages/tokens/CONTRIBUTING.md b/packages/tokens/CONTRIBUTING.md new file mode 100644 index 000000000..5efb87a23 --- /dev/null +++ b/packages/tokens/CONTRIBUTING.md @@ -0,0 +1,332 @@ +# Contributing to ODE Design Tokens + +Thank you for contributing to the ODE Design System! This guide will help you add, modify, or update design tokens. + +## Table of Contents + +1. [Getting Started](#getting-started) +2. [Token Structure](#token-structure) +3. [Adding New Tokens](#adding-new-tokens) +4. [Modifying Existing Tokens](#modifying-existing-tokens) +5. [Naming Conventions](#naming-conventions) +6. [Testing Your Changes](#testing-your-changes) +7. [Commit Guidelines](#commit-guidelines) + +--- + +## Getting Started + +### Prerequisites + +- Node.js (v14 or higher) +- npm (v6 or higher) + +### Setup + +```bash +# Navigate to the tokens package +cd packages/tokens + +# Install dependencies +npm install + +# Build tokens to see current output +npm run build +``` + +--- + +## Token Structure + +Tokens are organized into categories: + +``` +src/tokens/ +├── base/ # Foundation tokens (colors, typography, spacing, etc.) +├── semantic/ # Meaningful tokens (success, error, warning, info) +├── components/ # Component-specific tokens (icons, avatars, logos) +├── layout/ # Layout tokens (breakpoints, containers, grid) +└── accessibility/ # Accessibility tokens (contrast, focus, touch targets) +``` + +### When to Use Each Category + +- **Base**: Core design values that rarely change (colors, spacing, typography) +- **Semantic**: Tokens with meaning (success = green, error = red) +- **Components**: Values specific to UI components +- **Layout**: Structure-related values (breakpoints, containers) +- **Accessibility**: Inclusion-focused values (contrast, touch targets) + +--- + +## Adding New Tokens + +### Step 1: Choose the Right File + +Determine which category your token belongs to and edit the appropriate JSON file. + +**Example**: Adding a new color shade +- File: `src/tokens/base/colors.json` +- Category: Base (foundation) + +**Example**: Adding a new icon size +- File: `src/tokens/components/icons.json` +- Category: Components + +### Step 2: Add the Token + +Follow the existing structure in the JSON file. + +**Example**: Adding a new spacing value + +```json +{ + "spacing": { + "0": { "value": "0px" }, + "1": { "value": "4px" }, + // ... existing values ... + "28": { "value": "112px" } // ← New token + } +} +``` + +### Step 3: Follow Naming Conventions + +See [Naming Conventions](#naming-conventions) below. + +### Step 4: Build and Test + +```bash +npm run build +``` + +Check the generated files in `dist/` to ensure your token appears correctly. + +--- + +## Modifying Existing Tokens + +### Changing a Value + +1. Open the appropriate JSON file +2. Update the `value` field +3. Build: `npm run build` +4. Test in your application + +**Example**: Changing the primary brand color + +```json +// Before +"500": { "value": "#4F7F4E" } + +// After +"500": { "value": "#5A8F59" } +``` + +### Removing a Token + +1. Remove the token from the JSON file +2. Build: `npm run build` +3. Check for any breaking changes in dependent projects + +**⚠️ Warning**: Removing tokens can break existing code. Consider deprecating instead. + +--- + +## Naming Conventions + +### Pattern + +``` +{category}-{property}-{variant}-{scale} +``` + +### Examples + +| Token | Breakdown | +|-------|-----------| +| `color-brand-primary-500` | category: color, property: brand, variant: primary, scale: 500 | +| `spacing-4` | category: spacing, scale: 4 | +| `font-size-base` | category: font, property: size, variant: base | +| `border-radius-md` | category: border, property: radius, variant: md | + +### Rules + +1. **Use kebab-case** (lowercase with hyphens) +2. **Be descriptive** but concise +3. **Follow existing patterns** in the file +4. **Use semantic names** when possible (e.g., `base` instead of `16`) + +### Common Patterns + +- **Colors**: `color-{category}-{name}-{shade}` + - `color-brand-primary-500` + - `color-neutral-900` + - `color-semantic-success-500` + +- **Spacing**: `spacing-{number}` + - `spacing-0`, `spacing-1`, `spacing-4`, `spacing-24` + +- **Typography**: `font-{property}-{variant}` + - `font-size-base` + - `font-weight-bold` + - `line-height-normal` + +- **Borders**: `border-{property}-{variant}` + - `border-radius-md` + - `border-width-thin` + +--- + +## Testing Your Changes + +### 1. Build Tokens + +```bash +npm run build +``` + +This generates all output formats: +- `dist/css/tokens.css` - CSS variables +- `dist/js/tokens.js` - JavaScript +- `dist/js/tokens.d.ts` - TypeScript definitions +- `dist/json/tokens.json` - Raw JSON +- `dist/react-native/tokens.js` - React Native format + +### 2. Verify Output + +Check that your token appears in all output formats: + +```bash +# Check CSS output +grep "your-token-name" dist/css/tokens.css + +# Check JS output +grep "yourTokenName" dist/js/tokens.js +``` + +### 3. Test in Application + +Use your token in a test component: + +**CSS:** +```css +.test { + color: var(--color-your-new-token); +} +``` + +**React Native:** +```javascript +import { tokens } from '@ode/tokens/dist/react-native/tokens'; + +const style = { + color: tokens.color.your.new.token +}; +``` + +### 4. Check TypeScript (if applicable) + +If using TypeScript, verify autocomplete works: + +```typescript +import { colorYourNewToken } from '@ode/tokens/dist/js/tokens'; +``` + +--- + +## Commit Guidelines + +### Commit Message Format + +``` +type(scope): description + +[optional body] + +[optional footer] +``` + +### Types + +- `feat`: New token or token category +- `fix`: Bug fix in token values +- `docs`: Documentation updates +- `style`: Formatting changes (no token changes) +- `refactor`: Restructuring token files +- `chore`: Build process or tooling changes + +### Examples + +``` +feat(tokens): add spacing-28 token for large margins + +fix(tokens): correct primary brand color hex value + +docs(tokens): update README with new token examples +``` + +### What to Commit + +✅ **Do commit:** +- Source JSON files (`src/tokens/**/*.json`) +- Generated files (`dist/**/*`) +- Documentation updates +- Configuration changes + +❌ **Don't commit:** +- `node_modules/` +- Build artifacts (unless part of release) +- Personal IDE settings + +--- + +## Common Scenarios + +### Adding a New Color Scale + +1. Edit `src/tokens/base/colors.json` +2. Add the new color scale following existing pattern +3. Build and test + +```json +{ + "color": { + "brand": { + "tertiary": { + "50": { "value": "#..." }, + "500": { "value": "#..." }, + "900": { "value": "#..." } + } + } + } +} +``` + +### Adding a New Breakpoint + +1. Edit `src/tokens/layout/breakpoints.json` +2. Add the new breakpoint +3. Update container sizes if needed +4. Build and test + +### Adding Component-Specific Tokens + +1. Create or edit a file in `src/tokens/components/` +2. Add component-specific tokens +3. Document usage in EXAMPLES.md +4. Build and test + +--- + +## Questions? + +- Check the [Usage Examples section](./README.md#usage-examples) in README.md for usage examples +- See [Design Tokens Specification](./DESIGN_TOKENS_SPECIFICATION.md#1-color-tokens) for complete token reference +- Review [Examples Guide](./EXAMPLES.md#css-examples) for implementation patterns +- Open an issue or discussion on GitHub + +--- + +**Thank you for contributing to the ODE Design System!** + diff --git a/packages/tokens/DESIGN_TOKENS_SPECIFICATION.md b/packages/tokens/DESIGN_TOKENS_SPECIFICATION.md new file mode 100644 index 000000000..743db57a4 --- /dev/null +++ b/packages/tokens/DESIGN_TOKENS_SPECIFICATION.md @@ -0,0 +1,435 @@ +# ODE Design Tokens - Complete Specification + +This document provides the complete specification for all design tokens in the ODE Design System. For quick reference and usage examples, see the [README.md](./README.md#quick-start). + +## Table of Contents + +1. [Color Tokens](#1-color-tokens) +2. [Typography Tokens](#2-typography-tokens) +3. [Spacing Tokens](#3-spacing-tokens) +4. [Border Tokens](#4-border-tokens) +5. [Shadow Tokens](#5-shadow-tokens) +6. [Motion Tokens](#6-motion-tokens) +7. [Layout Tokens](#7-layout-tokens) +8. [Icon & Asset Tokens](#8-icon--asset-tokens) +9. [Z-Index Tokens](#9-z-index-tokens) +10. [Accessibility Tokens](#10-accessibility-tokens) +11. [Opacity Tokens](#11-opacity-tokens) + +--- + +## 1. Color Tokens + +### 1.1 Brand Colors + +Based on the ODE logo colors. + +#### Primary (Green) Scale + +| Shade | Token | Hex Value | Usage | +|-------|-------|-----------|-------| +| 50 | `color-brand-primary-50` | `#F0F7EF` | Lightest background | +| 100 | `color-brand-primary-100` | `#D9E9D8` | Subtle backgrounds | +| 200 | `color-brand-primary-200` | `#B9D5B8` | Dividers, borders | +| 300 | `color-brand-primary-300` | `#90BD8F` | Disabled states | +| 400 | `color-brand-primary-400` | `#6FA46E` | Hover states | +| 500 | `color-brand-primary-500` | `#4F7F4E` | **PRIMARY BRAND** | +| 600 | `color-brand-primary-600` | `#3F6A3E` | Pressed states | +| 700 | `color-brand-primary-700` | `#30552F` | Dark mode text | +| 800 | `color-brand-primary-800` | `#224021` | Dark mode backgrounds | +| 900 | `color-brand-primary-900` | `#173016` | Darkest elements | + +#### Secondary (Gold) Scale + +| Shade | Token | Hex Value | Usage | +|-------|-------|-----------|-------| +| 50 | `color-brand-secondary-50` | `#FEF9EE` | Light backgrounds | +| 100 | `color-brand-secondary-100` | `#FCEFD2` | Subtle accents | +| 200 | `color-brand-secondary-200` | `#F9E0A8` | Light borders | +| 300 | `color-brand-secondary-300` | `#F5CC75` | Medium accents | +| 400 | `color-brand-secondary-400` | `#F0B84D` | Hover states | +| 500 | `color-brand-secondary-500` | `#E9B85B` | **SECONDARY BRAND** | +| 600 | `color-brand-secondary-600` | `#D9A230` | Active states | +| 700 | `color-brand-secondary-700` | `#B8861C` | Important accents | +| 800 | `color-brand-secondary-800` | `#976D1A` | Dark borders | +| 900 | `color-brand-secondary-900` | `#7C5818` | Darkest accents | + +### 1.2 Neutral Colors + +| Shade | Token | Hex Value | Usage | +|-------|-------|-----------|-------| +| White | `color-neutral-white` | `#FFFFFF` | Pure white | +| 50 | `color-neutral-50` | `#FAFAFA` | Backgrounds | +| 100 | `color-neutral-100` | `#F5F5F5` | Subtle backgrounds | +| 200 | `color-neutral-200` | `#EEEEEE` | Dividers, borders | +| 300 | `color-neutral-300` | `#E0E0E0` | Disabled elements | +| 400 | `color-neutral-400` | `#BDBDBD` | Placeholder text | +| 500 | `color-neutral-500` | `#9E9E9E` | Secondary text | +| 600 | `color-neutral-600` | `#757575` | Body text | +| 700 | `color-neutral-700` | `#616161` | Primary text | +| 800 | `color-neutral-800` | `#424242` | Headings | +| 900 | `color-neutral-900` | `#212121` | Main headings | +| Black | `color-neutral-black` | `#000000` | Pure black | + +### 1.3 Semantic Colors + +#### Success + +| Shade | Token | Hex Value | Usage | +|-------|-------|-----------|-------| +| 50 | `color-semantic-success-50` | `#F0F9F0` | Success backgrounds | +| 500 | `color-semantic-success-500` | `#34C759` | Success messages | +| 600 | `color-semantic-success-600` | `#2E7D32` | Success borders | + +#### Error + +| Shade | Token | Hex Value | Usage | +|-------|-------|-----------|-------| +| 50 | `color-semantic-error-50` | `#FEF2F2` | Error backgrounds | +| 500 | `color-semantic-error-500` | `#F44336` | Error messages | +| 600 | `color-semantic-error-600` | `#DC2626` | Critical errors | + +#### Warning + +| Shade | Token | Hex Value | Usage | +|-------|-------|-----------|-------| +| 50 | `color-semantic-warning-50` | `#FFFBEB` | Warning backgrounds | +| 500 | `color-semantic-warning-500` | `#FF9500` | Warning messages | +| 600 | `color-semantic-warning-600` | `#D97706` | Important warnings | + +#### Info + +| Shade | Token | Hex Value | Usage | +|-------|-------|-----------|-------| +| 50 | `color-semantic-info-50` | `#EFF6FF` | Info backgrounds | +| 500 | `color-semantic-info-500` | `#2196F3` | Info messages | +| 600 | `color-semantic-info-600` | `#2563EB` | Important info | + +--- + +## 2. Typography Tokens + +### 2.1 Font Families + +| Token | Value | Usage | +|-------|-------|-------| +| `font-family-sans` | `-apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', sans-serif` | Primary UI text | +| `font-family-mono` | `'Courier New', Consolas, monospace` | Code, technical text | +| `font-family-display` | `-apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif` | Headings, titles | + +### 2.2 Font Sizes + +| Size | Token | Pixels | REM | Usage Example | +|------|-------|--------|-----|---------------| +| Extra Small | `font-size-xs` | 12px | 0.75rem | Labels, captions | +| Small | `font-size-sm` | 14px | 0.875rem | Small body text | +| Base | `font-size-base` | 16px | 1rem | **Body text** | +| Large | `font-size-lg` | 18px | 1.125rem | Lead paragraphs | +| Extra Large | `font-size-xl` | 20px | 1.25rem | Subheadings | +| 2X Large | `font-size-2xl` | 24px | 1.5rem | H4 headings | +| 3X Large | `font-size-3xl` | 32px | 2rem | H3 headings | +| 4X Large | `font-size-4xl` | 40px | 2.5rem | H2 headings | +| 5X Large | `font-size-5xl` | 48px | 3rem | H1 headings | +| 6X Large | `font-size-6xl` | 60px | 3.75rem | Hero headings | + +### 2.3 Font Weights + +| Token | Value | Usage | +|-------|-------|-------| +| `font-weight-light` | 300 | Light headings | +| `font-weight-regular` | 400 | **Body text** | +| `font-weight-medium` | 500 | Buttons, labels | +| `font-weight-semibold` | 600 | Subheadings | +| `font-weight-bold` | 700 | Main headings | + +### 2.4 Line Heights + +| Token | Value | Usage | +|-------|-------|-------| +| `line-height-none` | 1 | Tight (titles) | +| `line-height-tight` | 1.25 | Headings | +| `line-height-normal` | 1.5 | **Body text** | +| `line-height-relaxed` | 1.75 | Long paragraphs | +| `line-height-loose` | 2 | Poetry, quotes | + +### 2.5 Letter Spacing + +| Token | Value | Usage | +|-------|-------|-------| +| `letter-spacing-tighter` | -0.05em | Very tight (headings) | +| `letter-spacing-tight` | -0.025em | Tight (large text) | +| `letter-spacing-normal` | 0 | **Default spacing** | +| `letter-spacing-wide` | 0.025em | Slightly wider | +| `letter-spacing-wider` | 0.05em | Wider (uppercase text) | +| `letter-spacing-widest` | 0.1em | Very wide (labels) | + +--- + +## 3. Spacing Tokens + +### 3.1 Base Unit System + +- **Base Unit**: 4px (0.25rem) +- **Scale**: Multiples of 4px + +### 3.2 Spacing Scale + +| Size | Token | Pixels | REM | Common Use | +|------|-------|--------|-----|------------| +| 0 | `spacing-0` | 0px | 0rem | No space | +| 1 | `spacing-1` | 4px | 0.25rem | Tight padding | +| 2 | `spacing-2` | 8px | 0.5rem | Small padding | +| 3 | `spacing-3` | 12px | 0.75rem | Button padding | +| 4 | `spacing-4` | 16px | 1rem | **Default spacing** | +| 6 | `spacing-6` | 24px | 1.5rem | Section padding | +| 8 | `spacing-8` | 32px | 2rem | Container padding | +| 10 | `spacing-10` | 40px | 2.5rem | Large padding | +| 12 | `spacing-12` | 48px | 3rem | Page margins | +| 16 | `spacing-16` | 64px | 4rem | Section margins | +| 20 | `spacing-20` | 80px | 5rem | Large margins | +| 24 | `spacing-24` | 96px | 6rem | Hero margins | + +--- + +## 4. Border Tokens + +### 4.1 Border Radius + +| Size | Token | Value | Usage | +|------|-------|-------|-------| +| None | `border-radius-none` | 0px | Square elements | +| Small | `border-radius-sm` | 4px | Inputs, small buttons | +| Medium | `border-radius-md` | 8px | **Buttons, cards** | +| Large | `border-radius-lg` | 12px | Modals, large cards | +| Extra Large | `border-radius-xl` | 16px | Hero sections | +| Full | `border-radius-full` | 9999px | Pills, circles | + +### 4.2 Border Width + +| Token | Value | Usage | +|-------|-------|-------| +| `border-width-none` | 0px | No border | +| `border-width-hairline` | 0.5px | Subtle dividers | +| `border-width-thin` | 1px | **Default borders** | +| `border-width-medium` | 2px | Focus states | +| `border-width-thick` | 3px | Important elements | + +--- + +## 5. Shadow Tokens + +### 5.1 Shadow Scale (Web) + +| Level | Token | CSS Value | Usage | +|-------|-------|-----------|-------| +| None | `shadow-none` | `none` | No shadow | +| X-Small | `shadow-xs` | `0 1px 2px 0 rgba(0,0,0,0.05)` | Subtle elevation | +| Small | `shadow-sm` | `0 1px 3px 0 rgba(0,0,0,0.1)` | Cards, inputs | +| Medium | `shadow-md` | `0 4px 6px -1px rgba(0,0,0,0.1)` | **Dropdowns** | +| Large | `shadow-lg` | `0 10px 15px -3px rgba(0,0,0,0.1)` | Modals | +| X-Large | `shadow-xl` | `0 20px 25px -5px rgba(0,0,0,0.1)` | Popovers | +| 2X-Large | `shadow-2xl` | `0 25px 50px -12px rgba(0,0,0,0.25)` | Dialogs | + +### 5.2 React Native Shadows + +React Native uses a different shadow format with separate properties: + +- `shadowColor`: Color of the shadow +- `shadowOffset`: { width, height } offset +- `shadowOpacity`: Opacity (0-1) +- `shadowRadius`: Blur radius +- `elevation`: Android elevation + +See `src/tokens/base/shadows-react-native.json` for React Native shadow definitions. + +--- + +## 6. Motion Tokens + +### 6.1 Duration Tokens + +| Token | Value | Usage | +|-------|-------|-------| +| `duration-instant` | 0ms | Immediate changes | +| `duration-fast` | 150ms | Hover states | +| `duration-normal` | 250ms | **Default transitions** | +| `duration-slow` | 350ms | Modal animations | +| `duration-slower` | 500ms | Page transitions | + +### 6.2 Easing Functions + +| Token | Value | Usage | +|-------|-------|-------| +| `easing-linear` | `linear` | Progress bars | +| `easing-easeIn` | `cubic-bezier(0.4, 0, 1, 1)` | Exiting elements | +| `easing-easeOut` | `cubic-bezier(0, 0, 0.2, 1)` | **Entering elements** | +| `easing-easeInOut` | `cubic-bezier(0.4, 0, 0.2, 1)` | Default transitions | + +--- + +## 7. Layout Tokens + +### 7.1 Breakpoints + +| Name | Token | Value | Device Type | +|------|-------|-------|-------------| +| Mobile | `breakpoint-sm` | 640px | Small phones | +| Tablet | `breakpoint-md` | 768px | Large phones, small tablets | +| Desktop | `breakpoint-lg` | 1024px | Tablets, small laptops | +| Large Desktop | `breakpoint-xl` | 1280px | **Laptops** | +| Extra Large | `breakpoint-2xl` | 1536px | Large monitors | + +### 7.2 Container Max Widths + +| Size | Token | Value | Usage | +|------|-------|-------|-------| +| Small | `container-sm` | 640px | Mobile content | +| Medium | `container-md` | 768px | Tablet content | +| Large | `container-lg` | 1024px | Desktop content | +| Extra Large | `container-xl` | 1280px | **Default container** | +| 2X Large | `container-2xl` | 1536px | Wide screens | + +### 7.3 Grid System + +| Token | Value | Usage | +|-------|-------|-------| +| `grid-columns` | 12 | **Total columns in grid** | +| `grid-gutter` | `{spacing.4}` | Space between columns (16px) | +| `grid-gutterSm` | `{spacing.2}` | Small gutter (8px) | +| `grid-gutterLg` | `{spacing.6}` | Large gutter (24px) | + +--- + +## 8. Icon & Asset Tokens + +### 8.1 Icon Sizes + +| Size | Token | Pixels | Usage | +|------|-------|--------|-------| +| Extra Small | `icon-size-xs` | 12px | Inline with small text | +| Small | `icon-size-sm` | 16px | Buttons, labels | +| Medium | `icon-size-md` | 20px | **Default icon size** | +| Large | `icon-size-lg` | 24px | Navigation, headers | +| Extra Large | `icon-size-xl` | 32px | Feature icons | +| 2X Large | `icon-size-2xl` | 40px | Hero sections | +| 3X Large | `icon-size-3xl` | 48px | Large feature icons | + +### 8.2 Icon Stroke Width + +| Token | Value | Usage | +|-------|-------|-------| +| `icon-stroke-thin` | 1px | Small icons (12-16px) | +| `icon-stroke-normal` | 1.5px | **Default (20-24px)** | +| `icon-stroke-medium` | 2px | Large icons (32px+) | +| `icon-stroke-thick` | 2.5px | Very large icons (48px+) | + +### 8.3 Avatar Sizes + +| Size | Token | Pixels | Usage | +|------|-------|--------|-------| +| Small | `avatar-sm` | 24px | Comments, lists | +| Medium | `avatar-md` | 32px | **Default avatar** | +| Large | `avatar-lg` | 48px | Profile pages | +| Extra Large | `avatar-xl` | 64px | Hero sections | +| 2X Large | `avatar-2xl` | 96px | Large profiles | + +### 8.4 Logo Sizes + +| Size | Token | Pixels | Usage | +|------|-------|--------|-------| +| Small | `logo-sm` | 80px | Mobile header | +| Medium | `logo-md` | 120px | **Default logo** | +| Large | `logo-lg` | 160px | Desktop header | +| Extra Large | `logo-xl` | 200px | Landing pages | + +--- + +## 9. Z-Index Tokens + +### 9.1 Layering System + +| Layer | Token | Value | Usage | +|-------|-------|-------|-------| +| Hide | `z-index-hide` | -1 | Hidden elements | +| Base | `z-index-base` | 0 | Default layer | +| Docked | `z-index-docked` | 10 | Fixed headers | +| Dropdown | `z-index-dropdown` | 1000 | Dropdown menus | +| Sticky | `z-index-sticky` | 1100 | Sticky elements | +| Overlay | `z-index-overlay` | 1300 | Backdrops | +| Modal | `z-index-modal` | 1400 | Modal dialogs | +| Popover | `z-index-popover` | 1500 | Tooltips, popovers | +| Toast | `z-index-toast` | 1700 | Notifications | +| Tooltip | `z-index-tooltip` | 1800 | Tooltips (above all) | + +--- + +## 10. Accessibility Tokens + +### 10.1 Color Contrast Ratios + +| WCAG Level | Token | Ratio | Usage | +|------------|-------|-------|-------| +| AA Large Text | `contrast-aaLarge` | 3:1 | Headings 18px+ or bold 14px+ | +| AA Normal Text | `contrast-aaNormal` | 4.5:1 | **Body text (minimum)** | +| AAA Large Text | `contrast-aaaLarge` | 4.5:1 | Headings (enhanced) | +| AAA Normal Text | `contrast-aaaNormal` | 7:1 | Body text (enhanced) | + +### 10.2 Focus States + +| Token | Value | Usage | +|-------|-------|-------| +| `focus-ringWidth` | 2px | **Focus ring thickness** | +| `focus-ringOffset` | 2px | Space between element and ring | +| `focus-ringColor` | `{color.brand.primary.500}` | Focus ring color | +| `focus-ringOpacity` | `{opacity.100}` | Focus ring opacity | + +### 10.3 Touch Target Sizes + +| Token | Value | Usage | +|-------|-------|-------| +| `touchTarget-min` | 44px | **Minimum size (iOS/Android)** | +| `touchTarget-comfortable` | 48px | Comfortable size | +| `touchTarget-large` | 56px | Large buttons | + +--- + +## 11. Opacity Tokens + +### 11.1 Opacity Scale + +| Token | Value | Usage | +|-------|-------|-------| +| `opacity-0` | 0 | Completely transparent | +| `opacity-10` | 0.1 | Very subtle overlay | +| `opacity-20` | 0.2 | Light overlay | +| `opacity-30` | 0.3 | Medium overlay | +| `opacity-40` | 0.4 | Noticeable overlay | +| `opacity-50` | 0.5 | **Half transparent** | +| `opacity-60` | 0.6 | More visible | +| `opacity-70` | 0.7 | Mostly opaque | +| `opacity-80` | 0.8 | Very visible | +| `opacity-90` | 0.9 | Almost solid | +| `opacity-100` | 1 | Completely solid | + +--- + +## Token Naming Convention + +All tokens follow this pattern: + +``` +{category}-{property}-{variant}-{scale} +``` + +**Examples:** +- `color-brand-primary-500` (category: color, property: brand, variant: primary, scale: 500) +- `spacing-4` (category: spacing, scale: 4) +- `font-size-base` (category: font, property: size, variant: base) +- `border-radius-md` (category: border, property: radius, variant: md) + +--- + +**Document Version**: 1.0.0 +**Last Updated**: 2024 +**Maintained By**: ODE Design System Team + diff --git a/packages/tokens/EXAMPLES.md b/packages/tokens/EXAMPLES.md new file mode 100644 index 000000000..59d3ab4af --- /dev/null +++ b/packages/tokens/EXAMPLES.md @@ -0,0 +1,573 @@ +# Design Tokens - Usage Examples + +This document provides practical examples of using ODE design tokens in different contexts. + +## Table of Contents + +1. [CSS Examples](#css-examples) +2. [React Web Examples](#react-web-examples) +3. [React Native Examples](#react-native-examples) +4. [Material UI Theming](#material-ui-theming) + +--- + +## CSS Examples + +### Primary Button + +```css +.button-primary { + /* Colors */ + background-color: var(--color-brand-primary-500); + color: var(--color-neutral-white); + + /* Typography */ + font-size: var(--font-size-base); + font-weight: var(--font-weight-medium); + line-height: var(--line-height-normal); + + /* Spacing */ + padding: var(--spacing-3) var(--spacing-6); /* 12px 24px */ + + /* Borders */ + border: none; + border-radius: var(--border-radius-md); /* 8px */ + + /* Effects */ + box-shadow: var(--shadow-sm); + transition: all var(--duration-fast) var(--easing-ease-out); + + /* Accessibility */ + min-height: var(--touch-target-min); /* 44px */ +} + +.button-primary:hover { + background-color: var(--color-brand-primary-400); + box-shadow: var(--shadow-md); +} + +.button-primary:focus-visible { + outline: var(--focus-ringWidth) solid var(--focus-ringColor); + outline-offset: var(--focus-ringOffset); +} + +.button-primary:active { + background-color: var(--color-brand-primary-600); +} + +.button-primary:disabled { + background-color: var(--color-neutral-300); + color: var(--color-neutral-500); + opacity: var(--opacity-50); + cursor: not-allowed; +} +``` + +### Input Field + +```css +.input { + /* Colors */ + background-color: var(--color-neutral-white); + color: var(--color-neutral-900); + border-color: var(--color-neutral-300); + + /* Typography */ + font-size: var(--font-size-base); + font-weight: var(--font-weight-regular); + line-height: var(--line-height-normal); + + /* Spacing */ + padding: var(--spacing-3) var(--spacing-4); /* 12px 16px */ + + /* Borders */ + border-width: var(--border-width-thin); /* 1px */ + border-style: solid; + border-radius: var(--border-radius-sm); /* 4px */ + + /* Effects */ + transition: border-color var(--duration-fast) var(--easing-ease-out); +} + +.input:focus { + border-width: var(--border-width-medium); /* 2px */ + border-color: var(--focus-ringColor); + outline: none; +} + +.input-error { + border-color: var(--color-semantic-error-500); +} + +.input:disabled { + background-color: var(--color-neutral-100); + color: var(--color-neutral-400); + opacity: var(--opacity-50); + cursor: not-allowed; +} +``` + +### Card Component + +```css +.card { + /* Colors */ + background-color: var(--color-neutral-white); + border-color: var(--color-neutral-200); + + /* Spacing */ + padding: var(--spacing-6); /* 24px */ + + /* Borders */ + border-width: var(--border-width-thin); + border-style: solid; + border-radius: var(--border-radius-md); /* 8px */ + + /* Effects */ + box-shadow: var(--shadow-sm); +} + +.card-header { + margin-bottom: var(--spacing-4); /* 16px */ + font-size: var(--font-size-xl); + font-weight: var(--font-weight-semibold); + color: var(--color-neutral-900); +} + +.card-body { + color: var(--color-neutral-600); + font-size: var(--font-size-base); + line-height: var(--line-height-relaxed); +} +``` + +### Responsive Container + +```css +.container { + width: 100%; + max-width: var(--container-xl); /* 1280px */ + padding: var(--spacing-4); /* 16px */ + margin: 0 auto; +} + +/* Tablet and up */ +@media (min-width: var(--breakpoint-md)) { + .container { + padding: var(--spacing-6); /* 24px */ + } +} + +/* Desktop and up */ +@media (min-width: var(--breakpoint-lg)) { + .container { + padding: var(--spacing-8); /* 32px */ + } +} +``` + +### Alert/Toast Component + +```css +.alert { + padding: var(--spacing-4); + border-radius: var(--border-radius-md); + border-width: var(--border-width-thin); + border-style: solid; + box-shadow: var(--shadow-md); +} + +.alert-success { + background-color: var(--color-semantic-success-50); + border-color: var(--color-semantic-success-500); + color: var(--color-semantic-success-600); +} + +.alert-error { + background-color: var(--color-semantic-error-50); + border-color: var(--color-semantic-error-500); + color: var(--color-semantic-error-600); +} + +.alert-warning { + background-color: var(--color-semantic-warning-50); + border-color: var(--color-semantic-warning-500); + color: var(--color-semantic-warning-600); +} + +.alert-info { + background-color: var(--color-semantic-info-50); + border-color: var(--color-semantic-info-500); + color: var(--color-semantic-info-600); +} +``` + +--- + +## React Web Examples + +### Using CSS Variables + +```jsx +import './styles.css'; // Imports tokens.css + +function Button({ children, variant = 'primary' }) { + return ( + + ); +} +``` + +### Using JavaScript Tokens + +```jsx +import { + colorBrandPrimary500, + spacing3, + spacing6, + borderRadiusMd +} from '@ode/tokens/dist/js/tokens'; + +function Button({ children }) { + const buttonStyle = { + backgroundColor: colorBrandPrimary500, + padding: `${spacing3} ${spacing6}`, + borderRadius: borderRadiusMd, + color: '#FFFFFF', + border: 'none', + cursor: 'pointer' + }; + + return ( + + ); +} +``` + +### Styled Components + +```jsx +import styled from 'styled-components'; +import tokens from '@ode/tokens/dist/js/tokens'; + +const Button = styled.button` + background-color: ${tokens.color.brand.primary[500]}; + color: ${tokens.color.neutral.white}; + padding: ${tokens.spacing[3]} ${tokens.spacing[6]}; + border-radius: ${tokens.border.radius.md}; + font-size: ${tokens.font.size.base}; + font-weight: ${tokens.font.weight.medium}; + border: none; + cursor: pointer; + transition: all ${tokens.duration.fast} ${tokens.easing.easeOut}; + + &:hover { + background-color: ${tokens.color.brand.primary[400]}; + } + + &:focus-visible { + outline: ${tokens.focus.ringWidth} solid ${tokens.focus.ringColor}; + outline-offset: ${tokens.focus.ringOffset}; + } +`; +``` + +--- + +## React Native Examples + +### Basic Component Styling + +```jsx +import { StyleSheet } from 'react-native'; +import { tokens } from '@ode/tokens/dist/react-native/tokens'; + +const styles = StyleSheet.create({ + button: { + backgroundColor: tokens.color.brand.primary[500], // #4F7F4E + paddingVertical: parseInt(tokens.spacing[3]), // 12 + paddingHorizontal: parseInt(tokens.spacing[6]), // 24 + borderRadius: parseInt(tokens.border.radius.md), // 8 + minHeight: parseInt(tokens.touchTarget.min), // 44 + }, + buttonText: { + color: tokens.color.neutral.white, + fontSize: parseInt(tokens.font.size.base), // 16 + fontWeight: tokens.font.weight.medium, + } +}); + +function Button({ title, onPress }) { + return ( + + {title} + + ); +} +``` + +### Input Field + +```jsx +import { StyleSheet, TextInput } from 'react-native'; +import { tokens } from '@ode/tokens/dist/react-native/tokens'; + +const styles = StyleSheet.create({ + input: { + backgroundColor: tokens.color.neutral.white, + color: tokens.color.neutral[900], + paddingVertical: parseInt(tokens.spacing[3]), + paddingHorizontal: parseInt(tokens.spacing[4]), + borderWidth: parseInt(tokens.border.width.thin), + borderColor: tokens.color.neutral[300], + borderRadius: parseInt(tokens.border.radius.sm), + fontSize: parseInt(tokens.font.size.base), + minHeight: parseInt(tokens.touchTarget.min), + } +}); + +function Input({ value, onChangeText, placeholder }) { + return ( + + ); +} +``` + +### Card Component + +```jsx +import { StyleSheet, View, Text } from 'react-native'; +import { tokens } from '@ode/tokens/dist/react-native/tokens'; + +const styles = StyleSheet.create({ + card: { + backgroundColor: tokens.color.neutral.white, + padding: parseInt(tokens.spacing[6]), + borderRadius: parseInt(tokens.border.radius.md), + borderWidth: parseInt(tokens.border.width.thin), + borderColor: tokens.color.neutral[200], + ...tokens.shadow.reactNative.sm, // Spread shadow properties + }, + cardHeader: { + fontSize: parseInt(tokens.font.size.xl), + fontWeight: tokens.font.weight.semibold, + color: tokens.color.neutral[900], + marginBottom: parseInt(tokens.spacing[4]), + }, + cardBody: { + fontSize: parseInt(tokens.font.size.base), + color: tokens.color.neutral[600], + lineHeight: parseInt(tokens.font.lineHeight.relaxed) * parseInt(tokens.font.size.base), + } +}); + +function Card({ title, children }) { + return ( + + {title} + {children} + + ); +} +``` + +### Responsive Design + +```jsx +import { StyleSheet, Dimensions } from 'react-native'; +import { tokens } from '@ode/tokens/dist/react-native/tokens'; + +const { width } = Dimensions.get('window'); +const isTablet = width >= parseInt(tokens.breakpoint.md); + +const styles = StyleSheet.create({ + container: { + padding: isTablet + ? parseInt(tokens.spacing[8]) + : parseInt(tokens.spacing[4]), + maxWidth: isTablet + ? parseInt(tokens.container.lg) + : '100%', + } +}); +``` + +--- + +## Material UI Theming + +### Creating Custom MUI Theme + +```jsx +import { createTheme } from '@mui/material/styles'; +import tokens from '@ode/tokens/dist/js/tokens'; + +const odeTheme = createTheme({ + palette: { + primary: { + main: tokens.color.brand.primary[500], + light: tokens.color.brand.primary[400], + dark: tokens.color.brand.primary[600], + contrastText: tokens.color.neutral.white, + }, + secondary: { + main: tokens.color.brand.secondary[500], + light: tokens.color.brand.secondary[400], + dark: tokens.color.brand.secondary[600], + }, + success: { + main: tokens.color.semantic.success[500], + light: tokens.color.semantic.success[50], + dark: tokens.color.semantic.success[600], + }, + error: { + main: tokens.color.semantic.error[500], + light: tokens.color.semantic.error[50], + dark: tokens.color.semantic.error[600], + }, + warning: { + main: tokens.color.semantic.warning[500], + light: tokens.color.semantic.warning[50], + dark: tokens.color.semantic.warning[600], + }, + info: { + main: tokens.color.semantic.info[500], + light: tokens.color.semantic.info[50], + dark: tokens.color.semantic.info[600], + }, + grey: { + 50: tokens.color.neutral[50], + 100: tokens.color.neutral[100], + 200: tokens.color.neutral[200], + 300: tokens.color.neutral[300], + 400: tokens.color.neutral[400], + 500: tokens.color.neutral[500], + 600: tokens.color.neutral[600], + 700: tokens.color.neutral[700], + 800: tokens.color.neutral[800], + 900: tokens.color.neutral[900], + }, + }, + typography: { + fontFamily: tokens.font.family.sans, + fontSize: parseInt(tokens.font.size.base), + h1: { + fontSize: parseInt(tokens.font.size[5]), + fontWeight: tokens.font.weight.bold, + lineHeight: tokens.font.lineHeight.tight, + }, + h2: { + fontSize: parseInt(tokens.font.size[4]), + fontWeight: tokens.font.weight.bold, + }, + body1: { + fontSize: parseInt(tokens.font.size.base), + lineHeight: tokens.font.lineHeight.normal, + }, + }, + spacing: parseInt(tokens.spacing[1]), // Base spacing unit (4px) + shape: { + borderRadius: parseInt(tokens.border.radius.md), + }, + shadows: [ + 'none', + tokens.shadow.xs, + tokens.shadow.sm, + tokens.shadow.md, + tokens.shadow.lg, + tokens.shadow.xl, + tokens.shadow['2xl'], + ], +}); + +export default odeTheme; +``` + +### Using the Theme + +```jsx +import { ThemeProvider } from '@mui/material/styles'; +import CssBaseline from '@mui/material/CssBaseline'; +import odeTheme from './theme'; + +function App() { + return ( + + + {/* Your app components */} + + ); +} +``` + +--- + +## Common Patterns + +### Color Utilities + +```css +/* Text colors */ +.text-primary { color: var(--color-neutral-900); } +.text-secondary { color: var(--color-neutral-600); } +.text-muted { color: var(--color-neutral-500); } + +/* Background colors */ +.bg-primary { background-color: var(--color-brand-primary-500); } +.bg-secondary { background-color: var(--color-brand-secondary-500); } +.bg-white { background-color: var(--color-neutral-white); } +.bg-gray-50 { background-color: var(--color-neutral-50); } + +/* Border colors */ +.border-light { border-color: var(--color-neutral-200); } +.border-medium { border-color: var(--color-neutral-300); } +``` + +### Spacing Utilities + +```css +/* Padding */ +.p-0 { padding: var(--spacing-0); } +.p-1 { padding: var(--spacing-1); } +.p-2 { padding: var(--spacing-2); } +.p-4 { padding: var(--spacing-4); } +.p-6 { padding: var(--spacing-6); } + +/* Margin */ +.m-0 { margin: var(--spacing-0); } +.m-4 { margin: var(--spacing-4); } +.m-6 { margin: var(--spacing-6); } +.mb-4 { margin-bottom: var(--spacing-4); } +.mt-6 { margin-top: var(--spacing-6); } +``` + +### Typography Utilities + +```css +.text-xs { font-size: var(--font-size-xs); } +.text-sm { font-size: var(--font-size-sm); } +.text-base { font-size: var(--font-size-base); } +.text-lg { font-size: var(--font-size-lg); } +.text-xl { font-size: var(--font-size-xl); } + +.font-light { font-weight: var(--font-weight-light); } +.font-regular { font-weight: var(--font-weight-regular); } +.font-medium { font-weight: var(--font-weight-medium); } +.font-bold { font-weight: var(--font-weight-bold); } +``` + +--- + +**For more information:** +- [Quick Start Guide](./README.md#quick-start) - Getting started with tokens +- [Design Tokens Specification](./DESIGN_TOKENS_SPECIFICATION.md#1-color-tokens) - Complete token reference + diff --git a/packages/tokens/QUICK_START.md b/packages/tokens/QUICK_START.md new file mode 100644 index 000000000..17cbf16ae --- /dev/null +++ b/packages/tokens/QUICK_START.md @@ -0,0 +1,89 @@ +# Quick Start Guide + +Get up and running with ODE Design Tokens in a few minutes! + +## Installation + +```bash +cd packages/tokens +npm install +npm run build +``` + +## Using Tokens + +### Option 1: CSS Variables (Recommended for Web) + +```css +/* Import in your CSS file */ +@import '@ode/tokens/dist/css/tokens.css'; + +/* Use tokens */ +.button { + background-color: var(--color-brand-primary-500); + padding: var(--spacing-3) var(--spacing-6); + border-radius: var(--border-radius-md); +} +``` + +### Option 2: JavaScript/TypeScript + +```javascript +// Import tokens +import { + colorBrandPrimary500, + spacing3, + spacing6 +} from '@ode/tokens/dist/js/tokens'; + +// Use in your code +const buttonStyle = { + backgroundColor: colorBrandPrimary500, + padding: `${spacing3} ${spacing6}` +}; +``` + +### Option 3: React Native + +```javascript +// Import tokens +import { tokens } from '@ode/tokens/dist/react-native/tokens'; + +// Use in StyleSheet +const styles = StyleSheet.create({ + button: { + backgroundColor: tokens.color.brand.primary[500], + paddingVertical: parseInt(tokens.spacing[3]), + paddingHorizontal: parseInt(tokens.spacing[6]) + } +}); +``` + +## Common Tokens + +### Colors +- Primary: `--color-brand-primary-500` (#4F7F4E) +- Secondary: `--color-brand-secondary-500` (#E9B85B) +- Success: `--color-semantic-success-500` (#34C759) +- Error: `--color-semantic-error-500` (#F44336) + +### Spacing +- Small: `--spacing-2` (8px) +- Default: `--spacing-4` (16px) +- Large: `--spacing-6` (24px) + +### Typography +- Base: `--font-size-base` (16px) +- Large: `--font-size-lg` (18px) +- Heading: `--font-size-2xl` (24px) + +## Next Steps + +- Read the [README.md](./README.md#quick-start) for complete documentation +- Check [EXAMPLES.md](./EXAMPLES.md#css-examples) for usage patterns +- See [DESIGN_TOKENS_SPECIFICATION.md](./DESIGN_TOKENS_SPECIFICATION.md#1-color-tokens) for all available tokens + +--- + +**Need help?** Check the main [README.md](./README.md#quick-start) or open an issue on GitHub. + diff --git a/packages/tokens/README.md b/packages/tokens/README.md new file mode 100644 index 000000000..beed1255f --- /dev/null +++ b/packages/tokens/README.md @@ -0,0 +1,208 @@ +# @ode/tokens + +**ODE Design System - Unified Design Tokens** + +A comprehensive design token package for the Open Data Ensemble (ODE) ecosystem. This package provides a single source of truth for colors, typography, spacing, and all design values used across React Native, React Web, and all ODE applications. + +## What Are Design Tokens? + +Design tokens are the **smallest pieces of design information** - like colors, spacing, and font sizes. Instead of hardcoding values like `#4F7F4E` or `16px` throughout your code, you use tokens like `color-brand-primary-500` or `spacing-4`. + +**Benefits:** +- **Consistency** - Same values everywhere +- **Easy Updates** - Change once, update everywhere +- **Type Safety** - TypeScript definitions included +- **Multi-Platform** - Works for web, mobile, and more + +## Installation + +```bash +npm install @ode/tokens +``` + +## Quick Start + +### For React Web (CSS) + +```css +/* Import the CSS variables */ +@import '@ode/tokens/dist/css/tokens.css'; + +/* Use tokens in your CSS */ +.button { + background-color: var(--color-brand-primary-500); + padding: var(--spacing-3) var(--spacing-6); + border-radius: var(--border-radius-md); + color: var(--color-neutral-white); +} +``` + +### For React Web (JavaScript/TypeScript) + +```javascript +import { colorBrandPrimary500, spacing3, spacing6 } from '@ode/tokens/dist/js/tokens'; + +const buttonStyle = { + backgroundColor: colorBrandPrimary500, + padding: `${spacing3} ${spacing6}`, + borderRadius: '8px' +}; +``` + +### For React Native + +```javascript +import { tokens } from '@ode/tokens/dist/react-native/tokens'; + +const styles = StyleSheet.create({ + button: { + backgroundColor: tokens.color.brand.primary[500], // #4F7F4E + paddingVertical: tokens.spacing[3], // 12 + paddingHorizontal: tokens.spacing[6], // 24 + borderRadius: 8 + } +}); +``` + +## Package Structure + +``` +packages/tokens/ +├── src/tokens/ # Source token files (JSON) +│ ├── base/ # Foundation tokens +│ │ ├── colors.json +│ │ ├── typography.json +│ │ ├── spacing.json +│ │ ├── borders.json +│ │ ├── shadows.json +│ │ ├── motion.json +│ │ ├── z-index.json +│ │ └── opacity.json +│ ├── semantic/ # Meaningful tokens +│ │ └── colors.json # Success, error, warning, info +│ ├── components/ # Component-specific tokens +│ │ └── icons.json +│ ├── layout/ # Layout tokens +│ │ ├── breakpoints.json +│ │ ├── containers.json +│ │ └── grid.json +│ └── accessibility/ # Accessibility tokens +│ ├── contrast.json +│ ├── focus.json +│ └── touch-targets.json +├── dist/ # Generated outputs (auto-created) +│ ├── css/ # CSS variables +│ ├── js/ # JavaScript/TypeScript +│ ├── json/ # Raw JSON +│ └── react-native/ # React Native format +├── config.json # Style Dictionary configuration +└── package.json +``` + +## Available Tokens + +For a complete list of all available tokens with detailed specifications, see the [Design Tokens Specification](./DESIGN_TOKENS_SPECIFICATION.md). Key sections: +- [Color Tokens](./DESIGN_TOKENS_SPECIFICATION.md#1-color-tokens) +- [Typography Tokens](./DESIGN_TOKENS_SPECIFICATION.md#2-typography-tokens) +- [Spacing Tokens](./DESIGN_TOKENS_SPECIFICATION.md#3-spacing-tokens) +- [Layout Tokens](./DESIGN_TOKENS_SPECIFICATION.md#7-layout-tokens) +- [Accessibility Tokens](./DESIGN_TOKENS_SPECIFICATION.md#10-accessibility-tokens) + +**Quick Reference:** +- **Colors**: Brand (primary green, secondary gold), neutral grays, semantic colors (success, error, warning, info) +- **Typography**: Font families, sizes (12px-60px), weights, line heights, letter spacing +- **Spacing**: 4px-based scale (0-96px) +- **Borders**: Radius and width tokens +- **Shadows**: Web CSS shadows + React Native shadow objects +- **Motion**: Duration and easing functions +- **Layout**: Breakpoints, containers, grid system +- **Accessibility**: Contrast ratios, focus states, touch targets + +## Development + +### Building Tokens + +```bash +cd packages/tokens +npm install +npm run build +``` + +This generates all output formats in the `dist/` directory: +- CSS variables (`dist/css/tokens.css`) +- JavaScript/TypeScript (`dist/js/tokens.js` and `tokens.d.ts`) +- JSON (`dist/json/tokens.json`) +- React Native format (`dist/react-native/tokens.js`) + +### Adding New Tokens + +For detailed instructions on adding new tokens, naming conventions, and best practices, see the [Adding New Tokens section](./CONTRIBUTING.md#adding-new-tokens) in the Contributing Guide. + +## Usage Examples + +For comprehensive usage examples including CSS, React Web, React Native, and Material UI theming, see the [Examples Guide](./EXAMPLES.md). Key sections: +- [CSS Examples](./EXAMPLES.md#css-examples) +- [React Web Examples](./EXAMPLES.md#react-web-examples) +- [React Native Examples](./EXAMPLES.md#react-native-examples) +- [Material UI Theming](./EXAMPLES.md#material-ui-theming) + +## Design Principles + +Our design tokens follow these principles: + +1. **Accessibility First** - All colors meet WCAG 2.1 AA contrast ratios +2. **Consistency** - Unified visual language across all platforms +3. **Simplicity** - Clear, predictable token names +4. **Scalability** - Easy to extend and maintain + +## Token Categories Explained + +### Base Tokens +Foundation values that rarely change: colors, typography, spacing, borders, shadows, motion, z-index, opacity. + +### Semantic Tokens +Tokens with meaning: success (green), error (red), warning (orange), info (blue). These can change if the design system evolves. + +### Component Tokens +Values specific to components: icon sizes, avatar sizes, logo sizes. + +### Layout Tokens +Structure-related: breakpoints, container widths, grid system. + +### Accessibility Tokens +Inclusion-focused: contrast ratios, focus states, minimum touch target sizes. + +## Updating Tokens + +For detailed instructions on updating tokens, see the [Modifying Existing Tokens section](./CONTRIBUTING.md#modifying-existing-tokens) in the Contributing Guide. + +## Contributing + +We welcome contributions! For guidelines on adding new tokens, modifying existing ones, and following our conventions, see the [Contributing Guide](./CONTRIBUTING.md). Key sections: +- [Adding New Tokens](./CONTRIBUTING.md#adding-new-tokens) +- [Modifying Existing Tokens](./CONTRIBUTING.md#modifying-existing-tokens) +- [Naming Conventions](./CONTRIBUTING.md#naming-conventions) +- [Testing Your Changes](./CONTRIBUTING.md#testing-your-changes) + +## License + +MIT + +## Documentation + +- **[Quick Start Guide](./QUICK_START.md)** - Get started in a few minutes +- **[Design Tokens Specification](./DESIGN_TOKENS_SPECIFICATION.md)** - Complete token reference with all values +- **[Examples Guide](./EXAMPLES.md)** - Real-world usage examples for CSS, React, React Native, and Material UI +- **[Contributing Guide](./CONTRIBUTING.md)** - How to add, modify, and update tokens +- **[Setup Complete](./SETUP_COMPLETE.md)** - Package structure and overview + +## Related + +- [ODE Design System Discussion](https://github.com/OpenDataEnsemble/ode/discussions/29) +- [Style Dictionary Documentation](https://amzn.github.io/style-dictionary/) + +--- + +**Maintained by**: ODE Design System Team +**Version**: 1.0.0 + diff --git a/packages/tokens/SETUP_COMPLETE.md b/packages/tokens/SETUP_COMPLETE.md new file mode 100644 index 000000000..c7d3d957a --- /dev/null +++ b/packages/tokens/SETUP_COMPLETE.md @@ -0,0 +1,78 @@ +# Complete Design Tokens Package Setup + +The ODE Design Tokens package complete layout. + +## Package Structure + +``` +packages/tokens/ +├── src/tokens/ # Source token files (JSON) +│ ├── base/ # Foundation tokens +│ │ ├── colors.json # Brand & neutral colors +│ │ ├── typography.json # Font families, sizes, weights +│ │ ├── spacing.json # Spacing scale (4px base) +│ │ ├── borders.json # Border radius & width +│ │ ├── shadows.json # Web shadows +│ │ ├── shadows-react-native.json # React Native shadows +│ │ ├── motion.json # Duration & easing +│ │ ├── z-index.json # Layering system +│ │ └── opacity.json # Opacity scale +│ ├── semantic/ # Meaningful tokens +│ │ └── colors.json # Success, error, warning, info +│ ├── components/ # Component-specific +│ │ └── icons.json # Icon sizes, avatars, logos +│ ├── layout/ # Layout tokens +│ │ ├── breakpoints.json # Responsive breakpoints +│ │ ├── containers.json # Container max widths +│ │ └── grid.json # Grid system +│ └── accessibility/ # Accessibility tokens +│ ├── contrast.json # WCAG contrast ratios +│ ├── focus.json # Focus states +│ └── touch-targets.json # Minimum touch sizes +├── dist/ # Generated outputs (after build) +├── config.json # Style Dictionary config +├── style-dictionary.config.js # Style Dictionary setup +├── package.json # Package configuration +├── .gitignore # Git ignore rules +├── .npmignore # NPM ignore rules +├── README.md # Main documentation +├── DESIGN_TOKENS_SPECIFICATION.md # Complete token reference +├── EXAMPLES.md # Usage examples +├── CONTRIBUTING.md # Contribution guide +└── QUICK_START.md # Quick start guide +``` + +## What's Included + +This package includes a complete design token system with multiple output formats. For detailed information: + +- **Token System**: See [Design Tokens Specification](./DESIGN_TOKENS_SPECIFICATION.md#1-color-tokens) for all available tokens +- **Output Formats**: CSS variables, JavaScript/TypeScript, React Native, and JSON formats +- **Documentation**: Comprehensive guides - see [Documentation Files](#documentation-files) below +- **Developer Experience**: TypeScript definitions, Style Dictionary automation, clear naming conventions + +## Next Steps + +For getting started quickly, see the [Quick Start Guide](./QUICK_START.md#installation). For detailed usage examples, see the [Examples Guide](./EXAMPLES.md#css-examples). + +## Documentation Files + +- **[README.md](./README.md)** - Start here! Main documentation +- **[QUICK_START.md](./QUICK_START.md)** - Get started in 5 minutes +- **[DESIGN_TOKENS_SPECIFICATION.md](./DESIGN_TOKENS_SPECIFICATION.md)** - Complete token reference +- **[EXAMPLES.md](./EXAMPLES.md)** - Real-world usage examples +- **[CONTRIBUTING.md](./CONTRIBUTING.md)** - How to add/modify tokens + +For information about token categories and key features, see the [Token Categories Explained section](./README.md#token-categories-explained) in the README. + +## Related Resources + +- [ODE Design System Discussion](https://github.com/OpenDataEnsemble/ode/discussions/29) +- [Style Dictionary Documentation](https://amzn.github.io/style-dictionary/) + +--- + +**Status**: ✅ Ready to use +**Version**: 1.0.0 +**Last Updated**: 2024 + diff --git a/packages/tokens/config.json b/packages/tokens/config.json new file mode 100644 index 000000000..e9132e981 --- /dev/null +++ b/packages/tokens/config.json @@ -0,0 +1,57 @@ +{ + "source": ["src/tokens/**/*.json"], + "platforms": { + "css": { + "transformGroup": "css", + "buildPath": "dist/css/", + "files": [ + { + "destination": "tokens.css", + "format": "css/variables", + "options": { + "fileHeader": "customHeader" + } + } + ] + }, + "js": { + "transformGroup": "js", + "buildPath": "dist/js/", + "files": [ + { + "destination": "tokens.js", + "format": "javascript/es6" + }, + { + "destination": "tokens.d.ts", + "format": "typescript/es6-declarations" + } + ] + }, + "json": { + "transformGroup": "js", + "buildPath": "dist/json/", + "files": [ + { + "destination": "tokens.json", + "format": "json/nested" + } + ] + }, + "react-native": { + "transformGroup": "react-native", + "buildPath": "dist/react-native/", + "files": [ + { + "destination": "tokens.js", + "format": "javascript/module" + }, + { + "destination": "tokens.d.ts", + "format": "typescript/es6-declarations" + } + ] + } + } +} + diff --git a/packages/tokens/package.json b/packages/tokens/package.json new file mode 100644 index 000000000..a00302c63 --- /dev/null +++ b/packages/tokens/package.json @@ -0,0 +1,36 @@ +{ + "name": "@ode/tokens", + "version": "1.0.0", + "description": "ODE Design System - Unified design tokens for React Native, React Web, and all ODE applications", + "main": "dist/js/tokens.js", + "types": "dist/js/tokens.d.ts", + "files": [ + "dist", + "README.md" + ], + "scripts": { + "build": "style-dictionary build --config style-dictionary.config.js", + "clean": "rm -rf dist", + "prepublishOnly": "npm run build" + }, + "keywords": [ + "design-tokens", + "design-system", + "ode", + "react-native", + "react", + "css-variables", + "tokens" + ], + "author": "ODE Design System Team", + "license": "MIT", + "devDependencies": { + "style-dictionary": "^3.9.0" + }, + "repository": { + "type": "git", + "url": "https://github.com/OpenDataEnsemble/ode.git", + "directory": "packages/tokens" + } +} + diff --git a/packages/tokens/src/tokens/_tokensHeader.js b/packages/tokens/src/tokens/_tokensHeader.js new file mode 100644 index 000000000..d00eca97c --- /dev/null +++ b/packages/tokens/src/tokens/_tokensHeader.js @@ -0,0 +1,12 @@ +module.exports = function() { + return `/** + * ODE Design Tokens + * + * This file is auto-generated by Style Dictionary. + * Do not edit directly. Edit source files in src/tokens/ instead. + * + * Generated: ${new Date().toISOString()} + */ +`; +}; + diff --git a/packages/tokens/src/tokens/accessibility/contrast.json b/packages/tokens/src/tokens/accessibility/contrast.json new file mode 100644 index 000000000..ab100311d --- /dev/null +++ b/packages/tokens/src/tokens/accessibility/contrast.json @@ -0,0 +1,9 @@ +{ + "contrast": { + "aaLarge": { "value": "3:1" }, + "aaNormal": { "value": "4.5:1" }, + "aaaLarge": { "value": "4.5:1" }, + "aaaNormal": { "value": "7:1" } + } +} + diff --git a/packages/tokens/src/tokens/accessibility/focus.json b/packages/tokens/src/tokens/accessibility/focus.json new file mode 100644 index 000000000..061bc8e89 --- /dev/null +++ b/packages/tokens/src/tokens/accessibility/focus.json @@ -0,0 +1,9 @@ +{ + "focus": { + "ringWidth": { "value": "2px" }, + "ringOffset": { "value": "2px" }, + "ringColor": { "value": "{color.brand.primary.500}" }, + "ringOpacity": { "value": "{opacity.100}" } + } +} + diff --git a/packages/tokens/src/tokens/accessibility/touch-targets.json b/packages/tokens/src/tokens/accessibility/touch-targets.json new file mode 100644 index 000000000..955847330 --- /dev/null +++ b/packages/tokens/src/tokens/accessibility/touch-targets.json @@ -0,0 +1,8 @@ +{ + "touchTarget": { + "min": { "value": "44px" }, + "comfortable": { "value": "48px" }, + "large": { "value": "56px" } + } +} + diff --git a/packages/tokens/src/tokens/base/borders.json b/packages/tokens/src/tokens/base/borders.json new file mode 100644 index 000000000..44583e4c7 --- /dev/null +++ b/packages/tokens/src/tokens/base/borders.json @@ -0,0 +1,20 @@ +{ + "border": { + "radius": { + "none": { "value": "0px" }, + "sm": { "value": "4px" }, + "md": { "value": "8px" }, + "lg": { "value": "12px" }, + "xl": { "value": "16px" }, + "full": { "value": "9999px" } + }, + "width": { + "none": { "value": "0px" }, + "hairline": { "value": "0.5px" }, + "thin": { "value": "1px" }, + "medium": { "value": "2px" }, + "thick": { "value": "3px" } + } + } +} + diff --git a/packages/tokens/src/tokens/base/colors.json b/packages/tokens/src/tokens/base/colors.json new file mode 100644 index 000000000..662aa40e5 --- /dev/null +++ b/packages/tokens/src/tokens/base/colors.json @@ -0,0 +1,45 @@ +{ + "color": { + "brand": { + "primary": { + "50": { "value": "#F0F7EF" }, + "100": { "value": "#D9E9D8" }, + "200": { "value": "#B9D5B8" }, + "300": { "value": "#90BD8F" }, + "400": { "value": "#6FA46E" }, + "500": { "value": "#4F7F4E" }, + "600": { "value": "#3F6A3E" }, + "700": { "value": "#30552F" }, + "800": { "value": "#224021" }, + "900": { "value": "#173016" } + }, + "secondary": { + "50": { "value": "#FEF9EE" }, + "100": { "value": "#FCEFD2" }, + "200": { "value": "#F9E0A8" }, + "300": { "value": "#F5CC75" }, + "400": { "value": "#F0B84D" }, + "500": { "value": "#E9B85B" }, + "600": { "value": "#D9A230" }, + "700": { "value": "#B8861C" }, + "800": { "value": "#976D1A" }, + "900": { "value": "#7C5818" } + } + }, + "neutral": { + "white": { "value": "#FFFFFF" }, + "50": { "value": "#FAFAFA" }, + "100": { "value": "#F5F5F5" }, + "200": { "value": "#EEEEEE" }, + "300": { "value": "#E0E0E0" }, + "400": { "value": "#BDBDBD" }, + "500": { "value": "#9E9E9E" }, + "600": { "value": "#757575" }, + "700": { "value": "#616161" }, + "800": { "value": "#424242" }, + "900": { "value": "#212121" }, + "black": { "value": "#000000" } + } + } +} + diff --git a/packages/tokens/src/tokens/base/motion.json b/packages/tokens/src/tokens/base/motion.json new file mode 100644 index 000000000..c0473ca92 --- /dev/null +++ b/packages/tokens/src/tokens/base/motion.json @@ -0,0 +1,16 @@ +{ + "duration": { + "instant": { "value": "0ms" }, + "fast": { "value": "150ms" }, + "normal": { "value": "250ms" }, + "slow": { "value": "350ms" }, + "slower": { "value": "500ms" } + }, + "easing": { + "linear": { "value": "linear" }, + "easeIn": { "value": "cubic-bezier(0.4, 0, 1, 1)" }, + "easeOut": { "value": "cubic-bezier(0, 0, 0.2, 1)" }, + "easeInOut": { "value": "cubic-bezier(0.4, 0, 0.2, 1)" } + } +} + diff --git a/packages/tokens/src/tokens/base/opacity.json b/packages/tokens/src/tokens/base/opacity.json new file mode 100644 index 000000000..4b2871880 --- /dev/null +++ b/packages/tokens/src/tokens/base/opacity.json @@ -0,0 +1,16 @@ +{ + "opacity": { + "0": { "value": "0" }, + "10": { "value": "0.1" }, + "20": { "value": "0.2" }, + "30": { "value": "0.3" }, + "40": { "value": "0.4" }, + "50": { "value": "0.5" }, + "60": { "value": "0.6" }, + "70": { "value": "0.7" }, + "80": { "value": "0.8" }, + "90": { "value": "0.9" }, + "100": { "value": "1" } + } +} + diff --git a/packages/tokens/src/tokens/base/shadows-react-native.json b/packages/tokens/src/tokens/base/shadows-react-native.json new file mode 100644 index 000000000..880315d8e --- /dev/null +++ b/packages/tokens/src/tokens/base/shadows-react-native.json @@ -0,0 +1,28 @@ +{ + "shadow": { + "reactNative": { + "sm": { + "shadowColor": { "value": "#000000" }, + "shadowOffset": { "value": "{0, 1}" }, + "shadowOpacity": { "value": "0.1" }, + "shadowRadius": { "value": "2" }, + "elevation": { "value": "2" } + }, + "md": { + "shadowColor": { "value": "#000000" }, + "shadowOffset": { "value": "{0, 2}" }, + "shadowOpacity": { "value": "0.15" }, + "shadowRadius": { "value": "4" }, + "elevation": { "value": "4" } + }, + "lg": { + "shadowColor": { "value": "#000000" }, + "shadowOffset": { "value": "{0, 4}" }, + "shadowOpacity": { "value": "0.2" }, + "shadowRadius": { "value": "8" }, + "elevation": { "value": "8" } + } + } + } +} + diff --git a/packages/tokens/src/tokens/base/shadows.json b/packages/tokens/src/tokens/base/shadows.json new file mode 100644 index 000000000..10443a570 --- /dev/null +++ b/packages/tokens/src/tokens/base/shadows.json @@ -0,0 +1,12 @@ +{ + "shadow": { + "none": { "value": "none" }, + "xs": { "value": "0 1px 2px 0 rgba(0,0,0,0.05)" }, + "sm": { "value": "0 1px 3px 0 rgba(0,0,0,0.1)" }, + "md": { "value": "0 4px 6px -1px rgba(0,0,0,0.1)" }, + "lg": { "value": "0 10px 15px -3px rgba(0,0,0,0.1)" }, + "xl": { "value": "0 20px 25px -5px rgba(0,0,0,0.1)" }, + "2xl": { "value": "0 25px 50px -12px rgba(0,0,0,0.25)" } + } +} + diff --git a/packages/tokens/src/tokens/base/spacing.json b/packages/tokens/src/tokens/base/spacing.json new file mode 100644 index 000000000..de7f31682 --- /dev/null +++ b/packages/tokens/src/tokens/base/spacing.json @@ -0,0 +1,17 @@ +{ + "spacing": { + "0": { "value": "0px" }, + "1": { "value": "4px" }, + "2": { "value": "8px" }, + "3": { "value": "12px" }, + "4": { "value": "16px" }, + "6": { "value": "24px" }, + "8": { "value": "32px" }, + "10": { "value": "40px" }, + "12": { "value": "48px" }, + "16": { "value": "64px" }, + "20": { "value": "80px" }, + "24": { "value": "96px" } + } +} + diff --git a/packages/tokens/src/tokens/base/typography.json b/packages/tokens/src/tokens/base/typography.json new file mode 100644 index 000000000..5d36496c4 --- /dev/null +++ b/packages/tokens/src/tokens/base/typography.json @@ -0,0 +1,50 @@ +{ + "font": { + "family": { + "sans": { + "value": "-apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', sans-serif" + }, + "mono": { + "value": "'Courier New', Consolas, monospace" + }, + "display": { + "value": "-apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif" + } + }, + "size": { + "xs": { "value": "12px" }, + "sm": { "value": "14px" }, + "base": { "value": "16px" }, + "lg": { "value": "18px" }, + "xl": { "value": "20px" }, + "2xl": { "value": "24px" }, + "3xl": { "value": "32px" }, + "4xl": { "value": "40px" }, + "5xl": { "value": "48px" }, + "6xl": { "value": "60px" } + }, + "weight": { + "light": { "value": "300" }, + "regular": { "value": "400" }, + "medium": { "value": "500" }, + "semibold": { "value": "600" }, + "bold": { "value": "700" } + }, + "lineHeight": { + "none": { "value": "1" }, + "tight": { "value": "1.25" }, + "normal": { "value": "1.5" }, + "relaxed": { "value": "1.75" }, + "loose": { "value": "2" } + }, + "letterSpacing": { + "tighter": { "value": "-0.05em" }, + "tight": { "value": "-0.025em" }, + "normal": { "value": "0" }, + "wide": { "value": "0.025em" }, + "wider": { "value": "0.05em" }, + "widest": { "value": "0.1em" } + } + } +} + diff --git a/packages/tokens/src/tokens/base/z-index.json b/packages/tokens/src/tokens/base/z-index.json new file mode 100644 index 000000000..fc098227d --- /dev/null +++ b/packages/tokens/src/tokens/base/z-index.json @@ -0,0 +1,15 @@ +{ + "zIndex": { + "hide": { "value": "-1" }, + "base": { "value": "0" }, + "docked": { "value": "10" }, + "dropdown": { "value": "1000" }, + "sticky": { "value": "1100" }, + "overlay": { "value": "1300" }, + "modal": { "value": "1400" }, + "popover": { "value": "1500" }, + "toast": { "value": "1700" }, + "tooltip": { "value": "1800" } + } +} + diff --git a/packages/tokens/src/tokens/components/icons.json b/packages/tokens/src/tokens/components/icons.json new file mode 100644 index 000000000..96838afd7 --- /dev/null +++ b/packages/tokens/src/tokens/components/icons.json @@ -0,0 +1,33 @@ +{ + "icon": { + "size": { + "xs": { "value": "12px" }, + "sm": { "value": "16px" }, + "md": { "value": "20px" }, + "lg": { "value": "24px" }, + "xl": { "value": "32px" }, + "2xl": { "value": "40px" }, + "3xl": { "value": "48px" } + }, + "stroke": { + "thin": { "value": "1px" }, + "normal": { "value": "1.5px" }, + "medium": { "value": "2px" }, + "thick": { "value": "2.5px" } + } + }, + "avatar": { + "sm": { "value": "24px" }, + "md": { "value": "32px" }, + "lg": { "value": "48px" }, + "xl": { "value": "64px" }, + "2xl": { "value": "96px" } + }, + "logo": { + "sm": { "value": "80px" }, + "md": { "value": "120px" }, + "lg": { "value": "160px" }, + "xl": { "value": "200px" } + } +} + diff --git a/packages/tokens/src/tokens/layout/breakpoints.json b/packages/tokens/src/tokens/layout/breakpoints.json new file mode 100644 index 000000000..8bfe54f3c --- /dev/null +++ b/packages/tokens/src/tokens/layout/breakpoints.json @@ -0,0 +1,10 @@ +{ + "breakpoint": { + "sm": { "value": "640px" }, + "md": { "value": "768px" }, + "lg": { "value": "1024px" }, + "xl": { "value": "1280px" }, + "2xl": { "value": "1536px" } + } +} + diff --git a/packages/tokens/src/tokens/layout/containers.json b/packages/tokens/src/tokens/layout/containers.json new file mode 100644 index 000000000..212d981f0 --- /dev/null +++ b/packages/tokens/src/tokens/layout/containers.json @@ -0,0 +1,10 @@ +{ + "container": { + "sm": { "value": "640px" }, + "md": { "value": "768px" }, + "lg": { "value": "1024px" }, + "xl": { "value": "1280px" }, + "2xl": { "value": "1536px" } + } +} + diff --git a/packages/tokens/src/tokens/layout/grid.json b/packages/tokens/src/tokens/layout/grid.json new file mode 100644 index 000000000..eccbb8515 --- /dev/null +++ b/packages/tokens/src/tokens/layout/grid.json @@ -0,0 +1,9 @@ +{ + "grid": { + "columns": { "value": "12" }, + "gutter": { "value": "{spacing.4}" }, + "gutterSm": { "value": "{spacing.2}" }, + "gutterLg": { "value": "{spacing.6}" } + } +} + diff --git a/packages/tokens/src/tokens/semantic/colors.json b/packages/tokens/src/tokens/semantic/colors.json new file mode 100644 index 000000000..e2802df67 --- /dev/null +++ b/packages/tokens/src/tokens/semantic/colors.json @@ -0,0 +1,27 @@ +{ + "color": { + "semantic": { + "success": { + "50": { "value": "#F0F9F0" }, + "500": { "value": "#34C759" }, + "600": { "value": "#2E7D32" } + }, + "error": { + "50": { "value": "#FEF2F2" }, + "500": { "value": "#F44336" }, + "600": { "value": "#DC2626" } + }, + "warning": { + "50": { "value": "#FFFBEB" }, + "500": { "value": "#FF9500" }, + "600": { "value": "#D97706" } + }, + "info": { + "50": { "value": "#EFF6FF" }, + "500": { "value": "#2196F3" }, + "600": { "value": "#2563EB" } + } + } + } +} + diff --git a/packages/tokens/style-dictionary.config.js b/packages/tokens/style-dictionary.config.js new file mode 100644 index 000000000..e99448a86 --- /dev/null +++ b/packages/tokens/style-dictionary.config.js @@ -0,0 +1,24 @@ +const StyleDictionary = require('style-dictionary'); + +// Custom header function +const customHeader = () => { + return `/** + * ODE Design Tokens + * + * This file is auto-generated by Style Dictionary. + * Do not edit directly. Edit source files in src/tokens/ instead. + * + * Generated: ${new Date().toISOString()} + */ +`; +}; + +// Register custom format +StyleDictionary.registerFormat({ + name: 'customHeader', + formatter: customHeader +}); + +// Load and export the config +module.exports = require('./config.json'); + From ef21868391acdc251780b4f8cf1e63db95dbceb2 Mon Sep 17 00:00:00 2001 From: IamLRBA Date: Tue, 9 Dec 2025 11:33:22 +0300 Subject: [PATCH 2/2] fix(tokens): fix Style Dictionary build errors - Fixed fileHeader registration using registerFileHeader() - Fixed fileHeader return type to return array of strings - Fixed React Native shadows by splitting shadowOffset into width/height Resolves build errors and enables successful token generation. --- .../src/tokens/base/shadows-react-native.json | 9 +++-- packages/tokens/style-dictionary.config.js | 35 +++++++++++-------- 2 files changed, 26 insertions(+), 18 deletions(-) diff --git a/packages/tokens/src/tokens/base/shadows-react-native.json b/packages/tokens/src/tokens/base/shadows-react-native.json index 880315d8e..d30f96451 100644 --- a/packages/tokens/src/tokens/base/shadows-react-native.json +++ b/packages/tokens/src/tokens/base/shadows-react-native.json @@ -3,21 +3,24 @@ "reactNative": { "sm": { "shadowColor": { "value": "#000000" }, - "shadowOffset": { "value": "{0, 1}" }, + "shadowOffsetWidth": { "value": "0" }, + "shadowOffsetHeight": { "value": "1" }, "shadowOpacity": { "value": "0.1" }, "shadowRadius": { "value": "2" }, "elevation": { "value": "2" } }, "md": { "shadowColor": { "value": "#000000" }, - "shadowOffset": { "value": "{0, 2}" }, + "shadowOffsetWidth": { "value": "0" }, + "shadowOffsetHeight": { "value": "2" }, "shadowOpacity": { "value": "0.15" }, "shadowRadius": { "value": "4" }, "elevation": { "value": "4" } }, "lg": { "shadowColor": { "value": "#000000" }, - "shadowOffset": { "value": "{0, 4}" }, + "shadowOffsetWidth": { "value": "0" }, + "shadowOffsetHeight": { "value": "4" }, "shadowOpacity": { "value": "0.2" }, "shadowRadius": { "value": "8" }, "elevation": { "value": "8" } diff --git a/packages/tokens/style-dictionary.config.js b/packages/tokens/style-dictionary.config.js index e99448a86..2dd83405d 100644 --- a/packages/tokens/style-dictionary.config.js +++ b/packages/tokens/style-dictionary.config.js @@ -1,24 +1,29 @@ const StyleDictionary = require('style-dictionary'); -// Custom header function +// Custom header function - must return array of strings const customHeader = () => { - return `/** - * ODE Design Tokens - * - * This file is auto-generated by Style Dictionary. - * Do not edit directly. Edit source files in src/tokens/ instead. - * - * Generated: ${new Date().toISOString()} - */ -`; + return [ + '/**', + ' * ODE Design Tokens', + ' *', + ' * This file is auto-generated by Style Dictionary.', + ' * Do not edit directly. Edit source files in src/tokens/ instead.', + ' *', + ` * Generated: ${new Date().toISOString()}`, + ' */', + '' + ]; }; -// Register custom format -StyleDictionary.registerFormat({ +// Register custom fileHeader +StyleDictionary.registerFileHeader({ name: 'customHeader', - formatter: customHeader + fileHeader: customHeader }); -// Load and export the config -module.exports = require('./config.json'); +// Load config +const config = require('./config.json'); + +// Export the config +module.exports = config;