all files / src/modules/ props.ts

87.8% Statements 36/41
70% Branches 21/30
83.33% Functions 5/6
96.88% Lines 31/32
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76                                                                                         
import { ElementVNode, Module } from '../'
 
import { BaseModule } from './BaseModule'
import { emptyVNode } from './emptyVNode'
 
export function createPropsModule(): Module {
  return new PropsModule()
}
 
export const PROPERTIES_TO_SKIP: Record<string, boolean> = {
  class: true,
  on: true,
  listener: true,
  focus: true,
  style: true,
  attrs: true,
  key: true,
  module: true,
  init: true,
  create: true,
  update: true,
  insert: true,
  remove: true,
  destroy: true,
  prepatch: true,
  postpatch: true,
}
 
export const ATTRIBUTE_TO_REMOVE: Record<string, boolean> = {
  id: true,
}
 
class PropsModule extends BaseModule {
  public create(vNode: ElementVNode) {
    updateProps(emptyVNode as ElementVNode, vNode)
  }
 
  public update(formerVNode: ElementVNode, vNode: ElementVNode) {
    updateProps(formerVNode, vNode)
  }
}
 
function updateProps(formerVNode: ElementVNode, vNode: ElementVNode): void {
  const element: any = vNode.element
  let formerProps: any = formerVNode.props
  let props: any = vNode.props
 
  Iif (!formerProps && !props) return
 
  formerProps = formerProps || {}
  props = props || {}
 
  for (const key in formerProps) {
    const propertyIsMissing = !PROPERTIES_TO_SKIP[key] && !props[key]
    const keyIsClassName = propertyIsMissing && key === 'className'
    const shouldRemoveAttribute = propertyIsMissing && ATTRIBUTE_TO_REMOVE[key]
 
    Eif (propertyIsMissing) delete element[key]
 
    if (keyIsClassName) removePreviousClassName(formerProps[key], element)
 
    if (shouldRemoveAttribute) element.removeAttribute(key)
  }
 
  for (const key in props) if (!PROPERTIES_TO_SKIP[key]) element[key] = props[key]
}
 
function removePreviousClassName(className: string, element: Element) {
  const shouldRemoveClassName = className && element.classList
  const shouldRemoveClassAttribute = shouldRemoveClassName && element.getAttribute('class') === ''
 
  Eif (shouldRemoveClassName) element.classList.remove(...className.split(' '))
 
  Iif (shouldRemoveClassAttribute) element.removeAttribute('class')
}