-
-
Notifications
You must be signed in to change notification settings - Fork 1.6k
/
applyStyles.js
98 lines (82 loc) · 2.66 KB
/
applyStyles.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
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);