替换掉react-bootstrap中的组件

This commit is contained in:
catchonme 2019-08-07 15:36:05 +08:00
parent 69e45a026a
commit 2f12a79858
10 changed files with 199 additions and 71 deletions

View File

@ -11,7 +11,6 @@ const mapping: {
'immutability-helper': __moduleId('react-addons-update'), 'immutability-helper': __moduleId('react-addons-update'),
'react-cropper': __moduleId('react-cropper'), 'react-cropper': __moduleId('react-cropper'),
'react-dropzone': __moduleId('react-dropzone'), 'react-dropzone': __moduleId('react-dropzone'),
'react-bootstrap': __moduleId('react-bootstrap'),
'classnames': __moduleId('classnames'), 'classnames': __moduleId('classnames'),
'axios': __moduleId('axios'), 'axios': __moduleId('axios'),
'moment': __moduleId('moment'), 'moment': __moduleId('moment'),

View File

@ -53,7 +53,6 @@
"rc-input-number": "4.4.5", "rc-input-number": "4.4.5",
"react": "^16.8.6", "react": "^16.8.6",
"react-addons-update": "15.6.2", "react-addons-update": "15.6.2",
"react-bootstrap": "^0.32.3",
"react-overlays": "^0.8.3", "react-overlays": "^0.8.3",
"react-color": "2.13.8", "react-color": "2.13.8",
"react-cropper": "1.0.0", "react-cropper": "1.0.0",
@ -88,7 +87,6 @@
"@types/qs": "^6.5.1", "@types/qs": "^6.5.1",
"@types/react": "^16.8.1", "@types/react": "^16.8.1",
"@types/react-addons-update": "^0.14.19", "@types/react-addons-update": "^0.14.19",
"@types/react-bootstrap": "^0.32.3",
"@types/react-color": "^2.13.3", "@types/react-color": "^2.13.3",
"@types/react-cropper": "^0.10.1", "@types/react-cropper": "^0.10.1",
"@types/react-dom": "^16.0.7", "@types/react-dom": "^16.0.7",

View File

@ -1,6 +1,13 @@
.#{$ns}Tabs { .#{$ns}Tabs {
&-links { &-links {
border-bottom: $Tabs-borderWidth solid $Tabs-borderColor; border-bottom: $Tabs-borderWidth solid $Tabs-borderColor;
padding-left: 0;
margin-bottom: 0;
list-style: none;
&::before {
display: table;
content: " ";
}
> .#{$ns}Tabs-link { > .#{$ns}Tabs-link {
margin-bottom: -$Tabs-borderWidth; margin-bottom: -$Tabs-borderWidth;
@ -17,6 +24,7 @@
padding: $gap-sm $gap-base; padding: $gap-sm $gap-base;
text-decoration: none; text-decoration: none;
cursor: pointer; cursor: pointer;
display: block;
} }
&:hover > a, &:hover > a,
@ -49,6 +57,13 @@
border-style: solid; border-style: solid;
border-width: 0 $Tabs-borderWidth $Tabs-borderWidth; border-width: 0 $Tabs-borderWidth $Tabs-borderWidth;
border-color: $Tabs-borderColor; border-color: $Tabs-borderColor;
> .tab-pane {
display: none;
&.active {
display: block;
}
}
} }
&--line { &--line {

View File

@ -1,3 +1,113 @@
import {Collapse} from 'react-bootstrap'; /**
* @file Collapse
* @description
* @author fex
*/
export default Collapse; import React from 'react';
import cx from 'classnames';
import css = require('dom-helpers/style');
import {ClassNamesFn, themeable} from '../theme';
import Transition, { EXITED, ENTERED, ENTERING, EXITING } from 'react-transition-group/Transition';
import { autobind } from '../utils/helper';
const collapseStyles: {
[propName: string]: string;
} = {
[EXITED]: 'collapse',
[EXITING]: 'collapsing',
[ENTERING]: 'collapsing',
[ENTERED]: 'collapse show',
};
export interface CollapseProps {
show?: boolean,
mountOnEnter?: boolean,
unmountOnExit?: boolean,
className?: string,
classPrefix: string;
classnames: ClassNamesFn;
}
export class Collapse extends React.Component<CollapseProps, any> {
static defaultProps: Pick<
CollapseProps,
'show' | 'mountOnEnter' | 'unmountOnExit'
> = {
show: false,
mountOnEnter: false,
unmountOnExit: false
}
contentDom: any;
contentRef = (ref: any) => (this.contentDom = ref);
@autobind
handleEnter(elem: HTMLElement) {
elem.style['height'] = null;
}
@autobind
handleEntering(elem: HTMLElement) {
elem.style['height'] = `${elem['scrollHeight']}px`;
}
@autobind
handleEntered(elem: HTMLElement) {
elem.style['height'] = null;
}
@autobind
handleExit(elem: HTMLElement) {
let offsetHeight = elem['offsetHeight'];
const height = offsetHeight + parseInt(css(elem, 'marginTop'), 10) + parseInt(css(elem, 'marginBottom'), 10);
elem.style['height'] = `${height}px`;
// trigger browser reflow
elem.offsetHeight;
}
@autobind
handleExiting(elem: HTMLElement) {
elem.style['height'] = null;
}
render() {
const {
show,
children,
mountOnEnter,
unmountOnExit
} = this.props;
return (
<Transition
mountOnEnter={mountOnEnter}
unmountOnExit={unmountOnExit}
in={show}
timeout={300}
onEnter={this.handleEnter}
onEntering={this.handleEntering}
onEntered={this.handleEntered}
onExit={this.handleExit}
onExiting={this.handleExiting}
>
{(status:string, innerProps:any) => {
if (status === ENTERING) {
this.contentDom.offsetWidth;
}
return React.cloneElement(children as any, {
...innerProps,
ref: this.contentRef,
className: cx(
collapseStyles[status],
innerProps.className
)
})}
}
</Transition>
);
}
}
export default themeable(Collapse);

View File

@ -1,3 +0,0 @@
import {DropdownButton} from 'react-bootstrap';
export default DropdownButton;

View File

@ -15,7 +15,6 @@ import ColorPicker from './ColorPicker';
import DatePicker from './DatePicker'; import DatePicker from './DatePicker';
import DateRangePicker from './DateRangePicker'; import DateRangePicker from './DateRangePicker';
import Drawer from './Drawer'; import Drawer from './Drawer';
import DropdownButton from './DropdownButton';
// import Editor from './Editor'; // import Editor from './Editor';
import Html from './Html'; import Html from './Html';
import * as Icons from './icons'; import * as Icons from './icons';
@ -52,7 +51,6 @@ export {
DatePicker, DatePicker,
DateRangePicker, DateRangePicker,
Drawer, Drawer,
DropdownButton,
// Editor, // Editor,
Html, Html,
Icons, Icons,

View File

@ -26,7 +26,6 @@ import {
DatePicker, DatePicker,
DateRangePicker, DateRangePicker,
Drawer, Drawer,
DropdownButton,
// Editor, // Editor,
Icons, Icons,
Html, Html,
@ -192,7 +191,6 @@ export {
DatePicker, DatePicker,
DateRangePicker, DateRangePicker,
Drawer, Drawer,
DropdownButton,
// Editor, // Editor,
Html, Html,
Icons, Icons,

View File

@ -1,7 +1,6 @@
import React from 'react'; import React from 'react';
import {Renderer, RendererProps} from '../factory'; import { Renderer, RendererProps } from '../factory';
import cx from 'classnames'; import { Collapse as BasicCollapse } from '../components/Collapse';
import {Collapse as BasicCollapse} from 'react-bootstrap';
export interface CollapseProps extends RendererProps { export interface CollapseProps extends RendererProps {
title?: string; // 标题 title?: string; // 标题
@ -81,8 +80,6 @@ export default class Collapse extends React.Component<CollapseProps, CollapseSta
collapsable, collapsable,
} = this.props; } = this.props;
// todo 换掉 bootstrap 的 collapse
return ( return (
<WrapperComponent <WrapperComponent
className={cx( className={cx(
@ -102,7 +99,7 @@ export default class Collapse extends React.Component<CollapseProps, CollapseSta
</HeadingComponent> </HeadingComponent>
) : null} ) : null}
<BasicCollapse in={collapsable ? !this.state.collapsed : true}> <BasicCollapse show={collapsable ? !this.state.collapsed : true} classnames={cx} classPrefix={ns}>
<div className={cx(`Collapse-body`, bodyClassName)}> <div className={cx(`Collapse-body`, bodyClassName)}>
{children {children
? typeof children === 'function' ? typeof children === 'function'

View File

@ -11,7 +11,6 @@ import {
} from './Item'; } from './Item';
import pick = require("lodash/pick"); import pick = require("lodash/pick");
import React from 'react'; import React from 'react';
import { Row, Col } from "react-bootstrap";
import cx from 'classnames'; import cx from 'classnames';
export interface GridProps extends FormControlProps {}; export interface GridProps extends FormControlProps {};

View File

@ -1,14 +1,19 @@
import React from 'react'; import React from 'react';
import {Renderer, RendererProps} from '../factory'; import {Renderer, RendererProps} from '../factory';
import {ServiceStore, IServiceStore} from '../store/service'; import { Schema } from '../types';
import {Api, SchemaNode, Schema, Action} from '../types'; import { evalExpression } from '../utils/tpl';
import {filter, evalExpression} from '../utils/tpl'; import Transition, {ENTERED, ENTERING} from 'react-transition-group/Transition';
import {Tabs as BsTabs, TabContainer, TabContent, TabPane, NavItem, Nav, Tab} from 'react-bootstrap';
import cx = require('classnames');
import find = require('lodash/find'); import find = require('lodash/find');
import {isVisible} from '../utils/helper'; import { isVisible } from '../utils/helper';
import findIndex = require('lodash/findIndex'); import findIndex = require('lodash/findIndex');
const transitionStyles: {
[propName: string]: string;
} = {
[ENTERING]: 'in',
[ENTERED]: 'in'
};
export type TabProps = Schema & { export type TabProps = Schema & {
title?: string; // 标题 title?: string; // 标题
icon?: string; icon?: string;
@ -30,9 +35,9 @@ export interface TabsState {
prevKey: any; prevKey: any;
} }
let tabCount = 0;
export default class Tabs extends React.Component<TabsProps, TabsState> { export default class Tabs extends React.Component<TabsProps, TabsState> {
wrapperRef: React.RefObject<HTMLDivElement> = React.createRef();
static defaultProps: Partial<TabsProps> = { static defaultProps: Partial<TabsProps> = {
className: '', className: '',
mode: '', mode: '',
@ -40,7 +45,6 @@ export default class Tabs extends React.Component<TabsProps, TabsState> {
unmountOnExit: false, unmountOnExit: false,
}; };
id = '' + tabCount++;
constructor(props: TabsProps) { constructor(props: TabsProps) {
super(props); super(props);
@ -155,7 +159,7 @@ export default class Tabs extends React.Component<TabsProps, TabsState> {
// 是 hash需要更新到地址栏 // 是 hash需要更新到地址栏
if (typeof key === 'string' && env) { if (typeof key === 'string' && env) {
env.updateLocation(`#${key}`); env.updateLocation(`#${key}`);
} else if (typeof this.state.prevKey === 'string' && env) { } else if (typeof this.state.activeKey === 'string' && env) {
env.updateLocation(`#`); env.updateLocation(`#`);
} }
@ -207,8 +211,7 @@ export default class Tabs extends React.Component<TabsProps, TabsState> {
const mode = tabsMode || dMode; const mode = tabsMode || dMode;
return ( return (
<TabContainer <div
id={this.id}
className={cx( className={cx(
`Tabs`, `Tabs`,
{ {
@ -216,49 +219,63 @@ export default class Tabs extends React.Component<TabsProps, TabsState> {
}, },
className className
)} )}
activeKey={this.state.activeKey}
onSelect={this.handleSelect}
> >
<div> <ul className={cx('Tabs-links')} role="tablist">
<Nav className={cx('Tabs-links')} role="tablist">
{tabs.map((tab, index) => isVisible(tab, data) ? ( {tabs.map((tab, index) => isVisible(tab, data) ? (
<NavItem <li
className={cx('Tabs-link')} className={cx(
'Tabs-link',
this.state.activeKey === tab.hash || this.state.activeKey === index ? 'active' : '',
tab.disabled || (tab.disabledOn && evalExpression(tab.disabledOn, data)) ? 'disabled' : ''
)}
key={index} key={index}
eventKey={tab.hash || index} onClick={() => tab.disabled || (tab.disabledOn && evalExpression(tab.disabledOn, data)) ? '' : this.handleSelect(tab.hash || index)}
disabled={tab.disabled || (tab.disabledOn && evalExpression(tab.disabledOn, data))}
> >
{tab.icon ? ( {tab.icon ? (
<div> <div>
<i className={tab.icon} /> {tab.title} <i className={tab.icon} /><a>{tab.title}</a>
</div> </div>
) : ( ) : (
tab.title <a>{tab.title}</a>
)} )}
</NavItem> </li>
) : null)} ) : null)}
</Nav> </ul>
<TabContent <div
className={cx('Tabs-content', contentClassName)} ref={this.wrapperRef}
mountOnEnter={mountOnEnter} className={cx('Tabs-content', contentClassName, 'tab-content')}
unmountOnExit={unmountOnExit}
> >
{tabs.map((tab, index) => isVisible(tab, data) ? ( {tabs.map((tab, index) => isVisible(tab, data) ? (
<TabPane <Transition
key={index} in={this.state.activeKey === tab.hash || this.state.activeKey === index ? true : false}
eventKey={tab.hash || index}
mountOnEnter={mountOnEnter} mountOnEnter={mountOnEnter}
unmountOnExit={typeof tab.reload === 'boolean' ? tab.reload : tab.unmountOnExit} unmountOnExit={unmountOnExit}
timeout={500}
key={index}
> >
{(status:string) => {
if (status === ENTERING) {
this.wrapperRef.current && this.wrapperRef.current.childNodes.forEach((item:HTMLElement) => item.offsetHeight);
}
return (
<div className={cx(
transitionStyles[status],
this.state.activeKey === tab.hash || this.state.activeKey === index ? 'active' : '',
'tab-pane',
'fade'
)}>
{tabRender {tabRender
? tabRender(tab, this.props) ? tabRender(tab, this.props)
: render(`tab/${index}`, tab.tab || tab.body || '')} : render(`tab/${index}`, tab.tab || tab.body || '')}
</TabPane>
) : null)}
</TabContent>
</div> </div>
</TabContainer> )
}}
</Transition>
) : null)
}
</div>
</div>
); );
} }
} }