Skip to content
This repository has been archived by the owner on Aug 21, 2023. It is now read-only.

Commit

Permalink
Input: Resizer - Recalculate height on mount (#447)
Browse files Browse the repository at this point in the history
This update enhanced `Input.Resizer` to recalculate it's height on mount behind
a `requestAnimationFrame` call. This is to help ensure correct height values when
loaded into a heavier page/component (computation wise).

`Input.Resizer` has also been converted to Typescript, with minor performance/render
refactors for how it handles defining instance variables.
  • Loading branch information
Jon Quach committed Jan 10, 2019
1 parent 34712f2 commit 7861a3f
Show file tree
Hide file tree
Showing 2 changed files with 70 additions and 33 deletions.
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
// @flow
// See: https://github.com/Shopify/polaris/blob/master/src/components/TextField/Resizer.tsx
import React, { PureComponent as Component } from 'react'
import * as React from 'react'
import EventListener from '../EventListener'
import { classNames } from '../../utilities/classNames'
import { noop } from '../../utilities/other'
Expand All @@ -17,19 +15,19 @@ const ENTITIES_TO_REPLACE = {
}
const REPLACE_REGEX = /[\n&<>]/g

type Props = {
className?: string,
contents: string,
currentHeight: ?number,
minimumLines: number,
offsetAmount: number,
onResize: (size: number) => void,
seamless: boolean,
export interface Props {
className?: string
contents: string
currentHeight?: number
minimumLines: number
offsetAmount: number
onResize: (size: number) => void
seamless: boolean
}

type RefNode = HTMLDivElement | null

class Resizer extends Component<Props> {
export class Resizer extends React.PureComponent<Props> {
static defaultProps = {
contents: '',
currentHeight: null,
Expand All @@ -40,15 +38,45 @@ class Resizer extends Component<Props> {
}
contentNode: RefNode
minimumLinesNode: RefNode
_isMounted = false

componentDidMount() {
this._isMounted = true
this.handleOnResize()

// Re-trigger to help recalculate when used within heavier components/views.
/* istanbul ignore next */
requestAnimationFrame(() => {
if (this._isMounted) {
this.handleOnResize()
}
})
}

componentWillUnmount() {
this._isMounted = false
}

componentDidUpdate() {
this.handleOnResize()
}

getClassName() {
const { className } = this.props

return classNames('c-InputResizer', className)
}

getContentClassName() {
const { seamless } = this.props

return classNames(
'c-InputGhost',
'c-InputGhost--characters',
seamless && 'is-seamless'
)
}

// Ignoring as height calculation isn't possible with JSDOM
// (which is what Enzyme uses for tests)
/* istanbul ignore next */
Expand Down Expand Up @@ -89,39 +117,36 @@ class Resizer extends Component<Props> {
: '<br>'
}

render() {
const { className, contents, minimumLines, seamless } = this.props
const handleOnResize = this.handleOnResize
setMinimumLinesNode = node => (this.minimumLinesNode = node)
setContentNodeRef = node => (this.contentNode = node)

const componentClassName = classNames('c-InputResizer', className)
renderMinimumLines() {
const { minimumLines } = this.props
if (!minimumLines) return

const minimumLinesMarkup = minimumLines ? (
return (
<div
ref={(node: RefNode) => (this.minimumLinesNode = node)}
className={classNames(
'c-InputGhost',
'c-InputGhost--lineBreak',
seamless && 'is-seamless'
)}
ref={this.setMinimumLinesNode}
className={this.getContentClassName()}
dangerouslySetInnerHTML={{
__html: this.getContentsForMinimumLines(minimumLines),
}}
/>
) : null
)
}

render() {
const { contents } = this.props

return (
<div aria-hidden className={componentClassName}>
<EventListener event="resize" handler={handleOnResize} />
<div aria-hidden className={this.getClassName()}>
<EventListener event="resize" handler={this.handleOnResize} />
<div
ref={(node: RefNode) => (this.contentNode = node)}
className={classNames(
'c-InputGhost',
'c-InputGhost--characters',
seamless && 'is-seamless'
)}
ref={this.setContentNodeRef}
className={this.getContentClassName()}
dangerouslySetInnerHTML={{ __html: this.getFinalContents(contents) }}
/>
{minimumLinesMarkup}
{this.renderMinimumLines()}
</div>
)
}
Expand Down
12 changes: 12 additions & 0 deletions src/components/Input/__tests__/Resizer.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -122,3 +122,15 @@ describe('offsetAmount', () => {
expect(chars).not.toContain('R')
})
})

describe('isMounted/didMount', () => {
test('Unsets _isMounted on unmount', () => {
const wrapper = mount(<Resizer offsetAmount={5} />)
const inst = wrapper.instance()

expect(inst._isMounted).toBe(true)

wrapper.unmount()
expect(inst._isMounted).toBe(false)
})
})

0 comments on commit 7861a3f

Please sign in to comment.