@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
JavaScript
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