GithubHelp home page GithubHelp logo

onmotion / react-tabtab-next Goto Github PK

View Code? Open in Web Editor NEW
17.0 2.0 4.0 6 MB

[TypeScript] A mobile support, draggable, editable and api based Tab for ReactJS

License: MIT License

JavaScript 32.53% TypeScript 66.73% CSS 0.74%
react tabs tabtab draggable tabtab-next typescript sortable closable

react-tabtab-next's Introduction

react-tabtab-next

license npm npm

A mobile support, draggable, editable and api based Tab for ReactJS

(!) This lib based on react-tabtab but refactored using Typescript and replacing some deprecated libs

for build a local playground run

npm run demo

also here Codesandbox playground

Features

  • Mobile supported — Touch support. Easy to use on mobile device
  • Draggable tab — Support drag and drop tab
  • Add & Delete — Tab can be added and deleted
  • Async content — Lazy load panel content
  • Customizable style — Based on styled-components, super easy to customize tab style
  • API based — All actions are controllable
  • ARIA accessible

Table of Contents

Installation

Install it with npm or yarn

npm install @react-tabtab-next/tabtab --save

Then, import the module by module bundler like webpack, browserify

// es6
import { Tabs, DragTabList, PanelList, Panel, ExtraButton } from '@react-tabtab-next/tabtab';

// not using es6
var Tabtab = require('react-tabtab');
var Tabs = Tabtab.Tabs;

Usage

React-tabtab is a tab component with highly customization. You can create a tab in simply setting. You also can create a tab system full with draggable, async loading, close and create button. All the actions are api based. It means there is no state in the component. Developers have full control.

Minimal setup

import React from 'react';
import { Tabs, Panel, Tab, TabList, PanelList } from '@react-tabtab-next/tabtab';

export const Example = () => {
    return (
        <Tabs>
            <TabList>
                <Tab>Tab1</Tab>
                <Tab>Tab2</Tab>
            </TabList>
            <PanelList>
                <Panel>Content1</Panel>
                <Panel>Content2</Panel>
            </PanelList>
        </Tabs>
    );
};

It's simple to use. Zero configuration!

Draggable tab

import React, { Component } from 'react';
import { Tabs, DragTabList, PanelList, Panel, Tab, helpers } from '@react-tabtab-next/tabtab';

const makeData = (number, titlePrefix = 'Tab') => {
    const data = [];
    for (let i = 0; i < number; i++) {
        data.push({
            title: `${titlePrefix} ${i}`,
            content: <div>Content {i}</div>,
        });
    }
    return data;
};

export default class Drag extends Component {
    constructor(props) {
        super(props);
        this.handleTabChange = this.handleTabChange.bind(this);
        this.handleTabSequenceChange = this.handleTabSequenceChange.bind(this);
        const tabs = makeData(10, 'Some Tab');
        this.state = {
            activeIndex: 0,
            tabs,
        };
    }

    handleTabChange(index) {
        this.setState({ activeIndex: index });
    }

    handleTabSequenceChange({ oldIndex, newIndex }) {
        const { tabs } = this.state;
        const updateTabs = helpers.simpleSwitch(tabs, oldIndex, newIndex);
        this.setState({ tabs: updateTabs, activeIndex: newIndex });
    }

    render() {
        const { tabs, activeIndex } = this.state;
        const tabsTemplate = [];
        const panelTemplate = [];
        tabs.forEach((tab, index) => {
            tabsTemplate.push(<Tab key={index}>{tab.title}</Tab>);
            panelTemplate.push(<Panel key={index}>{tab.content}</Panel>);
        });
        return (
            <Tabs
                activeIndex={activeIndex}
                onTabChange={this.handleTabChange}
                onTabSequenceChange={this.handleTabSequenceChange}
                customStyle={this.props.customStyle}
            >
                <DragTabList>{tabsTemplate}</DragTabList>
                <PanelList>{panelTemplate}</PanelList>
            </Tabs>
        );
    }
}

ReactDOM.render(<Drag />, document.getElementById('root'));

Based on above example, the different to implement normal tab or drag tab is using different wrapper and child.

And all the actions are controllable. You can customize your switch action. But if you don't want to write customized switch logic, you can directly use import {simpleSwitch} from 'react-tabtab/lib/helpers/move' this built-in function.

normal tab

<Tabs>
    <TabList>
        <Tab>Tab1</Tab>
        <Tab>Tab2</Tab>
    </TabList>
    <PanelList>
        <Panel>Content1</Panel>
        <Panel>Content2</Panel>
    </PanelList>
</Tabs>

Sortable tabs (+ ExtraButton)

