Skip to content

(test) revert #2204 #2235

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27,090 changes: 16 additions & 27,074 deletions docs/package-lock.json

Large diffs are not rendered by default.

11 changes: 6 additions & 5 deletions src/Autocomplete/AutocompleteInput.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import React, {
ChangeEventHandler,
FocusEventHandler,
KeyboardEventHandler,
MutableRefObject,
useCallback,
useContext,
useEffect,
Expand All @@ -10,7 +11,7 @@ import React, {
import {ForwardRefComponent as PolymorphicForwardRefComponent} from '@radix-ui/react-polymorphic'
import {AutocompleteContext} from './AutocompleteContext'
import TextInput from '../TextInput'
import {useRefObjectAsForwardedRef} from '../hooks/useRefObjectAsForwardedRef'
import {useCombinedRefs} from '../hooks/useCombinedRefs'
import {ComponentProps} from '../utils/types'

type InternalAutocompleteInputProps = {
Expand Down Expand Up @@ -38,7 +39,7 @@ const AutocompleteInput = React.forwardRef(
setShowMenu,
showMenu
} = autocompleteContext
useRefObjectAsForwardedRef(forwardedRef, inputRef)
const combinedInputRef = useCombinedRefs(inputRef, forwardedRef)
const [highlightRemainingText, setHighlightRemainingText] = useState<boolean>(true)

const handleInputFocus: FocusEventHandler<HTMLInputElement> = useCallback(
Expand All @@ -57,12 +58,12 @@ const AutocompleteInput = React.forwardRef(
// this prevents the menu from hiding when the user is clicking an option in the Autoselect.Menu,
// but still hides the menu when the user blurs the input by tabbing out or clicking somewhere else on the page
setTimeout(() => {
if (document.activeElement !== inputRef.current) {
if (document.activeElement !== combinedInputRef.current) {
setShowMenu(false)
}
}, 0)
},
[onBlur, setShowMenu, inputRef]
[onBlur, setShowMenu, combinedInputRef]
)

const handleInputChange: ChangeEventHandler<HTMLInputElement> = useCallback(
Expand Down Expand Up @@ -156,7 +157,7 @@ const AutocompleteInput = React.forwardRef(
onKeyDown={handleInputKeyDown}
onKeyPress={onInputKeyPress}
onKeyUp={handleInputKeyUp}
ref={inputRef}
ref={combinedInputRef as MutableRefObject<HTMLInputElement>}
aria-controls={`${id}-listbox`}
aria-autocomplete="both"
role="combobox"
Expand Down
6 changes: 3 additions & 3 deletions src/Autocomplete/AutocompleteOverlay.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import {useAnchoredPosition} from '../hooks'
import Overlay, {OverlayProps} from '../Overlay'
import {ComponentProps} from '../utils/types'
import {AutocompleteContext} from './AutocompleteContext'
import {useRefObjectAsForwardedRef} from '../hooks/useRefObjectAsForwardedRef'
import {useCombinedRefs} from '../hooks/useCombinedRefs'

type AutocompleteOverlayInternalProps = {
/**
Expand Down Expand Up @@ -39,7 +39,7 @@ function AutocompleteOverlay({
[showMenu, selectedItemLength]
)

useRefObjectAsForwardedRef(scrollContainerRef, floatingElementRef)
const combinedOverlayRef = useCombinedRefs(scrollContainerRef, floatingElementRef)

const closeOptionList = useCallback(() => {
setShowMenu(false)
Expand All @@ -55,7 +55,7 @@ function AutocompleteOverlay({
preventFocusOnOpen={true}
onClickOutside={closeOptionList}
onEscape={closeOptionList}
ref={floatingElementRef as React.RefObject<HTMLDivElement>}
ref={combinedOverlayRef as React.RefObject<HTMLDivElement>}
top={position?.top}
left={position?.left}
visibility={showMenu ? 'visible' : 'hidden'}
Expand Down
15 changes: 15 additions & 0 deletions src/Details/Details.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import React from 'react'
import {Meta} from '@storybook/react'
import Details from './'
import useDetails from '../hooks/useDetails'

export default {
title: 'Details',
component: Details
} as Meta

export const Default = () => {
const {getDetailsProps} = useDetails({closeOnOutsideClick: true})

return <Details {...getDetailsProps()}>This is some content</Details>
}
7 changes: 4 additions & 3 deletions src/Details.tsx → src/Details/Details.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import styled from 'styled-components'
import sx, {SxProp} from './sx'
import {ComponentProps} from './utils/types'
import sx, {SxProp} from '../sx'
import {ComponentProps} from '../utils/types'
import {DetailsProps as GetDetailsProps} from '../hooks/useDetails'

const Details = styled.details<SxProp>`
const Details = styled.details<SxProp & GetDetailsProps>`
& > summary {
list-style: none;
}
Expand Down
4 changes: 4 additions & 0 deletions src/Details/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
import Details from './Details'
export default Details

export * from './Details'
5 changes: 2 additions & 3 deletions src/Dialog.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import useDialog from './hooks/useDialog'
import sx, {SxProp} from './sx'
import Text from './Text'
import {ComponentProps} from './utils/types'
import {useRefObjectAsForwardedRef} from './hooks/useRefObjectAsForwardedRef'
import {useCombinedRefs} from './hooks/useCombinedRefs'

const noop = () => null

Expand Down Expand Up @@ -95,8 +95,7 @@ type InternalDialogProps = {
const Dialog = forwardRef<HTMLDivElement, InternalDialogProps>(
({children, onDismiss = noop, isOpen, initialFocusRef, returnFocusRef, ...props}, forwardedRef) => {
const overlayRef = useRef(null)
const modalRef = useRef<HTMLDivElement>(null)
useRefObjectAsForwardedRef(forwardedRef, modalRef)
const modalRef = useCombinedRefs(forwardedRef)
const closeButtonRef = useRef(null)

const onCloseClick = () => {
Expand Down
6 changes: 3 additions & 3 deletions src/Dialog/Dialog.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import {XIcon} from '@primer/octicons-react'
import {useFocusZone} from '../hooks/useFocusZone'
import {FocusKeys} from '@primer/behaviors'
import Portal from '../Portal'
import {useRefObjectAsForwardedRef} from '../hooks/useRefObjectAsForwardedRef'
import {useCombinedRefs} from '../hooks/useCombinedRefs'
import {useSSRSafeId} from '@react-aria/ssr'

const ANIMATION_DURATION = '200ms'
Expand Down Expand Up @@ -274,7 +274,7 @@ const _Dialog = React.forwardRef<HTMLDivElement, React.PropsWithChildren<DialogP
const defaultedProps = {...props, title, subtitle, role, dialogLabelId, dialogDescriptionId}

const dialogRef = useRef<HTMLDivElement>(null)
useRefObjectAsForwardedRef(forwardedRef, dialogRef)
const combinedRef = useCombinedRefs(dialogRef, forwardedRef)
const backdropRef = useRef<HTMLDivElement>(null)
useFocusTrap({containerRef: dialogRef, restoreFocusOnCleanUp: true, initialFocusRef: autoFocusedFooterButtonRef})

Expand All @@ -297,7 +297,7 @@ const _Dialog = React.forwardRef<HTMLDivElement, React.PropsWithChildren<DialogP
<StyledDialog
width={width}
height={height}
ref={dialogRef}
ref={combinedRef}
role={role}
aria-labelledby={dialogLabelId}
aria-describedby={dialogDescriptionId}
Expand Down
12 changes: 6 additions & 6 deletions src/Overlay.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import {AriaRole, Merge} from './utils/types'
import {useOverlay, TouchOrMouseEvent} from './hooks'
import Portal from './Portal'
import sx, {SxProp} from './sx'
import {useRefObjectAsForwardedRef} from './hooks/useRefObjectAsForwardedRef'
import {useCombinedRefs} from './hooks/useCombinedRefs'
import type {AnchorSide} from '@primer/behaviors'
import {useTheme} from './ThemeProvider'
import {ForwardRefComponent as PolymorphicForwardRefComponent} from '@radix-ui/react-polymorphic'
Expand Down Expand Up @@ -142,7 +142,7 @@ const Overlay = React.forwardRef<HTMLDivElement, OwnOverlayProps>(
forwardedRef
): ReactElement => {
const overlayRef = useRef<HTMLDivElement>(null)
useRefObjectAsForwardedRef(forwardedRef, overlayRef)
const combinedRef = useCombinedRefs(overlayRef, forwardedRef)
const {theme} = useTheme()
const slideAnimationDistance = parseInt(get('space.2')(theme).replace('px', ''))
const slideAnimationEasing = get('animation.easeOutCubic')(theme)
Expand All @@ -158,10 +158,10 @@ const Overlay = React.forwardRef<HTMLDivElement, OwnOverlayProps>(
})

useEffect(() => {
if (height === 'initial' && overlayRef.current?.clientHeight) {
overlayRef.current.style.height = `${overlayRef.current.clientHeight}px`
if (height === 'initial' && combinedRef.current?.clientHeight) {
combinedRef.current.style.height = `${combinedRef.current.clientHeight}px`
}
}, [height])
}, [height, combinedRef])

useLayoutEffect(() => {
const {x, y} = getSlideAnimationStartingVector(anchorSide)
Expand All @@ -185,7 +185,7 @@ const Overlay = React.forwardRef<HTMLDivElement, OwnOverlayProps>(
height={height}
role={role}
{...rest}
ref={overlayRef}
ref={combinedRef}
style={
{
top: `${top || 0}px`,
Expand Down
16 changes: 9 additions & 7 deletions src/TextInputWithTokens.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@ import {isFocusable} from '@primer/behaviors/utils'
import {omit} from '@styled-system/props'
import React, {FocusEventHandler, KeyboardEventHandler, MouseEventHandler, RefObject, useRef, useState} from 'react'
import Box from './Box'
import {useRefObjectAsForwardedRef} from './hooks/useRefObjectAsForwardedRef'
import {useProvidedRefOrCreate} from './hooks'
import {useCombinedRefs} from './hooks/useCombinedRefs'
import {useFocusZone} from './hooks/useFocusZone'
import Text from './Text'
import {TextInputProps} from './TextInput'
Expand Down Expand Up @@ -92,11 +93,12 @@ function TextInputWithTokensInnerComponent<TokenComponentType extends AnyReactCo
visibleTokenCount,
...rest
}: TextInputWithTokensProps<TokenComponentType>,
forwardedRef: React.ForwardedRef<HTMLInputElement>
externalRef: React.ForwardedRef<HTMLInputElement>
) {
const {onBlur, onFocus, onKeyDown, ...inputPropsRest} = omit(rest)
const ref = useRef<HTMLInputElement>(null)
useRefObjectAsForwardedRef(forwardedRef, ref)
const ref = useProvidedRefOrCreate<HTMLInputElement>(externalRef as React.RefObject<HTMLInputElement>)
const localInputRef = useRef<HTMLInputElement>(null)
const combinedInputRef = useCombinedRefs(localInputRef, ref)
const [selectedTokenIndex, setSelectedTokenIndex] = useState<number | undefined>()
const [tokensAreTruncated, setTokensAreTruncated] = useState<boolean>(Boolean(visibleTokenCount))
const {containerRef} = useFocusZone(
Expand All @@ -122,7 +124,7 @@ function TextInputWithTokensInnerComponent<TokenComponentType extends AnyReactCo
}

if (nextIndex > tokens.length || nextIndex < 1) {
return ref.current || undefined
return combinedInputRef.current || undefined
}

return containerRef.current?.children[nextIndex] as HTMLElement
Expand Down Expand Up @@ -228,7 +230,7 @@ function TextInputWithTokensInnerComponent<TokenComponentType extends AnyReactCo
}

const focusInput: MouseEventHandler = () => {
ref.current?.focus()
combinedInputRef.current?.focus()
}

const preventTokenClickPropagation: MouseEventHandler = event => {
Expand Down Expand Up @@ -321,7 +323,7 @@ function TextInputWithTokensInnerComponent<TokenComponentType extends AnyReactCo
}}
>
<UnstyledTextInput
ref={ref}
ref={combinedInputRef}
disabled={disabled}
onFocus={handleInputFocus}
onBlur={handleInputBlur}
Expand Down
35 changes: 18 additions & 17 deletions src/drafts/InlineAutocomplete/InlineAutocomplete.tsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,17 @@
import React, {cloneElement, useRef} from 'react'
import Box from '../../Box'
import {useCombinedRefs} from '../../hooks/useCombinedRefs'
import {useSyntheticChange} from '../hooks/useSyntheticChange'
import Portal from '../../Portal'
import {BetterSystemStyleObject} from '../../sx'
import {getAbsoluteCharacterCoordinates} from '../utils/character-coordinates'
import {useSyntheticChange} from '../hooks/useSyntheticChange'

import {ShowSuggestionsEvent, Suggestions, TextInputCompatibleChild, TextInputElement, Trigger} from './types'
import {augmentHandler, calculateSuggestionsQuery, getSuggestionValue, requireChildrenToBeInput} from './utils'

import {useRefObjectAsForwardedRef} from '../../hooks'
import {
augmentHandler,
calculateSuggestionsQuery,
// getAbsoluteCharacterCoordinates,
getSuggestionValue,
requireChildrenToBeInput
} from './utils'
import AutocompleteSuggestions from './_AutocompleteSuggestions'

export type InlineAutocompleteProps = {
Expand Down Expand Up @@ -82,9 +85,7 @@ const InlineAutocomplete = ({
// Forward accessibility props so it works with FormControl
...forwardProps
}: InlineAutocompleteProps & React.ComponentProps<'textarea' | 'input'>) => {
const inputRef = useRef<HTMLInputElement & HTMLTextAreaElement>(null)
useRefObjectAsForwardedRef(children.ref ?? noop, inputRef)

const inputRef = useCombinedRefs(children.ref)
const externalInput = requireChildrenToBeInput(children, inputRef)

const emitSyntheticChange = useSyntheticChange({
Expand All @@ -101,14 +102,14 @@ const InlineAutocomplete = ({
// optimized by only re-rendering when suggestionsVisible changes. However, the user
// could move the cursor to a different location using arrow keys and then type a
// trigger, which would move the suggestions without closing/reopening them.
const suggestionsOffset =
inputRef.current && showEventRef.current && suggestionsVisible
? getAbsoluteCharacterCoordinates(
inputRef.current,
// Position the suggestions at the trigger character, not the current caret position
(getSelectionStart(inputRef.current) ?? 0) - showEventRef.current.query.length
)
: {top: 0, left: 0}
const suggestionsOffset = {top: 0, left: 0}
// inputRef.current && showEventRef.current && suggestionsVisible
// ? getAbsoluteCharacterCoordinates(
// inputRef.current,
// // Position the suggestions at the trigger character, not the current caret position
// (getSelectionStart(inputRef.current) ?? 0) - showEventRef.current.query.length
// )
// : {top: 0, left: 0}

// User can blur while suggestions are visible with shift+tab
const onBlur: React.FocusEventHandler<TextInputElement> = () => {
Expand Down
40 changes: 40 additions & 0 deletions src/hooks/useCombinedRefs.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import {ForwardedRef, useRef} from 'react'
import useLayoutEffect from '../utils/useIsomorphicLayoutEffect'

/**
* Creates a ref by combining multiple constituent refs. The ref returned by this hook
* should be passed as the ref for the element that needs to be shared. This is
* particularly useful when you are using `React.forwardRef` in your component but you
* also want to be able to access the local element. This is a small anti-pattern,
* though, as it breaks encapsulation.
* @param refs
*/
export function useCombinedRefs<T>(...refs: (ForwardedRef<T> | null | undefined)[]) {
const combinedRef = useRef<T | null>(null)

useLayoutEffect(() => {
function setRefs(current: T | null = null) {
for (const ref of refs) {
if (!ref) {
return
}
if (typeof ref === 'function') {
ref(current)
} else {
ref.current = current
}
}
}

setRefs(combinedRef.current)

return () => {
// ensure the refs get updated on unmount
// eslint-disable-next-line react-hooks/exhaustive-deps
setRefs(combinedRef.current)
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [...refs, combinedRef.current])

return combinedRef
}
8 changes: 7 additions & 1 deletion src/hooks/useDetails.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,12 @@ type UseDetailsParameters = {
onClickOutside?: (event: MouseEvent) => void
}

export type DetailsProps = {
onToggle?: (e: React.SyntheticEvent<HTMLElement, Event>) => void
open?: boolean
ref?: React.RefObject<HTMLElement>
}

function useDetails({ref, closeOnOutsideClick, defaultOpen, onClickOutside}: UseDetailsParameters) {
const [open, setOpen] = useState(defaultOpen)
const backupRef = useRef(null)
Expand Down Expand Up @@ -44,7 +50,7 @@ function useDetails({ref, closeOnOutsideClick, defaultOpen, onClickOutside}: Use
}
}

const getDetailsProps = () => {
const getDetailsProps: () => DetailsProps = () => {
return {onToggle: handleToggle, open, ref: customRef}
}

Expand Down