@itwin/itwinui-react
Version:
A react component library for iTwinUI
333 lines (332 loc) • 10 kB
JavaScript
;
Object.defineProperty(exports, '__esModule', {
value: true,
});
function _export(target, all) {
for (var name in all)
Object.defineProperty(target, name, {
enumerable: true,
get: all[name],
});
}
_export(exports, {
Panels: function () {
return Panels;
},
PanelsWrapper: function () {
return PanelsWrapper;
},
PanelsWrapperContext: function () {
return PanelsWrapperContext;
},
});
const _interop_require_default = require('@swc/helpers/_/_interop_require_default');
const _interop_require_wildcard = require('@swc/helpers/_/_interop_require_wildcard');
const _react = /*#__PURE__*/ _interop_require_wildcard._(require('react'));
const _reactdom = /*#__PURE__*/ _interop_require_wildcard._(
require('react-dom'),
);
const _index = require('../../utils/index.js');
const _IconButton = require('../Buttons/IconButton.js');
const _Flex = require('../Flex/Flex.js');
const _Text = require('../Typography/Text.js');
const _classnames = /*#__PURE__*/ _interop_require_default._(
require('classnames'),
);
const _helpers = require('./helpers.js');
const PanelsWrapper = _react.forwardRef((props, forwardedRef) => {
let {
children,
className,
onActiveIdChange: onActiveIdChangeProp,
instance,
...rest
} = props;
let onActiveIdChange = (0, _index.useLatestRef)(onActiveIdChangeProp);
let ref = _react.useRef(null);
let [activePanelId, setActivePanelId] = _react.useState(void 0);
let [triggers, setTriggers] = _react.useState({});
let panels = _react.useRef(new Set());
let [shouldFocus, setShouldFocus] = _react.useState(void 0);
let motionOk = (0, _index.useMediaQuery)(
'(prefers-reduced-motion: no-preference)',
);
let changeActivePanel = _react.useCallback(
(newActiveId) => {
if (!panels.current.has(newActiveId) || newActiveId === activePanelId)
return;
_reactdom.flushSync(() => setActivePanelId(newActiveId));
onActiveIdChange.current?.(newActiveId);
ref.current
?.getRootNode()
.getElementById(newActiveId)
?.scrollIntoView({
block: 'nearest',
inline: 'center',
behavior: motionOk ? 'smooth' : 'instant',
});
},
[activePanelId, motionOk, onActiveIdChange],
);
return _react.createElement(
PanelsWrapperContext.Provider,
{
value: _react.useMemo(
() => ({
activePanelId,
setActivePanelId,
changeActivePanel,
triggers,
setTriggers,
shouldFocus,
setShouldFocus,
panels,
}),
[
activePanelId,
changeActivePanel,
setActivePanelId,
setTriggers,
shouldFocus,
triggers,
],
),
},
_react.createElement(
_helpers.PanelsInstanceProvider,
{
instance: instance,
},
_react.createElement(
_index.Box,
{
ref: (0, _index.useMergedRefs)(ref, forwardedRef),
...rest,
className: (0, _classnames.default)('iui-panel-wrapper', className),
},
children,
),
),
);
});
if ('development' === process.env.NODE_ENV)
PanelsWrapper.displayName = 'Panels.Wrapper';
const PanelsWrapperContext = _react.createContext(void 0);
if ('development' === process.env.NODE_ENV)
PanelsWrapperContext.displayName = 'PanelsWrapperContext';
const Panel = _react.forwardRef((props, forwardedRef) => {
let { id, children, className, ...rest } = props;
let { activePanelId, triggers, panels, setActivePanelId } = (0,
_index.useSafeContext)(PanelsWrapperContext);
let associatedTrigger = _react.useMemo(() => triggers[id], [id, triggers]);
let previousActivePanelId = useDelayed(activePanelId) || activePanelId;
let isMounted = [activePanelId, previousActivePanelId].includes(id);
let isTransitioning =
activePanelId === id && activePanelId !== previousActivePanelId;
let isInert = previousActivePanelId === id && activePanelId !== id;
(0, _index.useLayoutEffect)(() => {
let isFirstPanel = null == activePanelId && 0 === panels.current.size;
if (isFirstPanel) setActivePanelId(id);
let panelsCurrent = panels.current;
if (!panelsCurrent.has(id)) panelsCurrent.add(id);
return () => {
panelsCurrent.delete(id);
};
}, [activePanelId, id, panels, setActivePanelId]);
return _react.createElement(
PanelContext.Provider,
{
value: _react.useMemo(
() => ({
id,
associatedTrigger,
}),
[associatedTrigger, id],
),
},
isMounted &&
_react.createElement(
_index.Box,
{
ref: forwardedRef,
id: id,
className: (0, _classnames.default)('iui-panel', className),
'aria-labelledby': `${id}-header-title`,
role: 'group',
inert: isInert ? 'true' : void 0,
'data-iui-transitioning': isTransitioning ? 'true' : void 0,
...rest,
},
children,
),
);
});
if ('development' === process.env.NODE_ENV) Panel.displayName = 'Panels.Panel';
const PanelContext = _react.createContext(void 0);
if ('development' === process.env.NODE_ENV)
PanelContext.displayName = 'PanelContext';
const PanelTrigger = (props) => {
let { children, for: forProp } = props;
let {
changeActivePanel,
triggers,
setTriggers,
activePanelId: activePanel,
shouldFocus,
setShouldFocus,
panels,
} = (0, _index.useSafeContext)(PanelsWrapperContext);
let { id: panelId } = (0, _index.useSafeContext)(PanelContext);
let fallbackId = (0, _index.useId)();
let triggerId = children.props.id || fallbackId;
let onClick = _react.useCallback(() => {
if (null == activePanel) return;
setShouldFocus({
fromPanelId: activePanel,
toPanelId: forProp,
direction: 'forward',
});
changeActivePanel?.(forProp);
}, [activePanel, changeActivePanel, forProp, setShouldFocus]);
let focusRef = _react.useCallback(
(el) => {
if (
shouldFocus?.direction === 'backward' &&
shouldFocus?.toPanelId === panelId &&
shouldFocus?.fromPanelId === forProp
) {
el?.focus({
preventScroll: true,
});
setShouldFocus(void 0);
}
},
[forProp, panelId, setShouldFocus, shouldFocus],
);
let logWarning = (0, _index.useWarningLogger)();
_react.useEffect(() => {
if (!panels.current.has(forProp))
logWarning(
`Panels.Trigger's \`for\` prop ("${forProp}") corresponds to no Panel.`,
);
}, [forProp, logWarning, panels, triggers]);
_react.useEffect(() => {
setTriggers((oldTriggers) => {
let triggersMatch = oldTriggers[forProp];
if (
null == triggersMatch ||
panelId !== triggersMatch.panelId ||
triggerId !== triggersMatch.triggerId
)
return {
...oldTriggers,
[forProp]: {
panelId,
triggerId,
},
};
return oldTriggers;
});
}, [forProp, panelId, setTriggers, triggerId]);
return (0, _index.cloneElementWithRef)(children, (children) => ({
...children.props,
id: triggerId,
ref: focusRef,
onClick: (0, _index.mergeEventHandlers)(children.props.onClick, onClick),
'aria-expanded': activePanel === forProp,
'aria-controls': forProp,
}));
};
if ('development' === process.env.NODE_ENV)
PanelTrigger.displayName = 'Panels.Trigger';
const PanelHeader = _react.forwardRef((props, forwardedRef) => {
let { titleProps, children, ...rest } = props;
let { shouldFocus, setShouldFocus } = (0, _index.useSafeContext)(
PanelsWrapperContext,
);
let { id: panelId, associatedTrigger: panelAssociatedTrigger } = (0,
_index.useSafeContext)(PanelContext);
let focusRef = _react.useCallback(
(el) => {
if (
shouldFocus?.direction === 'forward' &&
shouldFocus.toPanelId === panelId
) {
el?.focus({
preventScroll: true,
});
setShouldFocus(void 0);
}
},
[panelId, setShouldFocus, shouldFocus?.direction, shouldFocus?.toPanelId],
);
return _react.createElement(
_Flex.Flex,
{
ref: forwardedRef,
...rest,
},
panelAssociatedTrigger && _react.createElement(PanelBackButton, null),
_react.createElement(
_Text.Text,
{
id: `${panelId}-header-title`,
as: 'h2',
tabIndex: -1,
ref: focusRef,
...titleProps,
},
children,
),
);
});
if ('development' === process.env.NODE_ENV)
PanelHeader.displayName = 'Panels.Header';
const PanelBackButton = _react.forwardRef((props, forwardedRef) => {
let { children, onClick, ...rest } = props;
let { instance: panelInstance } = (0, _index.useSafeContext)(
_helpers.PanelsInstanceContext,
);
return _react.createElement(
_IconButton.IconButton,
{
ref: forwardedRef,
'aria-label': 'Previous panel',
styleType: 'borderless',
size: 'small',
'data-iui-shift': 'left',
...rest,
onClick: (0, _index.mergeEventHandlers)(
_react.useCallback(() => panelInstance?.goBack(), [panelInstance]),
onClick,
),
},
children || _react.createElement(_index.SvgChevronLeft, null),
);
});
if ('development' === process.env.NODE_ENV)
PanelBackButton.displayName = 'Panels.BackButton';
const Panels = {
Wrapper: PanelsWrapper,
Panel,
Trigger: PanelTrigger,
Header: PanelHeader,
useInstance: _index.useInstance,
};
function useDelayed(
value,
{ delay } = {
delay: 500,
},
) {
let [delayed, setDelayed] = _react.useState(void 0);
let timeout = _react.useRef(void 0);
_react.useEffect(() => {
if (0 === delay) setDelayed(value);
else timeout.current = setTimeout(() => setDelayed(value), delay);
return () => {
clearTimeout(timeout.current);
};
}, [value, delay]);
return delayed;
}