123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567 |
- import React, { useState, Component, isValidElement, PureComponent, createRef } from 'react';
- import ReactDOM from 'react-dom';
- import { storiesOf } from '@storybook/react';
- import { withKnobs, text, boolean } from '@storybook/addon-knobs';
- import withPropsCombinations from 'react-storybook-addon-props-combinations';
- import { Transition } from '../index';
- import QueueTransition from './queue-transition';
- import QueueStyledTransition from './queue-transition/styled';
- import { Modal, Button, IconButton, Collapse, Nav, Switch, RadioGroup, Radio } from '@douyinfe/semi-ui';
- const stories = storiesOf('semi-animation-react/Transition', module);
- stories.addDecorator(withKnobs);
- const itemStyle = {
- backgroundColor: 'rgb(241, 101, 101)',
- color: 'white',
- borderRadius: 4,
- padding: 10,
- textAlign: 'center',
- };
- const bigSquareStyle = {
- backgroundColor: 'rgb(241, 101, 101)',
- width: 100,
- height: 100,
- margin: 20,
- marginLeft: 50,
- borderRadius: 4,
- fontSize: 16,
- color: 'white',
- display: 'flex',
- alignItems: 'center',
- justifyContent: 'center',
- };
- stories.add('transition-bounceInOut', () => {
- class App extends PureComponent {
- constructor(props = {}) {
- super(props);
- this.state = {
- visible: true,
- };
- this.ref = createRef();
- }
- setVisible = visible => this.setState({ visible });
- render() {
- const { visible } = this.state;
- return (
- <div>
- <div>
- <Transition
- // config={{ ...presets.wobbly }}
- immediate
- config={{ tension: 745, friction: 35 }}
- from={{ scale: 0.7, opacity: { val: 0, duration: 200 } }}
- enter={{ scale: 1, opacity: { val: 1, duration: 200 } }}
- leave={{ scale: { val: 0.7, duration: 300 }, opacity: { val: 0, duration: 200 } }}
- >
- {visible
- ? ({ scale, opacity }) => {
- const node = this.ref.current;
- console.log('ref rect: ', node && node.getBoundingClientRect());
- return (
- <div
- ref={this.ref}
- style={{
- ...bigSquareStyle,
- opacity,
- transform: `scale(${scale}, ${scale})`,
- }}
- >
- bounceInOut
- </div>
- );
- }
- : null}
- </Transition>
- </div>
- <div>
- <button
- onClick={() => {
- this.setVisible(true);
- // setState('enter');
- }}
- >
- 入场
- </button>
- <button onClick={() => this.setVisible(false)}>出场</button>
- </div>
- </div>
- );
- }
- }
- class ModalDemo extends React.Component {
- constructor() {
- super();
- this.state = { visible: false, visibleWithAnimation: false };
- this.showDialog = this.showDialog.bind(this);
- this.handleOk = this.handleOk.bind(this);
- this.handleCancel = this.handleCancel.bind(this);
- }
- showDialog() {
- this.setState({
- visible: true,
- visibleWithAnimation: true,
- });
- }
- handleOk(e) {
- this.setState({
- // visible: false,
- visibleWithAnimation: false,
- });
- }
- handleCancel(e) {
- this.setState({
- // visible: false,
- visibleWithAnimation: false,
- });
- }
- render() {
- const { visibleWithAnimation, visible } = this.state;
- return (
- <>
- <Button onClick={this.showDialog}>Open Modal</Button>
- <Transition
- config={{
- // ...presets.wobbly
- duration: 200,
- easing: visibleWithAnimation ? 'easeInCubic' : 'easeOutCubic',
- }}
- from={{
- scale: 0,
- // opacity: { val: 0, easing: 'linear' },
- }}
- enter={{
- scale: 1,
- // opacity: { val: 1, easing: 'linear' },
- }}
- leave={{
- scale: 0,
- // opacity: { val: 0, easing: 'linear' },
- }}
- didLeave={() => this.setState({ visible: false })}
- >
- {visibleWithAnimation
- ? ({ opacity, scale }) => (
- <Modal
- title="自定义样式"
- visible={visible}
- onOk={this.handleOk}
- onCancel={this.handleCancel}
- style={{ top: '30vh', transform: `scale(${scale},${scale})` }}
- maskStyle={{ backgroundColor: 'pink', opacity: '.3' }}
- bodyStyle={{ backgroundColor: 'lightgrey' }}
- >
- <p>This is a modal with customized styles.</p>
- <p>More content...</p>
- </Modal>
- )
- : null}
- </Transition>
- </>
- );
- }
- }
- return (
- <>
- <ModalDemo />
- <App />
- </>
- );
- });
- stories.add('transition-bounceInOut-受控', () => {
- class App extends PureComponent {
- constructor(props = {}) {
- super(props);
- this.state = {
- state: 'enter',
- visible: true,
- };
- this.ref = createRef();
- }
- setVisible = visible => this.setState({ state: visible ? 'enter' : 'leave' });
- didEnter = () => {
- this.setState({ visible: true });
- };
- didLeave = () => {
- this.setState({ visible: false });
- };
- render() {
- const { visible, state } = this.state;
- return (
- <div>
- <div>
- <Transition
- // config={{ ...presets.wobbly }}
- state={state}
- config={{ tension: 745, friction: 35 }}
- from={{ scale: 0.7, opacity: { val: 0, duration: 200 } }}
- enter={{ scale: 1, opacity: { val: 1, duration: 200 } }}
- leave={{ scale: { val: 0.7, duration: 300 }, opacity: { val: 0, duration: 200 } }}
- didEnter={this.didEnter}
- didLeave={this.didLeave}
- >
- {state === 'enter' || visible
- ? ({ scale, opacity }) => {
- const node = this.ref.current;
- // console.log('ref rect: ', node && node.getBoundingClientRect());
- return (
- <div
- ref={this.ref}
- style={{
- ...bigSquareStyle,
- opacity,
- transform: `scale(${scale}, ${scale})`,
- }}
- >
- bounceInOut
- </div>
- );
- }
- : null}
- </Transition>
- </div>
- <div>
- <button onClick={() => this.setVisible(true)}>入场</button>
- <button onClick={() => this.setVisible(false)}>出场</button>
- </div>
- </div>
- );
- }
- }
- return (
- <>
- <App />
- </>
- );
- });
- stories.add('transition-slideInOutDown', () => {
- const SlideInOutDown = function SlideInOutDown(props = {}) {
- return (
- <Transition from={{ maxHeight: 0 }} enter={{ maxHeight: 100 }} leave={{ maxHeight: 0 }}>
- {props.children}
- </Transition>
- );
- };
- class App extends PureComponent {
- state = {
- itemKey: '',
- };
- setItemKey = itemKey => this.setState({ itemKey });
- render() {
- const { itemKey } = this.state;
- return (
- <Collapse accordion onChange={this.setItemKey}>
- {['1', '2', '3'].map(key => (
- <Collapse.Panel header={`This is panel header ${key}`} itemKey={key} key={key}>
- {/* <SlideInOutDown> */}
- <Transition from={{ maxHeight: 0 }} enter={{ maxHeight: 100 }} leave={{ maxHeight: 0 }}>
- {itemKey === key
- ? ({ maxHeight }) => (
- <p
- style={{
- maxHeight: `${maxHeight}%`,
- transform: `translateY(${maxHeight - 100}%)`,
- }}
- >
- Hi, bytedance dance dance. This is the docsite of Semi UI.{' '}
- </p>
- )
- : null}
- {/* </SlideInOutDown> */}
- </Transition>
- </Collapse.Panel>
- ))}
- </Collapse>
- );
- }
- }
- return <App />;
- });
- stories.add('transition-slideInOutLeft', () => {
- function SlideInOutLeft(props = {}) {
- return (
- <Transition {...props} from={{ translateX: -100 }} enter={{ translateX: 0 }} leave={{ translateX: -100 }}>
- {props.children}
- </Transition>
- );
- }
- class NavApp extends React.Component {
- constructor() {
- super();
- this.state = {
- isCollapsed: true,
- defaultOpenKeys: ['2', '2-3'],
- mode: 'vertical',
- navHeight: 480,
- selectedKeys: [],
- openKeys: ['2'],
- };
- this.onSelect = (data = {}) => {
- console.log('trigger onSelect: ', data);
- let selectedKeys = Array.from(data.selectedKeys);
- this.setState({ selectedKeys });
- };
- this.onOpenChange = (data = {}) => {
- console.log('trigger onOpenChange: ', data);
- let openKeys = Array.from(data.openKeys);
- this.setState({ openKeys });
- };
- }
- updateCollapsed(isCollapsed) {
- this.setState({ isCollapsed });
- }
- toggleMode() {
- let { mode, navHeight } = this.state;
- if (mode === 'vertical') {
- mode = 'horizontal';
- navHeight = 60;
- } else {
- mode = 'vertical';
- navHeight = 480;
- }
- this.setState({ mode, navHeight });
- }
- renderNavWithTransform = ({ transform, translateX }) => {
- let { isCollapsed, defaultOpenKeys, mode, navHeight, selectedKeys, openKeys } = this.state;
- let testIcon = '//lf1-cdn-tos.bytescm.com/obj/mosaic-legacy/da9d0015af0f09667998';
- let vigoIcon = '//lf1-cdn-tos.bytescm.com/obj/mosaic-legacy/504100070cbe0498d66f';
- let icon3 = '//lf1-cdn-tos.bytescm.com/eesz/resource/bear/public/doc-favicon-v4.902ddd709d8aaa55df8d.ico';
- return (
- <Nav
- // isCollapsed={isCollapsed}
- defaultOpenKeys={defaultOpenKeys}
- style={{ height: navHeight, transform: `translateX(${translateX}%)` }}
- mode={mode}
- selectedKeys={selectedKeys}
- openKeys={openKeys}
- onSelect={this.onSelect}
- onOpenChange={this.onOpenChange}
- >
- <Nav.Header logo="doc-toast" text="互娱运营" />
- <Nav.Item
- itemKey={'1'}
- text={<strong>火山运营</strong>}
- icon={<img width="20" height="20" src={vigoIcon} />}
- />
- <Nav.Sub
- itemKey={'2'}
- text={<strong>抖音运营</strong>}
- icon={<img width="20" height="20" src={testIcon} />}
- >
- {['2-1', '2-2'].map(k => (
- <Nav.Item key={k} itemKey={String(k)} text={'Option ' + k} />
- ))}
- <Nav.Sub text={'Group 2-3'} icon={<img width="20" height="20" src={icon3} />} itemKey="2-3">
- <Nav.Item itemKey={'2-3-1'} text={'Option 2-3-1'} />
- <Nav.Item itemKey={'2-3-2'} text={'Option 2-3-2'} />
- </Nav.Sub>
- </Nav.Sub>
- </Nav>
- );
- };
- render() {
- let { isCollapsed, defaultOpenKeys, mode, navHeight, selectedKeys, openKeys } = this.state;
- let testIcon = '//lf1-cdn-tos.bytescm.com/obj/mosaic-legacy/da9d0015af0f09667998';
- let vigoIcon = '//lf1-cdn-tos.bytescm.com/obj/mosaic-legacy/504100070cbe0498d66f';
- let icon3 = '//lf1-cdn-tos.bytescm.com/eesz/resource/bear/public/doc-favicon-v4.902ddd709d8aaa55df8d.ico';
- return (
- <div style={{ position: 'relative' }}>
- <SlideInOutLeft>
- {isCollapsed
- ? ({ transform, translateX }) => (
- <Nav
- // isCollapsed={isCollapsed}
- defaultOpenKeys={defaultOpenKeys}
- style={{ height: navHeight, transform: `translateX(${translateX}%)` }}
- mode={mode}
- selectedKeys={selectedKeys}
- openKeys={openKeys}
- onSelect={this.onSelect}
- onOpenChange={this.onOpenChange}
- >
- <Nav.Header logo="doc-toast" text="互娱运营" />
- <Nav.Item
- itemKey={'1'}
- text={<strong>火山运营</strong>}
- icon={<img width="20" height="20" src={vigoIcon} />}
- />
- <Nav.Sub
- itemKey={'2'}
- text={<strong>抖音运营</strong>}
- icon={<img width="20" height="20" src={testIcon} />}
- >
- {['2-1', '2-2'].map(k => (
- <Nav.Item key={k} itemKey={String(k)} text={'Option ' + k} />
- ))}
- <Nav.Sub
- text={'Group 2-3'}
- icon={<img width="20" height="20" src={icon3} />}
- itemKey="2-3"
- >
- <Nav.Item itemKey={'2-3-1'} text={'Option 2-3-1'} />
- <Nav.Item itemKey={'2-3-2'} text={'Option 2-3-2'} />
- </Nav.Sub>
- </Nav.Sub>
- </Nav>
- )
- : null}
- </SlideInOutLeft>
- <IconButton
- style={{ position: 'absolute', left: 10, top: 10 }}
- title="展开/收起切换"
- iconType="list"
- onClick={() => this.updateCollapsed(!isCollapsed)}
- />
- </div>
- );
- }
- }
- return <NavApp />;
- });
- stories.add('queue transition', () => {
- const Demo = () => {
- const animStyle = { ...itemStyle, width: 100, marginBottom: 10 };
- const [state, setState] = useState('enter');
- const [position, setPosition] = useState('left');
- const onSwitchPosition = e => {
- setPosition(e.target.value);
- };
- const positionList = ['left', 'top', 'right', 'bottom'];
- return (
- <div style={{ padding: 100 }}>
- <QueueTransition state={state} position={position}>
- <div style={{ ...animStyle }}>1</div>
- <div style={{ ...animStyle }}>2</div>
- <div style={{ ...animStyle }}>3</div>
- <div style={{ ...animStyle }}>4</div>
- </QueueTransition>
- <div>
- <div>
- <p>方向</p>
- <RadioGroup value={position} onChange={onSwitchPosition}>
- {positionList.map(pos => (
- <Radio value={pos} key={pos}>
- {pos}
- </Radio>
- ))}
- </RadioGroup>
- </div>
- <div>
- <Button onClick={() => setState('enter')}>入场</Button>
- <Button onClick={() => setState('leave')}>离场</Button>
- </div>
- </div>
- </div>
- );
- };
- return <Demo />;
- });
- stories.add('queue styled transition', () => {
- const Demo = () => {
- const animStyle = {
- backgroundColor: 'rgb(241, 101, 101)',
- color: 'white',
- borderRadius: 4,
- padding: 10,
- textAlign: 'center',
- width: 100,
- marginBottom: 10,
- };
- const [state, setState] = useState('enter');
- const [position, setPosition] = useState('Left');
- const switchState = state => {
- setState(undefined);
- setTimeout(() => setState(state));
- };
- const onSwitchPosition = e => {
- setPosition(e.target.value);
- };
- const positionList = ['Left', 'Up', 'Right', 'Down'];
- return (
- <div style={{ padding: 100, display: 'flex', flexDirection: 'row' }}>
- <div>
- <QueueStyledTransition state={state} position={position}>
- <div style={{ ...animStyle }}>1</div>
- <div style={{ ...animStyle }}>2</div>
- <div style={{ ...animStyle }}>3</div>
- <div style={{ ...animStyle }}>4</div>
- </QueueStyledTransition>
- </div>
- <div style={{ marginLeft: 20 }}>
- <div style={{ display: 'flex' }}>
- <label>方向:</label>
- <RadioGroup value={position} onChange={onSwitchPosition}>
- {positionList.map(pos => (
- <Radio value={pos} key={pos}>
- {pos}
- </Radio>
- ))}
- </RadioGroup>
- </div>
- <div>
- <label>时机:</label>
- <Button onClick={() => switchState('enter')}>入场</Button>
- <Button onClick={() => switchState('leave')}>离场</Button>
- </div>
- </div>
- </div>
- );
- };
- return <Demo />;
- });
|