@@ -147,6 +147,66 @@ export function lightenOklch(
147147 : `oklch(${ lightness } ${ chroma } ${ hue } / ${ alpha } )`
148148}
149149
150+ /**
151+ * Lighten an OKLCH color by a given factor.
152+ *
153+ * Works with strict TypeScript settings including `noUncheckedIndexedAccess`,
154+ * where `match[n]` is typed as `string | undefined`.
155+ *
156+ * @param oklch - Color in the form "oklch(L C H)" or "oklch(L C H / A)"
157+ * @param factor - Lightening force in range [0, 1]
158+ * @returns Lightened OKLCH color string (0.5 = 50% lighter)
159+ */
160+ export function darkenOklch (
161+ oklch : string | null | undefined ,
162+ factor : number ,
163+ ) : string | null | undefined {
164+ if ( oklch == null ) {
165+ return oklch
166+ }
167+
168+ const input = oklch . trim ( )
169+
170+ const match = input . match (
171+ / ^ o k l c h \( \s * ( [ + - ] ? [ \d . ] + % ? ) \s + ( [ + - ] ? [ \d . ] + ) \s + ( [ + - ] ? [ \d . ] + ) (?: \s * \/ \s * ( [ + - ] ? [ \d . ] + % ? ) ) ? \s * \) $ / i,
172+ )
173+
174+ if ( ! match ) {
175+ throw new Error ( 'Invalid OKLCH color format' )
176+ }
177+
178+ const [ , lightnessText , chromaText , hueText , alphaText ] = match
179+
180+ if ( lightnessText === undefined || chromaText === undefined || hueText === undefined ) {
181+ throw new Error ( 'Invalid OKLCH color format' )
182+ }
183+
184+ let lightness = lightnessText . endsWith ( '%' )
185+ ? Number . parseFloat ( lightnessText ) / 100
186+ : Number . parseFloat ( lightnessText )
187+ let chroma = Number . parseFloat ( chromaText )
188+ const hue = Number . parseFloat ( hueText )
189+ const alpha =
190+ alphaText === undefined
191+ ? null
192+ : alphaText . endsWith ( '%' )
193+ ? Number . parseFloat ( alphaText ) / 100
194+ : Number . parseFloat ( alphaText )
195+
196+ const clampedFactor = Math . min ( Math . max ( factor , 0 ) , 1 )
197+ lightness = lightness - ( 1 - lightness ) * clampedFactor
198+
199+ // Reduce chroma slightly as lightness increases
200+ chroma = chroma * ( 1 + clampedFactor * 0.3 )
201+
202+ lightness = Math . min ( Math . max ( lightness , 0 ) , 1 )
203+ chroma = Math . max ( chroma , 0 )
204+
205+ return alpha === null
206+ ? `oklch(${ lightness } ${ chroma } ${ hue } )`
207+ : `oklch(${ lightness } ${ chroma } ${ hue } / ${ alpha } )`
208+ }
209+
150210/**
151211 * Make an OKLCH color transparent by a given factor.
152212 *
0 commit comments