Skip to content

Commit

Permalink
Allow external window for bezier (channel-io#1764)
Browse files Browse the repository at this point in the history
<!--
  How to write a good PR title:
- Follow [the Conventional Commits
specification](https://www.conventionalcommits.org/en/v1.0.0/).
  - Give as much context as necessary and as little as possible
  - Prefix it with [WIP] while it’s a work in progress
-->

## Self Checklist

- [x] I wrote a PR title in **English** and added an appropriate
**label** to the PR.
- [x] I wrote the commit message in **English** and to follow [**the
Conventional Commits
specification**](https://www.conventionalcommits.org/en/v1.0.0/).
- [x] I [added the
**changeset**](https://github.com/changesets/changesets/blob/main/docs/adding-a-changeset.md)
about the changes that needed to be released. (or didn't have to)
- [ ] I wrote or updated **documentation** related to the changes. (or
didn't have to)
- [ ] I wrote or updated **tests** related to the changes. (or didn't
have to)
- [ ] I tested the changes in various browsers. (or didn't have to)
  - Windows: Chrome, Edge, (Optional) Firefox
  - macOS: Chrome, Edge, Safari, (Optional) Firefox

## Related Issue
<!-- Please link to issue if one exists -->
close channel-io#1763 

## Summary
<!-- Please brief explanation of the changes made -->
- 베지어 provider에 외부 window 객체를 주입할 수 있도록 합니다.

## Details
<!-- Please elaborate description of the changes -->
- WindowContext를 생성하고 베지어에서 사용할 window객체를 관리하도록 합니다.
- BezierProvider를 통해 external window를 WindowContext로 전달할 수 있습니다.
- 기존 utils/dom의 window, document를 사용하던 사용처를 우선으로 마이그레이션 했습니다.(context
value의 window와 docuement를 사용하도록)
- 추후 getRootElement도 마이그레이션되어야 합니다.

### Breaking change? (Yes/No)
<!-- If Yes, please describe the impact and migration path for users -->
no
  • Loading branch information
Tanney-102 authored Nov 29, 2023
1 parent 2cd9fe1 commit 475161b
Show file tree
Hide file tree
Showing 14 changed files with 143 additions and 32 deletions.
22 changes: 22 additions & 0 deletions .changeset/thin-carpets-remain.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
---
"@channel.io/bezier-react": minor
---

Allow external window for bezier

- You can inject window object with WindowProvider.
- example
```ts
<WindowProvider
window={givenExternalWindow ?? window}
document={givenExternalDocument ?? window.document}
>
// ...
</WindowProvider>

// use window in context with useWindow
const { window, document } = useWindow()
```
- BezierProvider includes WindowProvider so that inject external window with BezierProvider.
- WindowProvider also provide getRootElement function that returns window.document.
- Migrate Bezier components to use useWindow instead of functions in utils/dom.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import React, {
import { CancelCircleFilledIcon } from '@channel.io/bezier-icons'
import { v4 as uuid } from 'uuid'

import { window } from '~/src/utils/dom'
import { useWindow } from '~/src/providers/WindowProvider'
import { toString } from '~/src/utils/string'
import {
isArray,
Expand Down Expand Up @@ -80,6 +80,8 @@ function TextFieldComponent({
}: TextFieldProps,
forwardedRef: Ref<TextFieldRef>,
) {
const { window } = useWindow()

const {
disabled,
readOnly,
Expand Down Expand Up @@ -127,14 +129,14 @@ forwardedRef: Ref<TextFieldRef>,
focusTimeout.current = window.setTimeout(() => {
inputRef.current?.focus()
}, 0)
}, [])
}, [window])

const blur = useCallback(() => {
clearTimeout(blurTimeout.current)
blurTimeout.current = window.setTimeout(() => {
inputRef.current?.blur()
}, 0)
}, [])
}, [window])

const setSelectionRange = useCallback((start?: number, end?: number, direction?: SelectionRangeDirections) => {
if (type && [TextFieldType.Number, TextFieldType.Email, TextFieldType.Hidden].includes(type)) { return }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import React, {
useState,
} from 'react'

import { window } from '~/src/utils/dom'
import { useWindow } from '~/src/providers/WindowProvider'

import { type LegacyTooltipProps } from './LegacyTooltip.types'
import { LegacyTooltipPosition } from './LegacyTooltip.types'
Expand Down Expand Up @@ -43,6 +43,8 @@ export const LegacyTooltip = memo(forwardRef(function LegacyTooltip(
}: LegacyTooltipProps,
forwardedRef: Ref<any>,
) {
const { window } = useWindow()

const [show, setShow] = useState(false)
const [didMount, setDidMount] = useState(show)

Expand Down Expand Up @@ -74,6 +76,7 @@ export const LegacyTooltip = memo(forwardRef(function LegacyTooltip(
}, [
delayShow,
disabled,
window,
])

const handleMouseLeave = useCallback(() => {
Expand All @@ -91,6 +94,7 @@ export const LegacyTooltip = memo(forwardRef(function LegacyTooltip(
}, [
delayHide,
disabled,
window,
])

const TooltipComponent = useMemo(() => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ export interface GetTooltipStyle extends Required<Pick<LegacyTooltipOptions, 'pl

export interface GetReplacement extends Required<Pick<LegacyTooltipOptions, 'placement' | 'keepInContainer'>> {
tooltip: HTMLDivElement
rootElement: HTMLElement
}

export enum LegacyTooltipPosition {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import { Typography } from '~/src/foundation'

import useEventHandler from '~/src/hooks/useEventHandler'
import useMergeRefs from '~/src/hooks/useMergeRefs'
import { getRootElement } from '~/src/utils/dom'
import { useWindow } from '~/src/providers/WindowProvider'
import {
isArray,
isEmpty,
Expand Down Expand Up @@ -92,6 +92,8 @@ export const LegacyTooltipContent: React.FC<LegacyTooltipContentProps> = ({
testId,
forwardedRef,
}) => {
const { rootElement } = useWindow()

const tooltipRef = useRef<HTMLDivElement>(null)
const tooltipWrapperRef = useRef<HTMLDivElement>(null)
const mergedRef = useMergeRefs<HTMLDivElement>(tooltipRef, forwardedRef)
Expand All @@ -109,9 +111,11 @@ export const LegacyTooltipContent: React.FC<LegacyTooltipContentProps> = ({
tooltip: tooltipRef.current,
keepInContainer,
placement,
rootElement,
})
setReplacement(newPlacement)
}, [
rootElement,
keepInContainer,
placement,
])
Expand Down Expand Up @@ -159,7 +163,7 @@ export const LegacyTooltipContent: React.FC<LegacyTooltipContentProps> = ({
</EllipsisableContent>
</Content>
</ContentWrapper>,
getRootElement(),
rootElement,
)
)
}
Expand Down
5 changes: 2 additions & 3 deletions packages/bezier-react/src/components/LegacyTooltip/utils.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
import { getRootElement } from '~/src/utils/dom'

import {
type GetReplacement,
type GetTooltipStyle,
Expand All @@ -10,6 +8,7 @@ export function getReplacement({
tooltip,
keepInContainer,
placement,
rootElement,
}: GetReplacement): LegacyTooltipPosition {
if (!keepInContainer) {
return placement
Expand All @@ -27,7 +26,7 @@ export function getReplacement({
height: rootHeight,
top: rootTop,
left: rootLeft,
} = getRootElement().getBoundingClientRect()
} = rootElement.getBoundingClientRect()

const isOverTop = tooltipTop < rootTop
const isOverBottom = tooltipTop + tooltipHeight > rootTop + rootHeight
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import * as DialogPrimitive from '@radix-ui/react-dialog'

import { ZIndex } from '~/src/constants/ZIndex'
import useMergeRefs from '~/src/hooks/useMergeRefs'
import { getRootElement } from '~/src/utils/dom'
import { useWindow } from '~/src/providers/WindowProvider'
import {
cssVarName,
px,
Expand Down Expand Up @@ -38,7 +38,7 @@ const cv = cssVarName('modal')
export const ModalContent = forwardRef(function ModalContent({
children,
style,
container = getRootElement(),
container: givenContainer,
showCloseIcon = false,
preventHideOnOutsideClick = false,
width = 'max-content',
Expand All @@ -47,6 +47,8 @@ export const ModalContent = forwardRef(function ModalContent({
collisionPadding = { top: 40, bottom: 40 },
...rest
}: ModalContentProps, forwardedRef: React.Ref<HTMLDivElement>) {
const { rootElement } = useWindow()
const container = givenContainer ?? rootElement
const [contentContainer, setContentContainer] = useState<HTMLElement>()

const contentRef = useMergeRefs(
Expand Down
12 changes: 6 additions & 6 deletions packages/bezier-react/src/components/Overlay/Overlay.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,7 @@ import ReactDOM from 'react-dom'

import useEventHandler from '~/src/hooks/useEventHandler'
import useMergeRefs from '~/src/hooks/useMergeRefs'
import {
document,
getRootElement,
window,
} from '~/src/utils/dom'
import { useWindow } from '~/src/providers/WindowProvider'
import { noop } from '~/src/utils/function'

import { useModalContainerContext } from '~/src/components/Modals'
Expand Down Expand Up @@ -63,6 +59,9 @@ function Overlay(
}: OverlayProps,
forwardedRef: Ref<HTMLDivElement>,
) {
const { rootElement } = useWindow()
const { window, document } = useWindow()

const [shouldRender, setShouldRender] = useState(false)
const [shouldShow, setShouldShow] = useState(false)

Expand All @@ -75,7 +74,7 @@ function Overlay(
const overlayRef = useRef<HTMLDivElement>(null)
const mergedRef = useMergeRefs<HTMLDivElement>(overlayRef, forwardedRef)

const defaultContainer = getRootElement()
const defaultContainer = rootElement
const modalContainer = useModalContainerContext()

const hasContainer = Boolean(givenContainer || modalContainer)
Expand Down Expand Up @@ -295,6 +294,7 @@ function Overlay(
withTransition,
shouldRender,
shouldShow,
window,
])

if (!shouldRender) { return null }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import React, {
useState,
} from 'react'

import { window } from '~/src/utils/dom'
import { useWindow } from '~/src/providers/WindowProvider'

import { type ToastControllerProps } from './Toast.types'
import {
Expand All @@ -23,6 +23,8 @@ function ToastController({
version = 0,
...props
}: ToastControllerProps) {
const { window } = useWindow()

const [transform, setTransform] = useState(showedToastTranslateXStyle)
const dismissTimer = useRef<ReturnType<Window['setTimeout']>>()

Expand All @@ -35,13 +37,15 @@ function ToastController({
onDismiss,
placement,
transitionDuration,
window,
])

const startDismissTimer = useCallback(() => {
dismissTimer.current = window.setTimeout(handleDismiss, autoDismissTimeout)
}, [
autoDismissTimeout,
handleDismiss,
window,
])

const clearDismissTimer = useCallback(() => {
Expand Down
5 changes: 3 additions & 2 deletions packages/bezier-react/src/components/Toast/ToastProvider.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import {
} from '~/src/foundation'

import useIsMounted from '~/src/hooks/useIsMounted'
import { getRootElement } from '~/src/utils/dom'
import { useWindow } from '~/src/providers/WindowProvider'

import {
ToastPlacement,
Expand All @@ -26,6 +26,7 @@ function ToastProvider({
container: givenContainer,
children = [],
}: ToastProviderProps) {
const { rootElement } = useWindow()
const isMounted = useIsMounted()

const toastContextValue = useToastProviderValues()
Expand All @@ -34,7 +35,7 @@ function ToastProvider({
rightToasts,
dismiss,
} = toastContextValue
const container = givenContainer ?? getRootElement()
const container = givenContainer ?? rootElement

const createContainer = useCallback((placement: ToastPlacement, toasts: ToastType[]) => (
<ToastContainer
Expand Down
5 changes: 3 additions & 2 deletions packages/bezier-react/src/components/Tooltip/Tooltip.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import React, {

import * as TooltipPrimitive from '@radix-ui/react-tooltip'

import { getRootElement } from '~/src/utils/dom'
import { useWindow } from '~/src/providers/WindowProvider'
import { createContext } from '~/src/utils/react'
import {
isBoolean,
Expand Down Expand Up @@ -177,13 +177,14 @@ export const Tooltip = forwardRef<HTMLDivElement, TooltipProps>(function Tooltip
delayHide: delayHideProp,
...rest
}, forwardedRef) {
const { rootElement } = useWindow()
const [show, setShow] = useState<boolean>(defaultShow ?? false)
const timeoutRef = useRef<NodeJS.Timeout>()

const { delayHide: globalDelayHide } = useTooltipGlobalContext('Tooltip')
const delayHide = delayHideProp ?? globalDelayHide

const defaultContainer = getRootElement()
const defaultContainer = rootElement
const container = givenContainer ?? defaultContainer

const shouldBeHidden = useMemo(() => (
Expand Down
1 change: 1 addition & 0 deletions packages/bezier-react/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
/* Provider */
export { default as BezierProvider } from '~/src/providers/BezierProvider'
export { default as WindowProvider, useWindow } from '~/src/providers/WindowProvider'

/* Foundation */
export * from '~/src/foundation'
Expand Down
34 changes: 24 additions & 10 deletions packages/bezier-react/src/providers/BezierProvider.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,30 +9,44 @@ import {
type ThemeVarsAdditionalType,
} from '~/src/foundation'

import {
document as defaultDocument,
window as defaultWindow,
} from '~/src/utils/dom'

import { TooltipProvider } from '~/src/components/Tooltip'

import WindowProvider from './WindowProvider'

interface BezierProviderProps {
foundation: Foundation & GlobalStyleProp
children: React.ReactNode
themeVarsScope?: ThemeVarsAdditionalType['scope']
externalWindow?: Window
}

function BezierProvider({
foundation,
children,
themeVarsScope,
externalWindow,
}: BezierProviderProps) {
return (
<FoundationProvider foundation={foundation}>
<TooltipProvider>
<GlobalStyle foundation={foundation} />
<ThemeVars
foundation={foundation}
scope={themeVarsScope}
/>
{ children }
</TooltipProvider>
</FoundationProvider>
<WindowProvider
window={externalWindow ?? defaultWindow}
document={externalWindow?.document ?? defaultDocument}
>
<FoundationProvider foundation={foundation}>
<TooltipProvider>
<GlobalStyle foundation={foundation} />
<ThemeVars
foundation={foundation}
scope={themeVarsScope}
/>
{ children }
</TooltipProvider>
</FoundationProvider>
</WindowProvider>
)
}

Expand Down
Loading

0 comments on commit 475161b

Please sign in to comment.