<Tabs
    // customStyle={md}
    // activeIndex={activeTab}
    // onTabChange={handleOnTabChange}
    // onTabSequenceChange={handleOnTabSequenceChange}
    ExtraButton={
        <ExtraButton
            onClick={(e) => {
                console.log(e);
            }}
        >
            +
        </ExtraButton>
    }
>
    <DragTabList>
        <Tab>Tab1</Tab>
        <Tab>Tab2</Tab>
    </DragTabList>
    <PanelList>
        <Panel>Content1</Panel>
        <Panel>Content2</Panel>
    </PanelList>
</Tabs>

Async Panel

In some case, if the data is large or we want to save the bandwidth, lazy loading the content is possible solution. You can use AsyncPanel to laze load panel content. Moreover, you can mix lazy load panel with normal panel!

import React from 'react';
import { Tabs, Panel, Tab, TabList, PanelList, AsyncPanel } from '@react-tabtab-next/tabtab';

const AsyncTabsExmple = () => {
    const loadContentFunc = (callback) => {
        setTimeout(() => {
            callback(null, 'some content');
        }, 1000);
    };
    return (
        <Tabs>
            <TabList>
                <Tab>Tab1</Tab>
                <Tab>Tab2</Tab>
            </TabList>
            <PanelList>
                <Panel>Content1</Panel>
                <AsyncPanel
                    loadContent={loadContentFunc}
                    render={(data) => <div>{JSON.stringify(data)}</div>}
                    renderLoading={() => <div>Loading...</div>}
                    cache={true}
                />
            </PanelList>
        </Tabs>
    );
};

export default AsyncTabsExmple;

To implement lazy loading, use AsyncPanel to wrap your panel content. Remember to provide loadContent, render, renderLoading these 3 props.

In loadContent props, both callback and promise type are supported.

If you use callback, remember to call callback when finish async loading.

If you use promise, need to return promise action.

When data is loading, the panel content will show renderLoading component.

After finishing loading data, the panel content will show render component and react-tabtab will pass the loadContent result as first parameter. So you can customize the component of panel content.

Another Examples

More code examples are avalable here.

Components / Api

<Tabs />

<Tabs/> is the main component of react-tabtab. Most of the api is passed from it.

props type default
activeIndex number null control current activeIndex.
You need to pass new activeIndex value if you want to show different tab.
defaultIndex number 0 default selected index if active index is not provided
showModalButton boolean
number
4
  • true: always show button
  • false: always hide button
  • [number]: when number of tab >= [number], show button
