TS+react自建组件库 03
KGD的第五个组件-Icon
引用第三方图标库:fontowesome
安装指令:
yarn add @fortawesome/fontawesome-svg-core yarn add @fortawesome/free-solid-svg-icons yarn add @fortawesome/react-fontawesome
引入:
import {FontAwesomeIcon, FontAwesomeIconProps} from '@fortawesome/react-fontawesome' import {library} from '@fortawesome/fontawesome-svg-core' import {fas} from '@fortawesome/free-solid-svg-icons' library.add(fas)
实现:
import {FC} from 'react' import classNames from 'classnames' import {FontAwesomeIcon, FontAwesomeIconProps} from '@fortawesome/react-fontawesome' import {library} from '@fortawesome/fontawesome-svg-core' import {fas} from '@fortawesome/free-solid-svg-icons' library.add(fas) export type ThemeProps = 'success' | 'danger' | 'warning' | 'info' | 'primary' | 'secondary' | 'light' | 'dark' export interface IconProps extends FontAwesomeIconProps { theme ?: ThemeProps } const Icon : FC<IconProps> = (props) => { const {className, theme, ...restProps} = props const classes = classNames('kgd-icon', className, { [`icon-${theme}`] : theme }) return( <FontAwesomeIcon className = {classes} {...restProps} /> ) } export default Icon;
KGD的第六个组件-Transition
引用react库 : react-transition-group
安装指令:
yarn add react-transition-group @types/react-transition-group --save
引入:
import {CSSTransition} from 'react-transition-group' import {CSSTransitionProps} from 'react-transition-group/CSSTransition'
实现:
import {FC} from 'react' import {CSSTransition} from 'react-transition-group' import {CSSTransitionProps} from 'react-transition-group/CSSTransition' type AnimationName = 'zoom-in-top' | 'zoom-in-left' | 'zoom-in-bottom' | 'zoom-in-right' type TransitionProps = CSSTransitionProps & { animation ?: AnimationName } const Transition : FC<TransitionProps> = (props) => { const { classNames, children, animation, ...restProps } = props return( <CSSTransition classNames = {classNames ? classNames : animation} {...restProps} > {children} </CSSTransition> ) } export default Transition
使用storybook
安装指令:
npx sb init
运行:
yarn storybook
组件.stories.tsx编写:
import {FC} from 'react' import { storiesOf } from '@storybook/react' import { action } from '@storybook/addon-actions'
引入全局样式:
//URL:.storybook/preview.js // .storybook/preview.js import { addDecorator } from '@storybook/react'; import { withInfo } from '@storybook/addon-info'; import '../src/styles/index.scss' addDecorator(withInfo);
补全表格样式:
//_infoTable.scss .info-table { border-collapse: separate; tr th, td { padding: 4px; border: 1px solid gray; } width:100%; }
设置实现:
以Tabs为例:
import { storiesOf } from '@storybook/react' import Tabs from './' import TabItem from './TabItem' import Icon from '../Icon' const defaultTabs = () => ( <div style={{ padding: '20px 40px', width: '500px' }} > <Tabs defaultIndex={0} onSelect={function noRefCheck(){}} type="line" > <TabItem label="选项卡一"> this is content one </TabItem> <TabItem label="选项卡二"> this is content two </TabItem> <TabItem label="用户管理"> this is content three </TabItem> </Tabs> </div> ) const CardTabs = () => ( <div style={{ padding: '20px 40px', width: '500px' }} > <Tabs defaultIndex={0} onSelect={function noRefCheck(){}} type="card" > <TabItem label="card1"> this is card one </TabItem> <TabItem label="card2"> this is content two </TabItem> <TabItem disabled label="disabled" > this is content three </TabItem> </Tabs> </div> ) const CustomCardTabs = () => ( <div style={{ padding: '20px 40px', width: '500px' }} > <Tabs defaultIndex={0} onSelect={function noRefCheck(){}} type="card" > <TabItem label={<><Icon icon="exclamation-circle" />{' '}自定义图标</>}> this is card one </TabItem> <TabItem label="tab2"> this is content two </TabItem> </Tabs> </div> ) storiesOf('Tabs 标签页', module) .add('Tabs', defaultTabs) .add('选项卡Tabs', CardTabs) .add('自定义选项卡Tabs', CustomCardTabs)
import { FC, useState, createContext, HTMLAttributes, Children, FunctionComponentElement, cloneElement } from 'react' import classNames from 'classnames' import {TabItemProps} from './TabItem' type tabsType = 'line' | 'card' type SelectCallback = (SelectIndex:number) => void interface BaseTabs { /**当前激活 tab 面板的 index,默认为0 */ defaultIndex ?: number; /**用户自定义选项卡样式类名 */ className ?: string; /**点击 Tab 触发的函数 */ onSelect ?: SelectCallback /**Tabs的样式,两种可选,默认为 line */ type ?: tabsType /**默认打开的Tab */ defaultOpenTabs ?: number[]; } export type TabsProps = BaseTabs & HTMLAttributes<HTMLUListElement> interface ITabsContext { type ?: tabsType; index : number; onSelect ?: SelectCallback; defaultOpenTabs ?: number[]; } export const TabsContext = createContext<ITabsContext>({ index:0, }) /** *选项卡切换组件。 提供平级的区域将大块内容进行收纳和展现,保持界面整洁。 * ### 引用方法 * * ~~~js * import { Tabs } from 'kgd' * ~~~ */ const Tabs : FC<TabsProps> = (props) => { const { className, type, onSelect, defaultIndex, children, defaultOpenTabs } = props; const classes = classNames('kgd-tabs-nav', className, { [`nav-${type}`] : type }) const [currentActive, setActive] = useState(defaultIndex) const [content, setContent] = useState() const [tabsOpen,setTabsopen] = useState(false) const handleClick = (index:number) => { setActive(index) onSelect && onSelect(index) } const passedContext : ITabsContext = { index : currentActive ? currentActive : 0, onSelect: handleClick, type, defaultOpenTabs, } const getContent = (content : any, tabsOpen : boolean) => { return tabsOpen ? ( <div className = 'kgd-tabs-content'> <div className = 'kgd-tab-panel'> {content} </div> </div> ): null } const ChildrenContent = (content : any, tabsOpen : boolean) => { setContent(content) setTabsopen(tabsOpen) } const renderChildren = () => { return Children.map(children,(child, index) => { const childElement = child as FunctionComponentElement<TabItemProps> const { displayName } = childElement.type if(displayName === 'TabsItem') return cloneElement(childElement, { index, ChildrenContent }) else console.error('Warning: Tabs has a child which is not a TabsItem component') }) } return ( <> <ul className={classes} > <TabsContext.Provider value = {passedContext}> {renderChildren()} </TabsContext.Provider> </ul> {getContent(content,tabsOpen)} </> ) } Tabs.defaultProps = { defaultIndex : 0, defaultOpenTabs : [] } export default Tabs;