let _ultra, A = props => <a.link {...props} /> A.defaultProps = {createElement: React.createElement, getUltra: () => _ultra} let createMatch = select => { let transform = ({values: [year, make, vid], prefix, pValues}) => Object.assign({year, make, vid}, prefix && {curr: pValues[0].split(',')}) let specSelect = spec('/', '/:year', '/:year/:make', '/:year/:make/:vid')( pipe(transform, select) ) let currCheck = check(':curr')(/^\$(,€)?$|^€(,\$)?$/) let addCurrency = ({qs, path}) => appendPath(parseQS(qs, ['curr']), path) return [ prefixMatch(':curr', match(specSelect, currCheck), addCurrency), match(specSelect) ] } class App extends Component { constructor(props) { super(props) this.state = {} this.matchers = createMatch(this.setState.bind(this)) } componentDidMount() { _ultra = container(this.matchers, null, null, false) } componentWillUnmount() { _ultra.stop() } render() { let values = this.state return ( <div> <header> <SelectCurrency {...values} /> </header> <div id="main"> <nav> {Nav(values)} </nav> <article> <SelectVehicle {...values} /> {values.vid && <Price {...values} />} </article> </div> </div> ) } } let SelectCurrency = ({curr}) => { let encoded = [encodeURIComponent('$'), encodeURIComponent('€')] let hrefUSD = `${location.pathname}?curr=${encoded[0]}` let hrefEUR = `${location.pathname}?curr=${encoded[1]}` let hrefBoth = `${location.pathname}?curr=${encoded[0]}&curr=${encoded[1]}` let style = key => (curr && curr.includes(key) ? {border: 'solid'} : null) return ( <ul key="currency" style={{float: 'right'}} className="flat"> <li> <A href={hrefUSD} retain="" style={style('$')}> usd </A> </li> <li> <A href={hrefEUR} retain="" style={style('€')}> eur </A> </li> <li> <A href={hrefBoth} retain=""> both </A> </li> </ul> ) } let Price = ({vid, curr}) => { let [i, j = i] = (curr || ['$']).map(c => ['$', '€'].indexOf(c)) let price = _priceData[vid].slice(i, j + 1) return ( <ul key="price"> <li> <em> {price.toString()} </em> </li> </ul> ) } let Items = ({data, selected, hrefPrefix = ''}) => { let style = key => (selected === key ? {border: 'solid'} : null) return Object.keys(data).map(val => <li key={val}> <A href={`${hrefPrefix}/${val}`} style={style(val)} retain="qs"> {typeof data[val] === 'string' ? data[val] : val} </A> </li> ) } let Nav = ({vid}) => { let models = Object.keys(_data).map(year => Object.keys(_data[year]).map(make => Items({ data: _data[year][make], selected: vid, hrefPrefix: `/${year}/${make}` }) ) ) return ( <ul key="nav"> {models} </ul> ) } let SelectVehicle = ({year, make, vid}) => { return ( <ul key="vehicle"> {Items({data: _data, selected: year})} {year ? <ul key="make"> <MakeModel year={year} make={make} vid={vid} /> </ul> : null} </ul> ) } let MakeModel = ({year, make, vid}) => { let makes = _data[year] return ( <ul key="make"> {Items({data: makes, selected: make, hrefPrefix: `/${year}`})} {make ? <Model year={year} make={make} vid={vid} /> : null} </ul> ) } let Model = ({year, make, vid}) => { let models = _data[year][make] return ( <ul key="model"> {Items({data: models, selected: vid, hrefPrefix: `/${year}/${make}`})} </ul> ) } render(<App />, document.getElementById('root'))
<a href="https://github.com/gt3/ultra-react/tree/master/examples/01.carshop" target=_blank>source</a> <div id="root"></div> <script> var { Component, createElement } = React var { render } = ReactDOM var { a, spec, check, match, prefixMatch, container, appendPath, parseQS } = ultra function pipe(...fns) { function invoke(v) { return fns.reduce((acc, fn) => (fn ? fn.call(this, acc) : acc), v) } return invoke } var _data = { 2017: { acura: { nsx: "NSX" }, bmw: { bm5: "M5" }, porsche: { "607": "911 Turbo S 607", "3rs": "GT3 RS" } }, 2018: { audi: { aa8: "A8", sq5: "SQ5" }, "land rover": { rrv: "RR Velar" } } } var _priceData = { bm5: ["$77,000", "€77,009"], nsx: ["$156,000", "€156,009"], "607": ["$109,000", "€109,009"], "3rs": ["$200,000", "€200,009"], aa8: ["$85,000", "€85,009"], sq5: ["$80,000", "€80,009"], rrv: ["$70,000", "€70,009"] } </script>