fabiobiondi

Tabbar with Generics & custom prop / keyof

Oct 21st, 2020
416
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. import React, { useEffect, useState } from 'react';
  2. import cn from 'classnames';
  3.  
  4. interface Country {
  5.   id: number;
  6.   xxx: string;
  7.   description: string;
  8. }
  9.  
  10. const countries: Country[] = [
  11.   { id: 1, xxx: 'Japan', description: 'bla bla 1'},
  12.   { id: 2, xxx: 'Italy', description: 'bla bla 2'},
  13.   { id: 3, xxx: 'Spain', description: 'bla bla 3'},
  14. ];
  15.  
  16. export default function App() {
  17.   console.log('App: render')
  18.   const [opened, setOpened] = useState<boolean>(true);
  19.   const [active, setActive] = useState<Country>(countries[2])
  20.   const tabClickHandler = (tab: Country) => {
  21.     console.log(tab);
  22.     setActive(tab);
  23.   }
  24.   const tabClickHandler2 = (tab: Country) => {
  25.     console.log(tab);
  26.   }
  27.   return (
  28.      <div className="container mt-2">
  29.        <button onClick={() => setOpened(true)}>OPEN</button>
  30.        <button onClick={() => setOpened(false)}>CLOSE</button>
  31.        <Panel title="hello" style={{ width: 200}} isOpen={opened} toggle={() => console.log('ciao')}>
  32.          <input type="text"/>
  33.          <input type="text"/>
  34.          <input type="text"/>
  35.        </Panel>
  36.  
  37.        <Tabbar <Country>
  38.          labelField="xxx"
  39.           data={countries} onTabClick={tabClickHandler} active={active}/>
  40.        <Tabbar labelField="xxx" data={countries} onTabClick={tabClickHandler2} />
  41.  
  42.        <img src={'https://maps.googleapis.com/maps/api/staticmap?center=' + active.xxx + '&zoom=5&size=200x100&key=AIzaSyDSBmiSWV4-AfzaTPNSJhu-awtfBNi9o2k'} alt=""/>
  43.        <div>
  44.        {active.description}
  45.        </div>
  46.      {/*  <Tabbar data={....} onTabClick={} active={}></Tabbar>*/}
  47.      </div>
  48.   );
  49. }
  50.  
  51. interface TabbarProps<T> {
  52.   data?: T[];
  53.   active?: T;
  54.   onTabClick: (tab: T) => void;
  55.   labelField: keyof T;
  56. }
  57.  
  58. interface TabbarItemProps {
  59.   id: number;
  60.   [key: string]: any;
  61. }
  62. export const Tabbar = <T extends TabbarItemProps>(props: TabbarProps<T>) => {
  63.   const [tabActive, setTabActive] = useState<any>()
  64.  
  65.   useEffect(() => {
  66.     setTabActive(props.active);
  67.   }, [ props.active])
  68.  
  69.   function tabClickHAndler(item: T) {
  70.     setTabActive(item);
  71.     props.onTabClick(item);
  72.   }
  73.  
  74.   return (
  75.     <ul className="nav nav-tabs">
  76.       {
  77.         props.data?.map((item: T) => {
  78.           const active = item.id === tabActive?.id;
  79.           return <li key={item.id} className="nav-item" onClick={() => tabClickHAndler(item)}>
  80.             <a className={cn('nav-link', { active })} >{item[props.labelField || 'name']}</a>
  81.           </li>
  82.         })
  83.       }
  84.     </ul>
  85.   )
  86. }
  87.  
  88. // PANEL COMPONENT
  89. interface PanelProps {
  90.   title: string;
  91.   isOpen: boolean;
  92.   toggle?: () => void;
  93. }
  94.  
  95. const Panel: React.FC<PanelProps & React.HTMLProps<HTMLDivElement>> = props => {
  96.   const [opened, setOpened] = useState<boolean>(true);
  97.   const { children, title, isOpen, toggle, ...rest} = props;
  98.  
  99.   useEffect(() => {
  100.     setOpened(props.isOpen);
  101.   }, [ props.isOpen])
  102.  
  103.   function toggleHandler() {
  104.     setOpened(!opened);
  105.     if (props.toggle) {
  106.       props.toggle();
  107.     }
  108.   }
  109.  
  110.   return (
  111.     <div className={'card'} {...rest}>
  112.       <div className={'card-header'} onClick={toggleHandler}>{props.title}</div>
  113.       { opened && <div className="card-body">{props.children} </div>}
  114.     </div>
  115.   )
  116. }
  117.  
Add Comment
Please, Sign In to add comment