Skip to content

Commit

Permalink
refactor(comp: typography): modify code and test (IDuxFE#196)
Browse files Browse the repository at this point in the history
  • Loading branch information
LaamGinghong committed Feb 15, 2021
1 parent d8bb853 commit 0c36894
Show file tree
Hide file tree
Showing 5 changed files with 126 additions and 140 deletions.
42 changes: 42 additions & 0 deletions packages/cdk/utils/__tests__/dom.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import { addClass, hasClass, off, on, removeClass } from '../dom'

describe('dom.ts', () => {
let testElement: HTMLDivElement

beforeEach(() => {
testElement = document.createElement('div')
})

test('event listener', () => {
const log = jest.spyOn(console, 'log').mockImplementation(() => {})
const listener = () => console.log('click')
on(testElement, 'click', listener)
testElement.click()
expect(log).toBeCalled()
expect(log).toBeCalledTimes(1)
off(testElement, 'click', listener)
expect(log).toBeCalledTimes(1)
})

test('hasClass work', () => {
addClass(testElement, 'test-class')
expect(hasClass(testElement, 'test-class')).toBeTruthy()
expect(hasClass(testElement, '')).toBeFalsy()
})

test('add class work', () => {
expect(Array.from(testElement.classList)).toEqual([])
addClass(testElement, 'test-class')
expect(Array.from(testElement.classList)).toEqual(['test-class'])
addClass(testElement, ['test-class', 'test-class-2'])
expect(Array.from(testElement.classList)).toEqual(['test-class', 'test-class-2'])
})

test('remove class work', () => {
addClass(testElement, 'test-class')
removeClass(testElement, [])
expect(Array.from(testElement.classList)).toEqual(['test-class'])
removeClass(testElement, 'test-class')
expect(Array.from(testElement.classList)).toEqual([])
})
})
33 changes: 11 additions & 22 deletions packages/cdk/utils/dom.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
/* eslint-disable @typescript-eslint/no-explicit-any */

import { isString } from './typeof'

type ElType = HTMLElement | Document | Window

export function on<K extends keyof HTMLElementEventMap>(
Expand Down Expand Up @@ -36,34 +38,21 @@ export function off(
}
}

export function hasClass(el: HTMLElement, cls: string): boolean {
if (!el || !cls) {
export function hasClass(el: HTMLElement, className: string): boolean {
if (!className) {
return false
}
return cls
.split(' ')
.filter(item => item)
.every(item => el.classList.contains(item))
return el.classList.contains(className)
}

export function addClass(el: HTMLElement, cls: string): void {
if (!el || !cls) {
return
}
cls
.split(' ')
.filter(item => item)
.forEach(item => el.classList.add(item))
export function addClass(el: HTMLElement, className: string | string[]): void {
const cls: string[] = isString(className) ? [className] : className
el.classList.add(...cls)
}

export function removeClass(el: HTMLElement, cls: string): void {
if (!el || !cls) {
return
}
cls
.split(' ')
.filter(item => item)
.forEach(item => el.classList.remove(item))
export function removeClass(el: HTMLElement, className: string | string[]): void {
const cls: string[] = isString(className) ? [className] : className
el.classList.remove(...cls)
}

export const rAF = requestAnimationFrame || (cb => setTimeout(cb, 1000 / 60))
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`typography.ts render work 1`] = `"<article class=\\" ix-typography\\"><h1 class=\\" ix-typography\\">Title</h1><p class=\\" ix-typography\\"> In the process of internal desktop applications development, many different design specs and implementations would be involved, which might cause designers and developers difficulties and duplication and reduce the efficiency of development. </p><div class=\\" ix-typography\\"><ul><li><a href=\\"/docs/spec/proximity\\">Principles</a></li><li><a href=\\"/docs/pattern/navigation\\">Patterns</a></li><li><a href=\\"/docs/resource/download\\">Resource Download</a></li></ul></div><p class=\\" ix-typography\\"> Press <span class=\\" ix-typography\\"><kbd>Esc</kbd></span> to exist... </p></article>"`;
exports[`typography.ts render work 1`] = `"<p class=\\"ix-typography\\">Paragraph</p>"`;
126 changes: 49 additions & 77 deletions packages/components/typography/__tests__/typography.spec.ts
Original file line number Diff line number Diff line change
@@ -1,84 +1,60 @@
import type { TypographyConfig } from '../src/types'

import { renderWork } from '@tests'
import { mount, VueWrapper } from '@vue/test-utils'
import { ComponentOptions } from 'vue'
import IxTypography from '../src/typography'

const TestComponent = {
template: `
<article v-typography>
<h1 v-typography>Title</h1>
<p v-typography>
In the process of internal desktop applications development, many different design specs and implementations would be involved, which might cause designers and developers difficulties and duplication and reduce the efficiency of development.
</p>
<div v-typography>
<ul>
<li><a href="/docs/spec/proximity">Principles</a></li>
<li><a href="/docs/pattern/navigation">Patterns</a></li>
<li><a href="/docs/resource/download">Resource Download</a></li>
</ul>
</div>
<p v-typography>
Press <span v-typography><kbd>Esc</kbd></span> to exist...
</p>
</article>
`,
props: ['type'],
template: `<p v-typography="type">Paragraph</p>`,
}

describe('typography.ts', () => {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
let typographyMount: (options: ComponentOptions) => VueWrapper<any>
let typographyMount: (props?: { type: TypographyConfig }) => VueWrapper<any>

beforeEach(() => {
typographyMount = (options: ComponentOptions) => {
return mount(options, { global: { directives: { typography: IxTypography } } })
typographyMount = props => {
return mount(TestComponent, { global: { directives: { typography: IxTypography } }, props })
}
})

renderWork(TestComponent, { global: { directives: { typography: IxTypography } } })

test('type work', async () => {
const TestComponent = {
props: ['type'],
template: `<p v-typography="type">Paragraph</p>`,
}
const wrapper = typographyMount(TestComponent)
const wrapper = typographyMount()
expect(wrapper.classes()).toEqual(['ix-typography'])

await wrapper.setProps({ type: 'success' })
expect(wrapper.classes()).toContain('ix-typography-success')
expect(wrapper.classes()).toEqual(['ix-typography', 'ix-typography-success'])

await wrapper.setProps({ type: 'warning' })
expect(wrapper.classes()).toContain('ix-typography-warning')

await wrapper.setProps({ type: 'error' })
expect(wrapper.classes()).toContain('ix-typography-error')
expect(wrapper.classes()).toEqual(['ix-typography', 'ix-typography-warning'])

await wrapper.setProps({ type: 'secondary' })
expect(wrapper.classes()).toContain('ix-typography-secondary')
expect(wrapper.classes()).toEqual(['ix-typography', 'ix-typography-secondary'])

await wrapper.setProps({ type: 'error' })
expect(wrapper.classes()).toEqual(['ix-typography', 'ix-typography-error'])
})

test('option work', async () => {
const TestComponent = {
props: ['type'],
template: `<p v-typography="type">Paragraph</p>`,
}
const wrapper = typographyMount(TestComponent)
expect(wrapper.classes()).toEqual(['ix-typography'])

await wrapper.setProps({ type: {} })
expect(wrapper.classes()).toEqual(['ix-typography'])

await wrapper.setProps({ type: { type: 'success' } })
expect(wrapper.classes()).toContain('ix-typography-success')
const wrapper = typographyMount({ type: { type: 'success' } })
expect(wrapper.classes()).toEqual(['ix-typography', 'ix-typography-success'])

await wrapper.setProps({ type: { type: 'warning' } })
expect(wrapper.classes()).toContain('ix-typography-warning')
expect(wrapper.classes()).toEqual(['ix-typography', 'ix-typography-warning'])

await wrapper.setProps({ type: { type: 'secondary' } })
expect(wrapper.classes()).toEqual(['ix-typography', 'ix-typography-secondary'])

await wrapper.setProps({ type: { type: 'error' } })
expect(wrapper.classes()).toContain('ix-typography-error')
expect(wrapper.classes()).toEqual(['ix-typography', 'ix-typography-error'])
})

await wrapper.setProps({ type: { type: 'secondary' } })
expect(wrapper.classes()).toContain('ix-typography-secondary')
test('disabled word', async () => {
const wrapper = typographyMount()
expect(wrapper.classes()).not.toContain('ix-typography-disabled')

await wrapper.setProps({ type: { disabled: true } })
expect(wrapper.classes()).toContain('ix-typography-disabled')
Expand All @@ -89,39 +65,35 @@ describe('typography.ts', () => {

test('dev warn work', () => {
const error = jest.spyOn(console, 'error').mockImplementation(() => {})
const TestComponent = {
template: `<p v-typography="'hello'">Paragraph</p>`,
}
const wrapper = typographyMount(TestComponent)
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
const wrapper = typographyMount({ type: 'hello' })
expect(wrapper.classes()).toEqual(['ix-typography'])
expect(error).toBeCalled()
})

test('custom class', async () => {
const TestComponent = {
props: ['type'],
template: `
<p v-typography="type">Paragraph</p>
`,
}
const wrapper = typographyMount(TestComponent)
expect(wrapper.classes()).toEqual(['ix-typography'])
test('custom class work', async () => {
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
const wrapper = typographyMount({ class: 'custom' })
expect(wrapper.classes()).toEqual(['custom', 'ix-typography'])

await wrapper.setProps({ class: 'custom-paragraph' })
expect(wrapper.classes()).toEqual(['custom-paragraph', 'ix-typography'])
const wrapper2 = typographyMount()
await wrapper2.setProps({ class: 'custom' })
expect(wrapper.classes()).toEqual(['custom', 'ix-typography'])
})

await wrapper.setProps({ type: 'success' })
expect(wrapper.classes()).toEqual(['custom-paragraph', 'ix-typography', 'ix-typography-success'])

await wrapper.setProps({ type: { type: 'success', disabled: true } })
expect(wrapper.classes()).toEqual([
'custom-paragraph',
'ix-typography',
'ix-typography-success',
'ix-typography-disabled',
])

await wrapper.setProps({ type: undefined })
expect(wrapper.classes()).toEqual(['custom-paragraph', 'ix-typography'])
test('directive position work', () => {
const wrapper = mount(
{
template: `
<div v-typography class='custom-class1' id='directive1'>Directive1</div>
<div class='custom-class2' v-typography id='directive2'>Directive2</div>
`,
},
{ global: { directives: { typography: IxTypography } } },
)
expect(wrapper.get('#directive1').classes()).toEqual(['custom-class1', 'ix-typography'])
expect(wrapper.get('#directive2').classes()).toEqual(['custom-class2', 'ix-typography'])
})
})
63 changes: 23 additions & 40 deletions packages/components/typography/src/typography.ts
Original file line number Diff line number Diff line change
@@ -1,48 +1,31 @@
import type { Directive } from 'vue'
import type { TypographyConfig, TypographyOptions } from './types'

import { isNonNil, isObject } from '@idux/cdk/utils'
import { isObject, addClass, removeClass } from '@idux/cdk/utils'
import { Logger } from '@idux/components/core/logger'

const typography: Directive<HTMLElement, TypographyConfig> = {
created(el, binding) {
const classNames: string[] = [el.className, 'ix-typography']
const { value } = binding
const options: TypographyOptions = isObject(value) ? value : { type: value }
const { type, disabled } = options
if (isLegality(type)) {
classNames.push(`ix-typography-${type}`)
}
if (disabled) {
classNames.push('ix-typography-disabled')
}
el.className = classNames.join(' ')
},
updated(el, binding) {
const classNames = new Set([...Array.from(el.classList), 'ix-typography'])
const { oldValue, value } = binding

const { type: oldType, disabled: oldDisabled }: TypographyOptions = isObject(oldValue)
? oldValue
: { type: oldValue ?? undefined }

if (isLegality(oldType)) {
classNames.delete(`ix-typography-${oldType}`)
}
if (isNonNil(oldDisabled)) {
classNames.delete('ix-typography-disabled')
}

const { type, disabled }: TypographyOptions = isObject(value) ? value : { type: value }
if (isLegality(type)) {
classNames.add(`ix-typography-${type}`)
}
if (disabled) {
classNames.add('ix-typography-disabled')
}

el.className = Array.from(classNames).join(' ')
},
const typography: Directive<HTMLElement, TypographyConfig> = (el, binding) => {
const className: string[] = ['ix-typography']
const { value, oldValue } = binding

const oldOptions: TypographyOptions = isObject(oldValue) ? oldValue : { type: oldValue ?? undefined }
const newOptions: TypographyOptions = isObject(value) ? value : { type: value }

if (isLegality(oldOptions.type)) {
removeClass(el, `ix-typography-${oldOptions.type}`)
}
if (oldOptions.disabled) {
removeClass(el, 'ix-typography-disabled')
}

if (isLegality(newOptions.type)) {
className.push(`ix-typography-${newOptions.type}`)
}
if (newOptions.disabled) {
className.push('ix-typography-disabled')
}

addClass(el, className)
}

export default typography
Expand Down

0 comments on commit 0c36894

Please sign in to comment.