UNPKG

@awsui/components-react

Version:

On July 19th, 2022, we launched [Cloudscape Design System](https://cloudscape.design). Cloudscape is an evolution of AWS-UI. It consists of user interface guidelines, front-end components, design resources, and development tools for building intuitive, en

116 lines (115 loc) 8.18 kB
import { __rest } from "tslib"; // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. // SPDX-License-Identifier: Apache-2.0 import React, { useEffect, useLayoutEffect, useRef, useState } from 'react'; import clsx from 'clsx'; import { useAppLayoutToolbarDesignEnabled } from '../app-layout/utils/feature-flags'; import { useKeyboardEvents } from '../app-layout/utils/use-keyboard-events'; import { usePointerEvents } from '../app-layout/utils/use-pointer-events'; import { InternalButton } from '../button/internal'; import { getBaseProps } from '../internal/base-component'; import PanelResizeHandle from '../internal/components/panel-resize-handle'; import { useSplitPanelContext } from '../internal/context/split-panel-context'; import { useMergeRefs } from '../internal/hooks/use-merge-refs'; import { useUniqueId } from '../internal/hooks/use-unique-id'; import { useVisualRefresh } from '../internal/hooks/use-visual-mode'; import globalVars from '../internal/styles/global-vars'; import { createWidgetizedComponent } from '../internal/widgets'; import { SplitPanelContentBottom } from './bottom'; import PreferencesModal from './preferences-modal'; import { SplitPanelContentSide } from './side'; import styles from './styles.css.js'; import testUtilStyles from './test-classes/styles.css.js'; export function SplitPanelImplementation(_a) { var { __internalRootRef, header, children, hidePreferencesButton, closeBehavior, i18nStrings = {} } = _a, restProps = __rest(_a, ["__internalRootRef", "header", "children", "hidePreferencesButton", "closeBehavior", "i18nStrings"]); const isRefresh = useVisualRefresh(); const isToolbar = useAppLayoutToolbarDesignEnabled(); const { position, topOffset, bottomOffset, rightOffset, contentWidthStyles, isOpen, isForcedPosition, onPreferencesChange, onResize, onToggle, size, relativeSize, setSplitPanelToggle, refs, } = useSplitPanelContext(); const baseProps = getBaseProps(restProps); const [isPreferencesOpen, setPreferencesOpen] = useState(false); const appLayoutMaxWidth = isRefresh && position === 'bottom' ? contentWidthStyles : undefined; const openButtonAriaLabel = i18nStrings.openButtonAriaLabel; useEffect(() => { setSplitPanelToggle({ displayed: closeBehavior === 'collapse', ariaLabel: openButtonAriaLabel }); return () => { setSplitPanelToggle({ displayed: false, ariaLabel: undefined }); }; }, [setSplitPanelToggle, openButtonAriaLabel, closeBehavior]); const splitPanelRefObject = useRef(null); const sizeControlProps = { position, panelRef: splitPanelRefObject, handleRef: refs.slider, onResize, }; const onSliderPointerDown = usePointerEvents(sizeControlProps); const onKeyDown = useKeyboardEvents(sizeControlProps); const contentStyle = { [globalVars.stickyVerticalTopOffset]: topOffset, [globalVars.stickyVerticalBottomOffset]: bottomOffset, }; const panelHeaderId = useUniqueId('split-panel-header'); const wrappedHeader = (React.createElement("div", { className: clsx(styles.header, isToolbar && styles['with-toolbar']), style: appLayoutMaxWidth }, React.createElement("h2", { className: clsx(styles['header-text'], testUtilStyles['header-text']), id: panelHeaderId }, header), React.createElement("div", { className: styles['header-actions'] }, !hidePreferencesButton && isOpen && (React.createElement(React.Fragment, null, React.createElement(InternalButton, { className: testUtilStyles['preferences-button'], iconName: "settings", variant: "icon", onClick: () => setPreferencesOpen(true), formAction: "none", ariaLabel: i18nStrings.preferencesTitle, ref: refs.preferences }), React.createElement("span", { className: styles.divider }))), isOpen ? (React.createElement(InternalButton, { className: testUtilStyles['close-button'], iconName: isRefresh && closeBehavior === 'collapse' ? (position === 'side' ? 'angle-right' : 'angle-down') : 'close', variant: "icon", onClick: onToggle, formAction: "none", ariaLabel: i18nStrings.closeButtonAriaLabel, ariaExpanded: isOpen })) : position === 'side' ? null : (React.createElement(InternalButton, { className: testUtilStyles['open-button'], iconName: "angle-up", variant: "icon", formAction: "none", ariaLabel: i18nStrings.openButtonAriaLabel, ref: refs.toggle, ariaExpanded: isOpen }))))); const resizeHandle = (React.createElement(PanelResizeHandle, { ref: refs.slider, className: testUtilStyles.slider, ariaLabel: i18nStrings.resizeHandleAriaLabel, // Allows us to use the logical left/right keys to move the slider left/right, // but match aria keyboard behavior of using left/right to decrease/increase // the slider value. ariaValuenow: position === 'bottom' ? relativeSize : 100 - relativeSize, position: position, onKeyDown: onKeyDown, onPointerDown: onSliderPointerDown })); /* This effect forces the browser to recalculate the layout whenever the split panel might have moved. This is needed as a workaround for a bug in Safari, which does not automatically calculate the new position of the split panel _content_ when the split panel moves. */ useLayoutEffect(() => { const root = splitPanelRefObject.current; if (root) { const property = 'transform'; const temporaryValue = 'translateZ(0)'; const valueBefore = root.style[property]; root.style[property] = temporaryValue; // This line forces the browser to recalculate the layout void root.offsetHeight; root.style[property] = valueBefore; } }, [rightOffset, __internalRootRef]); const mergedRef = useMergeRefs(splitPanelRefObject, __internalRootRef); if (closeBehavior === 'hide' && !isOpen) { return React.createElement(React.Fragment, null); } /** * The AppLayout factor moved the circular buttons out of the * SplitPanel and into the Tools component. This conditional * is still needed for the early return to prevent execution * of the following code. */ if (isRefresh && !isToolbar && !isOpen && position === 'side') { return React.createElement(React.Fragment, null); } return (React.createElement(React.Fragment, null, position === 'side' && (React.createElement(SplitPanelContentSide, { style: contentStyle, resizeHandle: resizeHandle, baseProps: baseProps, isOpen: isOpen, splitPanelRef: mergedRef, cappedSize: size, onToggle: onToggle, openButtonAriaLabel: openButtonAriaLabel, toggleRef: refs.toggle, header: wrappedHeader, panelHeaderId: panelHeaderId }, children)), position === 'bottom' && (React.createElement(SplitPanelContentBottom, { style: contentStyle, resizeHandle: resizeHandle, baseProps: baseProps, isOpen: isOpen, splitPanelRef: mergedRef, cappedSize: size, onToggle: onToggle, header: wrappedHeader, panelHeaderId: panelHeaderId, appLayoutMaxWidth: appLayoutMaxWidth }, children)), isPreferencesOpen && (React.createElement(PreferencesModal, { visible: true, preferences: { position }, disabledSidePosition: position === 'bottom' && isForcedPosition, isRefresh: isRefresh, i18nStrings: { header: i18nStrings.preferencesTitle, confirm: i18nStrings.preferencesConfirm, cancel: i18nStrings.preferencesCancel, positionLabel: i18nStrings.preferencesPositionLabel, positionDescription: i18nStrings.preferencesPositionDescription, positionBottom: i18nStrings.preferencesPositionBottom, positionSide: i18nStrings.preferencesPositionSide, }, onConfirm: preferences => { onPreferencesChange(Object.assign({}, preferences)); setPreferencesOpen(false); }, onDismiss: () => { setPreferencesOpen(false); } })))); } export const createWidgetizedSplitPanel = createWidgetizedComponent(SplitPanelImplementation); //# sourceMappingURL=implementation.js.map