showArrowButton auto
boolean
auto
  • auto: detect tab width, if they exceed container, show button
  • true: always show button
  • false: always hide button
  • ExtraButton React Node null customize extra button content, example: `+` button
    onTabChange (tabIndex) => {} null return tabIndex is clicked
    You can use this api with activeIndex. When user click tab, update activeIndex.
    onTabSequenceChange (oldIndex, newIndex) => {} null return changed oldIndex and newIndex value
    With this api, you can do switch tab very easily. Note:This api is only called by <DragTabList/>
    onTabClose (index) => {} null When user click close button , this api will return the clicked close button index.
    customStyle
    {
      TabList: React.Element,
      Tab: React.Element,
      Panel: React.Element,
      ActionButton: React.Element
    }
    theme customized tab style component

    <TabList />

    Use to wrap <Tab/>.

    <DragTabList />

    Use to wrap <Tab/>.

    <Tab />

    Normal Tab. Show the children component on tab.

    props type default
    closable boolean false whether to show close button

    Example

    <Tab>
        <i className="fa fa-map-pin"></i>
        map tab
    </Tab>

    <PanelList/ >

    Use to wrap <Panel/>

    <Panel />

    Tab content.

    <AsyncPanel />

    Lazy loading panel content.

    props type default
    loadContent * (cb) => cb(error, data) or
    (cb) => Promise
    null when loadContent finish, call the callback or you can return promise
    render * (data) => Component null when finish loading data, render this component
    renderLoading * () => Component null when it is loading data, render this component
    cache boolean true should cache the data

    Customize style

    react-tabtab-next is based on styled-components. Therefore, it's super easy to customize the tab style.

    Just extend the default component style and pass it to customStyle props.

    Use current style

    Install tabtab themes

    npm install @react-tabtab-next/themes --save

    Available themes: md, bootstrap, bulma

    For example, if you want to use material-design, import the style and pass to customStyle props.

    Example:

    import React, { Component } from 'react';
    import { Tabs, TabList, Tab, PanelList, Panel } from '@react-tabtab-next/tabtab';
    import { md } from '@react-tabtab-next/themes';
    
    export default class Customized extends Component {
        render() {
            return (
                <Tabs customStyle={md}>
                    <TabList>
                        <Tab>Tab1</Tab>
                        <Tab>Tab2</Tab>
                    </TabList>
                    <PanelList>
                        <Panel>Content1</Panel>
                        <Panel>Content2</Panel>
                    </PanelList>
                </Tabs>
            );
        }
    }

    And now your tab is material design style!

    Make your own style

    If current theme doesn't meet your demand, follow this three steps and create a new one.

    • First step: import current style
    import styled from 'styled-components';
    import { styled as styledTabTab } from '@react-tabtab-next/tabtab';
    
    let { TabListStyle, ActionButtonStyle, TabStyle, PanelStyle } = styledTabTab;
    • Second: extend style and export it
    import styled from 'styled-components';
    import { styled as themeStyled } from '@react-tabtab-next/tabtab';
    
    let { TabList, ActionButton, Tab, Panel } = themeStyled;
    
    TabList = styled(TabList)`
        background-color: transparent;
        line-height: 1.2;
        border: 0;
    `;
    
    Tab = styled(Tab)`
        padding: 1px 10px;
        position: relative;
        font-size: 12px;
        text-transform: uppercase;
        border: 0;
        background: transparent;
        ${(props) => {
            return props.active && !props.vertical
                ? `
          border-bottom: 2px solid #ce93d8;
        `
                : null;
        }}
        &:hover .tab-label_close-button {
            opacity: 1;
        }
        &:hover {
            color: unset;
            background: #89898920;
        }
    `;
    
    ActionButton = styled(ActionButton)`
        background-color: transparent;
        border-radius: 0;
        border: none;
        opacity: 0.3;
        transition: opacity 0.2s;
        & svg {
            font-size: 21px;
            padding: 0;
        }
        &:hover {
            opacity: 1;
        }
    `;
    
    Panel = styled(Panel)``;
    
    export { TabList, ActionButton, Tab, Panel };
    • Last: import your style and use it!

    When you finish the new @react-tabtab-next/theme style, feel free to add it to theme/ folder and send PR!

    Development

    npm i
    npm run demo

    or

    yarn install
    yarn demo

    Build the bundle

    npm i

    License

    MIT

    react-tabtab-next's People

    Contributors

    onmotion avatar

    Stargazers

     avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

    Watchers

     avatar  avatar

    react-tabtab-next's Issues

    document is not defined error

    Thank you for putting this package together!

    I was trying to test it out locally, and I got this error:

    Server Error
    ReferenceError: document is not defined
    
    This error happened while generating the page. Any console logs will be displayed in the terminal window.
    Call Stack
    Object.<anonymous>
    file:///home/boghey/dbltime/node_modules/@react-tabtab-next/tabtab/dist/index.js (165:46)
    Module._compile
    node:internal/modules/cjs/loader (1108:14)
    Object.Module._extensions..js
    node:internal/modules/cjs/loader (1137:10)
    Module.load
    node:internal/modules/cjs/loader (973:32)
    Function.Module._load
    node:internal/modules/cjs/loader (813:14)
    Module.require
    node:internal/modules/cjs/loader (997:19)
    require
    node:internal/modules/cjs/helpers (92:18)
    Object.@react-tabtab-next/tabtab
    file:///home/boghey/dbltime/.next/server/pages/index.js (32:18)
    __webpack_require__
    file:///home/boghey/dbltime/.next/server/webpack-runtime.js (33:42)
    eval
    webpack-internal:///./pages/index.tsx (7:83)
    

    Any idea what I'm doing wrong?

    EDIT: Sorry, nothing to do with this package.

    Recommend Projects

    • React photo React

      A declarative, efficient, and flexible JavaScript library for building user interfaces.

    • Vue.js photo Vue.js

      🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

    • Typescript photo Typescript

      TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

    • TensorFlow photo TensorFlow

      An Open Source Machine Learning Framework for Everyone

    • Django photo Django

      The Web framework for perfectionists with deadlines.

    • D3 photo D3

      Bring data to life with SVG, Canvas and HTML. 📊📈🎉

    Recommend Topics

    • javascript

      JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

    • web

      Some thing interesting about web. New door for the world.

    • server

      A server is a program made to process requests and deliver data to clients.

    • Machine learning

      Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

    • Game

      Some thing interesting about game, make everyone happy.

    Recommend Org

    • Facebook photo Facebook

      We are working to build community through open source technology. NB: members must have two-factor auth.

    • Microsoft photo Microsoft

      Open source projects and samples from Microsoft.

    • Google photo Google

      Google ❤️ Open Source for everyone.

    • D3 photo D3

      Data-Driven Documents codes.