Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

test: updated tests, partial refactor #742

Merged
merged 1 commit into from
Jul 10, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 10 additions & 5 deletions biome.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,17 +7,22 @@
"lineEnding": "crlf",
"lineWidth": 120
},
"organizeImports": { "enabled": true },
"organizeImports": {
"enabled": true
},
"linter": {
"enabled": true,
"rules": {
"recommended": true,
"complexity": {
"noForEach": { "level": "off" },
"useOptionalChain": { "level": "off" }
"noForEach": {
"level": "off"
}
},
"suspicious": {
"noExplicitAny": { "level": "off" }
"noExplicitAny": {
"level": "off"
}
}
}
},
Expand All @@ -30,6 +35,6 @@
}
},
"files": {
"ignore": ["dist/**", "node_modules/**", "nuxt/**", "coverage/**"]
"ignore": ["dist/**", "node_modules/**", "nuxt/**", "coverage/**", ".vscode/**"]
}
}
4 changes: 2 additions & 2 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ const createDirective = (
[hooks.mounted](el, { value = {} }) {
optionMap.set(el, value)

markWaveBoundary(el, (value && value.trigger) ?? globalOptions.trigger)
markWaveBoundary(el, value?.trigger ?? globalOptions.trigger)

el.addEventListener('pointerdown', (event) => {
if (!optionMap.has(el)) return
Expand All @@ -62,7 +62,7 @@ const createDirective = (
},
[hooks.updated](el, { value = {} }) {
optionMap.set(el, value)
markWaveBoundary(el, (value && value.trigger) ?? globalOptions.trigger)
markWaveBoundary(el, value?.trigger ?? globalOptions.trigger)
},
}

Expand Down
4 changes: 4 additions & 0 deletions src/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
export type Vector = {
x: number
y: number
}
13 changes: 0 additions & 13 deletions src/utils/__snapshots__/createContainerElement.test.ts.snap

This file was deleted.

7 changes: 0 additions & 7 deletions src/utils/__snapshots__/createWaveElement.test.ts.snap

This file was deleted.

13 changes: 0 additions & 13 deletions src/utils/__snapshots__/markWaveBoundary.test.ts.snap

This file was deleted.

24 changes: 20 additions & 4 deletions src/utils/createContainerElement.test.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,23 @@
import { expect, test } from 'vitest'
import { describe, expect, test } from 'vitest'
import { createContainer } from './createContainerElement'

test('createContainerElement returns a an element based on `tagName`', () => {
expect(createContainer({} as CSSStyleDeclaration, 'div')).toMatchSnapshot()
expect(createContainer({} as CSSStyleDeclaration, 'span')).toMatchSnapshot()
describe('createContainerElement', () => {
test('returns an element based on `tagName`', () => {
expect(createContainer({} as CSSStyleDeclaration, 'div').tagName).toBe('DIV')
expect(createContainer({} as CSSStyleDeclaration, 'span').tagName).toBe('SPAN')
})

test('returns an element with the correct border radius', () => {
const container = createContainer(
{
borderTopLeftRadius: '10px',
borderTopRightRadius: '20px',
borderBottomLeftRadius: '30px',
borderBottomRightRadius: '40px',
} as CSSStyleDeclaration,
'div'
)

expect(container.style.borderRadius).toBe('10px 20px 40px 30px')
})
})
63 changes: 60 additions & 3 deletions src/utils/createWaveElement.test.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,64 @@
import { expect, test } from 'vitest'
import { describe, expect, test } from 'vitest'
import type { IVWaveDirectiveOptions } from '../options'
import { createWaveElement } from './createWaveElement'

test('createWaveElement returns a <div>', () => {
expect(createWaveElement(0, 0, 0, {} as IVWaveDirectiveOptions)).toMatchSnapshot()
describe('createWaveElement', () => {
test('returns a <div>', () => {
const waveElement = createWaveElement({ x: 0, y: 0 }, 0, {} as IVWaveDirectiveOptions)

expect(waveElement.tagName).toBe('DIV')
})

test('returns a <div> with the correct position', () => {
const waveElement = createWaveElement({ x: 10, y: 20 }, 0, {} as IVWaveDirectiveOptions)

expect(waveElement.style.top).toBe('20px')
expect(waveElement.style.left).toBe('10px')
})

test('returns a <div> with the correct size', () => {
const waveElement = createWaveElement({ x: 0, y: 0 }, 10, {} as IVWaveDirectiveOptions)

expect(waveElement.style.width).toBe('10px')
expect(waveElement.style.height).toBe('10px')
})

test('returns a <div> with the correct background color', () => {
const waveElement = createWaveElement({ x: 0, y: 0 }, 0, { color: 'red' } as IVWaveDirectiveOptions)

expect(waveElement.style.background).toBe('red')
})

test('returns a <div> with the correct border radius', () => {
const waveElement = createWaveElement({ x: 0, y: 0 }, 0, { color: 'red' } as IVWaveDirectiveOptions)

expect(waveElement.style.borderRadius).toBe('50%')
})

test('returns a <div> with the correct opacity', () => {
const waveElement = createWaveElement({ x: 0, y: 0 }, 0, {
initialOpacity: 0.5,
finalOpacity: 0.5,
} as IVWaveDirectiveOptions)

expect(waveElement.style.opacity).toBe('0.5')
})

test('returns a <div> with the correct transform', () => {
const waveElement = createWaveElement({ x: 0, y: 0 }, 0, {
initialOpacity: 0.5,
finalOpacity: 0.5,
} as IVWaveDirectiveOptions)

expect(waveElement.style.transform).toBe('translate(-50%,-50%) scale(0)')
})

test('returns a <div> with the correct transition', () => {
const waveElement = createWaveElement({ x: 0, y: 0 }, 0, {
duration: 1,
easing: 'ease-in',
} as IVWaveDirectiveOptions)

expect(waveElement.style.transition).toBe('transform 1s ease-in, opacity 1s ease-in')
})
})
3 changes: 2 additions & 1 deletion src/utils/createWaveElement.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import type { IVWaveDirectiveOptions } from '../options'
import type { Vector } from '../types'

export const createWaveElement = (x: number, y: number, size: number, options: IVWaveDirectiveOptions) => {
export const createWaveElement = ({ x, y }: Vector, size: number, options: IVWaveDirectiveOptions) => {
const waveElement = document.createElement('div')

waveElement.style.position = 'absolute'
Expand Down
4 changes: 2 additions & 2 deletions src/utils/getDistanceToFurthestCorner.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,6 @@ import { expect, test } from 'vitest'
import { getDistanceToFurthestCorner } from './getDistanceToFurthestCorner'

test('getDistanceToFurthestCorner', () => {
expect(getDistanceToFurthestCorner(25, 25, { width: 100, height: 100 } as DOMRect)).toBe(106.06601717798213)
expect(getDistanceToFurthestCorner(25, 25, { width: 30, height: 30 } as DOMRect)).toBe(35.35533905932738)
expect(getDistanceToFurthestCorner({ x: 25, y: 25 }, { width: 100, height: 100 } as DOMRect)).toBe(106.06601717798213)
expect(getDistanceToFurthestCorner({ x: 25, y: 25 }, { width: 30, height: 30 } as DOMRect)).toBe(35.35533905932738)
})
3 changes: 2 additions & 1 deletion src/utils/getDistanceToFurthestCorner.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import type { Vector } from '../types'
import { magnitude } from './magnitude'

export function getDistanceToFurthestCorner(x: number, y: number, { width, height }: DOMRect) {
export function getDistanceToFurthestCorner({ x, y }: Vector, { width, height }: DOMRect) {
const topLeft = magnitude(x, y, 0, 0)
const topRight = magnitude(x, y, width, 0)
const bottomLeft = magnitude(x, y, 0, height)
Expand Down
4 changes: 3 additions & 1 deletion src/utils/getRelativePointer.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
export const getRelativePointer = ({ x, y }: PointerEvent, { top, left }: DOMRect) => ({
import type { Vector } from '../types'

export const getRelativePointer = ({ x, y }: Vector, { top, left }: DOMRect): Vector => ({
x: x - left,
y: y - top,
})
2 changes: 2 additions & 0 deletions src/utils/magnitude.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,6 @@ import { magnitude } from './magnitude'

test('magnitude', () => {
expect(magnitude(5, 10, 10, 20)).toBe(11.180339887498949)

expect(magnitude(10, 20, 30, 40)).toBe(28.284271247461902)
})
4 changes: 2 additions & 2 deletions src/utils/markWaveBoundary.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,11 @@ describe('markWaveBoundary', () => {
test('sets dataset to true when trigger is not an id', () => {
const div = document.createElement('div')
markWaveBoundary(div, 'auto')
expect(div).toMatchSnapshot()
expect(div.dataset.vWaveBoundary).toBe('true')
})
test('sets dataset to the id when the trigger is an id', () => {
const div = document.createElement('div')
markWaveBoundary(div, 'stringId')
expect(div).toMatchSnapshot()
expect(div.dataset.vWaveBoundary).toBe('stringId')
})
})
4 changes: 2 additions & 2 deletions src/utils/markWaveBoundary.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { triggerIsID } from './triggerIsID'

export const markWaveBoundary = (el: HTMLElement, trigger: any) => {
el.dataset.vWaveBoundary = triggerIsID(trigger) ? (trigger as string) : 'true'
export const markWaveBoundary = (el: HTMLElement, trigger: string | boolean) => {
el.dataset.vWaveBoundary = triggerIsID(trigger) ? trigger : 'true'
}
48 changes: 48 additions & 0 deletions src/utils/parentElementStyles.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import { describe, expect, test, vi } from 'vitest'
import { restoreParentElementStyles, saveParentElementStyles } from './parentElementStyles'

describe('parentElementStyles', () => {
test('saveParentElementStyles', () => {
const el = document.createElement('div')
el.style.position = 'static'

saveParentElementStyles(el, window.getComputedStyle(el))

expect(el.style.position).toBe('relative')
expect(el.dataset.originalPositionValue).toBe('static')
})

test('restoreParentElementStyles', () => {
const el = document.createElement('div')
el.style.position = 'relative'
el.dataset.originalPositionValue = 'static'

restoreParentElementStyles(el)

expect(el.style.position).toBe('static')
expect(el.dataset.originalPositionValue).toBe(undefined)
})

test.each`
direction
${'top'}
${'left'}
${'right'}
${'bottom'}
`('saveParentElementStyles warns when position is static and $direction is not auto', ({ direction }) => {
const el = document.createElement('div')
el.style.position = 'static'
el.style[direction] = '10px'

console.warn = vi.fn()

saveParentElementStyles(el, window.getComputedStyle(el))

expect(console.warn).toHaveBeenCalledWith(
'[v-wave]:',
el,
`You're using a \`static\` positioned element with a non-auto value (10px) for \`${direction}\`.`,
"It's position will be changed to relative while displaying the wave which might cause the element to visually jump."
)
})
})
21 changes: 21 additions & 0 deletions src/utils/parentElementStyles.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
export const saveParentElementStyles = (el: HTMLElement, computedStyles: CSSStyleDeclaration) => {
if (computedStyles.position === 'static') {
;(['top', 'left', 'right', 'bottom'] as const).forEach((dir) => {
if (computedStyles[dir] && computedStyles[dir] !== 'auto')
console.warn(
'[v-wave]:',
el,
`You're using a \`static\` positioned element with a non-auto value (${computedStyles[dir]}) for \`${dir}\`.`,
"It's position will be changed to relative while displaying the wave which might cause the element to visually jump."
)
})

el.dataset.originalPositionValue = el.style.position
el.style.position = 'relative'
}
}

export const restoreParentElementStyles = (el: HTMLElement) => {
el.style.position = el.dataset.originalPositionValue ?? ''
delete el.dataset.originalPositionValue
}
2 changes: 1 addition & 1 deletion src/utils/triggerIsID.test.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { expect, test } from 'vitest'
import { triggerIsID } from './triggerIsID'

test('markWaveBoundary', () => {
test('triggerIsID', () => {
expect(triggerIsID('auto')).toEqual(false)
expect(triggerIsID(true)).toEqual(false)
expect(triggerIsID(false)).toEqual(false)
Expand Down
3 changes: 2 additions & 1 deletion src/utils/triggerIsID.ts
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
export const triggerIsID = (trigger: string | boolean) => typeof trigger === 'string' && trigger !== 'auto'
export const triggerIsID = (trigger: string | boolean): trigger is string /* and not 'auto' */ =>
typeof trigger === 'string' && trigger !== 'auto'
25 changes: 14 additions & 11 deletions src/wave.ts
Original file line number Diff line number Diff line change
@@ -1,36 +1,39 @@
import type { IVWaveDirectiveOptions } from './options'
import type { Vector } from './types'
import { createContainer } from './utils/createContainerElement'
import { createWaveElement } from './utils/createWaveElement'
import { getDistanceToFurthestCorner } from './utils/getDistanceToFurthestCorner'
import { getRelativePointer } from './utils/getRelativePointer'
import { restoreParentElementStyles, saveParentElementStyles } from './utils/parentElementStyles'
import { decrementWaveCount, deleteWaveCount, getWaveCount, incrementWaveCount } from './utils/wave-count'

const wave = (event: PointerEvent, el: HTMLElement, options: IVWaveDirectiveOptions) => {
if (options.disabled) return
// 2.05 is magic.
// Values smaller than this seem to cause the wave to stop
// just short of the edge of the element sometimes.
// (probably to floating point precision)
const SCALE_FACTOR = 2.05

const wave = (screenPos: Vector, el: HTMLElement, options: IVWaveDirectiveOptions) => {
if (options.disabled) return
if (options.respectDisabledAttribute && el.hasAttribute('disabled')) return

const rect = el.getBoundingClientRect()
const computedStyles = window.getComputedStyle(el)

const { x, y } = getRelativePointer(event, rect)
const size = 2.05 * getDistanceToFurthestCorner(x, y, rect) // 2.05 is magic, deal with it.
const relativePos = getRelativePointer(screenPos, rect)
const size = SCALE_FACTOR * getDistanceToFurthestCorner(relativePos, rect)

// We're creating a container for the "wave" with `overflow: hidden`
// because if we were to set `overflow: hidden` on `el` we
// risk altering its appearance.
const waveContainer = createContainer(computedStyles, options.tagName)
const waveEl = createWaveElement(x, y, size, options)
const waveEl = createWaveElement(relativePos, size, options)

// Keep track of how many waves are active on this element.
incrementWaveCount(el)

// We reply on absolute positioning, so we need to make sure `el`'s position is non-static
let originalPositionValue = ''
if (computedStyles.position === 'static') {
if (el.style.position) originalPositionValue = el.style.position
el.style.position = 'relative'
}
saveParentElementStyles(el, computedStyles)

waveContainer.appendChild(waveEl)
el.appendChild(waveContainer)
Expand Down Expand Up @@ -58,7 +61,7 @@ const wave = (event: PointerEvent, el: HTMLElement, options: IVWaveDirectiveOpti
if (getWaveCount(el) === 0) {
deleteWaveCount(el)
// Only reset the style after all active waves have been removed
el.style.position = originalPositionValue
restoreParentElementStyles(el)
}
}, options.dissolveDuration * 1000)
}
Expand Down