|
1 | 1 | import { NSVElement } from "../../dom";
|
| 2 | +import { NormalizedStyle } from "@vue/shared"; |
2 | 3 |
|
3 | 4 | type Style = string | null;
|
4 | 5 |
|
5 |
| -function isRule(node: any): boolean { |
6 |
| - return node.type === "rule"; |
| 6 | +function normalizeStyle(style: NormalizedStyle | Style): NormalizedStyle { |
| 7 | + if (!style) { |
| 8 | + return null; |
| 9 | + } |
| 10 | + |
| 11 | + if (typeof style === "string" && style?.trim().charAt(0) === "{") { |
| 12 | + return JSON.parse(style); |
| 13 | + } |
| 14 | + |
| 15 | + return style as NormalizedStyle; |
7 | 16 | }
|
8 | 17 |
|
9 |
| -function isDeclaration(node: any): boolean { |
10 |
| - return node.type === "declaration"; |
| 18 | +function normalizeProperty(property: string) { |
| 19 | + if (property.endsWith("Align")) { |
| 20 | + // NativeScript uses Alignment instead of Align, this ensures that text-align works |
| 21 | + property += "ment"; |
| 22 | + } |
| 23 | + |
| 24 | + return property; |
11 | 25 | }
|
12 | 26 |
|
13 |
| -function createDeclaration(decl: any): any { |
14 |
| - return { property: decl.property.toLowerCase(), value: decl.value }; |
| 27 | +export const STYLE_ORIGINAL_VALUE = Symbol("style_original_value"); |
| 28 | + |
| 29 | +function addStyleProperty(el: NSVElement, property: string, value: any) { |
| 30 | + const _sov: Map<string, any> = (el[STYLE_ORIGINAL_VALUE] ??= new Map()); |
| 31 | + property = normalizeProperty(property); |
| 32 | + |
| 33 | + if (!_sov.has(property)) { |
| 34 | + _sov.set(property, el.style[property]); |
| 35 | + } |
| 36 | + |
| 37 | + el.style[property] = value; |
15 | 38 | }
|
16 | 39 |
|
17 |
| -function declarationsFromAstNodes(astRules: any[]): any[] { |
18 |
| - return astRules.filter(isRule).map((rule) => { |
19 |
| - return rule.declarations.filter(isDeclaration).map(createDeclaration); |
20 |
| - }); |
| 40 | +function removeStyleProperty(el: NSVElement, property: string) { |
| 41 | + const _sov: Map<string, any> = (el[STYLE_ORIGINAL_VALUE] ??= new Map()); |
| 42 | + property = normalizeProperty(property); |
| 43 | + |
| 44 | + // only delete styles we added |
| 45 | + if (_sov.has(property)) { |
| 46 | + const originalValue = _sov.get(property); |
| 47 | + _sov.delete(property); |
| 48 | + // edge case: if a style property also exists as an attribute (ie backgroundColor) |
| 49 | + // changing the attribute will not update our originalValue, so when removing |
| 50 | + // the previous color will be applied. Fixing this would involve listening to |
| 51 | + // individual attribute changes, and it's not worth the overhead. |
| 52 | + el.style[property] = originalValue; |
| 53 | + } |
21 | 54 | }
|
22 | 55 |
|
23 | 56 | export function patchStyle(el: NSVElement, prev: Style, next: Style) {
|
24 | 57 | if (prev) {
|
25 |
| - // todo: check if we can substitute cssTreeParse with parseInlineCSS from compiler/transforms/transformStyle (by extracting it to shared) |
26 |
| - // reset previous styles |
27 |
| - const localStyle = `local { ${prev} }`; |
28 |
| - // const ast: any = cssTreeParse(localStyle, undefined) |
29 |
| - // const [declarations] = declarationsFromAstNodes(ast.stylesheet.rules) |
30 |
| - |
31 |
| - // declarations.forEach((d: any) => { |
32 |
| - // ;(el.nativeView.style as any)[d.property] = unsetValue |
33 |
| - // }) |
| 58 | + const style = normalizeStyle(prev); |
| 59 | + // undo old styles |
| 60 | + Object.keys(style).forEach((property) => { |
| 61 | + removeStyleProperty(el, property); |
| 62 | + }); |
34 | 63 | }
|
35 | 64 |
|
36 | 65 | if (!next) {
|
37 | 66 | el.removeAttribute("style");
|
38 | 67 | } else {
|
39 | 68 | // set new styles
|
40 |
| - el.style = next; |
| 69 | + const style = normalizeStyle(next); |
| 70 | + Object.keys(style).forEach((property) => { |
| 71 | + addStyleProperty(el, property, style[property]); |
| 72 | + }); |
41 | 73 | }
|
42 | 74 | }
|
0 commit comments