Skip to content

Commit

Permalink
feat(compiler): transformStyle
Browse files Browse the repository at this point in the history
  • Loading branch information
rigor789 committed Apr 1, 2020
1 parent 6b3feb2 commit 5a8d058
Show file tree
Hide file tree
Showing 4 changed files with 127 additions and 2 deletions.
76 changes: 76 additions & 0 deletions packages/compiler/__tests__/transforms/transformStyle.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
// todo: uncomment if/when vue-next#907 is merged/released
// import {
// baseParse as parse,
// transform,
// CompilerOptions,
// ElementNode,
// NodeTypes,
// VNodeCall,
// transformBind,
// transformElement
// } from '@vue/compiler-core'
// import { transformStyle } from '../../src/transforms/transformStyle'
//
// function transformWithStyleTransform(
// template: string,
// options: CompilerOptions = {}
// ) {
// const ast = parse(template)
// transform(ast, {
// nodeTransforms: [transformStyle],
// ...options
// })
// return {
// root: ast,
// node: ast.children[0] as ElementNode
// }
// }
//
describe('compiler: style transform', () => {
test.todo('uncomment tests')
// test('should transform into directive node', () => {
// const { node } = transformWithStyleTransform(`<Label style="color: red"/>`)
// expect(node.props[0]).toMatchObject({
// type: NodeTypes.DIRECTIVE,
// name: `bind`,
// arg: {
// type: NodeTypes.SIMPLE_EXPRESSION,
// content: `style`,
// isStatic: true
// },
// exp: {
// type: NodeTypes.SIMPLE_EXPRESSION,
// content: `{"color":"red"}`,
// isStatic: false
// }
// })
// })
//
// test('working with v-bind transform', () => {
// const { node } = transformWithStyleTransform(`<Label style="color: red"/>`, {
// nodeTransforms: [transformStyle, transformElement],
// directiveTransforms: {
// bind: transformBind
// }
// })
// expect((node.codegenNode as VNodeCall).props).toMatchObject({
// type: NodeTypes.JS_OBJECT_EXPRESSION,
// properties: [
// {
// key: {
// type: NodeTypes.SIMPLE_EXPRESSION,
// content: `style`,
// isStatic: true
// },
// value: {
// type: NodeTypes.SIMPLE_EXPRESSION,
// content: `{"color":"red"}`,
// isStatic: false
// }
// }
// ]
// })
// // should not cause the STYLE patchFlag to be attached
// expect((node.codegenNode as VNodeCall).patchFlag).toBeUndefined()
// })
})
48 changes: 48 additions & 0 deletions packages/compiler/src/transforms/transformStyle.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import {
NodeTransform,
NodeTypes,
createSimpleExpression,
SimpleExpressionNode,
SourceLocation
} from '@vue/compiler-core'

// Parse inline CSS strings for static style attributes into an object.
// This is a NodeTransform since it works on the static `style` attribute and
// converts it into a dynamic equivalent:
// style="color: red" -> :style='{ "color": "red" }'
// It is then processed by `transformElement` and included in the generated
// props.
export const transformStyle: NodeTransform = (node, context) => {
if (node.type === NodeTypes.ELEMENT) {
node.props.forEach((p, i) => {
if (p.type === NodeTypes.ATTRIBUTE && p.name === 'style' && p.value) {
// replace p with an expression node
node.props[i] = {
type: NodeTypes.DIRECTIVE,
name: `bind`,
arg: createSimpleExpression(`style`, true, p.loc),
exp: parseInlineCSS(p.value.content, p.loc),
modifiers: [],
loc: p.loc
}
}
})
}
}

const listDelimiterRE = /;(?![^(]*\))/g
const propertyDelimiterRE = /:(.+)/

function parseInlineCSS(
cssText: string,
loc: SourceLocation
): SimpleExpressionNode {
const res: Record<string, string> = {}
cssText.split(listDelimiterRE).forEach(item => {
if (item) {
const tmp = item.split(propertyDelimiterRE)
tmp.length > 1 && (res[tmp[0].trim()] = tmp[1].trim())
}
})
return createSimpleExpression(JSON.stringify(res), false, loc, true)
}
1 change: 1 addition & 0 deletions packages/runtime/src/modules/style.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ function declarationsFromAstNodes(astRules: any[]): any[] {

export function patchStyle(el: INSVElement, prev: Style, next: Style) {
if (prev) {
// todo: check if we can substitute cssTreeParse with parseInlineCSS from compiler/transforms/transformStyle (by extracting it to shared)
// reset previous styles
const localStyle = `local { ${prev} }`
const ast: any = cssTreeParse(localStyle, undefined)
Expand Down
4 changes: 2 additions & 2 deletions tests/registry.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import {
NSVViewMeta,
registerElement,
defaultViewMeta
defaultViewMeta,
NSVViewFlags
} from '@nativescript-vue/runtime'
import { TNSViewBase } from 'tests/ns-mocks/base'
import { NSVViewFlags } from '../packages/runtime/src/nodes'

export function registerTestElement(
elementName: string,
Expand Down

0 comments on commit 5a8d058

Please sign in to comment.