vuecssuiant-designantdreactantantd-vueenterprisefrontendui-designvue-antdvue-antd-uivue3vuecomponent
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
156 lines
4.2 KiB
156 lines
4.2 KiB
// Thanks to https://github.com/andreypopp/react-textarea-autosize/ |
|
|
|
/** |
|
* calculateNodeHeight(uiTextNode, useCache = false) |
|
*/ |
|
|
|
const HIDDEN_TEXTAREA_STYLE = ` |
|
min-height:0 !important; |
|
max-height:none !important; |
|
height:0 !important; |
|
visibility:hidden !important; |
|
overflow:hidden !important; |
|
position:absolute !important; |
|
z-index:-1000 !important; |
|
top:0 !important; |
|
right:0 !important |
|
`; |
|
|
|
const SIZING_STYLE = [ |
|
'letter-spacing', |
|
'line-height', |
|
'padding-top', |
|
'padding-bottom', |
|
'font-family', |
|
'font-weight', |
|
'font-size', |
|
'font-variant', |
|
'text-rendering', |
|
'text-transform', |
|
'width', |
|
'text-indent', |
|
'padding-left', |
|
'padding-right', |
|
'border-width', |
|
'box-sizing', |
|
]; |
|
|
|
const computedStyleCache = {}; |
|
let hiddenTextarea; |
|
|
|
export function calculateNodeStyling(node, useCache = false) { |
|
const nodeRef = |
|
node.getAttribute('id') || node.getAttribute('data-reactid') || node.getAttribute('name'); |
|
|
|
if (useCache && computedStyleCache[nodeRef]) { |
|
return computedStyleCache[nodeRef]; |
|
} |
|
|
|
const style = window.getComputedStyle(node); |
|
|
|
const boxSizing = |
|
style.getPropertyValue('box-sizing') || |
|
style.getPropertyValue('-moz-box-sizing') || |
|
style.getPropertyValue('-webkit-box-sizing'); |
|
|
|
const paddingSize = |
|
parseFloat(style.getPropertyValue('padding-bottom')) + |
|
parseFloat(style.getPropertyValue('padding-top')); |
|
|
|
const borderSize = |
|
parseFloat(style.getPropertyValue('border-bottom-width')) + |
|
parseFloat(style.getPropertyValue('border-top-width')); |
|
|
|
const sizingStyle = SIZING_STYLE.map(name => `${name}:${style.getPropertyValue(name)}`).join(';'); |
|
|
|
const nodeInfo = { |
|
sizingStyle, |
|
paddingSize, |
|
borderSize, |
|
boxSizing, |
|
}; |
|
|
|
if (useCache && nodeRef) { |
|
computedStyleCache[nodeRef] = nodeInfo; |
|
} |
|
|
|
return nodeInfo; |
|
} |
|
|
|
export default function calculateNodeHeight( |
|
uiTextNode, |
|
useCache = false, |
|
minRows = null, |
|
maxRows = null, |
|
) { |
|
if (!hiddenTextarea) { |
|
hiddenTextarea = document.createElement('textarea'); |
|
document.body.appendChild(hiddenTextarea); |
|
} |
|
|
|
// Fix wrap="off" issue |
|
// https://github.com/ant-design/ant-design/issues/6577 |
|
if (uiTextNode.getAttribute('wrap')) { |
|
hiddenTextarea.setAttribute('wrap', uiTextNode.getAttribute('wrap')); |
|
} else { |
|
hiddenTextarea.removeAttribute('wrap'); |
|
} |
|
|
|
// Copy all CSS properties that have an impact on the height of the content in |
|
// the textbox |
|
const { paddingSize, borderSize, boxSizing, sizingStyle } = 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 || uiTextNode.placeholder || ''; |
|
|
|
let minHeight = Number.MIN_SAFE_INTEGER; |
|
let maxHeight = Number.MAX_SAFE_INTEGER; |
|
let height = hiddenTextarea.scrollHeight; |
|
let overflowY; |
|
|
|
if (boxSizing === 'border-box') { |
|
// border-box: add border, since height = content + padding + border |
|
height = height + borderSize; |
|
} else if (boxSizing === 'content-box') { |
|
// remove padding, since height = content |
|
height = height - paddingSize; |
|
} |
|
|
|
if (minRows !== null || maxRows !== null) { |
|
// measure height of a textarea with a single row |
|
hiddenTextarea.value = ' '; |
|
const singleRowHeight = hiddenTextarea.scrollHeight - paddingSize; |
|
if (minRows !== null) { |
|
minHeight = singleRowHeight * minRows; |
|
if (boxSizing === 'border-box') { |
|
minHeight = minHeight + paddingSize + borderSize; |
|
} |
|
height = Math.max(minHeight, height); |
|
} |
|
if (maxRows !== null) { |
|
maxHeight = singleRowHeight * maxRows; |
|
if (boxSizing === 'border-box') { |
|
maxHeight = maxHeight + paddingSize + borderSize; |
|
} |
|
overflowY = height > maxHeight ? '' : 'hidden'; |
|
height = Math.min(maxHeight, height); |
|
} |
|
} |
|
// Remove scroll bar flash when autosize without maxRows |
|
// donot remove in vue |
|
if (!maxRows) { |
|
overflowY = 'hidden'; |
|
} |
|
return { |
|
height: `${height}px`, |
|
minHeight: `${minHeight}px`, |
|
maxHeight: `${maxHeight}px`, |
|
overflowY, |
|
}; |
|
}
|
|
|