Skip to content

Commit

Permalink
add custom value support for font-weight, bg-position, bg-size and bg…
Browse files Browse the repository at this point in the history
…-image
  • Loading branch information
dcastil committed Dec 10, 2021
1 parent 2837e54 commit f8acd7c
Show file tree
Hide file tree
Showing 5 changed files with 117 additions and 11 deletions.
10 changes: 9 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -504,6 +504,10 @@ interface Validators {
isInteger(classPart: string): boolean
isCustomValue(classPart: string): boolean
isTshirtSize(classPart: string): boolean
isCustomSize(classPart: string): boolean
isCustomPosition(classPart: string): boolean
isCustomUrl(classPart: string): boolean
isCustomWeight(classPart: string): boolean
isAny(classPart: string): boolean
}
```
Expand All @@ -520,7 +524,11 @@ A brief summary for each validator:
- `isCustomLength` checks for custom length values (`[3%]`, `[4px]`, `[length:var(--my-var)]`).
- `isInteger` checks for integer values (`3`) and custom integer values (`[3]`).
- `isCustomValue` checks whether the class part is enclosed in brackets (`[something]`)
- `isTshirtSize`checks whether class part is a T-shirt size (`sm`, `xl`), optionally with a preceding number (`2xl`)
- `isTshirtSize`checks whether class part is a T-shirt size (`sm`, `xl`), optionally with a preceding number (`2xl`).
- `isCustomSize` checks whether class part is custom value which starts with with `size:` (`[size:200px_100px]`) which is necessary for background-size classNames.
- `isCustomPosition` checks whether class part is custom value which starts with with `position:` (`[position:200px_100px]`) which is necessary for background-position classNames.
- `isCustomUrl` checks whether class part is custom value which starts with `url:` or `url(` (`[url('/path-to-image.png')]`, `url:var(--maybe-a-url-at-runtime)]`) which is necessary for background-image classNames.
- `isCustomWeight` checks whether class part is custom value whcih starts with `weight:` or is a number (`[weight:var(--value)]`, `[450]`) which is necessary for font-weight classNames.
- `isAny` always returns true. Be careful with this validator as it might match unwanted classes. I use it primarily to match colors or when I'm ceertain there are no other class groups in a namespace.

### `Config`
Expand Down
27 changes: 19 additions & 8 deletions src/default-config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,11 @@ import { fromTheme } from './from-theme'
import {
isAny,
isCustomLength,
isCustomPosition,
isCustomSize,
isCustomUrl,
isCustomValue,
isCustomWeight,
isInteger,
isLength,
isTshirtSize,
Expand Down Expand Up @@ -569,11 +573,6 @@ export function getDefaultConfig() {
*/
'max-h': [{ 'max-h': [spacing, 'min', 'max', 'fit'] }],
// Typography
/**
* Font Family
* @see https://tailwindcss.com/docs/font-family
*/
'font-family': [{ font: [isAny] }],
/**
* Font Size
* @see https://tailwindcss.com/docs/font-size
Expand Down Expand Up @@ -605,9 +604,15 @@ export function getDefaultConfig() {
'bold',
'extrabold',
'black',
isCustomWeight,
],
},
],
/**
* Font Family
* @see https://tailwindcss.com/docs/font-family
*/
'font-family': [{ font: [isAny] }],
/**
* Font Variant Numeric
* @see https://tailwindcss.com/docs/font-variant-numeric
Expand Down Expand Up @@ -790,7 +795,7 @@ export function getDefaultConfig() {
* Background Position
* @see https://tailwindcss.com/docs/background-position
*/
'bg-position': [{ bg: getPositions() }],
'bg-position': [{ bg: [...getPositions(), isCustomPosition] }],
/**
* Background Repeat
* @see https://tailwindcss.com/docs/background-repeat
Expand All @@ -800,13 +805,19 @@ export function getDefaultConfig() {
* Background Size
* @see https://tailwindcss.com/docs/background-size
*/
'bg-size': [{ bg: ['auto', 'cover', 'contain'] }],
'bg-size': [{ bg: ['auto', 'cover', 'contain', isCustomSize] }],
/**
* Background Image
* @see https://tailwindcss.com/docs/background-image
*/
'bg-image': [
{ bg: ['none', { 'gradient-to': ['t', 'tr', 'r', 'br', 'b', 'bl', 'l', 'tl'] }] },
{
bg: [
'none',
{ 'gradient-to': ['t', 'tr', 'r', 'br', 'b', 'bl', 'l', 'tl'] },
isCustomUrl,
],
},
],
/**
* Background Blend Mode
Expand Down
26 changes: 26 additions & 0 deletions src/validators.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,32 @@ export function isCustomLength(classPart: string) {
return false
}

export function isCustomSize(classPart: string) {
const customValue = customValueRegex.exec(classPart)?.[1]

return customValue ? customValue.startsWith('size:') : false
}

export function isCustomPosition(classPart: string) {
const customValue = customValueRegex.exec(classPart)?.[1]

return customValue ? customValue.startsWith('position:') : false
}

export function isCustomUrl(classPart: string) {
const customValue = customValueRegex.exec(classPart)?.[1]

return customValue ? customValue.startsWith('url(') || customValue.startsWith('url:') : false
}

export function isCustomWeight(classPart: string) {
const customValue = customValueRegex.exec(classPart)?.[1]

return customValue
? !Number.isNaN(Number(customValue)) || customValue.startsWith('weight:')
: false
}

export function isInteger(classPart: string) {
const customValue = customValueRegex.exec(classPart)?.[1]

Expand Down
10 changes: 9 additions & 1 deletion tests/public-api.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,12 @@ test('has correct export types', () => {
isCustomLength: expect.any(Function),
isInteger: expect.any(Function),
isCustomValue: expect.any(Function),
isAny: expect.any(Function),
isTshirtSize: expect.any(Function),
isCustomSize: expect.any(Function),
isCustomPosition: expect.any(Function),
isCustomUrl: expect.any(Function),
isCustomWeight: expect.any(Function),
isAny: expect.any(Function),
})
expect(mergeConfigs).toStrictEqual(expect.any(Function))
expect(extendTailwindMerge).toStrictEqual(expect.any(Function))
Expand Down Expand Up @@ -121,6 +125,10 @@ test('validators have correct inputs and outputs', () => {
expect(validators.isCustomValue('')).toEqual(expect.any(Boolean))
expect(validators.isAny()).toEqual(expect.any(Boolean))
expect(validators.isTshirtSize('')).toEqual(expect.any(Boolean))
expect(validators.isCustomSize('')).toEqual(expect.any(Boolean))
expect(validators.isCustomPosition('')).toEqual(expect.any(Boolean))
expect(validators.isCustomUrl('')).toEqual(expect.any(Boolean))
expect(validators.isCustomWeight('')).toEqual(expect.any(Boolean))
})

test('mergeConfigs has correct inputs and outputs', () => {
Expand Down
55 changes: 54 additions & 1 deletion tests/validators.test.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,17 @@
import { validators } from '../src'

const { isLength, isCustomLength, isInteger, isCustomValue, isAny, isTshirtSize } = validators
const {
isLength,
isCustomLength,
isInteger,
isCustomValue,
isAny,
isTshirtSize,
isCustomSize,
isCustomPosition,
isCustomUrl,
isCustomWeight,
} = validators

describe('validators', () => {
test('isLength', () => {
Expand Down Expand Up @@ -101,4 +112,46 @@ describe('validators', () => {
expect(isTshirtSize('-xl')).toBe(false)
expect(isTshirtSize('[sm]')).toBe(false)
})

test('isCustomSize', () => {
expect(isCustomSize('[size:2px]')).toBe(true)
expect(isCustomSize('[size:bla]')).toBe(true)

expect(isCustomSize('[2px]')).toBe(false)
expect(isCustomSize('[bla]')).toBe(false)
expect(isCustomSize('size:2px')).toBe(false)
})

test('isCustomPosition', () => {
expect(isCustomPosition('[position:2px]')).toBe(true)
expect(isCustomPosition('[position:bla]')).toBe(true)

expect(isCustomPosition('[2px]')).toBe(false)
expect(isCustomPosition('[bla]')).toBe(false)
expect(isCustomPosition('position:2px')).toBe(false)
})

test('isCustomUrl', () => {
expect(isCustomUrl('[url:var(--my-url)]')).toBe(true)
expect(isCustomUrl('[url(something)]')).toBe(true)
expect(isCustomUrl('[url:bla]')).toBe(true)

expect(isCustomUrl('[var(--my-url)]')).toBe(false)
expect(isCustomUrl('[bla]')).toBe(false)
expect(isCustomUrl('url:2px')).toBe(false)
expect(isCustomUrl('url(2px)')).toBe(false)
})

test('isCustomWeight', () => {
expect(isCustomWeight('[weight:black]')).toBe(true)
expect(isCustomWeight('[weight:bla]')).toBe(true)
expect(isCustomWeight('[weight:230]')).toBe(true)
expect(isCustomWeight('[450]')).toBe(true)

expect(isCustomWeight('[2px]')).toBe(false)
expect(isCustomWeight('[bla]')).toBe(false)
expect(isCustomWeight('[black]')).toBe(false)
expect(isCustomWeight('black')).toBe(false)
expect(isCustomWeight('450')).toBe(false)
})
})

0 comments on commit f8acd7c

Please sign in to comment.