You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

98 lines
2.7 KiB

// @flow
import type { Modifier, ModifierArguments } from '../types';
import getNodeName from '../dom-utils/getNodeName';
import { isHTMLElement } from '../dom-utils/instanceOf';
// This modifier takes the styles prepared by the `computeStyles` modifier
// and applies them to the HTMLElements such as popper and arrow
function applyStyles({ state }: ModifierArguments<{||}>) {
Object.keys(state.elements).forEach((name) => {
const style = state.styles[name] || {};
const attributes = state.attributes[name] || {};
const element = state.elements[name];
// arrow is optional + virtual elements
if (!isHTMLElement(element) || !getNodeName(element)) {
return;
}
// Flow doesn't support to extend this property, but it's the most
// effective way to apply styles to an HTMLElement
// $FlowFixMe[cannot-write]
Object.assign(element.style, style);
Object.keys(attributes).forEach((name) => {
const value = attributes[name];
if (value === false) {
element.removeAttribute(name);
} else {
element.setAttribute(name, value === true ? '' : value);
}
});
});
}
function effect({ state }: ModifierArguments<{||}>) {
const initialStyles = {
popper: {
position: state.options.strategy,
left: '0',
top: '0',
margin: '0',
},
arrow: {
position: 'absolute',
},
reference: {},
};
Object.assign(state.elements.popper.style, initialStyles.popper);
state.styles = initialStyles;
if (state.elements.arrow) {
Object.assign(state.elements.arrow.style, initialStyles.arrow);
}
return () => {
Object.keys(state.elements).forEach((name) => {
const element = state.elements[name];
const attributes = state.attributes[name] || {};
const styleProperties = Object.keys(
state.styles.hasOwnProperty(name)
? state.styles[name]
: initialStyles[name]
);
// Set all values to an empty string to unset them
const style = styleProperties.reduce((style, property) => {
style[property] = '';
return style;
}, {});
// arrow is optional + virtual elements
if (!isHTMLElement(element) || !getNodeName(element)) {
return;
}
Object.assign(element.style, style);
Object.keys(attributes).forEach((attribute) => {
element.removeAttribute(attribute);
});
});
};
}
// eslint-disable-next-line import/no-unused-modules
export type ApplyStylesModifier = Modifier<'applyStyles', {||}>;
export default ({
name: 'applyStyles',
enabled: true,
phase: 'write',
fn: applyStyles,
effect,
requires: ['computeStyles'],
}: ApplyStylesModifier);