99 lines
2.7 KiB
Plaintext
99 lines
2.7 KiB
Plaintext
// @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);
|