diff options
Diffstat (limited to 'popperjs/package/lib/modifiers/applyStyles.js.flow')
-rw-r--r-- | popperjs/package/lib/modifiers/applyStyles.js.flow | 98 |
1 files changed, 98 insertions, 0 deletions
diff --git a/popperjs/package/lib/modifiers/applyStyles.js.flow b/popperjs/package/lib/modifiers/applyStyles.js.flow new file mode 100644 index 0000000..e976cf0 --- /dev/null +++ b/popperjs/package/lib/modifiers/applyStyles.js.flow @@ -0,0 +1,98 @@ +// @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); |