Skip to content

Commit

Permalink
feature(form): improve focus handling for PT-input
Browse files Browse the repository at this point in the history
Remove redundant focus skipper, and build this functionality into ActivateOnFocus component
where it belongs.
  • Loading branch information
skogsmaskin authored and rexxars committed Sep 23, 2022
1 parent 13b4567 commit c0afe6c
Show file tree
Hide file tree
Showing 5 changed files with 69 additions and 47 deletions.
Original file line number Diff line number Diff line change
@@ -1,12 +1,17 @@
// This is transitional in order to track usage of the ActivateOnFocusPart part from within the form-builder package
import React from 'react'
import React, {KeyboardEvent, useCallback, useMemo, useState} from 'react'
import {Text} from '@sanity/ui'
import {
OverlayContainer,
FlexContainer,
CardContainer,
ContentContainer,
} from './ActivateOnFocus.styles'

const isTouchDevice = () =>
(typeof window !== 'undefined' && 'ontouchstart' in window) ||
(typeof navigator !== 'undefined' && navigator.maxTouchPoints > 0)

/**
* @internal
*/
Expand All @@ -20,23 +25,54 @@ export interface ActivateOnFocusProps {
/**
* @internal
*/

export function ActivateOnFocus(props: ActivateOnFocusProps) {
const {children, message, onActivate, isOverlayActive} = props
const [focused, setFocused] = useState(false)

function handleClick() {
const handleClick = useCallback(() => {
if (onActivate) {
onActivate()
}
}
}, [onActivate])

function handleBlur() {
if (onActivate && isOverlayActive) {
onActivate()
const handleKeyDown = useCallback(
(event: KeyboardEvent<HTMLDivElement>) => {
if (!isOverlayActive) {
return
}
if (event.code === 'Space' && onActivate) {
onActivate()
}
},
[isOverlayActive, onActivate]
)

const handleOnFocus = useCallback(() => {
setFocused(true)
}, [])

const handleBlur = useCallback(() => {
setFocused(false)
}, [])

const msg = useMemo(() => {
const isTouch = isTouchDevice()
let activateVerb = isTouch ? 'Tap' : 'Click'
if (focused && !isTouch) {
activateVerb += ' or press space'
}
}
const text = message || `${activateVerb} to activate`
return <Text weight="semibold">{text}</Text>
}, [focused, message])

return (
<OverlayContainer onClick={handleClick} onBlur={handleBlur}>
<OverlayContainer
onBlur={handleBlur}
onClick={handleClick}
onFocus={handleOnFocus}
onKeyDown={handleKeyDown}
>
{isOverlayActive && (
<FlexContainer tabIndex={0} align="center" justify="center">
<CardContainer
Expand All @@ -45,7 +81,7 @@ export function ActivateOnFocus(props: ActivateOnFocusProps) {
// @todo Consider making `radius` a component property of `ActivateOnFocus`.
radius={1}
/>
<ContentContainer>{message}</ContentContainer>
<ContentContainer>{msg}</ContentContainer>
</FlexContainer>
)}
{children}
Expand Down
18 changes: 1 addition & 17 deletions packages/sanity/src/form/inputs/PortableText/Compositor.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ import {
BoundaryElementProvider,
Portal,
PortalProvider,
Text,
useBoundaryElement,
usePortal,
} from '@sanity/ui'
Expand Down Expand Up @@ -51,17 +50,6 @@ interface InputProps extends ArrayOfObjectsInputProps<PortableTextBlock> {

export type PortableTextEditorElement = HTMLDivElement | HTMLSpanElement | null

function isTouchDevice() {
return (
(typeof window !== 'undefined' && 'ontouchstart' in window) ||
(typeof navigator !== 'undefined' && navigator.maxTouchPoints > 0)
)
}

const activateVerb = isTouchDevice() ? 'Tap' : 'Click'

const ACTIVATE_ON_FOCUS_MESSAGE = <Text weight="semibold">{activateVerb} to activate</Text>

export function Compositor(props: InputProps) {
const {
changed,
Expand Down Expand Up @@ -331,11 +319,7 @@ export function Compositor(props: InputProps) {
)
return (
<PortalProvider __unstable_elements={portalElements}>
<ActivateOnFocus
message={ACTIVATE_ON_FOCUS_MESSAGE}
onActivate={onActivate}
isOverlayActive={!isActive}
>
<ActivateOnFocus onActivate={onActivate} isOverlayActive={!isActive}>
<ChangeIndicator
disabled={isFullscreen}
hasFocus={Boolean(focused)}
Expand Down
12 changes: 0 additions & 12 deletions packages/sanity/src/form/inputs/PortableText/PortableTextInput.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -296,12 +296,6 @@ export function PortableTextInput(props: PortableTextInputProps) {
[onChange, toast, setFocusPathDebounced]
)

const handleFocusSkipperClick = useCallback(() => {
if (editorRef.current) {
PortableTextEditor.focus(editorRef.current)
}
}, [editorRef])

const handleIgnoreInvalidValue = useCallback((): void => {
setIgnoreValidationError(true)
}, [])
Expand Down Expand Up @@ -347,12 +341,6 @@ export function PortableTextInput(props: PortableTextInputProps) {

return (
<Box ref={innerElementRef}>
{!readOnly && (
<VisibleOnFocusButton onClick={handleFocusSkipperClick}>
<Text>Go to content</Text>
</VisibleOnFocusButton>
)}

{!ignoreValidationError && respondToInvalidContent}
{(!invalidValue || ignoreValidationError) && (
<PortableTextMarkersProvider markers={markers}>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ import {
interface BlockObjectProps {
attributes: RenderAttributes
block: PortableTextBlock
isActive?: boolean
isFullscreen?: boolean
onChange: (...patches: PatchArg[]) => void
onOpenItem: (path: Path) => void
Expand All @@ -47,6 +48,7 @@ export function BlockObject(props: BlockObjectProps) {
const {
attributes: {focused, selected, path},
block,
isActive,
isFullscreen,
onChange,
onOpenItem,
Expand Down Expand Up @@ -97,16 +99,17 @@ export function BlockObject(props: BlockObjectProps) {
const blockPreview = useMemo(() => {
return (
<BlockObjectPreview
type={type}
focused={focused}
value={block}
readOnly={readOnly}
isActive={isActive}
onClickingDelete={handleDelete}
onClickingEdit={handleEdit}
readOnly={readOnly}
renderPreview={renderPreview}
type={type}
value={block}
/>
)
}, [focused, type, block, readOnly, handleDelete, handleEdit, renderPreview])
}, [focused, isActive, handleDelete, handleEdit, readOnly, renderPreview, type, block])

const tone = selected || focused ? 'primary' : 'default'

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,12 +24,13 @@ import {is} from '../../../utils/is'

interface BlockObjectPreviewProps {
focused: boolean
type: ObjectSchemaType
value: PortableTextBlock
readOnly?: boolean
onClickingEdit: () => void
isActive?: boolean
onClickingDelete: (event: MouseEvent) => void
onClickingEdit: () => void
readOnly?: boolean
renderPreview: RenderPreviewCallback
type: ObjectSchemaType
value: PortableTextBlock
}

const POPOVER_PROPS: MenuButtonProps['popover'] = {
Expand All @@ -40,7 +41,16 @@ const POPOVER_PROPS: MenuButtonProps['popover'] = {
}

export function BlockObjectPreview(props: BlockObjectPreviewProps): ReactElement {
const {focused, value, type, readOnly, onClickingEdit, onClickingDelete, renderPreview} = props
const {
focused,
isActive,
onClickingDelete,
onClickingEdit,
readOnly,
renderPreview,
type,
value,
} = props
const {isTopLayer} = useLayer()
const editor = usePortableTextEditor()
const menuButtonId = useId() || ''
Expand Down Expand Up @@ -93,6 +103,7 @@ export function BlockObjectPreview(props: BlockObjectPreviewProps): ReactElement
iconRight={EllipsisVerticalIcon}
mode="bleed"
paddingX={2}
tabIndex={isActive ? 0 : 1}
/>
}
ref={menuButton}
Expand Down

0 comments on commit c0afe6c

Please sign in to comment.