Skip to content

Commit

Permalink
Fix actions reactivity (#585)
Browse files Browse the repository at this point in the history
Fix actions reactivity
  • Loading branch information
skjnldsv authored Sep 12, 2019
2 parents 4db24f2 + 7cc3f40 commit a5d4292
Show file tree
Hide file tree
Showing 2 changed files with 75 additions and 44 deletions.
2 changes: 1 addition & 1 deletion src/components/ActionLink/ActionLink.vue
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ export default {
*/
download: {
type: String,
default: ''
default: null
},
/**
* target to open the link
Expand Down
117 changes: 74 additions & 43 deletions src/components/Actions/Actions.vue
Original file line number Diff line number Diff line change
Expand Up @@ -46,11 +46,12 @@ https://www.w3.org/TR/wai-aria-practices/examples/menu-button/menu-button-action
<template>
<!-- if only one action, check if we need to bind to click or not -->
<element v-if="isValidSingleAction"
v-tooltip.auto="getVNodeProp(firstAction, 'text')"
v-bind="firstActionElement"
:class="getVNodeProp(firstAction, 'icon')" class="action-item action-item--single"
v-tooltip.auto="firstAction.text"
:aria-label="firstAction.text"
v-bind="firstActionBinding"
:class="firstAction.icon" class="action-item action-item--single"
rel="noreferrer noopener"
@[firstActionEvent]="execFirstAction">
@[firstActionEventBinding]="execFirstAction">
<!-- fake slot to gather main action -->
<span :aria-hidden="true" hidden>
<!-- @slot All action elements passed into the default slot will be used -->
Expand All @@ -59,7 +60,7 @@ https://www.w3.org/TR/wai-aria-practices/examples/menu-button/menu-button-action
</element>

<!-- more than one action -->
<div v-else v-show="actions.length > 0"
<div v-else v-show="hasMultipleActions"
:class="{'action-item--open': opened}"
class="action-item"
@keydown.up.exact.prevent="focusPreviousAction"
Expand Down Expand Up @@ -158,46 +159,85 @@ export default {
opened: this.open,
focusIndex: 0,
randomId: 'menu-' + GenRandomId(),
offsetX: 0
offsetX: 0,
// Making children reactive!
// By binding this here, vuejs will track the object content
// Needed for firstAction reactivity !!!
children: this.$children
}
},
computed: {
/**
* Is there more than one action?
*/
hasMultipleActions() {
return this.actions.length > 1
},
/**
* Is there any first action ?
* And is it allowed as a standalone element ?
*/
isValidSingleAction() {
return this.actions.length === 1
&& this.firstActionElement !== null
},
firstAction() {
/**
* First action vnode
*/
firstActionVNode() {
return this.actions[0]
},
firstActionElement() {
if (this.firstAction && this.firstAction.componentOptions) {
const tag = this.firstAction.componentOptions.tag
/**
* Reactive binding to the first children
* Since we're here, it means we already passed all the proper checks
* we can assume the first action is the first children too
*/
firstAction() {
return this.children[0]
? this.children[0]
: {}
},
/**
* Binding of the first action to the template
*/
firstActionBinding() {
if (this.firstActionVNode && this.firstActionVNode.componentOptions) {
const tag = this.firstActionVNode.componentOptions.tag
if (tag === 'ActionLink') {
return {
is: 'a',
href: this.getVNodeProp(this.firstAction, 'href'),
target: this.getVNodeProp(this.firstAction, 'target')
href: this.firstAction.href,
target: this.firstAction.target
}
} else if (tag === 'ActionRouter') {
}
if (tag === 'ActionRouter') {
return {
is: 'router-link',
to: this.getVNodeProp(this.firstAction, 'to'),
exact: this.getVNodeProp(this.firstAction, 'exact')
to: this.firstAction.to,
exact: this.firstAction.exact
}
}
if (tag === 'ActionButton') {
return {
is: 'button'
}
}
}
return {
is: 'button'
}
// other action types are not allowed as standalone buttons
return null
},
// return the event to bind if the firstAction have an action
// return the event to bind if the firstActionVNode have an action
firstActionEvent() {
return this.firstAction
&& this.firstAction.componentOptions
&& this.firstAction.componentOptions.listeners
&& this.firstAction.componentOptions.listeners.click
? 'click'
: null
return this.firstActionVNode
&& this.firstActionVNode.componentOptions
&& this.firstActionVNode.componentOptions.listeners
&& this.firstActionVNode.componentOptions.listeners.click
},
firstActionEventBinding() {
return this.firstActionEvent ? 'click' : null
}
},
Expand All @@ -223,9 +263,14 @@ export default {
this.popupItem = this.$el
},
beforeUpdate() {
// ! since we're using $slots to manage our actions
// ! we NEED to update the actions if anything change
// update children & actions
// no need to init actions again since we bound it to $children
// and the array is now reactive
// init actions
this.initActions()
ValidateSlot(this.$slots.default, allowedChildren, this)
},
Expand Down Expand Up @@ -352,30 +397,16 @@ export default {
this.focusAction()
},
/**
* Get a vNode prop
* @param {Object} vnode the vnode
* @param {string} prop the prop
* @returns {any} the prop data if any
*/
getVNodeProp(vnode, prop) {
return vnode.componentOptions.propsData[prop]
},
// ACTIONS MANAGEMENT
// exec the first action and prevent default
// exec the first action
execFirstAction(event) {
if (this.firstAction
&& this.firstAction.componentOptions
&& this.firstAction.componentOptions.listeners
&& this.firstAction.componentOptions.listeners.click) {
this.firstAction.componentOptions.listeners.click(event)
event.preventDefault()
if (this.firstActionEvent) {
this.firstActionEvent(event)
}
},
initActions() {
// filter out invalid slots
this.actions = (this.$slots.default || []).filter(node => node && node.componentOptions)
this.actions = (this.$slots.default || []).filter(node => !!node && !!node.componentOptions)
}
}
}
Expand Down

0 comments on commit a5d4292

Please sign in to comment.