All files / src/support/dom style.ts

100% Statements 38/38
100% Branches 22/22
100% Functions 10/10
100% Lines 37/37

Press n or j to go to the next uncovered block, b, p or k for the previous block.

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 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139                      7x                               7x           7x 51x 7x   29x     7x         58x 58x 53x 53x 51x   2x                                                     36x 36x   36x 17x 17x 12x 12x     23x 23x     17x   58x             7x 2x             7x 2x                 7x         6x 6x 6x 6x 6x 6x 6x 6x              
import { each, keys } from 'support/utils';
import { isString, isNumber, isArray, isUndefined } from 'support/utils/types';
import { PlainObject, StyleObject } from 'typings';
 
export interface TRBL {
  t: number;
  r: number;
  b: number;
  l: number;
}
 
const cssNumber = {
  // animationiterationcount: 1,
  // columncount: 1,
  // fillopacity: 1,
  // flexgrow: 1,
  // flexshrink: 1,
  // fontweight: 1,
  // lineheight: 1,
  // order: 1,
  // orphans: 1,
  // widows: 1,
  // zoom: 1,
  opacity: 1,
  zindex: 1,
};
 
const parseToZeroOrNumber = (value: string, toFloat?: boolean): number => {
  /* istanbul ignore next */
  const num = toFloat ? parseFloat(value) : parseInt(value, 10);
  /* istanbul ignore next */
  return Number.isNaN(num) ? 0 : num;
};
const adaptCSSVal = (prop: string, val: string | number): string | number =>
  !cssNumber[prop.toLowerCase()] && isNumber(val) ? `${val}px` : val;
const getCSSVal = (elm: HTMLElement, computedStyle: CSSStyleDeclaration, prop: string): string =>
  /* istanbul ignore next */
  computedStyle != null
    ? computedStyle[prop] || computedStyle.getPropertyValue(prop)
    : elm.style[prop];
const setCSSVal = (
  elm: HTMLElement | false | null | undefined,
  prop: string,
  val: string | number
): void => {
  try {
    if (elm) {
      const { style: elmStyle } = elm;
      if (!isUndefined(elmStyle[prop])) {
        elmStyle[prop] = adaptCSSVal(prop, val);
      } else {
        elmStyle.setProperty(prop, val as string);
      }
    }
  } catch (e) {}
};
 
/**
 * Gets or sets the passed styles to the passed element.
 * @param elm The element to which the styles shall be applied to / be read from.
 * @param styles The styles which shall be set or read.
 */
export function style<CustomCssProps>(
  elm: HTMLElement | false | null | undefined,
  styles: StyleObject<CustomCssProps>
): void;
export function style<CustomCssProps>(
  elm: HTMLElement | false | null | undefined,
  styles: string
): string;
export function style<CustomCssProps>(
  elm: HTMLElement | false | null | undefined,
  styles: Array<string> | string
): { [key: string]: string };
export function style<CustomCssProps>(
  elm: HTMLElement | false | null | undefined,
  styles: StyleObject<CustomCssProps> | Array<string> | string
): { [key: string]: string } | string | void {
  const getSingleStyle = isString(styles);
  const getStyles = isArray(styles) || getSingleStyle;
 
  if (getStyles) {
    let getStylesResult: string | PlainObject = getSingleStyle ? '' : {};
    if (elm) {
      const computedStyle: CSSStyleDeclaration = window.getComputedStyle(elm, null);
      getStylesResult = getSingleStyle
        ? getCSSVal(elm, computedStyle, styles as string)
        : (styles as Array<string>).reduce((result, key) => {
            result[key] = getCSSVal(elm, computedStyle, key as string);
            return result;
          }, getStylesResult);
    }
    return getStylesResult;
  }
  each(keys(styles), (key) => setCSSVal(elm, key, styles[key]));
}
 
/**
 * Hides the passed element (display: none).
 * @param elm The element which shall be hidden.
 */
export const hide = (elm: HTMLElement | false | null | undefined): void => {
  style(elm, { display: 'none' });
};
 
/**
 * Shows the passed element (display: block).
 * @param elm The element which shall be shown.
 */
export const show = (elm: HTMLElement | false | null | undefined): void => {
  style(elm, { display: 'block' });
};
 
/**
 * Returns the top right bottom left values of the passed css property.
 * @param elm The element of which the values shall be returned.
 * @param propertyPrefix The css property prefix. (e.g. "border")
 * @param propertySuffix The css property suffix. (e.g. "width")
 */
export const topRightBottomLeft = (
  elm?: HTMLElement | false | null | undefined,
  propertyPrefix?: string,
  propertySuffix?: string
): TRBL => {
  const finalPrefix = propertyPrefix ? `${propertyPrefix}-` : '';
  const finalSuffix = propertySuffix ? `-${propertySuffix}` : '';
  const top = `${finalPrefix}top${finalSuffix}`;
  const right = `${finalPrefix}right${finalSuffix}`;
  const bottom = `${finalPrefix}bottom${finalSuffix}`;
  const left = `${finalPrefix}left${finalSuffix}`;
  const result = style(elm, [top, right, bottom, left]);
  return {
    t: parseToZeroOrNumber(result[top]),
    r: parseToZeroOrNumber(result[right]),
    b: parseToZeroOrNumber(result[bottom]),
    l: parseToZeroOrNumber(result[left]),
  };
};