Skip to content

Commit

Permalink
Merge branch 'main' into feat/react/DevMode-svg-logo
Browse files Browse the repository at this point in the history
  • Loading branch information
minsoo-web authored Jan 4, 2024
2 parents 9b3a934 + f56c40e commit cb7e39b
Show file tree
Hide file tree
Showing 11 changed files with 54 additions and 55 deletions.
5 changes: 5 additions & 0 deletions .changeset/nine-rats-yawn.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@suspensive/react": patch
---

fix(react): add OmitKeyOf to remove PropsWithoutChildren, PropsWithoutDevMode
25 changes: 12 additions & 13 deletions packages/react/src/AsyncBoundary.tsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
import { type ComponentRef, forwardRef } from 'react'
import { ErrorBoundary, type ErrorBoundaryProps } from './ErrorBoundary'
import { Suspense, type SuspenseProps } from './Suspense'
import type { PropsWithoutDevMode } from './utility-types'
import type { OmitKeyOf } from './utility-types'

/**
* @deprecated Use SuspenseProps and ErrorBoundaryProps instead
*/
export interface AsyncBoundaryProps
extends Omit<PropsWithoutDevMode<SuspenseProps>, 'fallback'>,
Omit<PropsWithoutDevMode<ErrorBoundaryProps>, 'fallback'> {
extends OmitKeyOf<SuspenseProps, 'fallback' | 'devMode'>,
OmitKeyOf<ErrorBoundaryProps, 'fallback' | 'devMode'> {
pendingFallback?: SuspenseProps['fallback']
rejectedFallback: ErrorBoundaryProps['fallback']
}
Expand Down Expand Up @@ -38,16 +38,15 @@ export const AsyncBoundary = Object.assign(
* @deprecated Use `<Suspense clientOnly />` and `<ErrorBoundary/>` instead
*/
CSROnly: (() => {
const CSROnly = forwardRef<
ComponentRef<typeof ErrorBoundary>,
Omit<AsyncBoundaryProps, keyof Pick<SuspenseProps, 'clientOnly'>>
>(({ pendingFallback, rejectedFallback, children, ...errorBoundaryProps }, resetRef) => (
<ErrorBoundary {...errorBoundaryProps} ref={resetRef} fallback={rejectedFallback}>
<Suspense clientOnly fallback={pendingFallback}>
{children}
</Suspense>
</ErrorBoundary>
))
const CSROnly = forwardRef<ComponentRef<typeof ErrorBoundary>, OmitKeyOf<AsyncBoundaryProps, 'clientOnly'>>(
({ pendingFallback, rejectedFallback, children, ...errorBoundaryProps }, resetRef) => (
<ErrorBoundary {...errorBoundaryProps} ref={resetRef} fallback={rejectedFallback}>
<Suspense clientOnly fallback={pendingFallback}>
{children}
</Suspense>
</ErrorBoundary>
)
)
if (process.env.NODE_ENV !== 'production') {
CSROnly.displayName = 'AsyncBoundary.CSROnly'
}
Expand Down
2 changes: 1 addition & 1 deletion packages/react/src/ErrorBoundary.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ export interface ErrorBoundaryFallbackProps<TError extends Error = Error> {
reset: () => void
}

export interface ErrorBoundaryProps extends PropsWithChildren, PropsWithDevMode<ErrorBoundaryDevModeOptions> {
export interface ErrorBoundaryProps extends PropsWithDevMode<PropsWithChildren, ErrorBoundaryDevModeOptions> {
/**
* an array of elements for the ErrorBoundary to check each render. If any of those elements change between renders, then the ErrorBoundary will reset the state which will re-render the children
*/
Expand Down
10 changes: 3 additions & 7 deletions packages/react/src/Suspense.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
import { Suspense as ReactSuspense, type SuspenseProps as ReactSuspenseProps, useContext } from 'react'
import { SuspenseDefaultPropsContext, useDevModeObserve } from './contexts'
import { useIsClient } from './hooks'
import { type PropsWithDevMode } from './utility-types'
import type { OmitKeyOf, PropsWithDevMode } from './utility-types'
import { noop } from './utils'

const SuspenseClientOnly = (props: ReactSuspenseProps) =>
useIsClient() ? <ReactSuspense {...props} /> : <>{props.fallback}</>

export interface SuspenseProps extends PropsWithDevMode<SuspenseDevModeOptions>, ReactSuspenseProps {
export interface SuspenseProps extends PropsWithDevMode<ReactSuspenseProps, SuspenseDevModeOptions> {
/**
* With clientOnly prop, `<Suspense/>` will return fallback in server but after mount return children in client. Since mount only happens on the client, `<Suspense/>` can be avoid server-side rendering.
* @see https://suspensive.org/docs/react/Suspense#avoid-server-side-rendering-clientonly
Expand Down Expand Up @@ -41,11 +41,7 @@ export const Suspense = Object.assign(
* @deprecated Use `<Suspense clientOnly/>` instead
*/
CSROnly: (() => {
const Suspense = ({
devMode,
children,
fallback,
}: Omit<SuspenseProps, keyof Pick<SuspenseProps, 'clientOnly'>>) => {
const Suspense = ({ devMode, children, fallback }: OmitKeyOf<SuspenseProps, 'clientOnly'>) => {
const defaultProps = useContext(SuspenseDefaultPropsContext)
return (
<SuspenseClientOnly fallback={typeof fallback === 'undefined' ? defaultProps.fallback : fallback}>
Expand Down
9 changes: 4 additions & 5 deletions packages/react/src/contexts/DefaultOptionsContexts.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,15 @@
import { createContext } from 'react'
import { type DelayProps } from '../Delay'
import { type SuspenseProps } from '../Suspense'
import { type PropsWithoutChildren, type PropsWithoutDevMode } from '../utility-types'
import type { DelayProps, SuspenseProps } from '..'
import type { OmitKeyOf } from '../utility-types'

export const DelayDefaultPropsContext = createContext<PropsWithoutDevMode<PropsWithoutChildren<DelayProps>>>({
export const DelayDefaultPropsContext = createContext<OmitKeyOf<DelayProps, 'children'>>({
ms: undefined,
})
if (process.env.NODE_ENV !== 'production') {
DelayDefaultPropsContext.displayName = 'DelayDefaultPropsContext'
}

export const SuspenseDefaultPropsContext = createContext<PropsWithoutDevMode<PropsWithoutChildren<SuspenseProps>>>({
export const SuspenseDefaultPropsContext = createContext<OmitKeyOf<SuspenseProps, 'children' | 'devMode'>>({
fallback: undefined,
clientOnly: undefined,
})
Expand Down
1 change: 1 addition & 0 deletions packages/react/src/utility-types/OmitKeyOf.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export type OmitKeyOf<TObject extends object, TKey extends keyof TObject> = Omit<TObject, TKey>
7 changes: 6 additions & 1 deletion packages/react/src/utility-types/PropsWithDevMode.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,9 @@
export type PropsWithDevMode<TDevModeProps extends Record<string, any>> = {
import type { ComponentProps, ComponentType } from 'react'

export type PropsWithDevMode<
TProps extends ComponentProps<ComponentType>,
TDevModeProps extends Record<string, unknown>,
> = TProps & {
/**
* @experimental This is experimental feature.
*/
Expand Down
3 changes: 0 additions & 3 deletions packages/react/src/utility-types/PropsWithoutChildren.ts

This file was deleted.

3 changes: 0 additions & 3 deletions packages/react/src/utility-types/PropsWithoutDevMode.ts

This file was deleted.

3 changes: 1 addition & 2 deletions packages/react/src/utility-types/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,2 @@
export type { PropsWithoutChildren } from './PropsWithoutChildren'
export type { PropsWithDevMode } from './PropsWithDevMode'
export type { PropsWithoutDevMode } from './PropsWithoutDevMode'
export type { OmitKeyOf } from './OmitKeyOf'
41 changes: 21 additions & 20 deletions packages/react/src/wrap.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { Delay } from './Delay'
import { ErrorBoundary } from './ErrorBoundary'
import { ErrorBoundaryGroup } from './ErrorBoundaryGroup'
import { Suspense } from './Suspense'
import type { PropsWithoutChildren } from './utility-types'
import type { OmitKeyOf } from './utility-types'
import type { AsyncBoundaryProps, DelayProps, ErrorBoundaryGroupProps, ErrorBoundaryProps, SuspenseProps } from '.'

type WrapperItem<
Expand All @@ -14,7 +14,7 @@ type WrapperItem<
| typeof ErrorBoundary
| typeof ErrorBoundaryGroup
| typeof Delay,
> = [TWrapperComponent, PropsWithoutChildren<ComponentProps<TWrapperComponent>>]
> = [TWrapperComponent, OmitKeyOf<ComponentProps<TWrapperComponent>, 'children'>]

type Wrapper =
| WrapperItem<typeof Suspense>
Expand All @@ -25,19 +25,19 @@ type Wrapper =

class WrapWithoutCSROnly {
constructor(private wrappers: Wrapper[]) {}
Suspense = (props: PropsWithoutChildren<ComponentProps<typeof Suspense>> = {}) => {
Suspense = (props: OmitKeyOf<ComponentProps<typeof Suspense>, 'children'> = {}) => {
this.wrappers.unshift([Suspense, props])
return this
}
ErrorBoundary = (props: PropsWithoutChildren<ComponentProps<typeof ErrorBoundary>>) => {
ErrorBoundary = (props: OmitKeyOf<ComponentProps<typeof ErrorBoundary>, 'children'>) => {
this.wrappers.unshift([ErrorBoundary, props])
return this
}
ErrorBoundaryGroup = (props: PropsWithoutChildren<ComponentProps<typeof ErrorBoundaryGroup>> = {}) => {
ErrorBoundaryGroup = (props: OmitKeyOf<ComponentProps<typeof ErrorBoundaryGroup>, 'children'> = {}) => {
this.wrappers.unshift([ErrorBoundaryGroup, props])
return this
}
Delay = (props: PropsWithoutChildren<ComponentProps<typeof Delay>> = {}) => {
Delay = (props: OmitKeyOf<ComponentProps<typeof Delay>, 'children'> = {}) => {
this.wrappers.unshift([Delay, props])
return this
}
Expand Down Expand Up @@ -67,28 +67,29 @@ type Wrap = WrapWithoutCSROnly & {
/**
* @deprecated Use wrap.Suspense({ clientOnly: true }).on instead
*/
CSROnly: (props?: PropsWithoutChildren<ComponentProps<typeof Suspense.CSROnly>>) => Wrap
CSROnly: (props?: OmitKeyOf<ComponentProps<typeof Suspense.CSROnly>, 'children'>) => Wrap
}
}

const createWrap = () => {
const wrappers: Wrapper[] = []
const wrap = new WrapWithoutCSROnly(wrappers) as Wrap
wrap.Suspense.CSROnly = (props: PropsWithoutChildren<ComponentProps<typeof Suspense.CSROnly>> = {}) => {
wrap.Suspense.CSROnly = (props: OmitKeyOf<ComponentProps<typeof Suspense.CSROnly>, 'children'> = {}) => {
wrappers.unshift([Suspense.CSROnly, props])
return wrap
}
return wrap
}

const wrapSuspense = (props: PropsWithoutChildren<ComponentProps<typeof Suspense>> = {}) => createWrap().Suspense(props)
wrapSuspense.CSROnly = (props: PropsWithoutChildren<ComponentProps<typeof Suspense.CSROnly>> = {}) =>
const wrapSuspense = (props: OmitKeyOf<ComponentProps<typeof Suspense>, 'children'> = {}) =>
createWrap().Suspense(props)
wrapSuspense.CSROnly = (props: OmitKeyOf<ComponentProps<typeof Suspense.CSROnly>, 'children'> = {}) =>
createWrap().Suspense.CSROnly(props)
const wrapErrorBoundary = (props: PropsWithoutChildren<ComponentProps<typeof ErrorBoundary>>) =>
const wrapErrorBoundary = (props: OmitKeyOf<ComponentProps<typeof ErrorBoundary>, 'children'>) =>
createWrap().ErrorBoundary(props)
const wrapErrorBoundaryGroup = (props: PropsWithoutChildren<ComponentProps<typeof ErrorBoundaryGroup>>) =>
const wrapErrorBoundaryGroup = (props: OmitKeyOf<ComponentProps<typeof ErrorBoundaryGroup>, 'children'>) =>
createWrap().ErrorBoundaryGroup(props)
const wrapDelay = (props: PropsWithoutChildren<ComponentProps<typeof Delay>> = {}) => createWrap().Delay(props)
const wrapDelay = (props: OmitKeyOf<ComponentProps<typeof Delay>, 'children'> = {}) => createWrap().Delay(props)

export const wrap = {
Suspense: wrapSuspense,
Expand All @@ -103,15 +104,15 @@ export const wrap = {
export const withSuspense = Object.assign(
<TProps extends ComponentProps<ComponentType> = Record<string, never>>(
component: ComponentType<TProps>,
suspenseProps: PropsWithoutChildren<SuspenseProps> = {}
suspenseProps: OmitKeyOf<SuspenseProps, 'children'> = {}
) => wrap.Suspense(suspenseProps).on(component),
{
/**
* @deprecated Use wrap.Suspense({ clientOnly: true }).on instead
*/
CSROnly: <TProps extends ComponentProps<ComponentType> = Record<string, never>>(
component: ComponentType<TProps>,
suspenseProps: PropsWithoutChildren<SuspenseProps> = {}
suspenseProps: OmitKeyOf<SuspenseProps, 'children'> = {}
) => wrap.Suspense.CSROnly(suspenseProps).on(component),
}
)
Expand All @@ -121,23 +122,23 @@ export const withSuspense = Object.assign(
*/
export const withErrorBoundary = <TProps extends ComponentProps<ComponentType> = Record<string, never>>(
component: ComponentType<TProps>,
errorBoundaryProps: PropsWithoutChildren<ErrorBoundaryProps>
errorBoundaryProps: OmitKeyOf<ErrorBoundaryProps, 'children'>
) => wrap.ErrorBoundary(errorBoundaryProps).on(component)

/**
* @deprecated Use wrap.Delay().on instead
*/
export const withDelay = <TProps extends ComponentProps<ComponentType> = Record<string, never>>(
component: ComponentType<TProps>,
delayProps: PropsWithoutChildren<DelayProps> = {}
delayProps: OmitKeyOf<DelayProps, 'children'> = {}
) => wrap.Delay(delayProps).on(component)

/**
* @deprecated Use wrap.ErrorBoundaryGroup().on instead
*/
export const withErrorBoundaryGroup = <TProps extends ComponentProps<ComponentType> = Record<string, never>>(
component: ComponentType<TProps>,
errorBoundaryGroupProps: PropsWithoutChildren<ErrorBoundaryGroupProps> = {}
errorBoundaryGroupProps: OmitKeyOf<ErrorBoundaryGroupProps, 'children'> = {}
) => wrap.ErrorBoundaryGroup(errorBoundaryGroupProps).on(component)

/**
Expand All @@ -146,7 +147,7 @@ export const withErrorBoundaryGroup = <TProps extends ComponentProps<ComponentTy
export const withAsyncBoundary = Object.assign(
<TProps extends ComponentProps<ComponentType> = Record<string, never>>(
Component: ComponentType<TProps>,
asyncBoundaryProps: PropsWithoutChildren<AsyncBoundaryProps>
asyncBoundaryProps: OmitKeyOf<AsyncBoundaryProps, 'children'>
) => {
const Wrapped = (props: TProps) => (
<AsyncBoundary {...asyncBoundaryProps}>
Expand All @@ -167,7 +168,7 @@ export const withAsyncBoundary = Object.assign(
*/
CSROnly: <TProps extends ComponentProps<ComponentType> = Record<string, never>>(
Component: ComponentType<TProps>,
asyncBoundaryProps: PropsWithoutChildren<Omit<AsyncBoundaryProps, keyof Pick<SuspenseProps, 'clientOnly'>>>
asyncBoundaryProps: OmitKeyOf<AsyncBoundaryProps, 'clientOnly' | 'children'>
) => {
const Wrapped = (props: TProps) => (
<AsyncBoundary {...asyncBoundaryProps} clientOnly>
Expand Down

0 comments on commit cb7e39b

Please sign in to comment.