UNPKG

@a_ng_d/utils-ui-color-palette

Version:

Core utilities library for UI Color Palette - a color management plugin for design tools. This library provides the foundational color manipulation, contrast calculation, and palette generation features used in the plugin.

432 lines (339 loc) 12.4 kB
![GitHub package.json version](https://img.shields.io/github/package-json/v/a-ng-d/utils-ui-color-palette?color=informational) ![GitHub last commit](https://img.shields.io/github/last-commit/a-ng-d/utils-ui-color-palette?color=informational) ![GitHub Actions Workflow Status](https://img.shields.io/github/actions/workflow/status/a-ng-d/utils-ui-color-palette/npm.yml?label=npm) ![GitHub](https://img.shields.io/github/license/a-ng-d/utils-ui-color-palette?color=informational) # UI Color Palette Utils Core utilities library for UI Color Palette - a color management plugin for design tools. This library provides the foundational color manipulation, contrast calculation, and palette generation features used in the plugin. ## Design Tools Compatibility UI Color Palette is available for: - Figma - Create and manage color primitives directly in your Figma designs - FigJam - Collaborate on color decisions with your team - Penpot - Open-source design tool alternative with full color management support ## Features - **Color Contrast Tools**: - APCA contrast calculations - WCAG 2.1 compliance checking - Contrast ratio calculations between colors - Pre-computed text contrast scores (light/dark) per shade - **Color Manipulation**: - Color space conversions (RGB, HSL, HSLuv, LAB) - Color mixing and blending - Brightness and saturation adjustments - **Dominant Colors Extraction**: - Extract dominant colors from images using K-means clustering - Configurable number of colors to extract - Automatic color frequency calculation - Support for transparent pixel filtering - **Color Harmony Generation**: - Generate analogous, complementary, triadic, tetradic, square, and compound color harmonies - Configurable analogous spread angle - Automatic color relationship calculations - Support for all major color harmony types - **Color System & Semantic Tokens**: - Build a semantic color system from a taxonomy schema and palette data - Bind semantic tokens to primitive shades with optional per-theme overrides - Exclude specific tokens from code generation via the `isExcluded` flag - Generate semantic token files for CSS, SCSS, LESS, DTCG, Tailwind v3/v4, SwiftUI, UIKit, Compose, Native, Universal, CSV, Android Resources, and Style Dictionary v3 - **Palette Generation**: - Create harmonious color schemes - Generate accessible color combinations - Scale generation for design systems ## Installation ```bash npm install @a_ng_d/utils-ui-color-palette # or yarn add @a_ng_d/utils-ui-color-palette ``` ## Usage ```typescript import { Color, Contrast, Data, DominantColors, ColorHarmony, } from '@a_ng_d/utils-ui-color-palette' // Use Color class for color manipulation const color = new Color({ sourceColor: [255, 0, 0], // RGB values lightness: 50, hueShifting: 0, chromaShifting: 100, }) // Use Contrast class for accessibility checks const contrast = new Contrast({ backgroundColor: [255, 255, 255], textColor: '#000000', }) // Use Data class for palette generation const data = new Data({ base: baseConfig, themes: themesConfig, meta: metaConfig, }) ``` ## Examples ### Color Manipulation ```typescript import { Color } from '@a_ng_d/utils-ui-color-palette' // Create a color instance const color = new Color({ sourceColor: [255, 0, 0], // Red in RGB lightness: 50, chromaShifting: 100, }) // Convert to different color spaces const lchColor = color.lch() // Returns LCH color const oklchColor = color.oklch() // Returns OKLCH color const hslColor = color.hsl() // Returns HSL color const labColor = color.lab() // Returns LAB color // Mix colors const mixedRgb = color.mixColorsRgb( [255, 0, 0, 0.5], // Semi-transparent red [0, 0, 255, 1] // Solid blue ) const mixedHex = color.mixColorsHex('#FF0000', '#0000FF') ``` ### Contrast Calculations ```typescript import { Contrast } from '@a_ng_d/utils-ui-color-palette' // Create a contrast checker instance const contrast = new Contrast({ backgroundColor: [255, 255, 255], // White background textColor: '#000000', // Black text }) // Get contrast values const wcagContrast = contrast.getWCAGContrast() // WCAG 2.1 contrast ratio const apcaContrast = contrast.getAPCAContrast() // APCA contrast value const wcagScore = contrast.getWCAGScore() // Returns: 'AAA', 'AA', or 'A' // Get accessibility recommendations const usage = contrast.getRecommendedUsage() // Returns usage recommendation const minSizes = contrast.getMinFontSizes() // Returns minimum font sizes // Find specific contrast values const lightness = contrast.getLightnessForContrastRatio(4.5) // For WCAG AA ``` ### Dominant Colors Extraction ```typescript import { DominantColors } from '@a_ng_d/utils-ui-color-palette' // Prepare your image data (from canvas, file, etc.) const canvas = document.createElement('canvas') const ctx = canvas.getContext('2d') // ... load your image into the canvas const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height) // Create a dominant colors extractor const dominantColors = new DominantColors({ imageData: imageData, colorCount: 5, // Extract top 5 colors maxIterations: 50, // K-means algorithm iterations tolerance: 0.01, // Convergence tolerance skipTransparent: true, // Skip transparent pixels }) // Extract the dominant colors const colors = dominantColors.extractDominantColors() // Results array contains: colors.forEach((result) => { console.log({ color: result.color, // RGB array: [r, g, b] hex: result.hex, // Hex string: "#ff0000" percentage: result.percentage, // Percentage of image: 25.5 count: result.count, // Number of pixels: 1000 }) }) // Update settings dynamically dominantColors.setColorCount(8) // Change to 8 colors dominantColors.updateOptions({ maxIterations: 100, tolerance: 0.005, }) // Get current configuration const options = dominantColors.getOptions() ``` #### Working with File Uploads (ArrayBuffer) For modern web applications that need to extract colors from uploaded image files: ```typescript import { DominantColors } from '@a_ng_d/utils-ui-color-palette' // Handle file upload from user input const handleImageUpload = async (event: Event) => { const file = (event.target as HTMLInputElement).files?.[0] if (!file) return // Convert file to ArrayBuffer const arrayBuffer = await file.arrayBuffer() try { // Simple usage: extract 5 dominant colors const colors = await DominantColors.extract(arrayBuffer, 5) console.log('Extracted colors:', colors) // Each color object contains: { color, hex, percentage, count } } catch (error) { console.error('Error extracting colors:', error) } } // Advanced usage with custom options const extractColorsAdvanced = async (arrayBuffer: ArrayBuffer) => { const colors = await DominantColors.fromArrayBuffer(arrayBuffer, { colorCount: 8, maxIterations: 100, tolerance: 0.005, skipTransparent: true, maxImageSize: 300, // Resize large images for faster processing }) return colors } // HTML file input example // <input type="file" accept="image/*" onChange={handleImageUpload} /> ``` **Note**: ArrayBuffer extraction requires a browser environment with Canvas API support. ### Color Harmony Generation ```typescript import { ColorHarmony } from '@a_ng_d/utils-ui-color-palette' // Create a color harmony generator const colorHarmony = new ColorHarmony({ baseColor: [255, 0, 0], // Red base color analogousSpread: 30, // 30 degrees for analogous colors }) // Generate specific harmony types const analogous = colorHarmony.generateAnalogous() const complementary = colorHarmony.generateComplementary() const triadic = colorHarmony.generateTriadic() const tetradic = colorHarmony.generateTetradic() const square = colorHarmony.generateSquare() const compound = colorHarmony.generateCompound() // Generate harmony by type const harmony = colorHarmony.generateHarmony('TRIADIC') // Generate all harmonies at once (now includes 6 harmonies) const allHarmonies = colorHarmony.getAllHarmonies() // Results contain both RGB and hex values console.log(triadic.colors) // [[255, 0, 0], [0, 255, 0], [0, 0, 255]] console.log(triadic.hexColors) // ['#ff0000', '#00ff00', '#0000ff'] // Update settings colorHarmony.setBaseColor([0, 128, 255]) colorHarmony.setAnalogousSpread(45) colorHarmony.updateOptions({ analogousSpread: 60, returnFormat: 'hex', }) ``` ### Palette Generation ```typescript import { Data } from '@a_ng_d/utils-ui-color-palette' // Configure your palette const config = { base: { name: 'My Palette', colors: [ /* your colors */ ], colorSpace: 'LAB', algorithmVersion: 'v3', }, themes: [ { id: 'light', name: 'Light Theme', scale: { /* lightness values */ }, visionSimulationMode: 'NONE', }, ], meta: { /* metadata */ }, } // Create a data instance const data = new Data(config) // Generate palette data const paletteData = data.makePaletteData() const fullData = data.makePaletteFullData() // Access pre-computed text contrast scores paletteData.themes[0].colors[0].shades.forEach((shade) => { if (shade.textContrast) { // WCAG scores for light/dark text on this shade console.log(shade.textContrast.wcag.light) // { ratio: 4.5, score: 'AA' } console.log(shade.textContrast.wcag.dark) // { ratio: 12.6, score: 'AAA' } // APCA scores for light/dark text on this shade console.log(shade.textContrast.apca.light) // { lc: -60.2, recommendedUsage: 'BODY_TEXT' } console.log(shade.textContrast.apca.dark) // { lc: 85.1, recommendedUsage: 'FLUENT_TEXT' } } }) ``` ### Color System & Semantic Tokens ```typescript import { System, Code } from '@a_ng_d/utils-ui-color-palette' // Define a taxonomy schema (groups of semantic dimensions) const system = new System({ paletteData, system: { schema: { groups: [ { id: 'role', name: 'Role', members: [ { id: 'brand', name: 'Brand' }, { id: 'neutral', name: 'Neutral' }, ], }, { id: 'prominence', name: 'Prominence', members: [ { id: 'default', name: 'Default' }, { id: 'subtle', name: 'Subtle' }, ], }, ], }, bindings: [ { path: ['brand', 'default'], description: 'Primary brand color', ref: 'blue:500', overrides: { dark: 'blue:400' }, // per-theme override }, { path: ['neutral', 'subtle'], ref: 'gray:200', isExcluded: true, // skip this token in code generation }, ], }, }) // Resolve the system data (tokens + refs) const systemData = system.makeSystemData() // Generate semantic token files alongside primitives const code = new Code({ paletteData, systemData }) const files = code.makeCssFiles() // files[0].content includes both --color-blue-500 primitives // and --brand-default / --neutral-default semantic custom properties ``` ## Testing ```bash npm test # or yarn test ``` ## Code Coverage Current test coverage results: | File | % Stmts | % Branch | % Funcs | % Lines | | ----------------- | ------- | -------- | ------- | ------- | | **All files** | **91.61** | **87.27** | **91.59** | **91.61** | | code | 100 | 100 | 100 | 100 | | color | 93.54 | 77.51 | 83.33 | 93.54 | | color-harmony | 100 | 96.66 | 100 | 100 | | contrast | 89 | 93.33 | 100 | 89 | | data | 93.48 | 89.74 | 100 | 93.48 | | dominant-colors | 77.58 | 89.06 | 90.47 | 77.58 | To run coverage tests: ```bash npm run test:coverage ``` ## Credits This project relies on several excellent open source packages: ### Color Processing - [chroma.js](https://gka.github.io/chroma.js/) - A powerful library for color manipulations and conversions - Author: Gregor Aisch - License: BSD-3-Clause ### Contrast Calculation - [APCA-W3](https://github.com/Myndex/SAPC-APCA) - Advanced Perceptual Contrast Algorithm - Author: Andrew Somers - License: W3C Software and Document Notice and License ## License This project is licensed under the MIT License. See the [LICENSE](LICENSE) file for more information.