Skip to content

Commit

Permalink
feat(runtime): v-model directive
Browse files Browse the repository at this point in the history
  • Loading branch information
msaelices committed Apr 19, 2020
1 parent 9747bfa commit cd84b57
Show file tree
Hide file tree
Showing 5 changed files with 67 additions and 21 deletions.
14 changes: 3 additions & 11 deletions packages/compiler/src/runtimeHelpers.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,6 @@
import { registerRuntimeHelpers } from '@vue/compiler-core'

export const V_MODEL_RADIO = Symbol(__DEV__ ? `vModelRadio` : ``)
export const V_MODEL_CHECKBOX = Symbol(__DEV__ ? `vModelCheckbox` : ``)
export const V_MODEL_TEXT = Symbol(__DEV__ ? `vModelText` : ``)
export const V_MODEL_SELECT = Symbol(__DEV__ ? `vModelSelect` : ``)
export const V_MODEL_DYNAMIC = Symbol(__DEV__ ? `vModelDynamic` : ``)
export const V_MODEL = Symbol(__DEV__ ? `vModel` : ``)

export const V_ON_WITH_MODIFIERS = Symbol(__DEV__ ? `vOnModifiersGuard` : ``)
export const V_ON_WITH_KEYS = Symbol(__DEV__ ? `vOnKeysGuard` : ``)
Expand All @@ -17,15 +13,11 @@ export const TRANSITION_GROUP = Symbol(__DEV__ ? `TransitionGroup` : ``)
export const ACTION_BAR = Symbol(__DEV__ ? `ActionBar` : ``)

registerRuntimeHelpers({
[V_MODEL_RADIO]: `vModelRadio`,
[V_MODEL_CHECKBOX]: `vModelCheckbox`,
[V_MODEL_TEXT]: `vModelText`,
[V_MODEL_SELECT]: `vModelSelect`,
[V_MODEL_DYNAMIC]: `vModelDynamic`,
[V_MODEL]: `vModel`,
[V_ON_WITH_MODIFIERS]: `withModifiers`,
[V_ON_WITH_KEYS]: `withKeys`,
[V_SHOW]: `vShow`,
[TRANSITION]: `Transition`,
[TRANSITION_GROUP]: `TransitionGroup`,
[ACTION_BAR]: `ActionBar`
[ACTION_BAR]: `ActionBar`,
})
49 changes: 48 additions & 1 deletion packages/runtime/src/directives/vModel.ts
Original file line number Diff line number Diff line change
@@ -1 +1,48 @@
// todo: if the element is a knownView - we should transform v-model to rely on the built-in events (valueChanged) and not require wrapping them in a Vue component.
import { ObjectDirective, VNode } from '@vue/runtime-core'
import { getViewMeta, NSModel } from '../registry'
import { addEventListener } from '../modules/events'
import { INSVElement } from '../nodes'
import { isArray, invokeArrayFns } from '@vue/shared'

type AssignerFn = (value: any) => void

const getModelAssigner = (vnode: VNode): AssignerFn => {
const fn = vnode.props!['onUpdate:modelValue']
return isArray(fn) ? (value) => invokeArrayFns(fn, value) : fn
}

function toNumber(val: string): number | string {
const n = parseFloat(val)
return isNaN(n) ? val : n
}

type ModelDirective<T> = ObjectDirective<T & { _assign: AssignerFn }>

export const vModel: ModelDirective<INSVElement> = {
beforeMount(el, { value, modifiers: { trim, number } }, vnode) {
el._assign = getModelAssigner(vnode)
const castToNumber = number
const { prop, event } = getViewMeta(el.tagName).model as NSModel
el._assign(value)
el.setAttribute(prop, value)

addEventListener(el, event, () => {
let propValue: unknown = el.getAttribute(prop)
if (trim && typeof propValue === 'string') {
propValue = propValue.trim()
} else if (castToNumber && typeof propValue === 'string') {
propValue = toNumber(propValue)
}
el._assign(propValue)
})
},

beforeUpdate(el, { value, oldValue }, vnode) {
const { prop } = getViewMeta(el.tagName).model as NSModel
el._assign = getModelAssigner(vnode)
if (value === oldValue) {
return
}
el.setAttribute(prop, value)
},
}
9 changes: 5 additions & 4 deletions packages/runtime/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import {
RootRenderFunction,
CreateAppFunction,
ComponentPublicInstance,
VNode
VNode,
} from '@vue/runtime-core'
import { Application } from '@nativescript/core'
import { debug } from '@nativescript-vue/shared'
Expand All @@ -15,7 +15,7 @@ import './registry'

const rendererOptions = {
patchProp,
...nodeOps
...nodeOps,
}

let renderer: Renderer
Expand All @@ -31,11 +31,11 @@ function runApp(root: ComponentPublicInstance): ComponentPublicInstance {
`Root Node: ${JSON.stringify({
id: root.$el.nodeId,
type: root.$el.nodeType,
tag: root.$el.tagName
tag: root.$el.tagName,
})}`
)
return root.$el.nativeView
}
},
})

return root
Expand Down Expand Up @@ -63,6 +63,7 @@ export * from './registry'
export { resolveComponent } from './resolveAssets'

// runtime directive helpers
export { vModel } from './directives/vModel'
export { vShow } from './directives/vShow'

// Runtime components
Expand Down
4 changes: 2 additions & 2 deletions packages/runtime/src/modules/events.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ type EventValueWithOptions = {
invoker?: Invoker | null
}

function addEventListener(
export function addEventListener(
el: INSVElement,
event: string,
handler: EventListener,
Expand Down Expand Up @@ -68,7 +68,7 @@ export function patchEvent(
}

function createInvoker(initialValue: EventValue) {
const invoker: Invoker = e => {
const invoker: Invoker = (e) => {
callWithAsyncErrorHandling(invoker.value, null, 5, [e])
}
invoker.value = initialValue
Expand Down
12 changes: 9 additions & 3 deletions packages/runtime/src/registry.ts
Original file line number Diff line number Diff line change
@@ -1,20 +1,26 @@
import {
Frame as TNSFrame,
Page as TNSPage,
ViewBase as TNSViewBase
ViewBase as TNSViewBase,
} from '@nativescript/core'
import { NSVElement, NSVViewFlags } from './nodes'
import { actionBarNodeOps } from './components/ActionBar'
import { warn } from '@vue/runtime-core'

export type NSVElementResolver = () => TNSViewBase

export type NSModel = {
prop: string
event: string
}

export interface NSVViewMeta {
viewFlags: NSVViewFlags
nodeOps?: {
insert(child: NSVElement, parent: NSVElement, atIndex?: number): void
remove(child: NSVElement, parent: NSVElement): void
}
model?: NSModel
}

export interface NSVElementDescriptor {
Expand All @@ -23,7 +29,7 @@ export interface NSVElementDescriptor {
}

export let defaultViewMeta: NSVViewMeta = {
viewFlags: NSVViewFlags.NONE
viewFlags: NSVViewFlags.NONE,
}

let elementMap: Record<string, NSVElementDescriptor> = {}
Expand Down Expand Up @@ -76,7 +82,7 @@ export function registerElement(

elementMap[normalizedName] = {
meta: mergedMeta,
resolver
resolver,
}
// console.log(`->registerElement(${elementName})`)
}
Expand Down

0 comments on commit cd84b57

Please sign in to comment.