-
Notifications
You must be signed in to change notification settings - Fork 4.1k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(MountNode): add component (#2407)
* feat(MountNode): add component * restore Responsive test * test(Modal): fix test
- Loading branch information
1 parent
3f26bef
commit 0c5e2f9
Showing
25 changed files
with
703 additions
and
143 deletions.
There are no files selected for viewing
34 changes: 34 additions & 0 deletions
34
docs/app/Examples/addons/MountNode/Types/MountNodeExampleMountNode.js
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,34 @@ | ||
import React, { Component } from 'react' | ||
import { Form, Grid, MountNode, Segment } from 'semantic-ui-react' | ||
|
||
export default class MountNodeExampleMountNode extends Component { | ||
state = { className: '' } | ||
|
||
handleChange = (e, { value }) => this.setState({ className: value }) | ||
|
||
handleRef = node => this.setState({ node }) | ||
|
||
render() { | ||
const { className, node } = this.state | ||
|
||
return ( | ||
<Grid columns={2}> | ||
<Grid.Column> | ||
<Form> | ||
<Form.Input | ||
placeholder='Enter any className to apply...' | ||
onChange={this.handleChange} | ||
value={className} | ||
/> | ||
</Form> | ||
</Grid.Column> | ||
<Grid.Column> | ||
<Segment> | ||
{node && <MountNode className={className} node={node} />} | ||
<div ref={this.handleRef}>An example node</div> | ||
</Segment> | ||
</Grid.Column> | ||
</Grid> | ||
) | ||
} | ||
} |
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,16 @@ | ||
import React from 'react' | ||
|
||
import ComponentExample from 'docs/app/Components/ComponentDoc/ComponentExample' | ||
import ExampleSection from 'docs/app/Components/ComponentDoc/ExampleSection' | ||
|
||
const MountNodeTypesExamples = () => ( | ||
<ExampleSection title='Types'> | ||
<ComponentExample | ||
title='MountNode' | ||
description={<span>A component allows to set <code>className</code> to a DOM node.</span>} | ||
examplePath='addons/MountNode/Types/MountNodeExampleMountNode' | ||
/> | ||
</ExampleSection> | ||
) | ||
|
||
export default MountNodeTypesExamples |
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,10 @@ | ||
import React from 'react' | ||
import Types from './Types' | ||
|
||
const MountNodeExamples = () => ( | ||
<div> | ||
<Types /> | ||
</div> | ||
) | ||
|
||
export default MountNodeExamples |
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
import * as React from 'react'; | ||
|
||
export interface MountNodeProps { | ||
[key: string]: any; | ||
|
||
/** Additional classes. */ | ||
className?: string; | ||
|
||
/** The DOM node where we will apply class names. Defaults to document.body. */ | ||
node?: HTMLElement; | ||
} | ||
|
||
declare class MountNode extends React.Component<MountNodeProps, {}> { | ||
} | ||
|
||
export default MountNode; |
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,61 @@ | ||
import PropTypes from 'prop-types' | ||
import { Component } from 'react' | ||
|
||
import { customPropTypes, META } from '../../lib' | ||
import getNodeFromProps from './lib/getNodeFromProps' | ||
import handleClassNamesChange from './lib/handleClassNamesChange' | ||
import NodeRegistry from './lib/NodeRegistry' | ||
|
||
const nodeRegistry = new NodeRegistry() | ||
|
||
/** | ||
* A component that allows to manage classNames on a DOM node in declarative manner. | ||
*/ | ||
export default class MountNode extends Component { | ||
static propTypes = { | ||
/** Additional classes. */ | ||
className: PropTypes.string, | ||
|
||
/** The DOM node where we will apply class names. Defaults to document.body. */ | ||
node: customPropTypes.domNode, | ||
} | ||
|
||
static _meta = { | ||
name: 'MountNode', | ||
type: META.TYPES.ADDON, | ||
} | ||
|
||
shouldComponentUpdate({ className: nextClassName }) { | ||
const { className: currentClassName } = this.props | ||
|
||
return nextClassName !== currentClassName | ||
} | ||
|
||
componentWillMount() { | ||
const node = getNodeFromProps(this.props) | ||
|
||
if (node) { | ||
nodeRegistry.add(node, this) | ||
nodeRegistry.emit(node, handleClassNamesChange) | ||
} | ||
} | ||
|
||
componentDidUpdate() { | ||
const node = getNodeFromProps(this.props) | ||
|
||
if (node) nodeRegistry.emit(node, handleClassNamesChange) | ||
} | ||
|
||
componentWillUnmount() { | ||
const node = getNodeFromProps(this.props) | ||
|
||
if (node) { | ||
nodeRegistry.del(node, this) | ||
nodeRegistry.emit(node, handleClassNamesChange) | ||
} | ||
} | ||
|
||
render() { | ||
return null | ||
} | ||
} |
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 @@ | ||
export { default, MountNodeProps } from './MountNode'; |
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 @@ | ||
export default from './MountNode' |
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,33 @@ | ||
export default class NodeRegistry { | ||
constructor() { | ||
this.nodes = new Map() | ||
} | ||
|
||
add = (node, component) => { | ||
if (this.nodes.has(node)) { | ||
const set = this.nodes.get(node) | ||
|
||
set.add(component) | ||
return | ||
} | ||
|
||
this.nodes.set(node, new Set([component])) | ||
} | ||
|
||
del = (node, component) => { | ||
if (!this.nodes.has(node)) return | ||
|
||
const set = this.nodes.get(node) | ||
|
||
if (set.size === 1) { | ||
this.nodes.delete(node) | ||
return | ||
} | ||
|
||
set.delete(component) | ||
} | ||
|
||
emit = (node, callback) => { | ||
callback(node, this.nodes.get(node)) | ||
} | ||
} |
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,11 @@ | ||
import _ from 'lodash/fp' | ||
|
||
const computeClassNames = _.flow( | ||
_.toArray, | ||
_.map('props.className'), | ||
_.flatMap(_.split(/\s+/)), | ||
_.filter(_.identity), | ||
_.uniq, | ||
) | ||
|
||
export default computeClassNames |
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,8 @@ | ||
import _ from 'lodash' | ||
|
||
const computeClassNamesDifference = (prevClassNames, currentClassNames) => [ | ||
_.difference(currentClassNames, prevClassNames), | ||
_.difference(prevClassNames, currentClassNames), | ||
] | ||
|
||
export default computeClassNamesDifference |
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,19 @@ | ||
import _ from 'lodash' | ||
import { isBrowser } from '../../../lib' | ||
|
||
/** | ||
* Given `this.props`, return a `node` value or undefined. | ||
* | ||
* @param {object} props Component's props | ||
* @return {HTMLElement|undefined} | ||
*/ | ||
const getNodeFromProps = (props) => { | ||
const { node } = props | ||
|
||
if (isBrowser()) { | ||
if (_.isNil(node)) return document.body | ||
return node | ||
} | ||
} | ||
|
||
export default getNodeFromProps |
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,18 @@ | ||
import _ from 'lodash' | ||
|
||
import computeClassNames from './computeClassNames' | ||
import computeClassNamesDifference from './computeClassNamesDifference' | ||
|
||
const prevClassNames = new Map() | ||
|
||
const handleClassNamesChange = (node, components) => { | ||
const currentClassNames = computeClassNames(components) | ||
const [forAdd, forRemoval] = computeClassNamesDifference(prevClassNames.get(node), currentClassNames) | ||
|
||
_.forEach(forAdd, className => node.classList.add(className)) | ||
_.forEach(forRemoval, className => node.classList.remove(className)) | ||
|
||
prevClassNames.set(node, currentClassNames) | ||
} | ||
|
||
export default handleClassNamesChange |
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.