From b5e965577ae643308dba9adfae70463080d9e9b4 Mon Sep 17 00:00:00 2001 From: Jordan Pittman Date: Fri, 20 May 2022 16:50:47 -0400 Subject: [PATCH 1/6] Fix typo --- src/util/toPath.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/util/toPath.js b/src/util/toPath.js index bf9d1333c371..6dce9249a3da 100644 --- a/src/util/toPath.js +++ b/src/util/toPath.js @@ -4,7 +4,7 @@ * Square bracket notation `a[b]` may be used to "escape" dots that would otherwise be interpreted as path separators. * * Example: - * a -> ['a] + * a -> ['a'] * a.b.c -> ['a', 'b', 'c'] * a[b].c -> ['a', 'b', 'c'] * a[b.c].e.f -> ['a', 'b.c', 'e', 'f'] From 17cc428d4fa960720caddd3320279a1db49500d3 Mon Sep 17 00:00:00 2001 From: Jordan Pittman Date: Fri, 20 May 2022 16:51:05 -0400 Subject: [PATCH 2/6] Support alpha modifier for theme color values --- src/lib/evaluateTailwindFunctions.js | 22 ++- src/lib/setupContextUtils.js | 19 ++- src/util/resolveConfig.js | 20 ++- src/util/transformThemeValue.js | 6 +- tests/evaluateTailwindFunctions.test.js | 207 ++++++++++++++++++++++++ tests/opacity.test.js | 200 +++++++++++++++++++++++ 6 files changed, 459 insertions(+), 15 deletions(-) diff --git a/src/lib/evaluateTailwindFunctions.js b/src/lib/evaluateTailwindFunctions.js index fbe366a93197..bfeea5a52009 100644 --- a/src/lib/evaluateTailwindFunctions.js +++ b/src/lib/evaluateTailwindFunctions.js @@ -5,6 +5,7 @@ import parseValue from 'postcss-value-parser' import { normalizeScreens } from '../util/normalizeScreens' import buildMediaQuery from '../util/buildMediaQuery' import { toPath } from '../util/toPath' +import { withAlphaValue } from '../util/withAlphaVariable' function isObject(input) { return typeof input === 'object' && input !== null @@ -37,7 +38,7 @@ function listKeys(obj) { return list(Object.keys(obj)) } -function validatePath(config, path, defaultValue) { +function validatePath(config, path, defaultValue, themeOpts = {}) { const pathString = Array.isArray(path) ? pathToString(path) : path.replace(/^['"]+/g, '').replace(/['"]+$/g, '') @@ -114,7 +115,7 @@ function validatePath(config, path, defaultValue) { return { isValid: true, - value: transformThemeValue(themeSection)(value), + value: transformThemeValue(themeSection)(value, themeOpts), } } @@ -160,16 +161,29 @@ let nodeTypePropertyMap = { export default function ({ tailwindConfig: config }) { let functions = { theme: (node, path, ...defaultValue) => { - const { isValid, value, error } = validatePath( + let matches = path.match(/^([^\/\s]+)(?:\s*\/\s*([^\/\s]+))$/) + let alpha = undefined + + if (matches) { + path = matches[1] + alpha = matches[2] + } + + let { isValid, value, error } = validatePath( config, path, - defaultValue.length ? defaultValue : undefined + defaultValue.length ? defaultValue : undefined, + { opacityValue: alpha } ) if (!isValid) { throw node.error(error) } + if (alpha !== undefined) { + value = withAlphaValue(value, alpha, value) + } + return value }, screen: (node, screen) => { diff --git a/src/lib/setupContextUtils.js b/src/lib/setupContextUtils.js index d03007c38805..5f0a3203ede7 100644 --- a/src/lib/setupContextUtils.js +++ b/src/lib/setupContextUtils.js @@ -221,16 +221,25 @@ function buildPluginApi(tailwindConfig, context, { variantList, variantMap, offs return context.tailwindConfig.prefix + identifier } + function resolveThemeValue(path, defaultValue, opts = {}) { + const [pathRoot, ...subPaths] = toPath(path) + const value = getConfigValue(['theme', pathRoot, ...subPaths], defaultValue) + return transformThemeValue(pathRoot)(value, opts) + } + + const theme = Object.assign( + (path, defaultValue = undefined) => resolveThemeValue(path, defaultValue), + { + withAlpha: (path, opacityValue) => resolveThemeValue(path, undefined, { opacityValue }), + } + ) + let api = { postcss, prefix: applyConfiguredPrefix, e: escapeClassName, config: getConfigValue, - theme(path, defaultValue) { - const [pathRoot, ...subPaths] = toPath(path) - const value = getConfigValue(['theme', pathRoot, ...subPaths], defaultValue) - return transformThemeValue(pathRoot)(value) - }, + theme, corePlugins: (path) => { if (Array.isArray(tailwindConfig.corePlugins)) { return tailwindConfig.corePlugins.includes(path) diff --git a/src/util/resolveConfig.js b/src/util/resolveConfig.js index ad9c22529881..3a45552328f9 100644 --- a/src/util/resolveConfig.js +++ b/src/util/resolveConfig.js @@ -8,6 +8,7 @@ import { toPath } from './toPath' import { normalizeConfig } from './normalizeConfig' import isPlainObject from './isPlainObject' import { cloneDeep } from './cloneDeep' +import { withAlphaValue } from './withAlphaVariable' function isFunction(input) { return typeof input === 'function' @@ -187,11 +188,22 @@ function resolveFunctionKeys(object) { return val } - resolvePath.theme = resolvePath + Object.assign(resolvePath, { + theme: resolvePath, + ...configUtils, + withAlpha(key, opacityValue) { + // TODO: This is kinda iffy but it works + const path = toPath(key) + const lastSegment = path.pop() + let value = resolvePath(path)[lastSegment] + + if (value === undefined) { + return value + } - for (let key in configUtils) { - resolvePath[key] = configUtils[key] - } + return withAlphaValue(value, opacityValue) + }, + }) return Object.keys(object).reduce((resolved, key) => { return { diff --git a/src/util/transformThemeValue.js b/src/util/transformThemeValue.js index e6a8b8735317..30bd99cadfb0 100644 --- a/src/util/transformThemeValue.js +++ b/src/util/transformThemeValue.js @@ -44,8 +44,10 @@ export default function transformThemeValue(themeSection) { } } - return (value) => { - if (typeof value === 'function') value = value({}) + return (value, opts = {}) => { + if (typeof value === 'function') { + value = value(opts) + } return value } diff --git a/tests/evaluateTailwindFunctions.test.js b/tests/evaluateTailwindFunctions.test.js index 1cd07607b885..ecadb6edcb51 100644 --- a/tests/evaluateTailwindFunctions.test.js +++ b/tests/evaluateTailwindFunctions.test.js @@ -1,11 +1,16 @@ import postcss from 'postcss' import plugin from '../src/lib/evaluateTailwindFunctions' +import tailwind from '../src/index' import { css } from './util/run' function run(input, opts = {}) { return postcss([plugin({ tailwindConfig: opts })]).process(input, { from: undefined }) } +function runFull(input, config) { + return postcss([tailwind(config)]).process(input, { from: undefined }) +} + test('it looks up values in the theme using dot notation', () => { let input = css` .banana { @@ -817,3 +822,205 @@ test('screen arguments can be quoted', () => { expect(result.warnings().length).toBe(0) }) }) + +test('Theme function can extract alpha values for colors (1)', () => { + let input = css` + .foo { + color: theme(colors.blue.500 / 50%); + } + ` + + let output = css` + .foo { + color: rgb(59 130 246 / 50%); + } + ` + + return run(input, { + theme: { + colors: { blue: { 500: '#3b82f6' } }, + }, + }).then((result) => { + expect(result.css).toMatchCss(output) + expect(result.warnings().length).toBe(0) + }) +}) + +test('Theme function can extract alpha values for colors (2)', () => { + let input = css` + .foo { + color: theme(colors.blue.500 / 0.5); + } + ` + + let output = css` + .foo { + color: rgb(59 130 246 / 0.5); + } + ` + + return run(input, { + theme: { + colors: { blue: { 500: '#3b82f6' } }, + }, + }).then((result) => { + expect(result.css).toMatchCss(output) + expect(result.warnings().length).toBe(0) + }) +}) + +test('Theme function can extract alpha values for colors (3)', () => { + let input = css` + .foo { + color: theme(colors.blue.500 / var(--my-alpha)); + } + ` + + let output = css` + .foo { + color: rgb(59 130 246 / var(--my-alpha)); + } + ` + + return run(input, { + theme: { + colors: { blue: { 500: '#3b82f6' } }, + }, + }).then((result) => { + expect(result.css).toMatchCss(output) + expect(result.warnings().length).toBe(0) + }) +}) + +test('Theme function can extract alpha values for colors (4)', () => { + let input = css` + .foo { + color: theme(colors.blue.500 / 50%); + } + ` + + let output = css` + .foo { + color: hsl(217 91% 60% / 50%); + } + ` + + return run(input, { + theme: { + colors: { + blue: { 500: 'hsl(217, 91%, 60%)' }, + }, + }, + }).then((result) => { + expect(result.css).toMatchCss(output) + expect(result.warnings().length).toBe(0) + }) +}) + +test('Theme function can extract alpha values for colors (5)', () => { + let input = css` + .foo { + color: theme(colors.blue.500 / 0.5); + } + ` + + let output = css` + .foo { + color: hsl(217 91% 60% / 0.5); + } + ` + + return run(input, { + theme: { + colors: { + blue: { 500: 'hsl(217, 91%, 60%)' }, + }, + }, + }).then((result) => { + expect(result.css).toMatchCss(output) + expect(result.warnings().length).toBe(0) + }) +}) + +test('Theme function can extract alpha values for colors (6)', () => { + let input = css` + .foo { + color: theme(colors.blue.500 / var(--my-alpha)); + } + ` + + let output = css` + .foo { + color: hsl(217 91% 60% / var(--my-alpha)); + } + ` + + return run(input, { + theme: { + colors: { + blue: { 500: 'hsl(217, 91%, 60%)' }, + }, + }, + }).then((result) => { + expect(result.css).toMatchCss(output) + expect(result.warnings().length).toBe(0) + }) +}) + +test('Theme function can extract alpha values for colors (7)', () => { + let input = css` + .foo { + color: theme(colors.blue.500 / var(--my-alpha)); + } + ` + + let output = css` + .foo { + color: rgb(var(--foo) / var(--my-alpha)); + } + ` + + return runFull(input, { + theme: { + colors: ({ rgb }) => ({ + blue: { + 500: rgb('--foo'), + }, + }), + }, + }).then((result) => { + expect(result.css).toMatchCss(output) + expect(result.warnings().length).toBe(0) + }) +}) + +test('Theme function can extract alpha values for colors (8)', () => { + let input = css` + .foo { + color: theme(colors.blue.500 / theme(opacity.myalpha)); + } + ` + + let output = css` + .foo { + color: rgb(var(--foo) / 50%); + } + ` + + return runFull(input, { + theme: { + colors: ({ rgb }) => ({ + blue: { + 500: rgb('--foo'), + }, + }), + + opacity: { + myalpha: '50%', + }, + }, + }).then((result) => { + expect(result.css).toMatchCss(output) + expect(result.warnings().length).toBe(0) + }) +}) diff --git a/tests/opacity.test.js b/tests/opacity.test.js index cd18c479627a..36d9c60ccc7f 100644 --- a/tests/opacity.test.js +++ b/tests/opacity.test.js @@ -427,3 +427,203 @@ it('the hsl helper throws when not passing custom properties', () => { 'The hsl() helper requires a custom property name to be passed as the first argument.' ) }) + +test('Theme function in JS can apply alpha values to colors (1)', () => { + let input = css` + @tailwind utilities; + ` + + let output = css` + .text-foo { + color: rgb(59 130 246 / 50%); + } + ` + + return run(input, { + content: [{ raw: html`text-foo` }], + corePlugins: { textOpacity: false }, + theme: { + colors: { blue: { 500: '#3b82f6' } }, + extend: { + textColor: ({ theme }) => ({ + foo: theme.withAlpha('colors.blue.500', '50%'), + }), + }, + }, + }).then((result) => { + expect(result.css).toMatchCss(output) + expect(result.warnings().length).toBe(0) + }) +}) + +test('TTheme function in JS can apply alpha values to colors (2)', () => { + let input = css` + @tailwind utilities; + ` + + let output = css` + .text-foo { + color: rgb(59 130 246 / 0.5); + } + ` + + return run(input, { + content: [{ raw: html`text-foo` }], + corePlugins: { textOpacity: false }, + theme: { + colors: { blue: { 500: '#3b82f6' } }, + extend: { + textColor: ({ theme }) => ({ + foo: theme.withAlpha('colors.blue.500', '0.5'), + }), + }, + }, + }).then((result) => { + expect(result.css).toMatchCss(output) + expect(result.warnings().length).toBe(0) + }) +}) + +test('TTheme function in JS can apply alpha values to colors (3)', () => { + let input = css` + @tailwind utilities; + ` + + let output = css` + .text-foo { + color: rgb(59 130 246 / var(--my-alpha)); + } + ` + + return run(input, { + content: [{ raw: html`text-foo` }], + corePlugins: { textOpacity: false }, + theme: { + colors: { blue: { 500: '#3b82f6' } }, + extend: { + textColor: ({ theme }) => ({ + foo: theme.withAlpha('colors.blue.500', 'var(--my-alpha)'), + }), + }, + }, + }).then((result) => { + expect(result.css).toMatchCss(output) + expect(result.warnings().length).toBe(0) + }) +}) + +test('TTheme function in JS can apply alpha values to colors (4)', () => { + let input = css` + @tailwind utilities; + ` + + let output = css` + .text-foo { + color: hsl(217 91% 60% / 50%); + } + ` + + return run(input, { + content: [{ raw: html`text-foo` }], + corePlugins: { textOpacity: false }, + theme: { + colors: { blue: { 500: 'hsl(217, 91%, 60%)' } }, + extend: { + textColor: ({ theme }) => ({ + foo: theme.withAlpha('colors.blue.500', '50%'), + }), + }, + }, + }).then((result) => { + expect(result.css).toMatchCss(output) + expect(result.warnings().length).toBe(0) + }) +}) + +test('TTheme function in JS can apply alpha values to colors (5)', () => { + let input = css` + @tailwind utilities; + ` + + let output = css` + .text-foo { + color: hsl(217 91% 60% / 0.5); + } + ` + + return run(input, { + content: [{ raw: html`text-foo` }], + corePlugins: { textOpacity: false }, + theme: { + colors: { blue: { 500: 'hsl(217, 91%, 60%)' } }, + extend: { + textColor: ({ theme }) => ({ + foo: theme.withAlpha('colors.blue.500', '0.5'), + }), + }, + }, + }).then((result) => { + expect(result.css).toMatchCss(output) + expect(result.warnings().length).toBe(0) + }) +}) + +test('TTheme function in JS can apply alpha values to colors (6)', () => { + let input = css` + @tailwind utilities; + ` + + let output = css` + .text-foo { + color: hsl(217 91% 60% / var(--my-alpha)); + } + ` + + return run(input, { + content: [{ raw: html`text-foo` }], + corePlugins: { textOpacity: false }, + theme: { + colors: { blue: { 500: 'hsl(217, 91%, 60%)' } }, + extend: { + textColor: ({ theme }) => ({ + foo: theme.withAlpha('colors.blue.500', 'var(--my-alpha)'), + }), + }, + }, + }).then((result) => { + expect(result.css).toMatchCss(output) + expect(result.warnings().length).toBe(0) + }) +}) + +test('TTheme function in JS can apply alpha values to colors (7)', () => { + let input = css` + @tailwind utilities; + ` + + let output = css` + .text-foo { + color: rgb(var(--foo) / var(--my-alpha)); + } + ` + + return run(input, { + content: [{ raw: html`text-foo` }], + corePlugins: { textOpacity: false }, + theme: { + colors: ({ rgb }) => ({ + blue: { + 500: rgb('--foo'), + }, + }), + extend: { + textColor: ({ theme }) => ({ + foo: theme.withAlpha('colors.blue.500', 'var(--my-alpha)'), + }), + }, + }, + }).then((result) => { + expect(result.css).toMatchCss(output) + expect(result.warnings().length).toBe(0) + }) +}) From 17fb20d12195fc7bd9d44bdf216f36f9dcb69679 Mon Sep 17 00:00:00 2001 From: Jordan Pittman Date: Mon, 23 May 2022 12:52:26 -0400 Subject: [PATCH 3/6] Eliminate redundant object creation in resolveFunctionKeys Building an object of N keys incrementally using Object.reduce + splat results in N intermediate objects. We should just create one object and assign each key. --- src/util/resolveConfig.js | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/util/resolveConfig.js b/src/util/resolveConfig.js index 3a45552328f9..a9590aafe7eb 100644 --- a/src/util/resolveConfig.js +++ b/src/util/resolveConfig.js @@ -206,10 +206,9 @@ function resolveFunctionKeys(object) { }) return Object.keys(object).reduce((resolved, key) => { - return { - ...resolved, - [key]: isFunction(object[key]) ? object[key](resolvePath, configUtils) : object[key], - } + resolved[key] = isFunction(object[key]) ? object[key](resolvePath, configUtils) : object[key] + + return resolved }, {}) } From 7eb6c75a3e54c1a227f2d7dbafbc967b275c7bd0 Mon Sep 17 00:00:00 2001 From: Jordan Pittman Date: Wed, 25 May 2022 13:44:49 -0400 Subject: [PATCH 4/6] Switch to inline theme values in theme fn in config --- src/util/resolveConfig.js | 81 +++++++++++++++++++++++++++------------ tests/opacity.test.js | 14 +++---- 2 files changed, 63 insertions(+), 32 deletions(-) diff --git a/src/util/resolveConfig.js b/src/util/resolveConfig.js index a9590aafe7eb..f4808cf687f5 100644 --- a/src/util/resolveConfig.js +++ b/src/util/resolveConfig.js @@ -165,44 +165,75 @@ function mergeExtensions({ extend, ...theme }) { }) } +/** + * + * @param {string} key + * @return {Iterable} + */ +function* toPaths(key) { + let path = toPath(key) + + if (path.length === 0) { + return + } + + yield path + + if (Array.isArray(key)) { + return + } + + let pattern = /^(.*?)\s*\/\s*([^/]+)$/ + let matches = key.match(pattern) + + if (matches !== null) { + let [, prefix, alpha] = matches + + let newPath = toPath(prefix) + newPath.alpha = alpha + + yield newPath + } +} + function resolveFunctionKeys(object) { + // theme('colors.red.500 / 0.5') -> ['colors', 'red', '500 / 0', '5] + const resolvePath = (key, defaultValue) => { - const path = toPath(key) + for (const path of toPaths(key)) { + let index = 0 + let val = object - let index = 0 - let val = object + while (val !== undefined && val !== null && index < path.length) { + val = val[path[index++]] - while (val !== undefined && val !== null && index < path.length) { - val = val[path[index++]] - val = isFunction(val) ? val(resolvePath, configUtils) : val - } + let shouldResolveAsFn = + isFunction(val) && (path.alpha === undefined || index < path.length - 1) - if (val === undefined) { - return defaultValue - } + val = shouldResolveAsFn ? val(resolvePath, configUtils) : val + } + + if (val !== undefined) { + if (path.alpha !== undefined) { + return withAlphaValue(val, path.alpha) + } + + if (isPlainObject(val)) { + return cloneDeep(val) + } - if (isPlainObject(val)) { - return cloneDeep(val) + return val + } } - return val + return defaultValue } + // colors.red.500/50 + Object.assign(resolvePath, { theme: resolvePath, ...configUtils, - withAlpha(key, opacityValue) { - // TODO: This is kinda iffy but it works - const path = toPath(key) - const lastSegment = path.pop() - let value = resolvePath(path)[lastSegment] - - if (value === undefined) { - return value - } - - return withAlphaValue(value, opacityValue) - }, }) return Object.keys(object).reduce((resolved, key) => { diff --git a/tests/opacity.test.js b/tests/opacity.test.js index 36d9c60ccc7f..9fd36347ffa5 100644 --- a/tests/opacity.test.js +++ b/tests/opacity.test.js @@ -446,7 +446,7 @@ test('Theme function in JS can apply alpha values to colors (1)', () => { colors: { blue: { 500: '#3b82f6' } }, extend: { textColor: ({ theme }) => ({ - foo: theme.withAlpha('colors.blue.500', '50%'), + foo: theme('colors.blue.500 / 50%'), }), }, }, @@ -474,7 +474,7 @@ test('TTheme function in JS can apply alpha values to colors (2)', () => { colors: { blue: { 500: '#3b82f6' } }, extend: { textColor: ({ theme }) => ({ - foo: theme.withAlpha('colors.blue.500', '0.5'), + foo: theme('colors.blue.500 / 0.5'), }), }, }, @@ -502,7 +502,7 @@ test('TTheme function in JS can apply alpha values to colors (3)', () => { colors: { blue: { 500: '#3b82f6' } }, extend: { textColor: ({ theme }) => ({ - foo: theme.withAlpha('colors.blue.500', 'var(--my-alpha)'), + foo: theme('colors.blue.500 / var(--my-alpha)'), }), }, }, @@ -530,7 +530,7 @@ test('TTheme function in JS can apply alpha values to colors (4)', () => { colors: { blue: { 500: 'hsl(217, 91%, 60%)' } }, extend: { textColor: ({ theme }) => ({ - foo: theme.withAlpha('colors.blue.500', '50%'), + foo: theme('colors.blue.500 / 50%'), }), }, }, @@ -558,7 +558,7 @@ test('TTheme function in JS can apply alpha values to colors (5)', () => { colors: { blue: { 500: 'hsl(217, 91%, 60%)' } }, extend: { textColor: ({ theme }) => ({ - foo: theme.withAlpha('colors.blue.500', '0.5'), + foo: theme('colors.blue.500 / 0.5'), }), }, }, @@ -586,7 +586,7 @@ test('TTheme function in JS can apply alpha values to colors (6)', () => { colors: { blue: { 500: 'hsl(217, 91%, 60%)' } }, extend: { textColor: ({ theme }) => ({ - foo: theme.withAlpha('colors.blue.500', 'var(--my-alpha)'), + foo: theme('colors.blue.500 / var(--my-alpha)'), }), }, }, @@ -618,7 +618,7 @@ test('TTheme function in JS can apply alpha values to colors (7)', () => { }), extend: { textColor: ({ theme }) => ({ - foo: theme.withAlpha('colors.blue.500', 'var(--my-alpha)'), + foo: theme('colors.blue.500 / var(--my-alpha)'), }), }, }, From 672eb83f561108e692bcbece836f1823b22d4021 Mon Sep 17 00:00:00 2001 From: Jordan Pittman Date: Wed, 25 May 2022 13:47:49 -0400 Subject: [PATCH 5/6] Add test case And fix typos that were definitely not there --- tests/opacity.test.js | 44 +++++++++++++++++++++++++++++++++++++------ 1 file changed, 38 insertions(+), 6 deletions(-) diff --git a/tests/opacity.test.js b/tests/opacity.test.js index 9fd36347ffa5..18b43ec01a00 100644 --- a/tests/opacity.test.js +++ b/tests/opacity.test.js @@ -456,7 +456,7 @@ test('Theme function in JS can apply alpha values to colors (1)', () => { }) }) -test('TTheme function in JS can apply alpha values to colors (2)', () => { +test('Theme function in JS can apply alpha values to colors (2)', () => { let input = css` @tailwind utilities; ` @@ -484,7 +484,7 @@ test('TTheme function in JS can apply alpha values to colors (2)', () => { }) }) -test('TTheme function in JS can apply alpha values to colors (3)', () => { +test('Theme function in JS can apply alpha values to colors (3)', () => { let input = css` @tailwind utilities; ` @@ -512,7 +512,7 @@ test('TTheme function in JS can apply alpha values to colors (3)', () => { }) }) -test('TTheme function in JS can apply alpha values to colors (4)', () => { +test('Theme function in JS can apply alpha values to colors (4)', () => { let input = css` @tailwind utilities; ` @@ -540,7 +540,7 @@ test('TTheme function in JS can apply alpha values to colors (4)', () => { }) }) -test('TTheme function in JS can apply alpha values to colors (5)', () => { +test('Theme function in JS can apply alpha values to colors (5)', () => { let input = css` @tailwind utilities; ` @@ -568,7 +568,7 @@ test('TTheme function in JS can apply alpha values to colors (5)', () => { }) }) -test('TTheme function in JS can apply alpha values to colors (6)', () => { +test('Theme function in JS can apply alpha values to colors (6)', () => { let input = css` @tailwind utilities; ` @@ -596,7 +596,7 @@ test('TTheme function in JS can apply alpha values to colors (6)', () => { }) }) -test('TTheme function in JS can apply alpha values to colors (7)', () => { +test('Theme function in JS can apply alpha values to colors (7)', () => { let input = css` @tailwind utilities; ` @@ -627,3 +627,35 @@ test('TTheme function in JS can apply alpha values to colors (7)', () => { expect(result.warnings().length).toBe(0) }) }) + +test('Theme function prefers existing values in config', () => { + let input = css` + @tailwind utilities; + ` + + let output = css` + .text-foo { + color: purple; + } + ` + + return run(input, { + content: [{ raw: html`text-foo` }], + corePlugins: { textOpacity: false }, + theme: { + colors: { + blue: { + '500 / 50%': 'purple', + }, + }, + extend: { + textColor: ({ theme }) => ({ + foo: theme('colors.blue.500 / 50%'), + }), + }, + }, + }).then((result) => { + expect(result.css).toMatchCss(output) + expect(result.warnings().length).toBe(0) + }) +}) From 1f2f38e4ebaf0643321e6713951cbc5dd504542e Mon Sep 17 00:00:00 2001 From: Jordan Pittman Date: Wed, 25 May 2022 13:49:52 -0400 Subject: [PATCH 6/6] Update changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index edc653a0531a..23420e8ea65a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -49,6 +49,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Add `matchVariant` API ([#8310](https://github.com/tailwindlabs/tailwindcss/pull/8310)) - Add `prefers-contrast` media query variants ([#8410](https://github.com/tailwindlabs/tailwindcss/pull/8410)) - Experimental support for variant grouping ([#8405](https://github.com/tailwindlabs/tailwindcss/pull/8405)) +- Add opacity support when referencing colors with `theme` function ([#8416](https://github.com/tailwindlabs/tailwindcss/pull/8416)) ## [3.0.24] - 2022-04-12