mirror of
https://github.com/zhigang1992/react.git
synced 2026-04-28 20:25:29 +08:00
feat: initial
This commit is contained in:
53
components/utils/collections.ts
Normal file
53
components/utils/collections.ts
Normal file
@@ -0,0 +1,53 @@
|
||||
import React, { ReactNode } from 'react'
|
||||
|
||||
export const hasChild = (
|
||||
children: ReactNode | undefined,
|
||||
child: React.ElementType
|
||||
): Boolean => {
|
||||
const types = React.Children.map(children, item => {
|
||||
if (!React.isValidElement(item)) return null
|
||||
return item.type
|
||||
})
|
||||
|
||||
return (types || []).includes(child)
|
||||
}
|
||||
|
||||
export const pickChild = (
|
||||
children: ReactNode | undefined,
|
||||
targetChild: React.ElementType
|
||||
): [ReactNode | undefined, ReactNode | undefined] => {
|
||||
let target: ReactNode[] = []
|
||||
const withoutTargetChildren = React.Children.map(children, item => {
|
||||
if (!React.isValidElement(item)) return null
|
||||
if (item.type === targetChild) {
|
||||
target.push(item)
|
||||
return null
|
||||
}
|
||||
return item
|
||||
})
|
||||
|
||||
const targetChildren = target.length >= 0 ? target : undefined
|
||||
|
||||
return [withoutTargetChildren, targetChildren]
|
||||
}
|
||||
|
||||
export const pickChildByProps = (
|
||||
children: ReactNode | undefined,
|
||||
key: string,
|
||||
value: any,
|
||||
): [ReactNode | undefined, ReactNode | undefined] => {
|
||||
let target: ReactNode[] = []
|
||||
const withoutPropChildren = React.Children.map(children, item => {
|
||||
if (!React.isValidElement(item)) return null
|
||||
if (!item.props) return item
|
||||
if (item.props[key] === value) {
|
||||
target.push(item)
|
||||
return null
|
||||
}
|
||||
return item
|
||||
})
|
||||
|
||||
const targetChildren = target.length >= 0 ? target : undefined
|
||||
|
||||
return [withoutPropChildren, targetChildren]
|
||||
}
|
||||
40
components/utils/prop-types.ts
Normal file
40
components/utils/prop-types.ts
Normal file
@@ -0,0 +1,40 @@
|
||||
|
||||
export const tuple = <T extends string[]>(...args: T) => args
|
||||
|
||||
const buttonTypes = tuple(
|
||||
'default',
|
||||
'secondary',
|
||||
'success',
|
||||
'warning',
|
||||
'error',
|
||||
'abort',
|
||||
)
|
||||
|
||||
const normalSizes = tuple(
|
||||
'mini',
|
||||
'small',
|
||||
'medium',
|
||||
'large',
|
||||
)
|
||||
|
||||
const normalTypes = tuple(
|
||||
'default',
|
||||
'secondary',
|
||||
'success',
|
||||
'warning',
|
||||
'error',
|
||||
)
|
||||
|
||||
const themeTypes = tuple(
|
||||
'dark',
|
||||
'light',
|
||||
)
|
||||
|
||||
export type ButtonTypes = typeof buttonTypes[number]
|
||||
|
||||
export type NormalSizes = typeof normalSizes[number]
|
||||
|
||||
export type NormalTypes = typeof normalTypes[number]
|
||||
|
||||
export type ThemeTypes = typeof themeTypes[number]
|
||||
|
||||
23
components/utils/use-current-state.ts
Normal file
23
components/utils/use-current-state.ts
Normal file
@@ -0,0 +1,23 @@
|
||||
import { Dispatch, MutableRefObject, SetStateAction, useEffect, useRef, useState } from 'react'
|
||||
|
||||
export type CurrentStateType<S> = [
|
||||
S, Dispatch<SetStateAction<S>>, MutableRefObject<S>
|
||||
]
|
||||
|
||||
const useCurrentState = <S,>(initialState: S): CurrentStateType<S> => {
|
||||
const [state, setState] = useState<S>(initialState)
|
||||
const ref = useRef<S>(initialState)
|
||||
|
||||
useEffect(() => {
|
||||
ref.current = state
|
||||
}, [state])
|
||||
|
||||
const setValue = (val: S) => {
|
||||
ref.current = val
|
||||
setState(val)
|
||||
}
|
||||
|
||||
return [state, setValue, ref]
|
||||
}
|
||||
|
||||
export default useCurrentState
|
||||
39
components/utils/use-portal.ts
Normal file
39
components/utils/use-portal.ts
Normal file
@@ -0,0 +1,39 @@
|
||||
import { useEffect, useState } from 'react'
|
||||
import useSSR from '../utils/use-ssr'
|
||||
|
||||
const getId = () => {
|
||||
return Math.random().toString(32).slice(2, 10)
|
||||
}
|
||||
|
||||
const createElement = (id: string): HTMLElement => {
|
||||
const el = document.createElement('div')
|
||||
el.setAttribute('id', id)
|
||||
return el
|
||||
}
|
||||
|
||||
const usePortal = (selectId: string = getId()): Element | null => {
|
||||
const id = `zeit-ui-${selectId}`
|
||||
const { isBrowser } = useSSR()
|
||||
const [elSnapshot, setElSnapshot] = useState<Element | null>(isBrowser ? createElement(id) : null)
|
||||
|
||||
useEffect(() => {
|
||||
const hasElement = document.querySelector(`#${id}`)
|
||||
const el = hasElement || createElement(id)
|
||||
|
||||
if (!hasElement) {
|
||||
document.body.appendChild(el)
|
||||
}
|
||||
setElSnapshot(el)
|
||||
|
||||
return () => {
|
||||
const node = document.getElementById(id)
|
||||
if (node) {
|
||||
// document.body.removeChild(node)
|
||||
}
|
||||
}
|
||||
}, [])
|
||||
|
||||
return elSnapshot
|
||||
}
|
||||
|
||||
export default usePortal
|
||||
20
components/utils/use-ssr.ts
Normal file
20
components/utils/use-ssr.ts
Normal file
@@ -0,0 +1,20 @@
|
||||
|
||||
const isBrowser = (): boolean => {
|
||||
return Boolean(typeof window !== 'undefined' &&
|
||||
window.document &&
|
||||
window.document.createElement)
|
||||
}
|
||||
|
||||
export type SSRState = {
|
||||
isBrowser: boolean
|
||||
isServer: boolean
|
||||
}
|
||||
|
||||
const useSSR = (): SSRState => {
|
||||
return {
|
||||
isBrowser: isBrowser(),
|
||||
isServer: !isBrowser(),
|
||||
}
|
||||
}
|
||||
|
||||
export default useSSR
|
||||
22
components/utils/use-zeit-ui-context.ts
Normal file
22
components/utils/use-zeit-ui-context.ts
Normal file
@@ -0,0 +1,22 @@
|
||||
import React from 'react'
|
||||
import { ToastWithID } from '../toast/toast-container'
|
||||
|
||||
export type UpdateToastsFunction<T> = (fn: (toasts: Array<T>) => Array<T>) => any
|
||||
|
||||
export interface ZeitUiContextParams {
|
||||
toasts: Array<ToastWithID>
|
||||
toastHovering: boolean
|
||||
updateToasts: UpdateToastsFunction<ToastWithID>
|
||||
updateToastHoverStatus: Function
|
||||
}
|
||||
|
||||
const defaultParams: ZeitUiContextParams = {
|
||||
toasts: [],
|
||||
toastHovering: false,
|
||||
updateToasts: t => t,
|
||||
updateToastHoverStatus: () => {}
|
||||
}
|
||||
|
||||
export const ZEITUIContent:React.Context<ZeitUiContextParams> = React.createContext<ZeitUiContextParams>(defaultParams)
|
||||
|
||||
export const useZEITUIContext = (): ZeitUiContextParams => React.useContext<ZeitUiContextParams>(ZEITUIContent)
|
||||
13
components/utils/with-defaults.ts
Normal file
13
components/utils/with-defaults.ts
Normal file
@@ -0,0 +1,13 @@
|
||||
import React from 'react'
|
||||
|
||||
const withDefaults = <P, DP>(
|
||||
component: React.ComponentType<P>,
|
||||
defaultProps: DP,
|
||||
) => {
|
||||
type Props = Partial<DP> & Omit<P, keyof DP>
|
||||
component.defaultProps = defaultProps
|
||||
|
||||
return (component as React.ComponentType<any>) as React.ComponentType<Props>
|
||||
}
|
||||
|
||||
export default withDefaults
|
||||
Reference in New Issue
Block a user