-
Notifications
You must be signed in to change notification settings - Fork 2.2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[new] ResizeSensor component #2745
Merged
Merged
Changes from 11 commits
Commits
Show all changes
12 commits
Select commit
Hold shift + click to select a range
67eda7a
ResizeSensor is a React wrapper for ResizeObserver
d710b9d
use ResizeSensor in OverflowList & Popover
38d6b69
export component
0b186d9
enable Promise in tests
843c4b8
add test suite
9d48340
re-observe DOM node in DidUpdate (if necessary)
a7f4d1a
don't expose external types
7a3c473
allow changing props :+1:
7e56bff
add docs page
2580736
fix isotest
8d297b3
docs per comments
705baab
docs cleanup
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
27 changes: 27 additions & 0 deletions
27
packages/core/src/components/resize-sensor/resize-sensor.md
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
--- | ||
tag: new | ||
--- | ||
|
||
@# Resize sensor | ||
|
||
`ResizeSensor` is a higher-order component that effectively provides a | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. nit: this is a little wordy and im not sure it's even correct. Maybe rephrase:
But even then it's not "providing an event" in the sense of |
||
`"resize"` event for a single DOM element. It is a thin wrapper around | ||
[`ResizeObserver`][resizeobserver] to provide React bindings. | ||
|
||
[resizeobserver]: https://developers.google.com/web/updates/2016/10/resizeobserver | ||
|
||
```tsx | ||
import { IResizeEntry, ResizeSensor } from "@blueprintjs/core"; | ||
|
||
function handleResize(entries: IResizeEntry[]) { | ||
console.log(entries.map(e => `${e.contentRect.width} x ${e.contentRect.height}`)); | ||
} | ||
|
||
<ResizeSensor onChange={handleResize}> | ||
<div style={{ width: this.props.width }} /> | ||
</ResizeSensor> | ||
``` | ||
|
||
@## Props | ||
|
||
@interface IResizeSensorProps |
106 changes: 106 additions & 0 deletions
106
packages/core/src/components/resize-sensor/resizeSensor.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,106 @@ | ||
/* | ||
* Copyright 2018 Palantir Technologies, Inc. All rights reserved. | ||
* | ||
* Licensed under the terms of the LICENSE file distributed with this project. | ||
*/ | ||
|
||
import * as React from "react"; | ||
import ResizeObserver from "resize-observer-polyfill"; | ||
|
||
import { findDOMNode } from "react-dom"; | ||
import { DISPLAYNAME_PREFIX } from "../../common/props"; | ||
import { safeInvoke } from "../../common/utils"; | ||
|
||
/** A parallel type to `ResizeObserverEntry` (from resize-observer-polyfill). */ | ||
export interface IResizeEntry { | ||
/** Measured dimensions of the target. */ | ||
contentRect: DOMRectReadOnly; | ||
|
||
/** The resized element. */ | ||
target: Element; | ||
} | ||
|
||
/** `ResizeSensor` requires a single DOM element child and will error otherwise. */ | ||
export interface IResizeSensorProps { | ||
/** | ||
* Callback invoked when the wrapped element resizes. | ||
* | ||
* The `entries` array contains an entry for each observed element. In the | ||
* default case (no `observeParents`), the array will contain only one | ||
* element: the single child of the `ResizeSensor`. | ||
*/ | ||
onResize: (entries: IResizeEntry[]) => void; | ||
|
||
/** | ||
* If `true`, all parent DOM elements of the container will also be | ||
* observed for size changes. The array of entries passed to `onResize` | ||
* will now contain an entry for each parent element up to the root of the | ||
* document. | ||
* | ||
* Only enable this prop if a parent element resizes in a way that does | ||
* not also cause the child element to resize. | ||
* @default false | ||
*/ | ||
observeParents?: boolean; | ||
} | ||
|
||
export class ResizeSensor extends React.PureComponent<IResizeSensorProps> { | ||
public static displayName = `${DISPLAYNAME_PREFIX}.ResizeSensor`; | ||
|
||
private element: Element | null = null; | ||
private observer = new ResizeObserver(entries => safeInvoke(this.props.onResize, entries)); | ||
|
||
public render() { | ||
// pass-through render of single child | ||
return React.Children.only(this.props.children); | ||
} | ||
|
||
public componentDidMount() { | ||
// using findDOMNode for two reasons: | ||
// 1. cloning to insert a ref is unwieldy and not performant. | ||
// 2. ensure that we get an actual DOM node for observing. | ||
this.observeElement(findDOMNode(this)); | ||
} | ||
|
||
public componentDidUpdate(prevProps: IResizeSensorProps) { | ||
this.observeElement(findDOMNode(this), this.props.observeParents !== prevProps.observeParents); | ||
} | ||
|
||
public componentWillUnmount() { | ||
this.observer.disconnect(); | ||
} | ||
|
||
/** | ||
* Observe the given element, if defined and different from the currently | ||
* observed element. Pass `force` argument to skip element checks and always | ||
* re-observe. | ||
*/ | ||
private observeElement(element: Element | null, force = false) { | ||
if (element == null) { | ||
// stop everything if not defined | ||
this.observer.disconnect(); | ||
return; | ||
} | ||
|
||
if (element === this.element && !force) { | ||
// quit if given same element -- nothing to update (unless forced) | ||
return; | ||
} else { | ||
// clear observer list if new element | ||
this.observer.disconnect(); | ||
// remember element reference for next time | ||
this.element = element; | ||
} | ||
|
||
// observer callback is invoked immediately when observing new elements | ||
this.observer.observe(element); | ||
|
||
if (this.props.observeParents) { | ||
let parent = element.parentElement; | ||
while (parent != null) { | ||
this.observer.observe(parent); | ||
parent = parent.parentElement; | ||
} | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this is new and awesome and so simple. measures the target too!