|
2 | 2 |
|
3 | 3 | const _ = require('lodash'); |
4 | 4 | const { fileHeader } = require('style-dictionary/lib/common/formatHelpers'); |
5 | | -const Color = require('tinycolor2') |
| 5 | +const Color = require('colorjs.io').default; |
6 | 6 |
|
7 | | -const hexRegex = /#[0-9A-Fa-f]{6}\b/; |
8 | | -const rgx = /rgb\((\d{1,3}), (\d{1,3}), (\d{1,3})\)/; |
| 7 | +/** |
| 8 | + * Convert OKLCH color values to hex/rgba for React Native compatibility. |
| 9 | + */ |
| 10 | +const oklchToHex = (oklchString) => { |
| 11 | + try { |
| 12 | + const color = new Color(oklchString); |
| 13 | + return color.to('srgb').toString({ format: 'hex' }); |
| 14 | + } catch (e) { |
| 15 | + return oklchString; // Return original if conversion fails |
| 16 | + } |
| 17 | +}; |
| 18 | + |
| 19 | +const colorToRgba = (colorString, alpha) => { |
| 20 | + try { |
| 21 | + const color = new Color(colorString); |
| 22 | + const rgb = color.to('srgb'); |
| 23 | + const r = Math.round(Math.max(0, Math.min(255, rgb.r * 255))); |
| 24 | + const g = Math.round(Math.max(0, Math.min(255, rgb.g * 255))); |
| 25 | + const b = Math.round(Math.max(0, Math.min(255, rgb.b * 255))); |
| 26 | + return `rgba(${r}, ${g}, ${b}, ${alpha})`; |
| 27 | + } catch (e) { |
| 28 | + return colorString; |
| 29 | + } |
| 30 | +}; |
| 31 | + |
| 32 | +/** |
| 33 | + * Convert any OKLCH value (including relative color syntax) to React Native compatible format |
| 34 | + */ |
| 35 | +const convertToReactNative = (value) => { |
| 36 | + if (typeof value !== 'string') return value; |
| 37 | + |
| 38 | + // Handle linear-gradient - convert oklch colors inside but keep as CSS string |
| 39 | + if (value.includes('linear-gradient')) { |
| 40 | + let converted = value; |
| 41 | + // Convert oklch(from ... l c h / alpha) to rgba |
| 42 | + converted = converted.replace(/oklch\(from\s+(.+?)\s+l\s+c\s+h\s*\/\s*([\d.]+)\)/g, (match, baseColor, alpha) => { |
| 43 | + return colorToRgba(baseColor, parseFloat(alpha)); |
| 44 | + }); |
| 45 | + // Convert simple oklch() to hex |
| 46 | + converted = converted.replace(/oklch\([^)]+\)/g, (match) => oklchToHex(match)); |
| 47 | + return converted; |
| 48 | + } |
9 | 49 |
|
10 | | -const reactColorFormat= function ({ |
| 50 | + // Handle relative color syntax: oklch(from <color> l c h / <alpha>) |
| 51 | + const relativeMatch = value.match(/oklch\(from\s+(.+?)\s+l\s+c\s+h\s*\/\s*([\d.]+)\)/); |
| 52 | + if (relativeMatch) { |
| 53 | + const baseColor = relativeMatch[1]; |
| 54 | + const alpha = parseFloat(relativeMatch[2]); |
| 55 | + return colorToRgba(baseColor, alpha); |
| 56 | + } |
| 57 | + |
| 58 | + // Handle simple oklch values |
| 59 | + if (value.startsWith('oklch(')) { |
| 60 | + return oklchToHex(value); |
| 61 | + } |
| 62 | + |
| 63 | + return value; |
| 64 | +}; |
| 65 | + |
| 66 | +const reactColorFormat = function ({ |
11 | 67 | dictionary: { allTokens }, |
12 | 68 | options: { theme }, |
13 | 69 | file, |
14 | 70 | }) { |
15 | 71 | const colors = {}; |
16 | | - |
17 | | - const toReactColor = (value) => { |
18 | | - while (value.match(/rgba\(\#/)) { |
19 | | - let c = Color(value.match(hexRegex)[0]).toRgbString(); |
20 | | - value = value.replace(hexRegex, c).replace(rgx, '$1,$2,$3'); |
21 | | - } |
22 | | - return value; |
23 | | - }; |
24 | | - |
| 72 | + |
25 | 73 | allTokens.forEach((token) => { |
26 | 74 | const { path, value } = token; |
27 | 75 |
|
28 | 76 | _.setWith( |
29 | 77 | colors, |
30 | | - path.slice(1).map(a => _.camelCase(a)).join('.'), |
31 | | - toReactColor(value), |
| 78 | + path.slice(1).map((a) => _.camelCase(a)).join('.'), |
| 79 | + convertToReactNative(value), |
32 | 80 | Object |
33 | 81 | ); |
34 | 82 | }); |
|
0 commit comments