Skip to content

Commit

Permalink
fix(preset-mini): text-[] auto detection for font-size, close #1235
Browse files Browse the repository at this point in the history
  • Loading branch information
antfu committed Jul 9, 2022
1 parent ed5fbc2 commit 3d97a3a
Show file tree
Hide file tree
Showing 5 changed files with 46 additions and 40 deletions.
5 changes: 4 additions & 1 deletion packages/preset-mini/src/rules/color.ts
@@ -1,5 +1,6 @@
import type { Rule } from '@unocss/core'
import { colorResolver, handler as h } from '../utils'
import { numberWithUnitRE } from '../utils/handlers/handlers'

/**
* @example op10 op-30 opacity-100
Expand All @@ -12,7 +13,9 @@ export const opacity: Rule[] = [
* @example c-red color-red5 text-red-300
*/
export const textColors: Rule[] = [
[/^(?:text|color|c)-(.+)$/, colorResolver('color', 'text'), { autocomplete: '(text|color|c)-$colors' }],
[/^(?:color|c)-(.+)$/, colorResolver('color', 'text'), { autocomplete: '(text|color|c)-$colors' }],
// auto detection and fallback to font-size if the content looks like a size
[/^text-(.+)$/, colorResolver('color', 'text', css => !css.color?.toString().match(numberWithUnitRE)), { autocomplete: '(text|color|c)-$colors' }],
[/^(?:text|color|c)-op(?:acity)?-?(.+)$/, ([, opacity]) => ({ '--un-text-opacity': h.bracket.percent(opacity) }), { autocomplete: '(text|color|c)-(op|opacity)-<percent>' }],
]

Expand Down
6 changes: 3 additions & 3 deletions packages/preset-mini/src/utils/handlers/handlers.ts
Expand Up @@ -22,9 +22,9 @@ const cssProps = [
'border-radius',
]

const numberWithUnitRE = /^(-?[0-9.]+)(px|pt|pc|rem|em|%|vh|vw|in|cm|mm|ex|ch|vmin|vmax|cqw|cqh|cqi|cqb|cqmin|cqmax|rpx)?$/i
const numberRE = /^(-?[0-9.]+)$/i
const unitOnlyRE = /^(px)$/i
export const numberWithUnitRE = /^(-?[0-9.]+)(px|pt|pc|rem|em|%|vh|vw|in|cm|mm|ex|ch|vmin|vmax|cqw|cqh|cqi|cqb|cqmin|cqmax|rpx)?$/i
export const numberRE = /^(-?[0-9.]+)$/i
export const unitOnlyRE = /^(px)$/i

