Skip to content

Commit

Permalink
refactor: radial result
Browse files Browse the repository at this point in the history
  • Loading branch information
Jackie1210 committed Oct 14, 2023
1 parent b932bf4 commit 1190517
Show file tree
Hide file tree
Showing 3 changed files with 155 additions and 36 deletions.
18 changes: 11 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,16 +24,20 @@ interface LinearResult {

### `parseRadialGradient`
```ts
type ValueType = 'keyword' | 'length'

interface RadialResult {
shape: 'circle' | 'ellipse'
size: string
repeating: boolean
position: string
stops: Array<{
color: string
offset: string
hint?: string
}>
size: {
type: ValueType
value: string
}[]
position: {
x: { type: ValueType, value: string }
y: { type: ValueType, value: string }
}
stops: ColorStop[]
}
```

Expand Down
106 changes: 91 additions & 15 deletions src/radial.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,23 +3,74 @@ import { ColorStop } from './type.js'

export type RgExtentKeyword = 'closest-corner' | 'closest-side' | 'farthest-corner' | 'farthest-side'

type ValueType = 'keyword' | 'length'

export interface RadialResult {
shape: 'circle' | 'ellipse'
repeating: boolean
size: string
position: string
size: {
type: ValueType
value: string
}[]
position: {
x: { type: ValueType, value: string }
y: { type: ValueType, value: string }
}
stops: ColorStop[]
}

const rgExtentKeyword = new Set<RgExtentKeyword>([
'closest-corner',
'closest-side',
'farthest-corner',
'farthest-side'
])

type PositionKeyWord = 'center' | 'left' | 'right' | 'top' | 'bottom'

const positionKeyword = new Set<PositionKeyWord>([
'center',
'left',
'top',
'right',
'bottom'
])

//eslint-disable-next-line @typescript-eslint/no-explicit-any
function isRgExtentKeyword(v: any): v is RgExtentKeyword {
return rgExtentKeyword.has(v)
}

//eslint-disable-next-line @typescript-eslint/no-explicit-any
function isPositionKeyWord(v: any): v is PositionKeyWord {
return positionKeyword.has(v)
}

function extendPosition(v: string[]) {
const res = Array(2).fill('')
for (let i = 0; i < 2; i++) {
if (!v[i]) res[i] = 'center'
else res[i] = v[i]
}

return res
}

export function parseRadialGradient(input: string): RadialResult {
if (!/(repeating-)?radial-gradient/.test(input)) throw new SyntaxError(`could not find syntax for this item: ${input}`)

const [, repeating, props] = input.match(/(repeating-)?radial-gradient\((.+)\)/)
const result: RadialResult = {
shape: 'ellipse',
repeating: Boolean(repeating),
size: 'farthest-corner',
position: 'center',
size: [{
type: 'keyword',
value: 'farthest-corner'
}],
position: {
x: { type: 'keyword', value: 'center' },
y: { type: 'keyword', value: 'center' }
},
stops: []
}

Expand All @@ -32,19 +83,44 @@ export function parseRadialGradient(input: string): RadialResult {
const prefix = properties[0].split('at').map(v => v.trim())

const shape = ((prefix[0] || '').match(/(circle|ellipse)/) || [])[1]
const size = ((prefix[0] || '').match(/(\d+\.?\d*(vw|vh|px|em|rem)?|closest-corner|closest-side|farthest-corner|farthest-side)/) || [])[1]
const position = prefix[1]

if (shape || size || position) {
properties.shift()
Object.assign(result, {
shape: shape || 'ellipse',
size: size || 'farthest-corner',
position: position || 'center'
})
const size: string[] = (prefix[0] || '').match(/(\d+\.?\d*(vw|vh|px|em|rem)?|closest-corner|closest-side|farthest-corner|farthest-side)/g) || []
const position = extendPosition((prefix[1] || '').split(' '))

if (!shape) {
if (size.length === 1 && !isRgExtentKeyword(size[0])) {
result.shape = 'circle'
} else {
result.shape = 'ellipse'
}
} else {
result.shape = shape as RadialResult['shape']
}

if (size.length === 0) {
size.push('farthest-corner')
}

return { ...result, stops: resolveStops(properties) }
result.size = size.map(v => ({
type: isRgExtentKeyword(v) ? 'keyword' : 'length',
value: v
})) as Array<{ type: 'keyword' | 'length'; value: string }>

result.position.x = {
type: !position[0] || isPositionKeyWord(position[0]) ? 'keyword' : 'length',
value: position[0] || 'center'
} as { type: 'keyword' | 'length'; value: string }

result.position.y = {
type: isPositionKeyWord(position[1]) ? 'keyword' : 'length',
value: position[1]
} as { type: 'keyword' | 'length'; value: string }

if (shape || size.length > 0 || prefix[1]) properties.shift()

return {
...result,
stops: resolveStops(properties)
}
}

function isColor(v: string) {
Expand Down
67 changes: 53 additions & 14 deletions test/radial.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,16 @@ describe('radial', () => {
const g5 = parseRadialGradient('radial-gradient(circle 10vw, #333, #eee 80%)')
const g6 = parseRadialGradient('radial-gradient(#333, #eee 80%)')
const g7 = parseRadialGradient('repeating-radial-gradient(#333, #eee 80%)')
const g8 = parseRadialGradient('radial-gradient(ellipse 10px 30px at 10px 20px, #333, #eee 80%)')

expect(g1).toEqual({
shape: 'circle',
repeating: false,
position: '100%',
size: 'farthest-corner',
position: {
x: { type: 'length', value: '100%' },
y: { type: 'keyword', value: 'center' }
},
size: [{ type: 'keyword', value: 'farthest-corner'}],
stops: [
{ color: '#333' },
{ color: '#eee', offset: '80%' }
Expand All @@ -25,8 +29,11 @@ describe('radial', () => {
expect(g2).toEqual({
shape: 'circle',
repeating: false,
position: '10px 20px',
size: '20px',
position: {
x: { type: 'length', value: '10px' },
y: { type: 'length', value: '20px' }
},
size: [{ type: 'length', value: '20px'}],
stops: [
{ color: '#333' },
{ color: '#eee', offset: '80%' }
Expand All @@ -36,8 +43,11 @@ describe('radial', () => {
expect(g3).toEqual({
shape: 'circle',
repeating: false,
position: '10px 20px',
size: 'closest-corner',
position: {
x: { type: 'length', value: '10px' },
y: { type: 'length', value: '20px' }
},
size: [{ type: 'keyword', value: 'closest-corner'}],
stops: [
{ color: '#333' },
{ color: '#eee', offset: '80%' }
Expand All @@ -47,8 +57,11 @@ describe('radial', () => {
expect(g4).toEqual({
shape: 'circle',
repeating: false,
position: 'center',
size: 'farthest-corner',
position: {
x: { type: 'keyword', value: 'center' },
y: { type: 'keyword', value: 'center' },
},
size: [{ type: 'keyword', value: 'farthest-corner'}],
stops: [
{ color: '#333' },
{ color: '#eee', offset: '80%' }
Expand All @@ -58,8 +71,11 @@ describe('radial', () => {
expect(g5).toEqual({
shape: 'circle',
repeating: false,
position: 'center',
size: '10vw',
position: {
x: { type: 'keyword', value: 'center' },
y: { type: 'keyword', value: 'center' },
},
size: [{ type: 'length', value: '10vw'}],
stops: [
{ color: '#333' },
{ color: '#eee', offset: '80%' }
Expand All @@ -69,8 +85,11 @@ describe('radial', () => {
expect(g6).toEqual({
shape: 'ellipse',
repeating: false,
position: 'center',
size: 'farthest-corner',
position: {
x: { type: 'keyword', value: 'center' },
y: { type: 'keyword', value: 'center' },
},
size: [{ type: 'keyword', value: 'farthest-corner'}],
stops: [
{ color: '#333' },
{ color: '#eee', offset: '80%' }
Expand All @@ -80,8 +99,28 @@ describe('radial', () => {
expect(g7).toEqual({
shape: 'ellipse',
repeating: true,
position: 'center',
size: 'farthest-corner',
position: {
x: { type: 'keyword', value: 'center' },
y: { type: 'keyword', value: 'center' },
},
size: [{ type: 'keyword', value: 'farthest-corner'}],
stops: [
{ color: '#333' },
{ color: '#eee', offset: '80%' }
]
})

expect(g8).toEqual({
shape: 'ellipse',
repeating: false,
position: {
x: { type: 'length', value: '10px' },
y: { type: 'length', value: '20px' },
},
size: [
{ type: 'length', value: '10px' },
{ type: 'length', value: '30px' }
],
stops: [
{ color: '#333' },
{ color: '#eee', offset: '80%' }
Expand Down

0 comments on commit 1190517

Please sign in to comment.