react#FocusEventHandler TypeScript Examples

The following examples show how to use react#FocusEventHandler. You can vote up the ones you like or vote down the ones you don't like, and go to the original project or source file by following the links above each example. You may check out the related API usage on the sidebar.
Example #1
Source File: useSlate.ts    From ui-schema with MIT License 7 votes vote down vote up
useSlate = (schema: WidgetProps['schema'], value: SlateImmutableType | undefined) => {
    const [focused, setFocus] = React.useState(false)

    const onBlur: FocusEventHandler = React.useCallback(() => {
        setFocus(false)
    }, [setFocus])

    const onFocus: FocusEventHandler = React.useCallback(() => {
        setFocus(true)
    }, [setFocus])

    const dense = schema.getIn(['view', 'dense'])

    const empty = isSlateEmpty(value)

    return {
        focused, setFocus,
        onFocus, onBlur,
        dense, empty,
    }
}
Example #2
Source File: aria.ts    From pybricks-code with MIT License 5 votes vote down vote up
/**
 * React hook for creating toolbar item element props for focus management.
 *
 * Using this hook requires the current element to be inside of an
 * {@link ToolbarStateContext} and to be inside of a {@link FocusScope}.
 */
export function useToolbarItemFocus(props: { id: string }): ToolbarItemFocusAria {
    const { id } = props;
    const state = useContext(ToolbarStateContext);
    const focusManager = useFocusManager();

    const onKeyDown = useCallback<KeyboardEventHandler<HTMLElement>>(
        (e) => {
            switch (e.key) {
                case 'ArrowLeft':
                    focusManager.focusPrevious({ wrap: true });
                    break;
                case 'ArrowRight':
                    focusManager.focusNext({ wrap: true });
                    break;
                case 'Home':
                    focusManager.focusFirst();
                    break;
                case 'End':
                    focusManager.focusLast();
                    break;
                default:
                    return;
            }
        },
        [focusManager],
    );

    const onFocus = useCallback<FocusEventHandler<HTMLElement>>(
        (e) => {
            state.setLastFocusedItem(e.target.id);
        },
        [state.setLastFocusedItem],
    );
    const excludeFromTabOrder = id !== state.lastFocusedItem;

    return { toolbarItemFocusProps: { onKeyDown, onFocus }, excludeFromTabOrder };
}
Example #3
Source File: App.tsx    From pybricks-code with MIT License 4 votes vote down vote up
App: React.VFC = () => {
    const { isDarkMode } = useTernaryDarkMode();
    const { isSettingShowDocsEnabled } = useSettingIsShowDocsEnabled();
    const [isDragging, setIsDragging] = useState(false);

    const [docsSplit, setDocsSplit] = useLocalStorage('app-docs-split', 30);
    const [terminalSplit, setTerminalSplit] = useLocalStorage('app-terminal-split', 30);

    // Classes.DARK has to be applied to body element, otherwise it won't
    // affect portals
    useEffect(() => {
        if (!isDarkMode) {
            // no class for light mode, so nothing to do
            return;
        }

        document.body.classList.add(Classes.DARK);
        return () => document.body.classList.remove(Classes.DARK);
    }, [isDarkMode]);

    useEffect(() => {
        const listener = (e: KeyboardEvent) => {
            // prevent default browser keyboard shortcuts that we use
            // NB: some of these like 'n' and 'w' cannot be prevented when
            // running "in the browser"
            if (e.ctrlKey && ['d', 'n', 's', 'w'].includes(e.key)) {
                e.preventDefault();
            }
        };

        addEventListener('keydown', listener);
        return () => removeEventListener('keydown', listener);
    }, []);

    // keep track of last focused element in the activities area and restore
    // focus to that element if any non-interactive area is clicked

    const [lastActivitiesFocusChild, setLastActivitiesFocusChild] =
        useState<HTMLElement | null>(null);

    const handleFocus = useCallback<FocusEventHandler>(
        (e) => {
            if (e.target instanceof HTMLElement) {
                setLastActivitiesFocusChild(e.target);
            }
        },
        [setLastActivitiesFocusChild],
    );

    const handleActivitiesMouseDown = useCallback<MouseEventHandler<HTMLDivElement>>(
        (e) => {
            if (
                lastActivitiesFocusChild &&
                e.currentTarget.contains(lastActivitiesFocusChild)
            ) {
                // if the last focused child exists and it is still inside of
                // the activities area, focus it
                lastActivitiesFocusChild.focus();
            } else {
                // otherwise, focus the first focusable element
                const walker = getFocusableTreeWalker(e.currentTarget);
                const first = walker.nextNode();

                if (first instanceof HTMLElement) {
                    first.focus();
                }
            }

            // prevent document body from getting focus
            e.stopPropagation();
            e.preventDefault();
        },
        [lastActivitiesFocusChild],
    );

    return (
        <div className="pb-app" onContextMenu={(e) => e.preventDefault()}>
            <div className="pb-app-body">
                <div
                    className="pb-app-activities"
                    onFocus={handleFocus}
                    onMouseDown={handleActivitiesMouseDown}
                >
                    <Activities />
                </div>
                {/* need a container with position: relative; for SplitterLayout since it uses position: absolute; */}
                <div className="pb-app-main" style={{ position: 'relative' }}>
                    <SplitterLayout
                        customClassName={
                            isSettingShowDocsEnabled ? 'pb-show-docs' : 'pb-hide-docs'
                        }
                        onDragStart={(): void => setIsDragging(true)}
                        onDragEnd={(): void => setIsDragging(false)}
                        percentage={true}
                        secondaryInitialSize={docsSplit}
                        onSecondaryPaneSizeChange={setDocsSplit}
                    >
                        <SplitterLayout
                            vertical={true}
                            percentage={true}
                            secondaryInitialSize={terminalSplit}
                            onSecondaryPaneSizeChange={setTerminalSplit}
                        >
                            <div className="pb-app-editor">
                                <Toolbar />
                                <Editor />
                            </div>
                            <div className="pb-app-terminal">
                                <Terminal />
                            </div>
                        </SplitterLayout>
                        <div className="pb-app-docs">
                            {isDragging && <div className="pb-app-docs-drag-helper" />}
                            <Docs />
                        </div>
                    </SplitterLayout>
                </div>
            </div>
            <StatusBar />
        </div>
    );
}
Example #4
Source File: SlateRenderer.tsx    From ui-schema with MIT License 4 votes vote down vote up
SlateRenderer: React.ComponentType<SlateRendererProps & WidgetProps & WithValue & {
    ElementMapper: ElementMapperType
    onFocus: FocusEventHandler
    onBlur: FocusEventHandler
    className?: string
    onlyInline?: boolean
    withPlugins: withPluginsType
    plugins: EditablePluginsProps['plugins']
    renderLeaf?: RenderLeaf[]
}> = (
    {
        value,
        internalValue,
        onChange,
        storeKeys,
        required,
        schema,
        onFocus,
        onBlur,
        ElementMapper,
        className,
        onlyInline = false,
        plugins,
        renderLeaf,
    }
) => {
    const enableOnly = schema.getIn(['editor', 'enableOnly']) as editorEnableOnly
    const renderElements = React.useMemo(() => {
        return [
            ({children, ...props}: RenderElementProps): JSX.Element =>
                <ElementMapper {...props} enableOnly={enableOnly}>
                    {children}
                </ElementMapper>,
        ]
    }, [enableOnly])

    const valueRef = React.useRef(value)
    const handledInitial = React.useRef(false)
    const valueIsSameOrInitialised = handledInitial.current && valueRef.current?.equals(value)
    React.useEffect(() => {
        if (!valueIsSameOrInitialised) {
            const handledInitialTemp = handledInitial.current
            handledInitial.current = true
            onChange({
                storeKeys,
                scopes: ['internal', 'value'],
                type: 'update',
                updater: ({internal: currentInternal = Map(), value: storeValue}) => {
                    if (storeValue && storeValue.size) {
                        // handling setting internal value for keyword `default`
                        // must check for really non empty, e.g. when used in root level `value` and `internal` will be an empty list
                        valueRef.current = storeValue
                    } else {
                        valueRef.current = !handledInitialTemp && schema.get('default') ? schema.get('default') as List<any> : List()
                    }
                    if (valueRef.current.size) {
                        currentInternal = currentInternal.set('value', valueRef.current.toJS())
                    } else {
                        const initial = [...initialValue]
                        initial[0] = {...initial[0]}
                        if (schema.getIn(['editor', 'initialRoot'])) {
                            initial[0].type = schema.getIn(['editor', 'initialRoot']) as string
                        } else if (onlyInline) {
                            initial[0].type = 'span'
                        }
                        currentInternal = currentInternal.set('value', initial)
                    }

                    return {
                        internal: currentInternal,
                        value: valueRef.current,
                    }
                },
                schema,
                required,
            })
        }
    }, [valueIsSameOrInitialised, handledInitial, valueRef, schema, required, onChange, onlyInline, storeKeys])

    // @ts-ignore
    const editor: ReactEditor = React.useMemo(
        () => pipe(createEditor() as ReactEditor, withReact, withHistory, ...withPlugins({enableOnly, onlyInline})),
        [withPlugins, enableOnly, onlyInline]
    )

    const onChangeHandler = React.useCallback((editorValue) => {
        onChange({
            storeKeys,
            scopes: ['value', 'internal'],
            type: 'update',
            updater: ({internal: currentInternal = Map()}) => {
                let newValue = fromJS(editorValue) as List<any>
                if (isSlateEmpty(newValue)) {
                    newValue = List()
                }
                valueRef.current = newValue
                return {
                    value: newValue,
                    internal: currentInternal.set('value', editorValue),
                }
            },
            schema,
            required,
        })
    }, [valueRef, onChange, storeKeys, schema, required])

    return internalValue.get('value') ? <Slate editor={editor} value={internalValue.get('value') || initialValue} onChange={onChangeHandler}>
        {!schema.getIn(['editor', 'hideToolbar']) ?
            <SlateToolbarHead
                enableOnly={enableOnly}
                onlyInline={onlyInline}
                onFocus={onFocus}
                onBlur={onBlur}
            /> : null}
        {!schema.getIn(['editor', 'hideBalloon']) ?
            <SlateToolbarBalloon
                enableOnly={enableOnly}
            /> : null}
        <Editable
            renderElement={renderElements}
            renderLeaf={renderLeaf}
            plugins={plugins}
            onFocus={onFocus}
            onBlur={onBlur}
            placeholder={schema.getIn(['editor', 'placeholder']) as string | undefined}
            spellCheck={schema.getIn(['editor', 'spellCheck']) as boolean}
            autoFocus={schema.getIn(['editor', 'autoFocus']) as boolean}
            className={className}
        />
    </Slate> : null
}
Example #5
Source File: SlateToolbarHead.tsx    From ui-schema with MIT License 4 votes vote down vote up
SlateToolbarHead: React.ComponentType<{
    enableOnly?: editorEnableOnly
    onlyInline?: boolean
    onFocus: FocusEventHandler
    onBlur: FocusEventHandler
}> = (
    {
        enableOnly,
        onlyInline,
        onBlur,
        onFocus,
    }
) => {
    return <HeadingToolbar>
        {!onlyInline && editorIsEnabled(enableOnly, pluginOptions.ul.type) &&
        <ToolbarList
            {...pluginOptions}
            type={pluginOptions.ul.type}
            icon={<IcListBulleted/>}
            onFocus={onFocus}
            onBlur={onBlur}
        />}
        {!onlyInline && editorIsEnabled(enableOnly, pluginOptions.ol.type) &&
        <ToolbarList
            {...pluginOptions}
            type={pluginOptions.ol.type}
            icon={<IcListNumbered/>}
            onFocus={onFocus}
            onBlur={onBlur}
        />}
        {!onlyInline && editorIsEnabled(enableOnly, pluginOptions.todo_li.type) &&
        <ToolbarElement
            type={pluginOptions.todo_li.type}
            icon={<IcListTodo/>}
            onFocus={onFocus}
            onBlur={onBlur}
        />}

        {!onlyInline && editorIsEnabled(enableOnly, pluginOptions.blockquote.type) &&
        <ToolbarElement
            type={pluginOptions.blockquote.type}
            icon={<IcQuote/>}
            onFocus={onFocus}
            onBlur={onBlur}
        />}

        {!onlyInline && editorIsEnabled(enableOnly, pluginOptions.code_block.type) &&
        <ToolbarCodeBlock
            type={pluginOptions.code_block.type}
            icon={<IcCode/>}
            options={pluginOptions}
            onFocus={onFocus}
            onBlur={onBlur}
        />}

        {editorIsEnabled(enableOnly, pluginOptions.align_center.type) ||
        editorIsEnabled(enableOnly, pluginOptions.align_right.type) ||
        editorIsEnabled(enableOnly, pluginOptions.align_justify.type) ?
            <ToolbarAlign
                icon={<IcAlignLeft/>}
                type={''}
                onFocus={onFocus}
                onBlur={onBlur}
            /> : null}
        {editorIsEnabled(enableOnly, pluginOptions.align_center.type) &&
        <ToolbarAlign
            type={pluginOptions.align_center.type}
            icon={<IcAlignCenter/>}
            onFocus={onFocus}
            onBlur={onBlur}
        />}
        {editorIsEnabled(enableOnly, pluginOptions.align_right.type) &&
        <ToolbarAlign
            type={pluginOptions.align_right.type}
            icon={<IcAlignRight/>}
            onFocus={onFocus}
            onBlur={onBlur}
        />}
        {editorIsEnabled(enableOnly, pluginOptions.align_justify.type) &&
        <ToolbarAlign
            type={pluginOptions.align_justify.type}
            icon={<IcAlignJustify/>}
            onFocus={onFocus}
            onBlur={onBlur}
        />}
    </HeadingToolbar>
}