UNPKG

autosizer

Version:

Automatically resize textarea to fit text when typing.

111 lines 4.31 kB
const defaults = { viewportMargin: null, follow: true, triggers: ['input', 'change', 'focus'] }; function scrollTop(top) { let doc = document.documentElement; if (typeof top !== 'undefined') { const left = (window.pageXOffset || doc.scrollLeft) - (doc.clientLeft || 0); window.scrollTo(left, top); } return (window.pageYOffset || doc.scrollTop) - (doc.clientTop || 0); } class Autosizer { constructor(el, options = {}) { this.isUserResized = false; this.x = null; this.y = null; this.el = el; this.options = { ...defaults, ...options }; this.height = this.el.style.height; this.initListeners(); this.el.autosizer = this; } initListeners() { this.onTrigger = this.onTrigger.bind(this); this.onResize = this.onResize.bind(this); this.options.triggers.forEach((event) => { this.el.addEventListener(event, this.onTrigger); }); this.el.addEventListener('mousemove', this.onResize); if (this.el.form) { this.onReset = this.onReset.bind(this); this.el.addEventListener('reset', this.onReset); } } onTrigger() { this.resize(); } onResize(e) { if (this.x !== e.clientX || this.y !== e.clientY) { const newHeight = this.el.style.height; if (this.height && this.height !== newHeight) { this.isUserResized = true; this.el.style.maxHeight = ''; this.el.removeEventListener('mousemove', this.onResize); } } } onReset() { this.isUserResized = false; this.el.style.height = ''; this.el.style.maxHeight = ''; } getOverflowOffset() { const document = this.el.ownerDocument; const documentEl = document.documentElement; let offsetTop = 0; let el = this.el; while (el !== document.body && el !== null) { offsetTop += el.offsetTop || 0; el = el.offsetParent; } const top = offsetTop - document.defaultView.pageYOffset; const bottom = documentEl.clientHeight - (top + this.el.offsetHeight); return { top, bottom }; } resize() { if (this.isUserResized) return; if (this.el.offsetWidth <= 0 && this.el.offsetHeight <= 0) return; const { top, bottom } = this.getOverflowOffset(); if (!this.options.follow && (top < 0 || bottom < 0)) return; let style = getComputedStyle(this.el); const topBorder = Number(style.borderTopWidth.replace(/px/, '')); const bottomBorder = Number(style.borderBottomWidth.replace(/px/, '')); const isBorderBox = style.boxSizing === 'border-box'; const borderAdjust = isBorderBox ? topBorder + bottomBorder : 0; if (this.options.viewportMargin !== null) { const maxHeight = Number(style.height.replace(/px/, '')) + bottom; const adjustViewportMargin = bottom < this.options.viewportMargin ? bottom : this.options.viewportMargin; this.el.style.maxHeight = `${maxHeight - adjustViewportMargin}px`; } const container = this.el.parentElement; const followBottom = this.el.getBoundingClientRect().bottom; if (container) { const containerHeight = container.style.height; container.style.height = getComputedStyle(container).height; this.el.style.height = 'auto'; this.el.style.height = `${this.el.scrollHeight + borderAdjust}px`; container.style.height = containerHeight; this.height = this.el.style.height; if (this.options.follow) { const diff = this.el.getBoundingClientRect().bottom - followBottom; scrollTop(scrollTop() + diff); } } } destroy() { this.options.triggers.forEach((event) => { this.el.removeEventListener(event, this.onTrigger); }); this.el.removeEventListener('mousemove', this.onResize); this.el.removeEventListener('reset', this.onReset); delete this.el.autosizer; } } export default Autosizer; //# sourceMappingURL=index.js.map