<commit_before>/**
 * calculateNodeHeight(uiTextNode, useCache = false)
 */

const HIDDEN_TEXTAREA_STYLE = `
  height:0;
  visibility:hidden;
  overflow:hidden;
  position:absolute;
  z-index:-1000;
  top:0;
  right:0
`;

const SIZING_STYLE = [
  'line-height',
  'padding-top',
  'padding-bottom',
  'font-family',
  'font-weight',
  'font-size',
  'width',
  'padding-left',
  'padding-right'
];

let computedStyleCache = {};
let hiddenTextarea;

export default function calculateNodeHeight(uiTextNode, useCache = false) {
  if (!hiddenTextarea) {
    hiddenTextarea = document.createElement('textarea');
    document.body.appendChild(hiddenTextarea);
  }

  // Copy all CSS properties that have an impact on the height of the content in
  // the textbox
  let {sizingStyle, sumVerticalPaddings} = calculateNodeStyling(uiTextNode, useCache);

  // Need to have the overflow attribute to hide the scrollbar otherwise
  // text-lines will not calculated properly as the shadow will technically be
  // narrower for content
  hiddenTextarea.setAttribute('style', sizingStyle + ';' + HIDDEN_TEXTAREA_STYLE);
  hiddenTextarea.value = uiTextNode.value;
  return hiddenTextarea.scrollHeight - sumVerticalPaddings;
}

function calculateNodeStyling(node, useCache = false) {
  let nodeRef = (
    node.getAttribute('id') ||
    node.getAttribute('data-reactid') ||
    node.getAttribute('name')
  );

  if (useCache && computedStyleCache[nodeRef]) {
    return computedStyleCache[nodeRef];
  }

  let compStyle = window.getComputedStyle(node);

  let sumPaddings = 0;

  // If the textarea is set to border-box, it's not necessary to
  // subtract the padding.
  if (
    compStyle.getPropertyValue('box-sizing') !== 'border-box' &&
    compStyle.getPropertyValue('-moz-box-sizing') !== 'border-box' &&
    compStyle.getPropertyValue('-webkit-box-sizing') !== 'border-box'
  ) {
    sumPaddings = (
      parseFloat(compStyle.getPropertyValue('padding-bottom')) +
      parseFloat(compStyle.getPropertyValue('padding-top'))
    );
  }

  let nodeInfo = {
    sizingStyle: SIZING_STYLE
      .map(name => `${name}:${compStyle.getPropertyValue(name)}`)
      .join(';'),
    sumVerticalPaddings: sumPaddings
  };

  if (useCache && nodeRef) {
    computedStyleCache[nodeRef] = nodeInfo;
  }
  return nodeInfo;
}
<commit_msg>fix(height util): fix height calculation by copying border-width & box-sizing as well<commit_after>/**
 * calculateNodeHeight(uiTextNode, useCache = false)
 */

const HIDDEN_TEXTAREA_STYLE = `
  height:0;
  visibility:hidden;
  overflow:hidden;
  position:absolute;
  z-index:-1000;
  top:0;
  right:0
`;

const SIZING_STYLE = [
  'line-height',
  'padding-top',
  'padding-bottom',
  'font-family',
  'font-weight',
  'font-size',
  'width',
  'padding-left',
  'padding-right',
  'border-width',
  'box-sizing'
];

let computedStyleCache = {};
let hiddenTextarea;

export default function calculateNodeHeight(uiTextNode, useCache = false) {
  if (!hiddenTextarea) {
    hiddenTextarea = document.createElement('textarea');
    document.body.appendChild(hiddenTextarea);
  }

  // Copy all CSS properties that have an impact on the height of the content in
  // the textbox
  let {sizingStyle, sumVerticalPaddings} = calculateNodeStyling(uiTextNode, useCache);

  // Need to have the overflow attribute to hide the scrollbar otherwise
  // text-lines will not calculated properly as the shadow will technically be
  // narrower for content
  hiddenTextarea.setAttribute('style', sizingStyle + ';' + HIDDEN_TEXTAREA_STYLE);
  hiddenTextarea.value = uiTextNode.value;
  return hiddenTextarea.scrollHeight - sumVerticalPaddings;
}

function calculateNodeStyling(node, useCache = false) {
  let nodeRef = (
    node.getAttribute('id') ||
    node.getAttribute('data-reactid') ||
    node.getAttribute('name')
  );

  if (useCache && computedStyleCache[nodeRef]) {
    return computedStyleCache[nodeRef];
  }

  let compStyle = window.getComputedStyle(node);

  let sumPaddings = 0;

  // If the textarea is set to border-box, it's not necessary to
  // subtract the padding.
  if (
    compStyle.getPropertyValue('box-sizing') !== 'border-box' &&
    compStyle.getPropertyValue('-moz-box-sizing') !== 'border-box' &&
    compStyle.getPropertyValue('-webkit-box-sizing') !== 'border-box'
  ) {
    sumPaddings = (
      parseFloat(compStyle.getPropertyValue('padding-bottom')) +
      parseFloat(compStyle.getPropertyValue('padding-top'))
    );
  }

  let nodeInfo = {
    sizingStyle: SIZING_STYLE
      .map(name => `${name}:${compStyle.getPropertyValue(name)}`)
      .join(';'),
    sumVerticalPaddings: sumPaddings
  };

  if (useCache && nodeRef) {
    computedStyleCache[nodeRef] = nodeInfo;
  }
  return nodeInfo;
}

{'fraction_non_alphanumeric': 0.13048986486486486, 'fraction_numerical': 0.0033783783783783786, 'mean_word_length': 4.018008474576271, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 5, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1330829', 'n_tokens_mistral': 1542, 'n_tokens_neox': 1514, 'n_words': 320}