245 lines
11 KiB
JavaScript
245 lines
11 KiB
JavaScript
'use client';
|
|
"use strict";
|
|
Object.defineProperty(exports, "__esModule", {
|
|
value: true
|
|
});
|
|
Object.defineProperty(exports, "useTreeItemLayout_unstable", {
|
|
enumerable: true,
|
|
get: function() {
|
|
return useTreeItemLayout_unstable;
|
|
}
|
|
});
|
|
const _interop_require_wildcard = require("@swc/helpers/_/_interop_require_wildcard");
|
|
const _react = /*#__PURE__*/ _interop_require_wildcard._(require("react"));
|
|
const _reactutilities = require("@fluentui/react-utilities");
|
|
const _contexts = require("../../contexts");
|
|
const _reactcheckbox = require("@fluentui/react-checkbox");
|
|
const _reactradio = require("@fluentui/react-radio");
|
|
const _TreeItemChevron = require("../TreeItemChevron");
|
|
const _reacttabster = require("@fluentui/react-tabster");
|
|
const _reactsharedcontexts = require("@fluentui/react-shared-contexts");
|
|
const useTreeItemLayout_unstable = (props, ref)=>{
|
|
'use no memo';
|
|
const { main, iconAfter, iconBefore } = props;
|
|
const layoutRef = (0, _contexts.useTreeItemContext_unstable)((ctx)=>ctx.layoutRef);
|
|
const selectionMode = (0, _contexts.useTreeContext_unstable)((ctx)=>ctx.selectionMode);
|
|
const navigationMode = (0, _contexts.useTreeContext_unstable)((ctx)=>{
|
|
var _ctx_navigationMode;
|
|
return (_ctx_navigationMode = ctx.navigationMode) !== null && _ctx_navigationMode !== void 0 ? _ctx_navigationMode : 'tree';
|
|
});
|
|
const [isActionsVisibleFromProps, onActionVisibilityChange] = (0, _reactutilities.isResolvedShorthand)(props.actions) ? [
|
|
props.actions.visible,
|
|
props.actions.onVisibilityChange
|
|
] : [
|
|
undefined,
|
|
undefined
|
|
];
|
|
const [isActionsVisible, setIsActionsVisible] = (0, _reactutilities.useControllableState)({
|
|
state: isActionsVisibleFromProps,
|
|
initialState: false
|
|
});
|
|
const selectionRef = (0, _contexts.useTreeItemContext_unstable)((ctx)=>ctx.selectionRef);
|
|
const expandIconRef = (0, _contexts.useTreeItemContext_unstable)((ctx)=>ctx.expandIconRef);
|
|
const actionsRef = (0, _contexts.useTreeItemContext_unstable)((ctx)=>ctx.actionsRef);
|
|
const actionsRefInternal = _react.useRef(null);
|
|
const treeItemRef = (0, _contexts.useTreeItemContext_unstable)((ctx)=>ctx.treeItemRef);
|
|
const subtreeRef = (0, _contexts.useTreeItemContext_unstable)((ctx)=>ctx.subtreeRef);
|
|
const checked = (0, _contexts.useTreeItemContext_unstable)((ctx)=>ctx.checked);
|
|
const isBranch = (0, _contexts.useTreeItemContext_unstable)((ctx)=>ctx.itemType === 'branch');
|
|
// FIXME: Asserting is required here, as converting this to RefObject on context type would be a breaking change
|
|
assertIsRefObject(treeItemRef);
|
|
// FIXME: Asserting is required here, as converting this to RefObject on context type would be a breaking change
|
|
assertIsRefObject(subtreeRef);
|
|
const setActionsVisibleIfNotFromSubtree = _react.useCallback((event)=>{
|
|
const isTargetFromSubtree = Boolean(subtreeRef.current && (0, _reactutilities.elementContains)(subtreeRef.current, event.target));
|
|
if (!isTargetFromSubtree) {
|
|
onActionVisibilityChange === null || onActionVisibilityChange === void 0 ? void 0 : onActionVisibilityChange(event, {
|
|
visible: true,
|
|
event,
|
|
type: event.type
|
|
});
|
|
if (event.defaultPrevented) {
|
|
return;
|
|
}
|
|
setIsActionsVisible(true);
|
|
}
|
|
}, [
|
|
subtreeRef,
|
|
setIsActionsVisible,
|
|
onActionVisibilityChange
|
|
]);
|
|
const { targetDocument } = (0, _reactsharedcontexts.useFluent_unstable)();
|
|
const isNavigatingWithKeyboard = (0, _reacttabster.useIsNavigatingWithKeyboard)();
|
|
const setActionsInvisibleIfNotFromSubtree = _react.useCallback((event)=>{
|
|
const isRelatedTargetFromActions = ()=>Boolean(actionsRefInternal.current && (0, _reactutilities.elementContains)(actionsRefInternal.current, event.relatedTarget));
|
|
const isRelatedTargetFromTreeItem = ()=>Boolean(treeItemRef.current && (0, _reactutilities.elementContains)(treeItemRef.current, event.relatedTarget));
|
|
const isTargetFromActions = ()=>{
|
|
var _actionsRefInternal_current;
|
|
return Boolean((_actionsRefInternal_current = actionsRefInternal.current) === null || _actionsRefInternal_current === void 0 ? void 0 : _actionsRefInternal_current.contains(event.target));
|
|
};
|
|
if (isRelatedTargetFromActions()) {
|
|
onActionVisibilityChange === null || onActionVisibilityChange === void 0 ? void 0 : onActionVisibilityChange(event, {
|
|
visible: true,
|
|
event,
|
|
type: event.type
|
|
});
|
|
if (event.defaultPrevented) {
|
|
return;
|
|
}
|
|
setIsActionsVisible(true);
|
|
return;
|
|
}
|
|
if (isTargetFromActions() && isRelatedTargetFromTreeItem()) {
|
|
return;
|
|
}
|
|
// when a mouseout event happens during keyboard interaction
|
|
// we should not hide the actions if the activeElement is the treeitem or an action
|
|
// as the focus on the treeitem takes precedence over the mouseout event
|
|
if (event.type === 'mouseout' && isNavigatingWithKeyboard() && ((targetDocument === null || targetDocument === void 0 ? void 0 : targetDocument.activeElement) === treeItemRef.current || (0, _reactutilities.elementContains)(actionsRefInternal.current, targetDocument === null || targetDocument === void 0 ? void 0 : targetDocument.activeElement))) {
|
|
return;
|
|
}
|
|
onActionVisibilityChange === null || onActionVisibilityChange === void 0 ? void 0 : onActionVisibilityChange(event, {
|
|
visible: false,
|
|
event,
|
|
type: event.type
|
|
});
|
|
if (event.defaultPrevented) {
|
|
return;
|
|
}
|
|
setIsActionsVisible(false);
|
|
}, [
|
|
setIsActionsVisible,
|
|
onActionVisibilityChange,
|
|
treeItemRef,
|
|
isNavigatingWithKeyboard,
|
|
targetDocument
|
|
]);
|
|
const expandIcon = _reactutilities.slot.optional(props.expandIcon, {
|
|
renderByDefault: isBranch,
|
|
defaultProps: {
|
|
children: /*#__PURE__*/ _react.createElement(_TreeItemChevron.TreeItemChevron, null),
|
|
'aria-hidden': true
|
|
},
|
|
elementType: 'div'
|
|
});
|
|
const expandIconRefs = (0, _reactutilities.useMergedRefs)(expandIcon === null || expandIcon === void 0 ? void 0 : expandIcon.ref, expandIconRef);
|
|
if (expandIcon) {
|
|
expandIcon.ref = expandIconRefs;
|
|
}
|
|
const arrowNavigationProps = (0, _reacttabster.useArrowNavigationGroup)({
|
|
circular: navigationMode === 'tree',
|
|
axis: 'horizontal'
|
|
});
|
|
const actions = isActionsVisible ? _reactutilities.slot.optional(props.actions, {
|
|
defaultProps: {
|
|
...arrowNavigationProps,
|
|
role: 'toolbar'
|
|
},
|
|
elementType: 'div'
|
|
}) : undefined;
|
|
actions === null || actions === void 0 ? true : delete actions.visible;
|
|
actions === null || actions === void 0 ? true : delete actions.onVisibilityChange;
|
|
const actionsRefs = (0, _reactutilities.useMergedRefs)(actions === null || actions === void 0 ? void 0 : actions.ref, actionsRef, actionsRefInternal);
|
|
const handleActionsBlur = (0, _reactutilities.useEventCallback)((event)=>{
|
|
if ((0, _reactutilities.isResolvedShorthand)(props.actions)) {
|
|
var _props_actions_onBlur, _props_actions;
|
|
(_props_actions_onBlur = (_props_actions = props.actions).onBlur) === null || _props_actions_onBlur === void 0 ? void 0 : _props_actions_onBlur.call(_props_actions, event);
|
|
}
|
|
const isRelatedTargetFromActions = Boolean((0, _reactutilities.elementContains)(event.currentTarget, event.relatedTarget));
|
|
onActionVisibilityChange === null || onActionVisibilityChange === void 0 ? void 0 : onActionVisibilityChange(event, {
|
|
visible: isRelatedTargetFromActions,
|
|
event,
|
|
type: event.type
|
|
});
|
|
setIsActionsVisible(isRelatedTargetFromActions);
|
|
});
|
|
if (actions) {
|
|
actions.ref = actionsRefs;
|
|
actions.onBlur = handleActionsBlur;
|
|
}
|
|
const hasActions = Boolean(props.actions);
|
|
_react.useEffect(()=>{
|
|
if (treeItemRef.current && hasActions) {
|
|
const treeItemElement = treeItemRef.current;
|
|
const handleMouseOver = setActionsVisibleIfNotFromSubtree;
|
|
const handleMouseOut = setActionsInvisibleIfNotFromSubtree;
|
|
const handleFocus = setActionsVisibleIfNotFromSubtree;
|
|
const handleBlur = setActionsInvisibleIfNotFromSubtree;
|
|
treeItemElement.addEventListener('mouseover', handleMouseOver);
|
|
treeItemElement.addEventListener('mouseout', handleMouseOut);
|
|
treeItemElement.addEventListener('focus', handleFocus);
|
|
treeItemElement.addEventListener('blur', handleBlur);
|
|
return ()=>{
|
|
treeItemElement.removeEventListener('mouseover', handleMouseOver);
|
|
treeItemElement.removeEventListener('mouseout', handleMouseOut);
|
|
treeItemElement.removeEventListener('focus', handleFocus);
|
|
treeItemElement.removeEventListener('blur', handleBlur);
|
|
};
|
|
}
|
|
}, [
|
|
hasActions,
|
|
treeItemRef,
|
|
setActionsVisibleIfNotFromSubtree,
|
|
setActionsInvisibleIfNotFromSubtree
|
|
]);
|
|
return {
|
|
components: {
|
|
root: 'div',
|
|
expandIcon: 'div',
|
|
iconBefore: 'div',
|
|
main: 'div',
|
|
iconAfter: 'div',
|
|
actions: 'div',
|
|
aside: 'div',
|
|
// Casting here to a union between checkbox and radio
|
|
selector: selectionMode === 'multiselect' ? _reactcheckbox.Checkbox : _reactradio.Radio
|
|
},
|
|
buttonContextValue: {
|
|
size: 'small'
|
|
},
|
|
root: _reactutilities.slot.always((0, _reactutilities.getIntrinsicElementProps)('div', {
|
|
...props,
|
|
// FIXME:
|
|
// `ref` is wrongly assigned to be `HTMLElement` instead of `HTMLDivElement`
|
|
// but since it would be a breaking change to fix it, we are casting ref to it's proper type
|
|
ref: (0, _reactutilities.useMergedRefs)(ref, layoutRef)
|
|
}), {
|
|
elementType: 'div'
|
|
}),
|
|
iconBefore: _reactutilities.slot.optional(iconBefore, {
|
|
elementType: 'div'
|
|
}),
|
|
main: _reactutilities.slot.always(main, {
|
|
elementType: 'div'
|
|
}),
|
|
iconAfter: _reactutilities.slot.optional(iconAfter, {
|
|
elementType: 'div'
|
|
}),
|
|
aside: !isActionsVisible ? _reactutilities.slot.optional(props.aside, {
|
|
elementType: 'div'
|
|
}) : undefined,
|
|
actions,
|
|
expandIcon,
|
|
selector: _reactutilities.slot.optional(props.selector, {
|
|
renderByDefault: selectionMode !== 'none',
|
|
defaultProps: {
|
|
checked,
|
|
tabIndex: -1,
|
|
'aria-hidden': true,
|
|
ref: selectionRef
|
|
},
|
|
elementType: selectionMode === 'multiselect' ? _reactcheckbox.Checkbox : _reactradio.Radio
|
|
})
|
|
};
|
|
};
|
|
function assertIsRefObject(ref) {
|
|
if (process.env.NODE_ENV !== 'production') {
|
|
if (typeof ref !== 'object' || ref === null || !('current' in ref)) {
|
|
throw new Error(`
|
|
@fluentui/react-tree [${useTreeItemLayout_unstable.name}]:
|
|
Internal Error: contextual ref is not a RefObject! Please report this bug immediately, as contextual refs should be RefObjects.
|
|
`);
|
|
}
|
|
}
|
|
}
|