lodash-es#clone TypeScript Examples

The following examples show how to use lodash-es#clone. You can vote up the ones you like or vote down the ones you don't like, and go to the original project or source file by following the links above each example. You may check out the related API usage on the sidebar.
Example #1
Source File: Cascader.tsx    From UUI with MIT License 6 votes vote down vote up
function searchInOptions(q: string, options: CascaderOption[], predicate?: CascaderFeatureProps['onSearch']) {
  const current: CascaderOption[] = []
  const flatOptions: CascaderOption[][] = []
  const initialOption: CascaderOption = {
    label: '', value: '',
    children: options
  }
  const backtracking = (current: CascaderOption[], flatOptions: CascaderOption[][], option: CascaderOption) => {
    if (!option.children) {
      const searched = current.some((i) => !!(i as any)['matched'])
      if (searched) flatOptions.push(clone(current.map((i) => {
        delete (i as any)['matched']
        return i
      })))
      return
    }
    for (const child of option.children) {
      (child as any)['matched'] = (() => { return predicate ? predicate(child, q) : child.label.includes(q) })()
      current.push(child)
      backtracking(current, flatOptions, child)
      current.pop()
    }
  }
  backtracking(current, flatOptions, initialOption)

  return flatOptions
}
Example #2
Source File: actions.ts    From github-deploy-center with MIT License 6 votes vote down vote up
editApplication = ({ state }: Context) => {
  state.editApplicationDialog = createApplicationDialogState()
  if (state.selectedApplication) {
    state.editApplicationDialog.repo = clone(state.selectedApplication.repo)
    state.editApplicationDialog.name = state.selectedApplication.name
    state.editApplicationDialog.releaseFilter =
      state.selectedApplication.releaseFilter
  }
}
Example #3
Source File: actions.ts    From github-deploy-center with MIT License 6 votes vote down vote up
saveApplication = (
  { state }: Context,
  {
    repo,
    name,
    releaseFilter,
  }: {
    repo: RepoModel
    name: string
    releaseFilter: string
  }
) => {
  if (!state.editApplicationDialog) return
  const id = state.selectedApplicationId
  if (
    some(
      state.applicationsById,
      (app) => app.id !== id && app.repo.id === repo.id && app.name === name
    )
  ) {
    state.editApplicationDialog.warning =
      'App with same name and repo already exists!'
    return
  }

  state.applicationsById[id].repo = clone(repo)
  state.applicationsById[id].name = name
  state.applicationsById[id].releaseFilter = releaseFilter
  delete state.editApplicationDialog
}
Example #4
Source File: compileProps.ts    From UUI with MIT License 5 votes vote down vote up
export function compileProps(props: any, ref?: any): any {
  const compiledProps = clone(props)
  if (!compiledProps.customize) {
    compiledProps.customize = {}
  }

  const rootCustomizeProps: any = (compiledProps.customize as any)['Root'] || {};
  /**
   * Convenience props: className, style
   * `className` will be injected into customize.Root { extendClassName: ... }
   * `style` will be injected into customize.Root { extendStyle: ... }
   * `id` will be injected into customize.Root { overrideId: ... }
   * `data-*` will be injected into customize.Root { dataAttributes: ... }
   * `aria-*` will be injected into customize.Root { ariaAttributes: ... }
   */
  if (compiledProps.className) rootCustomizeProps.extendClassName = classNames(compiledProps.className, rootCustomizeProps.extendClassName);
  if (compiledProps.style) rootCustomizeProps.extendStyle = Object.assign(compiledProps.style, rootCustomizeProps.extendStyle);
  if (compiledProps.id) rootCustomizeProps.overrideId = compiledProps.id;
  if (ref) rootCustomizeProps.ref = ref;

  let dataAttributes = pickBy(compiledProps, (v, k) => k.startsWith('data-'))
  dataAttributes = mapKeys(dataAttributes, (v, k) => k.replace('data-', ''))
  if (!isEmpty(dataAttributes)) {
    rootCustomizeProps.dataAttributes = Object.assign(dataAttributes, rootCustomizeProps.dataAttributes);
  }

  let ariaAttributes = pickBy(compiledProps, (v, k) => k.startsWith('aria-'))
  ariaAttributes = mapKeys(ariaAttributes, (v, k) => k.replace('aria-', ''))
  if (!isEmpty(ariaAttributes)) {
    rootCustomizeProps.ariaAttributes = Object.assign(ariaAttributes, rootCustomizeProps.ariaAttributes);
  }

  /**
   * set undefined if customize is empty
   */

  if (!isEmpty(rootCustomizeProps)) {
    (compiledProps.customize as any)['Root'] = rootCustomizeProps;
  }
  if (isEmpty(compiledProps.customize)) {
    compiledProps.customize = undefined;
  }

  compiledProps.ref = ref;

  return compiledProps
}
Example #5
Source File: useCacheRender.ts    From UUI with MIT License 5 votes vote down vote up
export function useArrayCacheRender<T>(
  data: T[],
  render: (data: T) => React.ReactNode,
  options: {
    id: (i: T) => string;
    comparator?: (previous: T, current: T) => boolean;
  },
) {
  const [list, setList] = useState<{
    id: string;
    rendered: React.ReactNode;
  }[]>([])
  const previous = usePrevious<T[]>(data) as T[]
  const current = data

  useEffect(() => {
    const isSameOne = (i: T, j: T) => options.id(i) === options.id(j)
    const intersected = intersectionWith(previous, current, isSameOne)
    const removing = xorWith(previous, intersected, isSameOne)
    const adding = xorWith(current, intersected, isSameOne)
    const updating = intersected.filter((i) => {
      const p = previous.find((j) => options.id(i) === options.id(j))
      const c = current.find((j) => options.id(i) === options.id(j))
      if (!p) return false
      if (!c) return false

      return options.comparator ? options.comparator(c, p) : !isEqual(c, p)
    })

    const newList = clone(list)

    for (const i of removing) {
      remove(newList, (r) => r.id === options.id(i))
    }
    for (const i of updating) {
      const index = list.findIndex((r) => r.id === options.id(i))
      const c = current.find((c) => options.id(c) === options.id(i))
      if (index > -1 && c) newList[index] = { id: options.id(c), rendered: render(c) }
    }
    for (const i of adding) {
      newList.push({ id: options.id(i), rendered: render(i) })
    }

    setList(newList)
  // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [previous, current])

  const rendered = useMemo(() => {
    return list.map((i) => i.rendered)
  }, [list])

  return rendered
}
Example #6
Source File: actions.ts    From github-deploy-center with MIT License 5 votes vote down vote up
showNewApplicationModal = ({ state }: Context) => {
  state.newApplicationDialog = createApplicationDialogState()

  if (state.selectedApplication) {
    state.newApplicationDialog.repo = clone(state.selectedApplication.repo)
  }
}
Example #7
Source File: actions.ts    From github-deploy-center with MIT License 5 votes vote down vote up
editDeployment = ({ state }: Context) => {
  const deploySettings = state.selectedApplication?.deploySettings
  if (DeployWorkflowCodec.is(deploySettings))
    state.deploymentDialog = clone(deploySettings)
}
Example #8
Source File: actions.ts    From github-deploy-center with MIT License 5 votes vote down vote up
saveDeployment = ({ state }: Context) => {
  if (state.selectedApplication && state.deploymentDialog) {
    state.selectedApplication.deploySettings = clone(state.deploymentDialog)
  }
  delete state.deploymentDialog
}
Example #9
Source File: Slider.tsx    From UUI with MIT License 4 votes vote down vote up
Slider = UUIFunctionComponent({
  name: 'Slider',
  nodes: {
    Root: 'div',
    Container: 'div',
    ActiveLine: 'div',
    InactiveLine: 'div',
    Thumb: 'div',
    Remark: 'div',
    RemarkLabel: 'div',
  },
  propTypes: SliderPropTypes,
}, (props: SliderFeatureProps, { nodes, NodeDataProps }) => {
  const { Root, Container, ActiveLine, InactiveLine, Thumb, Remark, RemarkLabel } = nodes

  const finalProps = {
    remarks: props.remarks || [],
  }

  /**
   * Due to Slider supports the selection of a value or a range of values,
   * a unified interface is needed to handle what type of data the component should return.
   */
  const finalValue = useMemo(() => {
    return [
      typeof props.value === 'number' ? props.min : props.value[0],
      typeof props.value === 'number' ? props.value : props.value[1],
    ] as const
  }, [props.min, props.value])
  const onFinalChange = useCallback((value: [number, number]) => {
    const newValue: [number, number] = [Number(value[0].toFixed(8)), Number(value[1].toFixed(8))]
    if (typeof props.value === 'number') {
      props.onChange.call(undefined, newValue[1])
    } else {
      props.onChange.call(undefined, newValue)
    }
  }, [props.value, props.onChange])

  /**
   * Handle thumbs position
   */
  const [thumbDragging, setThumbDragging] = useState<0 | 1 | null>(null)
  const [finalPosition, setFinalPosition] = useState<[number, number]>([
    (finalValue[0]-props.min) / (props.max-props.min),
    (finalValue[1]-props.min) / (props.max-props.min),
  ])
  useEffect(() => {
    setFinalPosition([
      (finalValue[0]-props.min) / (props.max-props.min),
      (finalValue[1]-props.min) / (props.max-props.min),
    ])
  }, [finalValue, props.min, props.max])
  const containerRef = useRef<any>()
  const getPositionFromEvent = (event: MouseEvent | TouchEvent) => {
    if (!containerRef.current) return null
    const containerRect = containerRef.current.getBoundingClientRect()
    const leadingPosition = props.vertical ? containerRect.bottom : containerRect.left
    const trailingPosition = props.vertical ? containerRect.top : containerRect.right

    const currentPosition = (() => {
      switch (event.type) {
        case 'mousedown':
        case 'mousemove':
        case 'click':
            return props.vertical ? (event as MouseEvent).clientY : (event as MouseEvent).clientX
        case 'touchstart':
        case 'touchmove':
          return props.vertical ? (event as TouchEvent).touches[0].clientY :(event as TouchEvent).touches[0].clientX
        default:
          return null
      }
    })();
    if (!currentPosition) return null
    let newPosition = (currentPosition - leadingPosition) / (trailingPosition - leadingPosition)
    newPosition = clamp(newPosition, 0.00, 1.00)
    return newPosition
  }

  const onEventPositionChange = (position: number, thumbIndex: 0 | 1) => {
    const newValue = Math.round((props.max-props.min) / props.step * position) * props.step + props.min
    setFinalPosition((value) => {
      value[thumbIndex] = position
      return value
    })
    if (newValue !== props.value) {
      const newFinalValue: [number, number] = [finalValue[0], finalValue[1]]
      newFinalValue[thumbIndex] = newValue
      onFinalChange(newFinalValue)
    }
  }

  const onMouseDownOrTouchStart = (event: React.MouseEvent<HTMLDivElement, MouseEvent> | React.TouchEvent<HTMLDivElement>) => {
    if (props.disabled) return;
    const newPosition = getPositionFromEvent(event as any)
    if (!newPosition) return;

    const targetIndex = isArray(props.value)
      ? (Math.abs(finalPosition[0] - newPosition) < Math.abs(finalPosition[1] - newPosition) ? 0 : 1)
      : 1;
    !props.disabled && setThumbDragging(targetIndex)

    onEventPositionChange(newPosition, targetIndex)
  }
  const onMouseUpOrTouchEnd = () => { !props.disabled && setThumbDragging(null) }
  const onMouseOrTouchMove = (event: MouseEvent | TouchEvent) => {
    if (props.disabled) return;
    if (thumbDragging === null) return;
    const newPosition = getPositionFromEvent(event)
    if (newPosition === null) return;

    onEventPositionChange(newPosition, thumbDragging)

  }
  useEvent('mousemove', onMouseOrTouchMove as any, window, { capture: !props.disabled && !!thumbDragging })
  useEvent('touchmove', onMouseOrTouchMove as any, window, { capture: !props.disabled && !!thumbDragging })
  useEvent('mouseup', onMouseUpOrTouchEnd as any, window, { capture: !props.disabled && !!thumbDragging })
  useEvent('touchend', onMouseUpOrTouchEnd as any, window, { capture: !props.disabled && !!thumbDragging })

  /**
   * Calculate the position and size of thumbs, remarks and lines.
   */
  const styles = useMemo(() => {
    const sortPosition = clone(finalPosition).sort()
    switch (props.vertical) {
      case false:
      case undefined:
        return {
          LeadingInactiveLine: {
            width: toPercentage(sortPosition[0]),
            display: typeof props.value === 'number' ? 'none' : undefined,
          },
          ActiveLine: {
            width: toPercentage(sortPosition[1] - sortPosition[0]),
          },
          TrailingInactiveLine: {
            width: toPercentage(1 - sortPosition[1]),
          },
          LeadingThumb: {
            left: toPercentage(finalPosition[0]),
            display: typeof props.value === 'number' ? 'none' : undefined,
            transform: 'translateX(-50%)',
          },
          TrailingThumb: {
            left: toPercentage(finalPosition[1]),
            transform: 'translateX(-50%)',
          },
          Remark: finalProps.remarks.map((remark) => {
            const position = (remark.value - props.min) / (props.max - props.min)
            return {
              left: toPercentage(position),
              transform: 'translateX(-50%)',
            }
          })
        }
      case true:
        return {
          TrailingInactiveLine: {
            height: toPercentage(sortPosition[0]),
            display: typeof props.value === 'number' ? 'none' : undefined,
          },
          ActiveLine: {
            height: toPercentage(sortPosition[1] - sortPosition[0]),
          },
          LeadingInactiveLine: {
            height: toPercentage(1 - sortPosition[1]),
          },
          LeadingThumb: {
            bottom: toPercentage(finalPosition[0]),
            display: typeof props.value === 'number' ? 'none' : undefined,
            transform: 'translateY(50%)',
          },
          TrailingThumb: {
            bottom: toPercentage(finalPosition[1]),
            transform: 'translateY(50%)',
          },
          Remark: finalProps.remarks.map((remark) => {
            const position = (remark.value - props.min) / (props.max - props.min)
            return {
              bottom: toPercentage(position),
              transform: 'translateY(50%)',
            }
          })
        }
    }
  }, [finalPosition, props.value, props.max, props.min, props.vertical, finalProps.remarks])

  const [focusThumbIndex, setFocusThumbIndex] = useState<number | null>(null)

  return (
    <Root
      {...NodeDataProps({
        'disabled': !!props.disabled,
        'vertical': !!props.vertical,
      })}
      onMouseDown={onMouseDownOrTouchStart}
      onTouchStart={onMouseDownOrTouchStart}
      onKeyDown={(event) => {
        switch (event.keyCode) {
          case KeyCode.ArrowLeft:
          case KeyCode.ArrowDown: {
            if (focusThumbIndex !== null) {
              const newValue = Array.from(finalValue) as [number, number];
              newValue[focusThumbIndex] = clamp(newValue[focusThumbIndex] - props.step, props.min, props.max);
              onFinalChange(newValue)
            }
            break
          }
          case KeyCode.ArrowRight:
          case KeyCode.ArrowUp: {
            if (focusThumbIndex !== null) {
              const newValue = Array.from(finalValue) as [number, number];
              newValue[focusThumbIndex] = clamp(newValue[focusThumbIndex] + props.step, props.min, props.max);
              onFinalChange(newValue)
            }
            break
          }
          case KeyCode.PageDown: {
            if (focusThumbIndex !== null) {
              const newValue = Array.from(finalValue) as [number, number];
              newValue[focusThumbIndex] = clamp(newValue[focusThumbIndex] - props.step * 10, props.min, props.max);
              onFinalChange(newValue)
            }
            break
          }
          case KeyCode.PageUp: {
            if (focusThumbIndex !== null) {
              const newValue = Array.from(finalValue) as [number, number];
              newValue[focusThumbIndex] = clamp(newValue[focusThumbIndex] + props.step * 10, props.min, props.max);
              onFinalChange(newValue)
            }
            break
          }
          case KeyCode.Home: {
            if (focusThumbIndex !== null) {
              const newValue = Array.from(finalValue) as [number, number];
              newValue[focusThumbIndex] = props.max;
              onFinalChange(newValue)
            }
            break
          }
          case KeyCode.End: {
            if (focusThumbIndex !== null) {
              const newValue = Array.from(finalValue) as [number, number];
              newValue[focusThumbIndex] = props.min;
              onFinalChange(newValue)
            }
            break
          }
          default:
            // do nothing
        }
      }}
      onFocus={props.onFocus}
      onBlur={props.onBlur}
    >
      <Container ref={containerRef}>
        <InactiveLine style={{ ...styles.LeadingInactiveLine }} />
        <ActiveLine style={{ ...styles.ActiveLine }} />
        <InactiveLine style={{ ...styles.TrailingInactiveLine }} />
        {finalProps.remarks.map((remark, index) => {
          const isActive = inRange(remark.value, finalValue[0], finalValue[1])
          return (
            <Remark
              key={index}
              {...NodeDataProps({
                'active': !!isActive,
              })}
              style={{ ...styles.Remark[index] }}
            >
              <RemarkLabel>{remark.label}</RemarkLabel>
            </Remark>
          )
        })}
        <Thumb
          role="slider"
          aria-orientation={props.vertical ? "vertical" : "horizontal"}
          aria-valuemin={props.min}
          aria-valuemax={props.max}
          aria-valuenow={finalValue[0]}
          aria-valuetext={`${finalValue[0]}`}
          tabIndex={props.disabled ? -1 : 0}
          style={{ ...styles.LeadingThumb }}
          onFocus={() => { setFocusThumbIndex(0) }}
          onBlur={() => { setFocusThumbIndex(null)}}
        />
        <Thumb
          role="slider"
          aria-orientation={props.vertical ? "vertical" : "horizontal"}
          aria-valuemin={props.min}
          aria-valuemax={props.max}
          aria-valuenow={finalValue[1]}
          aria-valuetext={`${finalValue[1]}`}
          tabIndex={props.disabled ? -1 : 0}
          style={{ ...styles.TrailingThumb }}
          onFocus={() => { setFocusThumbIndex(1) }}
          onBlur={() => { setFocusThumbIndex(null)}}
        />

      </Container>
    </Root>
  )
})