Fix kbd shadow colors not being calculated on oklch colors (#387)

* fix: correctly apply alpha to kbd shadows when not hex

* Use `color-mix(…)` for non hex values

* Add changelog

---------

Co-authored-by: Philipp Spiess <[email protected]>
This commit is contained in:
Joo Chanhwi
2025-09-18 12:44:39 +02:00
committed by GitHub
co-authored by Philipp Spiess
parent 628f7917c5
commit ced5ccba02
2 changed files with 23 additions and 15 deletions
+1
View File
@@ -10,6 +10,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Fixed
- Include unit in `hr` border-width value ([#379](https://github.com/tailwindlabs/tailwindcss-typography/pull/379)
- Ensure `<kbd>` styles work with Tailwind CSS v4 ([#387](https://github.com/tailwindlabs/tailwindcss-typography/pull/387))
### Changed
+22 -15
View File
@@ -7,13 +7,21 @@ const round = (num) =>
.replace(/\.0$/, '')
const rem = (px) => `${round(px / 16)}rem`
const em = (px, base) => `${round(px / base)}em`
const hexToRgb = (hex) => {
hex = hex.replace('#', '')
const opacity = (color, opacity) => {
// In v3, the colors are hex encoded and a previous typography plugin version
// only handled these values. We keep the old behavior for backward
// compatibility with v3 codebases but use color-mix for any other color
// values.
hex = color.replace('#', '')
hex = hex.length === 3 ? hex.replace(/./g, '$&$&') : hex
const r = parseInt(hex.substring(0, 2), 16)
const g = parseInt(hex.substring(2, 4), 16)
const b = parseInt(hex.substring(4, 6), 16)
return `${r} ${g} ${b}`
if (Number.isNaN(r) || Number.isNaN(g) || Number.isNaN(b)) {
return `color-mix(in oklab, ${color} ${opacity}, transparent)`
}
return `rgb(${r}, ${g}, ${b} / ${opacity})`
}
let defaultModifiers = {
@@ -1059,7 +1067,7 @@ let defaultModifiers = {
'--tw-prose-quote-borders': colors.slate[200],
'--tw-prose-captions': colors.slate[500],
'--tw-prose-kbd': colors.slate[900],
'--tw-prose-kbd-shadows': hexToRgb(colors.slate[900]),
'--tw-prose-kbd-shadows': opacity(colors.slate[900], '10%'),
'--tw-prose-code': colors.slate[900],
'--tw-prose-pre-code': colors.slate[200],
'--tw-prose-pre-bg': colors.slate[800],
@@ -1077,7 +1085,7 @@ let defaultModifiers = {
'--tw-prose-invert-quote-borders': colors.slate[700],
'--tw-prose-invert-captions': colors.slate[400],
'--tw-prose-invert-kbd': colors.white,
'--tw-prose-invert-kbd-shadows': hexToRgb(colors.white),
'--tw-prose-invert-kbd-shadows': opacity(colors.white, '10%'),
'--tw-prose-invert-code': colors.white,
'--tw-prose-invert-pre-code': colors.slate[300],
'--tw-prose-invert-pre-bg': 'rgb(0 0 0 / 50%)',
@@ -1100,7 +1108,7 @@ let defaultModifiers = {
'--tw-prose-quote-borders': colors.gray[200],
'--tw-prose-captions': colors.gray[500],
'--tw-prose-kbd': colors.gray[900],
'--tw-prose-kbd-shadows': hexToRgb(colors.gray[900]),
'--tw-prose-kbd-shadows': opacity(colors.gray[900], '10%'),
'--tw-prose-code': colors.gray[900],
'--tw-prose-pre-code': colors.gray[200],
'--tw-prose-pre-bg': colors.gray[800],
@@ -1118,7 +1126,7 @@ let defaultModifiers = {
'--tw-prose-invert-quote-borders': colors.gray[700],
'--tw-prose-invert-captions': colors.gray[400],
'--tw-prose-invert-kbd': colors.white,
'--tw-prose-invert-kbd-shadows': hexToRgb(colors.white),
'--tw-prose-invert-kbd-shadows': opacity(colors.white, '10%'),
'--tw-prose-invert-code': colors.white,
'--tw-prose-invert-pre-code': colors.gray[300],
'--tw-prose-invert-pre-bg': 'rgb(0 0 0 / 50%)',
@@ -1141,7 +1149,7 @@ let defaultModifiers = {
'--tw-prose-quote-borders': colors.zinc[200],
'--tw-prose-captions': colors.zinc[500],
'--tw-prose-kbd': colors.zinc[900],
'--tw-prose-kbd-shadows': hexToRgb(colors.zinc[900]),
'--tw-prose-kbd-shadows': opacity(colors.zinc[900], '10%'),
'--tw-prose-code': colors.zinc[900],
'--tw-prose-pre-code': colors.zinc[200],
'--tw-prose-pre-bg': colors.zinc[800],
@@ -1159,7 +1167,7 @@ let defaultModifiers = {
'--tw-prose-invert-quote-borders': colors.zinc[700],
'--tw-prose-invert-captions': colors.zinc[400],
'--tw-prose-invert-kbd': colors.white,
'--tw-prose-invert-kbd-shadows': hexToRgb(colors.white),
'--tw-prose-invert-kbd-shadows': opacity(colors.white, '10%'),
'--tw-prose-invert-code': colors.white,
'--tw-prose-invert-pre-code': colors.zinc[300],
'--tw-prose-invert-pre-bg': 'rgb(0 0 0 / 50%)',
@@ -1182,7 +1190,7 @@ let defaultModifiers = {
'--tw-prose-quote-borders': colors.neutral[200],
'--tw-prose-captions': colors.neutral[500],
'--tw-prose-kbd': colors.neutral[900],
'--tw-prose-kbd-shadows': hexToRgb(colors.neutral[900]),
'--tw-prose-kbd-shadows': opacity(colors.neutral[900], '10%'),
'--tw-prose-code': colors.neutral[900],
'--tw-prose-pre-code': colors.neutral[200],
'--tw-prose-pre-bg': colors.neutral[800],
@@ -1200,7 +1208,7 @@ let defaultModifiers = {
'--tw-prose-invert-quote-borders': colors.neutral[700],
'--tw-prose-invert-captions': colors.neutral[400],
'--tw-prose-invert-kbd': colors.white,
'--tw-prose-invert-kbd-shadows': hexToRgb(colors.white),
'--tw-prose-invert-kbd-shadows': opacity(colors.white, '10%'),
'--tw-prose-invert-code': colors.white,
'--tw-prose-invert-pre-code': colors.neutral[300],
'--tw-prose-invert-pre-bg': 'rgb(0 0 0 / 50%)',
@@ -1223,7 +1231,7 @@ let defaultModifiers = {
'--tw-prose-quote-borders': colors.stone[200],
'--tw-prose-captions': colors.stone[500],
'--tw-prose-kbd': colors.stone[900],
'--tw-prose-kbd-shadows': hexToRgb(colors.stone[900]),
'--tw-prose-kbd-shadows': opacity(colors.stone[900], '10%'),
'--tw-prose-code': colors.stone[900],
'--tw-prose-pre-code': colors.stone[200],
'--tw-prose-pre-bg': colors.stone[800],
@@ -1241,7 +1249,7 @@ let defaultModifiers = {
'--tw-prose-invert-quote-borders': colors.stone[700],
'--tw-prose-invert-captions': colors.stone[400],
'--tw-prose-invert-kbd': colors.white,
'--tw-prose-invert-kbd-shadows': hexToRgb(colors.white),
'--tw-prose-invert-kbd-shadows': opacity(colors.white, '10%'),
'--tw-prose-invert-code': colors.white,
'--tw-prose-invert-pre-code': colors.stone[300],
'--tw-prose-invert-pre-bg': 'rgb(0 0 0 / 50%)',
@@ -1527,8 +1535,7 @@ module.exports = {
fontWeight: '500',
fontFamily: 'inherit',
color: 'var(--tw-prose-kbd)',
boxShadow:
'0 0 0 1px rgb(var(--tw-prose-kbd-shadows) / 10%), 0 3px 0 rgb(var(--tw-prose-kbd-shadows) / 10%)',
boxShadow: '0 0 0 1px var(--tw-prose-kbd-shadows), 0 3px 0 var(--tw-prose-kbd-shadows)',
},
code: {
color: 'var(--tw-prose-code)',