function round(n: number) {
return n.toFixed(10).replace(/\.0+$/, '').replace(/(\.\d+?)0+$/, '$1')
Expand Down
63 changes: 32 additions & 31 deletions packages/preset-mini/src/utils/utilities.ts
@@ -1,4 +1,4 @@
import type { CSSEntries, CSSObject, ParsedColorValue, Rule, RuleContext, VariantContext } from '@unocss/core'
import type { CSSEntries, CSSObject, DynamicMatcher, ParsedColorValue, Rule, RuleContext, VariantContext } from '@unocss/core'
import { toArray } from '@unocss/core'
import type { Theme } from '../theme'
import { colorOpacityToString, colorToString, parseCssColor } from './colors'
Expand All @@ -11,19 +11,20 @@ export const CONTROL_MINI_NO_NEGATIVE = '$$mini-no-negative'
* Provide {@link DynamicMatcher} function returning spacing definition. See spacing rules.
*
* @param {string} propertyPrefix - Property for the css value to be created. Postfix will be appended according to direction matched.
* @return {@link DynamicMatcher} object.
* @see {@link directionMap}
*/
export const directionSize = (propertyPrefix: string) => ([_, direction, size]: string[], { theme }: RuleContext<Theme>): CSSEntries | undefined => {
const v = theme.spacing?.[size || 'DEFAULT'] ?? h.bracket.cssvar.global.auto.fraction.rem(size)
if (v != null)
return directionMap[direction].map(i => [`${propertyPrefix}${i}`, v])
export function directionSize(propertyPrefix: string): DynamicMatcher {
return ([_, direction, size]: string[], { theme }: RuleContext<Theme>): CSSEntries | undefined => {
const v = theme.spacing?.[size || 'DEFAULT'] ?? h.bracket.cssvar.global.auto.fraction.rem(size)
if (v != null)
return directionMap[direction].map(i => [`${propertyPrefix}${i}`, v])
}
}

/**
* Obtain color from theme by camel-casing colors.
*/
const getThemeColor = (theme: Theme, colors: string[]) => {
function getThemeColor(theme: Theme, colors: string[]) {
let obj: Theme['colors'] | string = theme.colors
let index = -1

Expand Down Expand Up @@ -59,7 +60,7 @@ const getThemeColor = (theme: Theme, colors: string[]) => {
* @param {Theme} theme - {@link Theme} object.
* @return {ParsedColorValue|undefined} {@link ParsedColorValue} object if string is parseable.
*/
export const parseColor = (body: string, theme: Theme): ParsedColorValue | undefined => {
export function parseColor(body: string, theme: Theme): ParsedColorValue | undefined {
const split = body.split(/(?:\/|:)/)
let main, opacity
if (split[0] === '[color') {
Expand Down Expand Up @@ -151,35 +152,35 @@ export const parseColor = (body: string, theme: Theme): ParsedColorValue | undef
* @param {string} varName - Base name for the opacity variable.
* @return {@link DynamicMatcher} object.
*/
export const colorResolver = (property: string, varName: string) => ([, body]: string[], { theme }: RuleContext<Theme>): CSSObject | undefined => {
const data = parseColor(body, theme)
export function colorResolver(property: string, varName: string, shouldPass?: (css: CSSObject) => boolean): DynamicMatcher {
return ([, body]: string[], { theme }: RuleContext<Theme>): CSSObject | undefined => {
const data = parseColor(body, theme)

if (!data)
return
if (!data)
return

const { alpha, color, cssColor } = data
const { alpha, color, cssColor } = data

if (cssColor) {
if (alpha != null) {
return {
[property]: colorToString(cssColor, alpha),
const css: CSSObject = {}
if (cssColor) {
if (alpha != null) {
css[property] = colorToString(cssColor, alpha)
}
}
else {
return {
[`--un-${varName}-opacity`]: colorOpacityToString(cssColor),
[property]: colorToString(cssColor, `var(--un-${varName}-opacity)`),
else {
css[`--un-${varName}-opacity`] = colorOpacityToString(cssColor)
css[property] = colorToString(cssColor, `var(--un-${varName}-opacity)`)
}
}
}
else if (color) {
return {
[property]: colorToString(color, alpha),
else if (color) {
css[property] = colorToString(color, alpha)
}

if (shouldPass?.(css) !== false)
return css
}
}

export const colorableShadows = (shadows: string | string[], colorVar: string) => {
export function colorableShadows(shadows: string | string[], colorVar: string) {
const colored = []
shadows = toArray(shadows)
for (let i = 0; i < shadows.length; i++) {
Expand All @@ -195,11 +196,11 @@ export const colorableShadows = (shadows: string | string[], colorVar: string) =
return colored
}

export const hasParseableColor = (color: string | undefined, theme: Theme) => {
export function hasParseableColor(color: string | undefined, theme: Theme) {
return color != null && !!parseColor(color, theme)?.color
}

export const resolveBreakpoints = ({ theme, generator }: Readonly<VariantContext<Theme>>) => {
export function resolveBreakpoints({ theme, generator }: Readonly<VariantContext<Theme>>) {
let breakpoints: Record<string, string> | undefined
if (generator.userConfig && generator.userConfig.theme)
breakpoints = (generator.userConfig.theme as any).breakpoints
Expand All @@ -210,7 +211,7 @@ export const resolveBreakpoints = ({ theme, generator }: Readonly<VariantContext
return breakpoints
}

export const resolveVerticalBreakpoints = ({ theme, generator }: Readonly<VariantContext<Theme>>) => {
export function resolveVerticalBreakpoints({ theme, generator }: Readonly<VariantContext<Theme>>) {
let verticalBreakpoints: Record<string, string> | undefined
if (generator.userConfig && generator.userConfig.theme)
verticalBreakpoints = (generator.userConfig.theme as any).verticalBreakpoints
Expand All @@ -221,7 +222,7 @@ export const resolveVerticalBreakpoints = ({ theme, generator }: Readonly<Varian
return verticalBreakpoints
}

export const makeGlobalStaticRules = (prefix: string, property?: string) => {
export function makeGlobalStaticRules(prefix: string, property?: string) {
return globalKeywords.map(keyword => [`${prefix}-${keyword}`, { [property ?? prefix]: keyword }] as Rule)
}

Expand Down
11 changes: 6 additions & 5 deletions test/__snapshots__/preset-mini.test.ts.snap
Expand Up @@ -286,6 +286,8 @@ div:hover .group-\\\\[div\\\\:hover\\\\]-\\\\[combinator\\\\:test-4\\\\]{combina
.peer:is(:placeholder-shown)~.peer-is-placeholder-shown\\\\:text-3xl,
.peer:not(:placeholder-shown)~.peer-not-placeholder-shown\\\\:text-3xl{font-size:1.875rem;line-height:2.25rem;}
.peer:not(:placeholder-shown)~.peer-not-placeholder-shown\\\\:text-2xl{font-size:1.5rem;line-height:2rem;}
.text-\\\\[100px\\\\]{font-size:100px;}
.text-\\\\[2em\\\\],
.text-\\\\[length\\\\:2em\\\\],
.text-2em,
.text-size-\\\\[2em\\\\]{font-size:2em;}
Expand Down Expand Up @@ -403,8 +405,6 @@ div:hover .group-\\\\[div\\\\:hover\\\\]-\\\\[combinator\\\\:test-4\\\\]{combina
.c-\\\\$color-variable,
.c-\\\\$color-variable\\\\/\\\\$opacity-variable,
.c-\\\\$color-variable\\\\/10{color:var(--color-variable);}
.checked\\\\:next\\\\:hover\\\\:text-slate-500:hover+*:checked{--un-text-opacity:1;color:rgba(100,116,139,var(--un-text-opacity));}
.checked\\\\:next\\\\:text-slate-100+*:checked{--un-text-opacity:1;color:rgba(241,245,249,var(--un-text-opacity));}
.color-\\\\$red{color:var(--red);}
.color-blue,
.color-blue-400{--un-text-opacity:1;color:rgba(96,165,250,var(--un-text-opacity));}
Expand All @@ -421,16 +421,17 @@ div:hover .group-\\\\[div\\\\:hover\\\\]-\\\\[combinator\\\\:test-4\\\\]{combina
.in-range\\\\:color-pink-100:in-range,
.open\\\\:color-pink-100[open],
.out-of-range\\\\:color-pink-100:out-of-range{--un-text-opacity:1;color:rgba(252,231,243,var(--un-text-opacity));}
.next\\\\:checked\\\\:children\\\\:text-slate-600>*:checked+*{--un-text-opacity:1;color:rgba(71,85,105,var(--un-text-opacity));}
.next\\\\:checked\\\\:text-slate-200:checked+*{--un-text-opacity:1;color:rgba(226,232,240,var(--un-text-opacity));}
.placeholder-color-red-1::placeholder,
.text-red-100,
.text-red100{--un-text-opacity:1;color:rgba(254,226,226,var(--un-text-opacity));}
.placeholder-shown-color-transparent:placeholder-shown,
.placeholder\\\\:color-transparent::placeholder{color:transparent;}
.selection\\\\:color-\\\\[var\\\\(--select-color\\\\)\\\\]::selection{color:var(--select-color);}
.checked\\\\:next\\\\:hover\\\\:text-slate-500:hover+*:checked{--un-text-opacity:1;color:rgba(100,116,139,var(--un-text-opacity));}
.checked\\\\:next\\\\:text-slate-100+*:checked{--un-text-opacity:1;color:rgba(241,245,249,var(--un-text-opacity));}
.next\\\\:checked\\\\:children\\\\:text-slate-600>*:checked+*{--un-text-opacity:1;color:rgba(71,85,105,var(--un-text-opacity));}
.next\\\\:checked\\\\:text-slate-200:checked+*{--un-text-opacity:1;color:rgba(226,232,240,var(--un-text-opacity));}
.text-\\\\[\\\\#124\\\\]{--un-text-opacity:1;color:rgba(17,34,68,var(--un-text-opacity));}
.text-\\\\[2em\\\\]{color:2em;}
.text-\\\\[calc\\\\(1em-1px\\\\)\\\\]{color:calc(1em - 1px);}
.text-\\\\[color\\\\:var\\\\(--color-x\\\\)\\\\]\\\\:\\\\[trick\\\\]{color:var(--color-x);}
.text-\\\\[color\\\\:var\\\\(--color\\\\)\\\\],
Expand Down
1 change: 1 addition & 0 deletions test/assets/preset-mini-targets.ts
Expand Up @@ -196,6 +196,7 @@ export const presetMiniTargets: string[] = [
'text-[var(--color)]',
'text-[#124]',
'text-[2em]',
'text-[100px]',
'text-[calc(1em-1px)]',
'text-[length:var(--size)]',
'text-[length:2em]',
Expand Down

0 comments on commit 3d97a3a

Please sign in to comment.