improve perf of compose box
This commit is contained in:
parent
6c71910660
commit
2ffd38383d
5
package-lock.json
generated
5
package-lock.json
generated
|
@ -357,11 +357,6 @@
|
|||
"postcss-value-parser": "3.3.0"
|
||||
}
|
||||
},
|
||||
"autosize": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/autosize/-/autosize-4.0.0.tgz",
|
||||
"integrity": "sha1-egWZsbqE1zvXWJsNnaOHAVLGkjc="
|
||||
},
|
||||
"aws-sign2": {
|
||||
"version": "0.6.0",
|
||||
"resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.6.0.tgz",
|
||||
|
|
|
@ -25,7 +25,6 @@
|
|||
"dependencies": {
|
||||
"@gamestdio/websocket": "^0.2.2",
|
||||
"a11y-dialog": "^4.0.1",
|
||||
"autosize": "^4.0.0",
|
||||
"cheerio": "^1.0.0-rc.2",
|
||||
"child-process-promise": "^2.2.1",
|
||||
"chokidar": "^2.0.0",
|
||||
|
@ -95,7 +94,8 @@
|
|||
"__shell__",
|
||||
"__assets__",
|
||||
"test",
|
||||
"fixture"
|
||||
"fixture",
|
||||
"Element"
|
||||
],
|
||||
"ignore": [
|
||||
"dist",
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
<div class="lite-compose-box">
|
||||
<div class="lite-compose-box {{overLimit ? 'over-char-limit' : ''}}">
|
||||
<div class="compose-profile-current-user">
|
||||
<Avatar account="{{verifyCredentials}}" className="compose-profile-avatar" size="small"/>
|
||||
<a class="compose-profile-display-name" href="/accounts/{{verifyCredentials.id}}">
|
||||
|
@ -13,13 +13,13 @@
|
|||
ref:textarea
|
||||
bind:value=inputText
|
||||
></textarea>
|
||||
<div class="compose-profile-length-gauge {{overLimit ? 'over-char-limit' : ''}}"
|
||||
style="transform: scaleX({{inputLengthAsFractionOfMax}});"
|
||||
<div class="compose-profile-length-gauge"
|
||||
style="transform: scaleX({{inputLengthAsFractionOfMaxAfterRaf || 0}});"
|
||||
aria-hidden="true"
|
||||
></div>
|
||||
<span class="compose-profile-length {{overLimit ? 'over-char-limit' : ''}}"
|
||||
<span class="compose-profile-length"
|
||||
aria-label="{{inputLengthLabel}}">
|
||||
{{inputLengthToDisplay}}
|
||||
{{inputLengthToDisplayAfterRaf || '0'}}
|
||||
</span>
|
||||
<button class="primary compose-profile-button">
|
||||
Toot!
|
||||
|
@ -88,6 +88,7 @@
|
|||
margin-top: 10px;
|
||||
resize: none;
|
||||
overflow: hidden;
|
||||
width: calc(100% - 5px);
|
||||
}
|
||||
|
||||
.compose-profile-button {
|
||||
|
@ -113,11 +114,11 @@
|
|||
font-size: 1.1em;
|
||||
}
|
||||
|
||||
.compose-profile-length.over-char-limit {
|
||||
.over-char-limit .compose-profile-length {
|
||||
color: var(--warning-color);
|
||||
}
|
||||
|
||||
.compose-profile-length-gauge.over-char-limit {
|
||||
.over-char-limit .compose-profile-length-gauge {
|
||||
background: var(--warning-color);
|
||||
}
|
||||
|
||||
|
@ -137,7 +138,7 @@
|
|||
<script>
|
||||
import Avatar from '../Avatar.html'
|
||||
import { store } from '../../_store/store'
|
||||
import autosize from 'autosize'
|
||||
import { autosize } from '../../_utils/autosize'
|
||||
import { scheduleIdleTask } from '../../_utils/scheduleIdleTask'
|
||||
import debounce from 'lodash/debounce'
|
||||
import { mark, stop } from '../../_utils/marks'
|
||||
|
@ -160,6 +161,22 @@
|
|||
this.store.set({inputTextInCompose: inputTextInCompose})
|
||||
saveText()
|
||||
}, {init: false})
|
||||
|
||||
// Avoid input delays by updating these values after a rAF
|
||||
this.observe('inputLengthToDisplay', inputLengthToDisplay => {
|
||||
requestAnimationFrame(() => {
|
||||
mark('set inputLengthToDisplayAfterRaf')
|
||||
this.set({inputLengthToDisplayAfterRaf: inputLengthToDisplay})
|
||||
stop('set inputLengthToDisplayAfterRaf')
|
||||
})
|
||||
})
|
||||
this.observe('inputLengthAsFractionOfMax', inputLengthAsFractionOfMax => {
|
||||
requestAnimationFrame(() => {
|
||||
mark('set inputLengthAsFractionOfMaxAfterRaf')
|
||||
this.set({inputLengthAsFractionOfMaxAfterRaf: inputLengthAsFractionOfMax})
|
||||
stop('set inputLengthAsFractionOfMaxAfterRaf')
|
||||
})
|
||||
})
|
||||
},
|
||||
ondestroy() {
|
||||
mark('autosize.destroy()')
|
||||
|
@ -177,7 +194,7 @@
|
|||
currentInputTextInCompose: ($currentInputTextInCompose) => $currentInputTextInCompose,
|
||||
inputLength: (inputText) => inputText ? inputText.length : 0,
|
||||
inputLengthToDisplay: (inputLength) => (inputLength <= CHAR_LIMIT ? inputLength : CHAR_LIMIT - inputLength),
|
||||
inputLengthAsFractionOfMax: (inputLength) => (Math.min(CHAR_LIMIT, inputLength)) / CHAR_LIMIT,
|
||||
inputLengthAsFractionOfMax: (inputLength) => Math.round(100 * (Math.min(CHAR_LIMIT, inputLength)) / CHAR_LIMIT) / 100,
|
||||
overLimit: (inputLength) => inputLength > CHAR_LIMIT,
|
||||
inputLengthLabel: (overLimit, inputLengthToDisplay) => {
|
||||
if (overLimit) {
|
||||
|
|
166
routes/_utils/autosize.js
Normal file
166
routes/_utils/autosize.js
Normal file
|
@ -0,0 +1,166 @@
|
|||
// Modified from https://github.com/jackmoore/autosize/commit/113f1b345868901619d4b01cda02b09aa1690ebd
|
||||
// The only change is to remove IE-specific hacks,
|
||||
// remove parent overflow checks, make page resizes more performant,
|
||||
// add deferredUpdate, and add perf marks.
|
||||
|
||||
import { mark, stop } from './marks'
|
||||
import debounce from 'lodash/debounce'
|
||||
import throttle from 'lodash/throttle'
|
||||
|
||||
const map = new Map()
|
||||
let createEvent = (name) => new Event(name, {bubbles: true})
|
||||
|
||||
function assign (ta) {
|
||||
if (!ta || !ta.nodeName || ta.nodeName !== 'TEXTAREA' || map.has(ta)) return
|
||||
|
||||
let heightOffset = null
|
||||
let cachedHeight = null
|
||||
|
||||
function init () {
|
||||
const style = window.getComputedStyle(ta, null)
|
||||
|
||||
if (style.resize === 'vertical') {
|
||||
ta.style.resize = 'none'
|
||||
} else if (style.resize === 'both') {
|
||||
ta.style.resize = 'horizontal'
|
||||
}
|
||||
|
||||
if (style.boxSizing === 'content-box') {
|
||||
heightOffset = -(parseFloat(style.paddingTop) + parseFloat(style.paddingBottom))
|
||||
} else {
|
||||
heightOffset = parseFloat(style.borderTopWidth) + parseFloat(style.borderBottomWidth)
|
||||
}
|
||||
// Fix when a textarea is not on document body and heightOffset is Not a Number
|
||||
if (isNaN(heightOffset)) {
|
||||
heightOffset = 0
|
||||
}
|
||||
|
||||
update()
|
||||
}
|
||||
|
||||
function resize () {
|
||||
mark('autosize:resize()')
|
||||
let res = _resize()
|
||||
stop('autosize:resize()')
|
||||
return res
|
||||
}
|
||||
|
||||
function _resize () {
|
||||
const originalHeight = ta.style.height
|
||||
|
||||
ta.style.height = ''
|
||||
|
||||
let endHeight = ta.scrollHeight + heightOffset
|
||||
|
||||
if (ta.scrollHeight === 0) {
|
||||
// If the scrollHeight is 0, then the element probably has display:none or is detached from the DOM.
|
||||
ta.style.height = originalHeight
|
||||
return
|
||||
}
|
||||
|
||||
ta.style.height = endHeight + 'px'
|
||||
return endHeight
|
||||
}
|
||||
|
||||
const deferredUpdate = throttle(() => requestAnimationFrame(update), 100)
|
||||
|
||||
function update () {
|
||||
mark('autosize:update()')
|
||||
_update()
|
||||
stop('autosize:update()')
|
||||
}
|
||||
|
||||
function _update () {
|
||||
let newHeight = resize()
|
||||
if (cachedHeight !== newHeight) {
|
||||
cachedHeight = newHeight
|
||||
const evt = createEvent('autosize:resized')
|
||||
try {
|
||||
ta.dispatchEvent(evt)
|
||||
} catch (err) {
|
||||
// Firefox will throw an error on dispatchEvent for a detached element
|
||||
// https://bugzilla.mozilla.org/show_bug.cgi?id=889376
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const pageResize = debounce(update, 1000)
|
||||
|
||||
const destroy = (style => {
|
||||
window.removeEventListener('resize', pageResize, false)
|
||||
ta.removeEventListener('input', deferredUpdate, false)
|
||||
ta.removeEventListener('autosize:destroy', destroy, false)
|
||||
ta.removeEventListener('autosize:update', update, false)
|
||||
|
||||
Object.keys(style).forEach(key => {
|
||||
ta.style[key] = style[key]
|
||||
})
|
||||
|
||||
map.delete(ta)
|
||||
}).bind(ta, {
|
||||
height: ta.style.height,
|
||||
resize: ta.style.resize,
|
||||
overflowY: ta.style.overflowY,
|
||||
overflowX: ta.style.overflowX,
|
||||
wordWrap: ta.style.wordWrap
|
||||
})
|
||||
|
||||
ta.addEventListener('autosize:destroy', destroy, false)
|
||||
|
||||
window.addEventListener('resize', pageResize, false)
|
||||
ta.addEventListener('input', deferredUpdate, false)
|
||||
ta.addEventListener('autosize:update', update, false)
|
||||
ta.style.overflowX = 'hidden'
|
||||
ta.style.wordWrap = 'break-word'
|
||||
|
||||
map.set(ta, {
|
||||
destroy,
|
||||
update
|
||||
})
|
||||
|
||||
init()
|
||||
}
|
||||
|
||||
function destroy (ta) {
|
||||
const methods = map.get(ta)
|
||||
if (methods) {
|
||||
methods.destroy()
|
||||
}
|
||||
}
|
||||
|
||||
function update (ta) {
|
||||
const methods = map.get(ta)
|
||||
if (methods) {
|
||||
methods.update()
|
||||
}
|
||||
}
|
||||
|
||||
let autosize = null
|
||||
|
||||
// Do nothing in Node.js environment and IE8 (or lower)
|
||||
if (!process.browser) {
|
||||
autosize = el => el
|
||||
autosize.destroy = el => el
|
||||
autosize.update = el => el
|
||||
} else {
|
||||
autosize = (el, options) => {
|
||||
if (el) {
|
||||
Array.prototype.forEach.call(el.length ? el : [el], x => assign(x, options))
|
||||
}
|
||||
return el
|
||||
}
|
||||
autosize.destroy = el => {
|
||||
if (el) {
|
||||
Array.prototype.forEach.call(el.length ? el : [el], destroy)
|
||||
}
|
||||
return el
|
||||
}
|
||||
autosize.update = el => {
|
||||
if (el) {
|
||||
Array.prototype.forEach.call(el.length ? el : [el], update)
|
||||
}
|
||||
return el
|
||||
}
|
||||
}
|
||||
|
||||
export { autosize }
|
|
@ -135,3 +135,9 @@ button::-moz-focus-inner {
|
|||
input:required, input:invalid {
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
textarea {
|
||||
font-family: inherit;
|
||||
font-size: inherit;
|
||||
box-sizing: border-box;
|
||||
}
|
|
@ -11,7 +11,7 @@
|
|||
<style>
|
||||
/* auto-generated w/ build-sass.js */
|
||||
body{--button-primary-bg:#6081e6;--button-primary-text:#fff;--button-primary-border:#132c76;--button-primary-bg-active:#456ce2;--button-primary-bg-hover:#6988e7;--button-bg:#e6e6e6;--button-text:#333;--button-border:#a7a7a7;--button-bg-active:#bfbfbf;--button-bg-hover:#f2f2f2;--input-border:#dadada;--anchor-text:#4169e1;--main-bg:#fff;--body-bg:#e8edfb;--body-text-color:#333;--main-border:#dadada;--svg-fill:#4169e1;--form-bg:#f7f7f7;--form-border:#c1c1c1;--nav-bg:#4169e1;--nav-border:#214cce;--nav-a-border:#4169e1;--nav-a-selected-border:#fff;--nav-a-selected-bg:#6d8ce8;--nav-svg-fill:#fff;--nav-text-color:#fff;--nav-a-selected-border-hover:#fff;--nav-a-selected-bg-hover:#839deb;--nav-a-bg-hover:#577ae4;--nav-a-border-hover:#4169e1;--nav-svg-fill-hover:#fff;--nav-text-color-hover:#fff;--action-button-fill-color:#90a8ee;--action-button-fill-color-hover:#a2b6f0;--action-button-fill-color-active:#577ae4;--action-button-fill-color-pressed:#2351dc;--action-button-fill-color-pressed-hover:#3862e0;--action-button-fill-color-pressed-active:#1d44b8;--settings-list-item-bg:#fff;--settings-list-item-text:#4169e1;--settings-list-item-text-hover:#4169e1;--settings-list-item-border:#dadada;--settings-list-item-bg-active:#e6e6e6;--settings-list-item-bg-hover:#fafafa;--toast-bg:#333;--toast-border:#fafafa;--toast-text:#fff;--mask-bg:#333;--mask-svg-fill:#fff;--mask-opaque-bg:rgba(51,51,51,0.8);--loading-bg:#ededed;--deemphasized-text-color:#666;--focus-outline:#c5d1f6;--very-deemphasized-link-color:rgba(65,105,225,0.6);--very-deemphasized-text-color:rgba(102,102,102,0.6);--status-direct-background:#d2dcf8;--main-theme-color:#4169e1;--warning-color:#e01f19}
|
||||
body{margin:0;font-family:system-ui, -apple-system, BlinkMacSystemFont, Segoe UI, Roboto, Oxygen, Ubuntu, Cantarell, Fira Sans, Droid Sans, Helvetica Neue;font-size:14px;line-height:1.4;color:var(--body-text-color);background:var(--body-bg);position:fixed;left:0;right:0;bottom:0;top:0}.container{overflow-y:auto;overflow-x:hidden;-webkit-overflow-scrolling:touch;will-change:transform;position:absolute;top:72px;left:0;right:0;bottom:0}@media (max-width: 767px){.container{top:62px}}main{position:relative;width:602px;max-width:100vw;padding:0;box-sizing:border-box;margin:30px auto 15px;background:var(--main-bg);border:1px solid var(--main-border);border-radius:1px}@media (max-width: 767px){main{margin:5px auto 15px}}h1,h2,h3,h4,h5,h6{margin:0 0 0.5em 0;font-weight:400;line-height:1.2}h1{font-size:2em}a{color:var(--anchor-text);text-decoration:none}a:visited{color:var(--anchor-text)}a:hover{text-decoration:underline}input{border:1px solid var(--input-border);padding:5px;box-sizing:border-box}button{font-size:1.2em;background:var(--button-bg);border-radius:2px;padding:10px 15px;border:1px solid var(--button-border);cursor:pointer;color:var(--button-text)}button:hover{background:var(--button-bg-hover)}button:active{background:var(--button-bg-active)}button[disabled]{opacity:0.35;pointer-events:none;cursor:not-allowed}button.primary{border:1px solid var(--button-primary-border);background:var(--button-primary-bg);color:var(--button-primary-text)}button.primary:hover{background:var(--button-primary-bg-hover)}button.primary:active{background:var(--button-primary-bg-active)}p,label,input{font-size:1.3em}ul,li,p{padding:0;margin:0}.hidden{opacity:0}*:focus{outline:2px solid var(--focus-outline)}button::-moz-focus-inner{border:0}input:required,input:invalid{box-shadow:none}
|
||||
body{margin:0;font-family:system-ui, -apple-system, BlinkMacSystemFont, Segoe UI, Roboto, Oxygen, Ubuntu, Cantarell, Fira Sans, Droid Sans, Helvetica Neue;font-size:14px;line-height:1.4;color:var(--body-text-color);background:var(--body-bg);position:fixed;left:0;right:0;bottom:0;top:0}.container{overflow-y:auto;overflow-x:hidden;-webkit-overflow-scrolling:touch;will-change:transform;position:absolute;top:72px;left:0;right:0;bottom:0}@media (max-width: 767px){.container{top:62px}}main{position:relative;width:602px;max-width:100vw;padding:0;box-sizing:border-box;margin:30px auto 15px;background:var(--main-bg);border:1px solid var(--main-border);border-radius:1px}@media (max-width: 767px){main{margin:5px auto 15px}}h1,h2,h3,h4,h5,h6{margin:0 0 0.5em 0;font-weight:400;line-height:1.2}h1{font-size:2em}a{color:var(--anchor-text);text-decoration:none}a:visited{color:var(--anchor-text)}a:hover{text-decoration:underline}input{border:1px solid var(--input-border);padding:5px;box-sizing:border-box}button{font-size:1.2em;background:var(--button-bg);border-radius:2px;padding:10px 15px;border:1px solid var(--button-border);cursor:pointer;color:var(--button-text)}button:hover{background:var(--button-bg-hover)}button:active{background:var(--button-bg-active)}button[disabled]{opacity:0.35;pointer-events:none;cursor:not-allowed}button.primary{border:1px solid var(--button-primary-border);background:var(--button-primary-bg);color:var(--button-primary-text)}button.primary:hover{background:var(--button-primary-bg-hover)}button.primary:active{background:var(--button-primary-bg-active)}p,label,input{font-size:1.3em}ul,li,p{padding:0;margin:0}.hidden{opacity:0}*:focus{outline:2px solid var(--focus-outline)}button::-moz-focus-inner{border:0}input:required,input:invalid{box-shadow:none}textarea{font-family:inherit;font-size:inherit;box-sizing:border-box}
|
||||
body.offline,body.theme-hotpants.offline,body.theme-majesty.offline,body.theme-oaken.offline,body.theme-scarlet.offline,body.theme-seafoam.offline,body.theme-gecko.offline{--button-primary-bg:#ababab;--button-primary-text:#fff;--button-primary-border:#4d4d4d;--button-primary-bg-active:#9c9c9c;--button-primary-bg-hover:#b0b0b0;--button-bg:#e6e6e6;--button-text:#333;--button-border:#a7a7a7;--button-bg-active:#bfbfbf;--button-bg-hover:#f2f2f2;--input-border:#dadada;--anchor-text:#999;--main-bg:#fff;--body-bg:#fafafa;--body-text-color:#333;--main-border:#dadada;--svg-fill:#999;--form-bg:#f7f7f7;--form-border:#c1c1c1;--nav-bg:#999;--nav-border:gray;--nav-a-border:#999;--nav-a-selected-border:#fff;--nav-a-selected-bg:#b3b3b3;--nav-svg-fill:#fff;--nav-text-color:#fff;--nav-a-selected-border-hover:#fff;--nav-a-selected-bg-hover:#bfbfbf;--nav-a-bg-hover:#a6a6a6;--nav-a-border-hover:#999;--nav-svg-fill-hover:#fff;--nav-text-color-hover:#fff;--action-button-fill-color:#c7c7c7;--action-button-fill-color-hover:#d1d1d1;--action-button-fill-color-active:#a6a6a6;--action-button-fill-color-pressed:#878787;--action-button-fill-color-pressed-hover:#949494;--action-button-fill-color-pressed-active:#737373;--settings-list-item-bg:#fff;--settings-list-item-text:#999;--settings-list-item-text-hover:#999;--settings-list-item-border:#dadada;--settings-list-item-bg-active:#e6e6e6;--settings-list-item-bg-hover:#fafafa;--toast-bg:#333;--toast-border:#fafafa;--toast-text:#fff;--mask-bg:#333;--mask-svg-fill:#fff;--mask-opaque-bg:rgba(51,51,51,0.8);--loading-bg:#ededed;--deemphasized-text-color:#666;--focus-outline:#bfbfbf;--very-deemphasized-link-color:rgba(153,153,153,0.6);--very-deemphasized-text-color:rgba(102,102,102,0.6);--status-direct-background:#ededed;--main-theme-color:#999;--warning-color:#e01f19}
|
||||
|
||||
</style>
|
||||
|
|
Loading…
Reference in a new issue