82 lines
3.4 KiB
JavaScript
82 lines
3.4 KiB
JavaScript
import { tokens } from '@fluentui/react-theme';
|
|
/**
|
|
* @internal
|
|
* Helper that creates a makeStyles rule for an arrow element.
|
|
* For runtime arrow size toggling simply create extra classnames to apply to the arrow element
|
|
*
|
|
* ```ts
|
|
* makeStyles({
|
|
* arrowWithSize: createArrowStyles({ arrowHeight: 6 }),
|
|
*
|
|
* arrowWithoutSize: createArrowStyles({ arrowHeight: undefined }),
|
|
* mediumArrow: createArrowHeightStyles(4),
|
|
* smallArrow: createArrowHeightStyles(2),
|
|
* })
|
|
* ...
|
|
*
|
|
* state.arrowWithSize.className = styles.arrowWithSize;
|
|
* state.arrowWithoutSize.className = mergeClasses(
|
|
* styles.arrowWithoutSize,
|
|
* state.smallArrow && styles.smallArrow,
|
|
* state.mediumArrow && styles.mediumArrow,
|
|
* )
|
|
* ```
|
|
*/ export function createArrowStyles(options) {
|
|
const { arrowHeight, borderWidth = '1px', borderStyle = 'solid', borderColor = tokens.colorTransparentStroke } = options;
|
|
return {
|
|
boxSizing: 'border-box',
|
|
position: 'absolute',
|
|
zIndex: -1,
|
|
...arrowHeight && createArrowHeightStyles(arrowHeight),
|
|
backgroundColor: 'inherit',
|
|
backgroundClip: 'content-box',
|
|
borderBottomLeftRadius: `${tokens.borderRadiusSmall} /* @noflip */`,
|
|
transform: 'rotate(var(--fui-positioning-arrow-angle)) /* @noflip */',
|
|
height: 'var(--fui-positioning-arrow-height)',
|
|
width: 'var(--fui-positioning-arrow-height)',
|
|
'::before': {
|
|
content: '""',
|
|
display: 'block',
|
|
backgroundColor: 'inherit',
|
|
margin: `-${borderWidth}`,
|
|
width: '100%',
|
|
height: '100%',
|
|
border: `${borderWidth} ${borderStyle} ${borderColor}`,
|
|
borderBottomLeftRadius: `${tokens.borderRadiusSmall} /* @noflip */`,
|
|
clipPath: 'polygon(0% 0%, 100% 100%, 0% 100%)'
|
|
},
|
|
// Popper sets data-popper-placement on the root element, which is used to align the arrow
|
|
':global([data-popper-placement^="top"])': {
|
|
bottom: 'var(--fui-positioning-arrow-offset)',
|
|
'--fui-positioning-arrow-angle': '-45deg'
|
|
},
|
|
':global([data-popper-placement^="right"])': {
|
|
left: `var(--fui-positioning-arrow-offset) /* @noflip */`,
|
|
'--fui-positioning-arrow-angle': '45deg'
|
|
},
|
|
':global([data-popper-placement^="bottom"])': {
|
|
top: 'var(--fui-positioning-arrow-offset)',
|
|
'--fui-positioning-arrow-angle': '135deg'
|
|
},
|
|
':global([data-popper-placement^="left"])': {
|
|
right: `var(--fui-positioning-arrow-offset) /* @noflip */`,
|
|
'--fui-positioning-arrow-angle': '225deg'
|
|
}
|
|
};
|
|
}
|
|
/**
|
|
* @internal
|
|
* Creates CSS styles to size the arrow created by createArrowStyles to the given height.
|
|
*
|
|
* Use this when you need to create classes for several different arrow sizes. If you only need a
|
|
* constant arrow size, you can pass the `arrowHeight` param to createArrowStyles instead.
|
|
*/ export function createArrowHeightStyles(arrowHeight) {
|
|
// The arrow is a square rotated 45 degrees to have its bottom and right edges form a right triangle.
|
|
// Multiply the triangle's height by sqrt(2) to get length of its edges.
|
|
const edgeLength = 1.414 * arrowHeight;
|
|
return {
|
|
'--fui-positioning-arrow-height': `${edgeLength}px`,
|
|
'--fui-positioning-arrow-offset': `${edgeLength / 2 * -1}px`
|
|
};
|
|
}
|