diff --git a/packages/theme-management/package.json b/packages/theme-management/package.json index 8b68bcb..4180eef 100644 --- a/packages/theme-management/package.json +++ b/packages/theme-management/package.json @@ -134,6 +134,7 @@ "access": "public" }, "dependencies": { + "color": "^5.0.3", "react-colorful": "^5.6.1", "server-only": "^0.0.1" } diff --git a/packages/theme-management/src/fields/ThemeColorPickerField.tsx b/packages/theme-management/src/fields/ThemeColorPickerField.tsx index 9a9cad8..57de36c 100644 --- a/packages/theme-management/src/fields/ThemeColorPickerField.tsx +++ b/packages/theme-management/src/fields/ThemeColorPickerField.tsx @@ -1,6 +1,7 @@ 'use client' import { useField } from '@payloadcms/ui' +import Color from 'color' import type { TextFieldClientComponent } from 'payload' import { HexColorInput, HexColorPicker } from 'react-colorful' import { useCallback, useEffect, useRef, useState } from 'react' @@ -33,69 +34,7 @@ function resolveLocalizedValue(value: unknown, fallback: string) { function toHex(color: string): string { if (!color) return '#000000' - // Already hex - if (color.startsWith('#')) return color - - // OKLCH format - extract hue and convert to approximate hex - if (color.startsWith('oklch')) { - // For now, return a default - proper conversion requires color-conversion library - return '#3b82f6' // blue-500 as default - } - - // HSL format - if (color.startsWith('hsl')) { - const regex = /hsl\((\d+),\s*(\d+)%,\s*(\d+)%\)/ - const match = regex.exec(color) - if (match) { - const [, h, s, l] = match.map(Number) - return hslToHex(h, s, l) - } - } - - return '#000000' -} - -/** - * Convert HSL to HEX - */ -function hslToHex(h: number, s: number, l: number): string { - s /= 100 - l /= 100 - - const c = (1 - Math.abs(2 * l - 1)) * s - const x = c * (1 - Math.abs(((h / 60) % 2) - 1)) - const m = l - c / 2 - - let r = 0 - let g = 0 - let b = 0 - - if (h >= 0 && h < 60) { - r = c - g = x - } else if (h >= 60 && h < 120) { - r = x - g = c - } else if (h >= 120 && h < 180) { - g = c - b = x - } else if (h >= 180 && h < 240) { - g = x - b = c - } else if (h >= 240 && h < 300) { - r = x - b = c - } else if (h >= 300 && h < 360) { - r = c - b = x - } - - const toHex = (n: number) => { - const hex = Math.round((n + m) * 255).toString(16) - return hex.length === 1 ? '0' + hex : hex - } - - return `#${toHex(r)}${toHex(g)}${toHex(b)}` + return Color(color).hex().toString() } const ThemeColorPickerField: TextFieldClientComponent = ({ field, path }) => { diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 05e569c..2155851 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -307,6 +307,9 @@ importers: '@payloadcms/ui': specifier: ^3.0.0 version: 3.59.1(@types/react@19.2.1)(monaco-editor@0.54.0)(next@15.5.4(@babel/core@7.28.4)(@playwright/test@1.56.0)(babel-plugin-macros@3.1.0)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(sass@1.77.4))(payload@3.58.0(graphql@16.11.0)(typescript@5.9.3))(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(typescript@5.9.3) + color: + specifier: ^5.0.3 + version: 5.0.3 react-colorful: specifier: ^5.6.1 version: 5.6.1(react-dom@19.2.0(react@19.2.0))(react@19.2.0) @@ -3759,19 +3762,35 @@ packages: resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} engines: {node: '>=7.0.0'} + color-convert@3.1.3: + resolution: {integrity: sha512-fasDH2ont2GqF5HpyO4w0+BcewlhHEZOFn9c1ckZdHpJ56Qb7MHhH/IcJZbBGgvdtwdwNbLvxiBEdg336iA9Sg==} + engines: {node: '>=14.6'} + color-name@1.1.3: resolution: {integrity: sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==} color-name@1.1.4: resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} + color-name@2.1.0: + resolution: {integrity: sha512-1bPaDNFm0axzE4MEAzKPuqKWeRaT43U/hyxKPBdqTfmPF+d6n7FSoTFxLVULUJOmiLp01KjhIPPH+HrXZJN4Rg==} + engines: {node: '>=12.20'} + color-string@1.9.1: resolution: {integrity: sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg==} + color-string@2.1.4: + resolution: {integrity: sha512-Bb6Cq8oq0IjDOe8wJmi4JeNn763Xs9cfrBcaylK1tPypWzyoy2G3l90v9k64kjphl/ZJjPIShFztenRomi8WTg==} + engines: {node: '>=18'} + color@4.2.3: resolution: {integrity: sha512-1rXeuUUiGGrykh+CeBdu5Ie7OJwinCgQY0bc7GCRxy5xVHy+moaqkpL/jqQq0MtQOeYcrqEz4abc5f0KtU7W4A==} engines: {node: '>=12.5.0'} + color@5.0.3: + resolution: {integrity: sha512-ezmVcLR3xAVp8kYOm4GS45ZLLgIE6SPAFoduLr6hTDajwb3KZ2F46gulK3XpcwRFb5KKGCSezCBAY4Dw4HsyXA==} + engines: {node: '>=18'} + colorette@2.0.20: resolution: {integrity: sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==} @@ -9523,6 +9542,7 @@ snapshots: '@kilivi/payloadcms-theme-management@file:packages/theme-management(@payloadcms/ui@3.68.5(@types/react@19.2.1)(monaco-editor@0.54.0)(next@15.4.10(@babel/core@7.28.4)(@playwright/test@1.56.1)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(sass@1.77.4))(payload@3.68.5(graphql@16.11.0)(typescript@5.7.2))(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(typescript@5.7.2))(next@15.4.10(@babel/core@7.28.4)(@playwright/test@1.56.1)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(sass@1.77.4))(payload@3.68.5(graphql@16.11.0)(typescript@5.7.2))(react-dom@19.2.1(react@19.2.1))(react@19.2.1)': dependencies: '@payloadcms/ui': 3.68.5(@types/react@19.2.1)(monaco-editor@0.54.0)(next@15.4.10(@babel/core@7.28.4)(@playwright/test@1.56.1)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(sass@1.77.4))(payload@3.68.5(graphql@16.11.0)(typescript@5.7.2))(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(typescript@5.7.2) + color: 5.0.3 next: 15.4.10(@babel/core@7.28.4)(@playwright/test@1.56.1)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(sass@1.77.4) payload: 3.68.5(graphql@16.11.0)(typescript@5.7.2) react: 19.2.1 @@ -11856,20 +11876,35 @@ snapshots: dependencies: color-name: 1.1.4 + color-convert@3.1.3: + dependencies: + color-name: 2.1.0 + color-name@1.1.3: {} color-name@1.1.4: {} + color-name@2.1.0: {} + color-string@1.9.1: dependencies: color-name: 1.1.4 simple-swizzle: 0.2.4 + color-string@2.1.4: + dependencies: + color-name: 2.1.0 + color@4.2.3: dependencies: color-convert: 2.0.1 color-string: 1.9.1 + color@5.0.3: + dependencies: + color-convert: 3.1.3 + color-string: 2.1.4 + colorette@2.0.20: {} commander@13.1.0: {}