Skip to content

Commit

Permalink
feat(TransitionablePortal): add component (#2155)
Browse files Browse the repository at this point in the history
* feat(TransitionablePortal): add component

* feat(TransitionablePortal): add component

* mixed(TransitionablePortal): fix style, move event handlers, clean up tests

* fix(TransitionablePortal): fix typings
  • Loading branch information
layershifter authored and levithomason committed Oct 29, 2017
1 parent 454daaa commit de69da9
Show file tree
Hide file tree
Showing 13 changed files with 588 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import React, { Component } from 'react'
import { Button, Header, Segment, TransitionablePortal } from 'semantic-ui-react'

export default class TransitionablePortalExampleControlled extends Component {
state = { open: false }

handleClick = () => this.setState({ open: !this.state.open })

handleClose = () => this.setState({ open: false })

render() {
const { open } = this.state

return (
<div>
<Button
content={open ? 'Close Portal' : 'Open Portal'}
negative={open}
positive={!open}
onClick={this.handleClick}
/>

<TransitionablePortal onClose={this.handleClose} open={open}>
<Segment style={{ left: '40%', position: 'fixed', top: '50%', zIndex: 1000 }}>
<Header>This is a controlled portal</Header>
<p>Portals have tons of great callback functions to hook into.</p>
<p>To close, simply click the close button or click away</p>
</Segment>
</TransitionablePortal>
</div>
)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import React, { Component } from 'react'
import { Button, Header, Segment, TransitionablePortal } from 'semantic-ui-react'

export default class TransitionablePortalExamplePortal extends Component {
state = { open: false }

handleOpen = () => this.setState({ open: true })

handleClose = () => this.setState({ open: false })

render() {
const { open } = this.state

return (
<TransitionablePortal
closeOnTriggerClick
onOpen={this.handleOpen}
onClose={this.handleClose}
openOnTriggerClick
trigger={(
<Button
content={open ? 'Close Portal' : 'Open Portal'}
negative={open}
positive={!open}
/>
)}
>
<Segment style={{ left: '40%', position: 'fixed', top: '50%', zIndex: 1000 }}>
<Header>This is an example portal</Header>
<p>Portals have tons of great callback functions to hook into.</p>
<p>To close, simply click the close button or click away</p>
</Segment>
</TransitionablePortal>
)
}
}
21 changes: 21 additions & 0 deletions docs/app/Examples/addons/TransitionablePortal/Types/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import React from 'react'

import ComponentExample from 'docs/app/Components/ComponentDoc/ComponentExample'
import ExampleSection from 'docs/app/Components/ComponentDoc/ExampleSection'

const TransitionablePortalTypesExamples = () => (
<ExampleSection title='Types'>
<ComponentExample
title='Transitionable Portal'
description='A basic transitionable portal.'
examplePath='addons/TransitionablePortal/Types/TransitionablePortalExamplePortal'
/>
<ComponentExample
title='Controlled'
description='A controlled transitionable portal.'
examplePath='addons/TransitionablePortal/Types/TransitionablePortalExampleControlled'
/>
</ExampleSection>
)

export default TransitionablePortalTypesExamples
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
import React, { Component } from 'react'
import { Form, Grid, Header, Segment, TransitionablePortal } from 'semantic-ui-react'

const transitions = [
'scale',
'fade', 'fade up', 'fade down', 'fade left', 'fade right',
'horizontal flip', 'vertical flip',
'drop',
'fly left', 'fly right', 'fly up', 'fly down',
'swing left', 'swing right', 'swing up', 'swing down',
'browse', 'browse right',
'slide down', 'slide up', 'slide right',
]
const options = transitions.map(name => ({ key: name, text: name, value: name }))

export default class TransitionablePortalExampleTransition extends Component {
state = { animation: transitions[0], duration: 500, open: false }

handleChange = (e, { name, value }) => this.setState({ [name]: value })

handleClick = () => this.setState({ open: !this.state.open })

render() {
const { animation, duration, open } = this.state

return (
<Grid columns={2}>
<Grid.Column>
<Form>
<Form.Select
label='Choose transition'
name='animation'
onChange={this.handleChange}
options={options}
value={animation}
/>
<Form.Input
label={`Duration: ${duration}ms `}
min={100}
max={2000}
name='duration'
onChange={this.handleChange}
step={100}
type='range'
value={duration}
/>
<Form.Button
content={open ? 'Close Portal' : 'Open Portal'}
negative={open}
positive={!open}
onClick={this.handleClick}
/>
</Form>

<TransitionablePortal open={open} transition={{ animation, duration }}>
<Segment style={{ left: '40%', position: 'fixed', top: '50%', zIndex: 1000 }}>
<Header>This is a controlled portal</Header>
<p>Portals have tons of great callback functions to hook into.</p>
<p>To close, simply click the close button or click away</p>
</Segment>
</TransitionablePortal>
</Grid.Column>
</Grid>
)
}
}
22 changes: 22 additions & 0 deletions docs/app/Examples/addons/TransitionablePortal/Usage/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import React from 'react'
import { Link } from 'react-router-dom'
import { Message } from 'semantic-ui-react'

import ComponentExample from 'docs/app/Components/ComponentDoc/ComponentExample'
import ExampleSection from 'docs/app/Components/ComponentDoc/ExampleSection'

const TransitionablePortalUsageExamples = () => (
<ExampleSection title='Usage'>
<ComponentExample
title='Transition'
description='You can use define transitions.'
examplePath='addons/TransitionablePortal/Usage/TransitionablePortalExampleTransition'
>
<Message info>
See <Link to='/modules/transition'>Transition</Link> for more examples of usage.
</Message>
</ComponentExample>
</ExampleSection>
)

export default TransitionablePortalUsageExamples
13 changes: 13 additions & 0 deletions docs/app/Examples/addons/TransitionablePortal/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import React from 'react'

import Types from './Types'
import Usage from './Usage'

const TransitionablePortalExamples = () => (
<div>
<Types />
<Usage />
</div>
)

export default TransitionablePortalExamples
5 changes: 5 additions & 0 deletions index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,11 @@ export { default as Radio, RadioProps } from './dist/commonjs/addons/Radio';
export { default as Ref, RefProps } from './dist/commonjs/addons/Ref';
export { default as Select, SelectProps } from './dist/commonjs/addons/Select';
export { default as TextArea, TextAreaProps } from './dist/commonjs/addons/TextArea';
export {
default as TransitionablePortal,
TransitionablePortalProps,
TransitionablePortalState
} from './dist/commonjs/addons/TransitionablePortal';

// Behaviors
export {
Expand Down
58 changes: 58 additions & 0 deletions src/addons/TransitionablePortal/TransitionablePortal.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import * as React from 'react';

import { TransitionEventData, TransitionProps } from '../../modules/Transition/Transition';
import { PortalProps } from '../Portal/Portal';

export interface TransitionablePortalProps {
[key: string]: any;

/** Primary content. */
children: React.ReactNode;

/**
* Called when a close event happens.
*
* @param {SyntheticEvent} event - React's original SyntheticEvent.
* @param {object} data - All props and internal state.
*/
onClose?: (nothing: null, data: PortalProps & TransitionablePortalState) => void;

/**
* Callback on each transition that changes visibility to hidden.
*
* @param {null}
* @param {object} data - All props with status.
*/
onHide?: (nothing: null, data: TransitionEventData & TransitionablePortalState) => void;

/**
* Called when an open event happens.
*
* @param {SyntheticEvent} event - React's original SyntheticEvent.
* @param {object} data - All props and internal state.
*/
onOpen?: (nothing: null, data: PortalProps & TransitionablePortalState) => void;

/**
* Callback on animation start.
*
* @param {null}
* @param {object} data - All props with status.
*/
onStart?: (nothing: null, data: TransitionEventData & TransitionablePortalState) => void;

/** Controls whether or not the portal is displayed. */
open?: boolean;

/** Transition props. */
transition?: TransitionProps;
}

export interface TransitionablePortalState {
portalOpen: boolean;
transitionVisible: boolean;
}

declare const TransitionablePortal: React.ComponentClass<TransitionablePortalProps>;

export default TransitionablePortal;
Loading

0 comments on commit de69da9

Please sign in to comment.