All files / src StackUtils.js

71.05% Statements 27/38
69.44% Branches 25/36
76.92% Functions 10/13
78.79% Lines 26/33
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120                3x             14x 14x 14x                                 42x     65x         3x 50x           3x 32x 32x 45x   32x 32x               3x                                                   3x       26x 54x 127x 54x       73x         54x         32x     19x   54x 54x      
/* @flow */
 
import React from 'react'
import { matchPath } from 'react-router'
import type { Location, MatchPathOptions } from 'react-router'
import type { Route } from './TypeDefinitions'
 
// Test if current stack item should be updated
export const shouldUpdate = (
  currentItem: MatchPathOptions,
  nextItem: MatchPathOptions,
  currentLocation: Location,
  nextLocation: Location,
): boolean => {
  // Get entries and matchs
  const matchCurrentRoute = matchPath(currentLocation.pathname, currentItem)
  const matchNextRoute = matchPath(nextLocation.pathname, nextItem)
  return (
    // Test if pathames are different
    currentLocation.pathname !== nextLocation.pathname &&
    // case 1) basic pathname
    (currentItem.path !== nextItem.path ||
      // case 2) pathname with query params
      // ex: with same path article/:id,
      //     pathname article/2 !== article/3
      (matchCurrentRoute !== null &&
        matchNextRoute !== null &&
        Object.keys(matchCurrentRoute.params).length !== 0 &&
        Object.keys(matchNextRoute.params).length !== 0 &&
        currentLocation.pathname !== nextLocation.pathname))
  )
}
 
// Get stack item from a specific route
export const get = <Item>(items: Array<Item>, route: Route): Item => ({
  ...route,
  ...items.find(item => {
    return item && item.key && route.routeName === item.key
  }),
})
 
// Generate unique key
export const createKey = (route: Route): string => {
  return `${route.key}@@${Math.random()
    .toString(10)
    .slice(1)}`
}
 
// Get current route from a specific history location
export const getRoute = (stack: Array<Object>, location: Location): ?Route => {
  const { pathname } = location
  const item = stack.find(stackItem => {
    return matchPath(pathname, stackItem)
  })
  Iif (!item || !item.key) return null
  return {
    key: createKey(item),
    routeName: item.key,
    match: matchPath(pathname, item),
  }
}
 
// Render a subview with props
export const renderSubView = (render: Function, additionalProps?: * = {}) => (
  ownProps: *,
): React$Element<*> => {
  const props = { ...additionalProps, ...ownProps }
  const {
    cards,
    tabs,
    scene,
    route,
    navigationState: { routes, index },
  } = props
  const item = {
    ...props,
    ...get(cards || tabs, (scene && scene.route) || route || routes[index]),
  }
  return render(
    Object.keys(item).reduce((acc, key) => {
      const value = item[key]
      if (value === undefined) return acc
      return { ...acc, [key]: value }
    }, {}),
    props,
  )
}
 
// Build stack with React elements
export const build = <Item>(
  children: Array<React$Element<Item>>,
  oldBuild?: Array<Item>,
): Array<Item> => {
  return React.Children.toArray(children).reduce((stack, child, index) => {
    const item = Object.keys(child.props).reduce((props, key) => {
      if (key === 'path') {
        return {
          ...props,
          key: child.props[key],
        }
      } else if (
        key === 'render' ||
        key === 'component' ||
        key === 'children'
      ) {
        return {
          ...props,
          [key]:
            oldBuild && oldBuild[index] // $FlowFixMe
              ? oldBuild[index][key]
              : () => React.cloneElement(child),
        }
      }
      return props
    }, child.props)
    Iif (!item.key) return stack
    return [...stack, item]
  }, [])
}