From 2865cf46308ae74146a7fcffbb1d45bcbbe9a0b5 Mon Sep 17 00:00:00 2001 From: Dany Castillo <31006608+dcastil@users.noreply.github.com> Date: Sat, 19 Aug 2023 15:52:26 +0200 Subject: [PATCH 1/6] split arbitrary and non-arbitrary validators into distinct validators --- docs/api-reference.md | 5 ++-- src/lib/validators.ts | 63 ++++++++++++++++++++----------------------- 2 files changed, 32 insertions(+), 36 deletions(-) diff --git a/docs/api-reference.md b/docs/api-reference.md index 3a2b3b97..36012d8d 100644 --- a/docs/api-reference.md +++ b/docs/api-reference.md @@ -243,11 +243,12 @@ const paddingClassGroup = [{ p: [validators.isLength] }] A brief summary for each validator: -- `isLength` checks whether a class part is a number (`3`, `1.5`), a fraction (`3/4`), a arbitrary length (`[3%]`, `[4px]`, `[length:var(--my-var)]`), or one of the strings `px`, `full` or `screen`. +- `isLength` checks whether a class part is a number (`3`, `1.5`), a fraction (`3/4`), or one of the strings `px`, `full` or `screen`. - `isArbitraryLength` checks for arbitrary length values (`[3%]`, `[4px]`, `[length:var(--my-var)]`). - `isNumber` checks for numbers (`3`, `1.5`) - `isArbitraryNumber` checks whether class part is an arbitrary value which starts with `number:` or is a number (`[number:var(--value)]`, `[450]`) which is necessary for font-weight and stroke-width classNames. -- `isInteger` checks for integer values (`3`) and arbitrary integer values (`[3]`). +- `isInteger` checks for integer values (`3`). +- `isArbitraryInteger` checks for arbitrary integer values (`[3]`). - `isPercent` checks for percent values (`12.5%`) which is used for color stop positions. - `isArbitraryValue` 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`). diff --git a/src/lib/validators.ts b/src/lib/validators.ts index f08aa01d..58ba0b12 100644 --- a/src/lib/validators.ts +++ b/src/lib/validators.ts @@ -8,62 +8,65 @@ const lengthUnitRegex = const shadowRegex = /^-?((\d+)?\.?(\d+)[a-z]+|0)_-?((\d+)?\.?(\d+)[a-z]+|0)/ export function isLength(value: string) { - return ( - isNumber(value) || - stringLengths.has(value) || - fractionRegex.test(value) || - isArbitraryLength(value) - ) + return isNumber(value) || stringLengths.has(value) || fractionRegex.test(value) } export function isArbitraryLength(value: string) { return getIsArbitraryValue(value, 'length', isLengthOnly) } -export function isArbitrarySize(value: string) { - return getIsArbitraryValue(value, 'size', isNever) -} - -export function isArbitraryPosition(value: string) { - return getIsArbitraryValue(value, 'position', isNever) -} - -export function isArbitraryUrl(value: string) { - return getIsArbitraryValue(value, 'url', isUrl) +export function isNumber(value: string) { + return !Number.isNaN(Number(value)) } export function isArbitraryNumber(value: string) { return getIsArbitraryValue(value, 'number', isNumber) } -export function isNumber(value: string) { - return !Number.isNaN(Number(value)) +export function isInteger(value: string) { + return Number.isInteger(Number(value)) } -export function isPercent(value: string) { - return value.endsWith('%') && isNumber(value.slice(0, -1)) +export function isArbitraryInteger(value: string) { + return getIsArbitraryValue(value, 'number', isInteger) } -export function isInteger(value: string) { - return isIntegerOnly(value) || getIsArbitraryValue(value, 'number', isIntegerOnly) +export function isPercent(value: string) { + return value.endsWith('%') && isNumber(value.slice(0, -1)) } export function isArbitraryValue(value: string) { return arbitraryValueRegex.test(value) } -export function isAny() { - return true -} - export function isTshirtSize(value: string) { return tshirtUnitRegex.test(value) } +export function isArbitrarySize(value: string) { + return getIsArbitraryValue(value, 'size', isNever) +} + +export function isArbitraryPosition(value: string) { + return getIsArbitraryValue(value, 'position', isNever) +} + +export function isArbitraryUrl(value: string) { + return getIsArbitraryValue(value, 'url', isUrl) +} + export function isArbitraryShadow(value: string) { return getIsArbitraryValue(value, '', isShadow) } +export function isAny() { + return true +} + +function isLengthOnly(value: string) { + return lengthUnitRegex.test(value) +} + function getIsArbitraryValue(value: string, label: string, testValue: (value: string) => boolean) { const result = arbitraryValueRegex.exec(value) @@ -78,10 +81,6 @@ function getIsArbitraryValue(value: string, label: string, testValue: (value: st return false } -function isLengthOnly(value: string) { - return lengthUnitRegex.test(value) -} - function isNever() { return false } @@ -90,10 +89,6 @@ function isUrl(value: string) { return value.startsWith('url(') } -function isIntegerOnly(value: string) { - return Number.isInteger(Number(value)) -} - function isShadow(value: string) { return shadowRegex.test(value) } From 00f1e7f616530e9fc47d30514359e248c21f2caf Mon Sep 17 00:00:00 2001 From: Dany Castillo <31006608+dcastil@users.noreply.github.com> Date: Sat, 19 Aug 2023 15:58:01 +0200 Subject: [PATCH 2/6] adjust default config to change in isLength validator --- src/lib/default-config.ts | 26 ++++++++++++++------------ 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/src/lib/default-config.ts b/src/lib/default-config.ts index e8b357ff..ef433fb0 100644 --- a/src/lib/default-config.ts +++ b/src/lib/default-config.ts @@ -47,7 +47,7 @@ export function getDefaultConfig() { const getOverflow = () => ['auto', 'hidden', 'clip', 'visible', 'scroll'] as const const getSpacingWithAutoAndArbitrary = () => ['auto', isArbitraryValue, spacing] as const const getSpacingWithArbitrary = () => [isArbitraryValue, spacing] as const - const getLengthWithEmpty = () => ['', isLength] as const + const getLengthWithEmptyAndArbitrary = () => ['', isLength, isArbitraryLength] as const const getNumberWithAutoAndArbitrary = () => ['auto', isNumber, isArbitraryValue] as const const getPositions = () => [ @@ -95,13 +95,13 @@ export function getDefaultConfig() { separator: ':', theme: { colors: [isAny], - spacing: [isLength], + spacing: [isLength, isArbitraryLength], blur: ['none', '', isTshirtSize, isArbitraryValue], brightness: getNumber(), borderColor: [colors], borderRadius: ['none', '', 'full', isTshirtSize, isArbitraryValue], borderSpacing: getSpacingWithArbitrary(), - borderWidth: getLengthWithEmpty(), + borderWidth: getLengthWithEmptyAndArbitrary(), contrast: getNumber(), grayscale: getZeroAndEmpty(), hueRotate: getNumberAndArbitrary(), @@ -606,7 +606,7 @@ export function getDefaultConfig() { * Min-Height * @see https://tailwindcss.com/docs/min-height */ - 'min-h': [{ 'min-h': ['min', 'max', 'fit', isArbitraryValue, isLength] }], + 'min-h': [{ 'min-h': ['min', 'max', 'fit', isLength, isArbitraryValue] }], /** * Max-Height * @see https://tailwindcss.com/docs/max-height @@ -718,8 +718,8 @@ export function getDefaultConfig() { 'normal', 'relaxed', 'loose', - isArbitraryValue, isLength, + isArbitraryValue, ], }, ], @@ -778,12 +778,14 @@ export function getDefaultConfig() { * Text Decoration Thickness * @see https://tailwindcss.com/docs/text-decoration-thickness */ - 'text-decoration-thickness': [{ decoration: ['auto', 'from-font', isLength] }], + 'text-decoration-thickness': [ + { decoration: ['auto', 'from-font', isLength, isArbitraryLength] }, + ], /** * Text Underline Offset * @see https://tailwindcss.com/docs/text-underline-offset */ - 'underline-offset': [{ 'underline-offset': ['auto', isArbitraryValue, isLength] }], + 'underline-offset': [{ 'underline-offset': ['auto', isLength, isArbitraryValue] }], /** * Text Decoration Color * @see https://tailwindcss.com/docs/text-decoration-color @@ -1140,12 +1142,12 @@ export function getDefaultConfig() { * Outline Offset * @see https://tailwindcss.com/docs/outline-offset */ - 'outline-offset': [{ 'outline-offset': [isArbitraryValue, isLength] }], + 'outline-offset': [{ 'outline-offset': [isLength, isArbitraryValue] }], /** * Outline Width * @see https://tailwindcss.com/docs/outline-width */ - 'outline-w': [{ outline: [isLength] }], + 'outline-w': [{ outline: [isLength, isArbitraryLength] }], /** * Outline Color * @see https://tailwindcss.com/docs/outline-color @@ -1155,7 +1157,7 @@ export function getDefaultConfig() { * Ring Width * @see https://tailwindcss.com/docs/ring-width */ - 'ring-w': [{ ring: getLengthWithEmpty() }], + 'ring-w': [{ ring: getLengthWithEmptyAndArbitrary() }], /** * Ring Width Inset * @see https://tailwindcss.com/docs/ring-width @@ -1175,7 +1177,7 @@ export function getDefaultConfig() { * Ring Offset Width * @see https://tailwindcss.com/docs/ring-offset-width */ - 'ring-offset-w': [{ 'ring-offset': [isLength] }], + 'ring-offset-w': [{ 'ring-offset': [isLength, isArbitraryLength] }], /** * Ring Offset Color * @see https://tailwindcss.com/docs/ring-offset-color @@ -1671,7 +1673,7 @@ export function getDefaultConfig() { * Stroke Width * @see https://tailwindcss.com/docs/stroke-width */ - 'stroke-w': [{ stroke: [isLength, isArbitraryNumber] }], + 'stroke-w': [{ stroke: [isLength, isArbitraryLength, isArbitraryNumber] }], /** * Stroke * @see https://tailwindcss.com/docs/stroke From e0e89532bee53d487ed2f62c02de7aa9f49b741d Mon Sep 17 00:00:00 2001 From: Dany Castillo <31006608+dcastil@users.noreply.github.com> Date: Sat, 19 Aug 2023 16:05:40 +0200 Subject: [PATCH 3/6] remove isArbitraryInteger as it is not needed --- docs/api-reference.md | 1 - src/lib/validators.ts | 4 ---- 2 files changed, 5 deletions(-) diff --git a/docs/api-reference.md b/docs/api-reference.md index 36012d8d..ff0d41f0 100644 --- a/docs/api-reference.md +++ b/docs/api-reference.md @@ -248,7 +248,6 @@ A brief summary for each validator: - `isNumber` checks for numbers (`3`, `1.5`) - `isArbitraryNumber` checks whether class part is an arbitrary value which starts with `number:` or is a number (`[number:var(--value)]`, `[450]`) which is necessary for font-weight and stroke-width classNames. - `isInteger` checks for integer values (`3`). -- `isArbitraryInteger` checks for arbitrary integer values (`[3]`). - `isPercent` checks for percent values (`12.5%`) which is used for color stop positions. - `isArbitraryValue` 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`). diff --git a/src/lib/validators.ts b/src/lib/validators.ts index 58ba0b12..295ffdd4 100644 --- a/src/lib/validators.ts +++ b/src/lib/validators.ts @@ -27,10 +27,6 @@ export function isInteger(value: string) { return Number.isInteger(Number(value)) } -export function isArbitraryInteger(value: string) { - return getIsArbitraryValue(value, 'number', isInteger) -} - export function isPercent(value: string) { return value.endsWith('%') && isNumber(value.slice(0, -1)) } From 0b68413bc23536c3369c21c90461fca2ba4cc1bf Mon Sep 17 00:00:00 2001 From: Dany Castillo <31006608+dcastil@users.noreply.github.com> Date: Sat, 19 Aug 2023 16:06:49 +0200 Subject: [PATCH 4/6] adjust default config to change in isInteger validator --- src/lib/default-config.ts | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/src/lib/default-config.ts b/src/lib/default-config.ts index ef433fb0..a026dcaa 100644 --- a/src/lib/default-config.ts +++ b/src/lib/default-config.ts @@ -303,7 +303,7 @@ export function getDefaultConfig() { * Z-Index * @see https://tailwindcss.com/docs/z-index */ - z: [{ z: ['auto', isInteger] }], + z: [{ z: ['auto', isInteger, isArbitraryValue] }], // Flexbox and Grid /** * Flex Basis @@ -339,7 +339,7 @@ export function getDefaultConfig() { * Order * @see https://tailwindcss.com/docs/order */ - order: [{ order: ['first', 'last', 'none', isInteger] }], + order: [{ order: ['first', 'last', 'none', isInteger, isArbitraryValue] }], /** * Grid Template Columns * @see https://tailwindcss.com/docs/grid-template-columns @@ -349,7 +349,15 @@ export function getDefaultConfig() { * Grid Column Start / End * @see https://tailwindcss.com/docs/grid-column */ - 'col-start-end': [{ col: ['auto', { span: ['full', isInteger] }, isArbitraryValue] }], + 'col-start-end': [ + { + col: [ + 'auto', + { span: ['full', isInteger, isArbitraryValue] }, + isArbitraryValue, + ], + }, + ], /** * Grid Column Start * @see https://tailwindcss.com/docs/grid-column @@ -369,7 +377,9 @@ export function getDefaultConfig() { * Grid Row Start / End * @see https://tailwindcss.com/docs/grid-row */ - 'row-start-end': [{ row: ['auto', { span: [isInteger] }, isArbitraryValue] }], + 'row-start-end': [ + { row: ['auto', { span: [isInteger, isArbitraryValue] }, isArbitraryValue] }, + ], /** * Grid Row Start * @see https://tailwindcss.com/docs/grid-row From 113b2c17050dcb3d51824fc9337c0208397de137 Mon Sep 17 00:00:00 2001 From: Dany Castillo <31006608+dcastil@users.noreply.github.com> Date: Sat, 19 Aug 2023 16:08:28 +0200 Subject: [PATCH 5/6] adjust validator tests --- tests/validators.test.ts | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/tests/validators.test.ts b/tests/validators.test.ts index a5405fc2..536bec1f 100644 --- a/tests/validators.test.ts +++ b/tests/validators.test.ts @@ -25,12 +25,12 @@ test('isLength', () => { expect(isLength('screen')).toBe(true) expect(isLength('1/2')).toBe(true) expect(isLength('123/345')).toBe(true) - expect(isLength('[3.7%]')).toBe(true) - expect(isLength('[481px]')).toBe(true) - expect(isLength('[19.1rem]')).toBe(true) - expect(isLength('[50vw]')).toBe(true) - expect(isLength('[56vh]')).toBe(true) - expect(isLength('[length:var(--arbitrary)]')).toBe(true) + expect(isLength('[3.7%]')).toBe(false) + expect(isLength('[481px]')).toBe(false) + expect(isLength('[19.1rem]')).toBe(false) + expect(isLength('[50vw]')).toBe(false) + expect(isLength('[56vh]')).toBe(false) + expect(isLength('[length:var(--arbitrary)]')).toBe(false) expect(isLength('1d5')).toBe(false) expect(isLength('[1]')).toBe(false) @@ -60,8 +60,8 @@ test('isInteger', () => { expect(isInteger('1')).toBe(true) expect(isInteger('123')).toBe(true) expect(isInteger('8312')).toBe(true) - expect(isInteger('[8312]')).toBe(true) - expect(isInteger('[2]')).toBe(true) + expect(isInteger('[8312]')).toBe(false) + expect(isInteger('[2]')).toBe(false) expect(isInteger('[8312px]')).toBe(false) expect(isInteger('[8312%]')).toBe(false) From 76d5d491d0122f28c67555bcee2bce30191e0858 Mon Sep 17 00:00:00 2001 From: Dany Castillo <31006608+dcastil@users.noreply.github.com> Date: Sat, 19 Aug 2023 16:09:45 +0200 Subject: [PATCH 6/6] make separation in validators test clear again --- tests/validators.test.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/tests/validators.test.ts b/tests/validators.test.ts index 536bec1f..d45cbb60 100644 --- a/tests/validators.test.ts +++ b/tests/validators.test.ts @@ -25,13 +25,13 @@ test('isLength', () => { expect(isLength('screen')).toBe(true) expect(isLength('1/2')).toBe(true) expect(isLength('123/345')).toBe(true) + expect(isLength('[3.7%]')).toBe(false) expect(isLength('[481px]')).toBe(false) expect(isLength('[19.1rem]')).toBe(false) expect(isLength('[50vw]')).toBe(false) expect(isLength('[56vh]')).toBe(false) expect(isLength('[length:var(--arbitrary)]')).toBe(false) - expect(isLength('1d5')).toBe(false) expect(isLength('[1]')).toBe(false) expect(isLength('[12px')).toBe(false) @@ -60,9 +60,9 @@ test('isInteger', () => { expect(isInteger('1')).toBe(true) expect(isInteger('123')).toBe(true) expect(isInteger('8312')).toBe(true) + expect(isInteger('[8312]')).toBe(false) expect(isInteger('[2]')).toBe(false) - expect(isInteger('[8312px]')).toBe(false) expect(isInteger('[8312%]')).toBe(false) expect(isInteger('[8312rem]')).toBe(false) @@ -178,6 +178,7 @@ test('isPercent', () => { expect(isPercent('100.001%')).toBe(true) expect(isPercent('.01%')).toBe(true) expect(isPercent('0%')).toBe(true) + expect(isPercent('0')).toBe(false) expect(isPercent('one%')).toBe(false) })