Skip to content

Commit

Permalink
Migrate to vue 3
Browse files Browse the repository at this point in the history
Signed-off-by: Raimund Schlüßler <[email protected]>
  • Loading branch information
raimund-schluessler committed Sep 30, 2022
1 parent 148048b commit a9bbe06
Show file tree
Hide file tree
Showing 52 changed files with 16,502 additions and 24,139 deletions.
39,448 changes: 15,949 additions & 23,499 deletions package-lock.json

Large diffs are not rendered by default.

51 changes: 29 additions & 22 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@
"dist"
],
"dependencies": {
"@ckpack/vue-color": "^1.2.0",
"@nextcloud/auth": "^2.0.0",
"@nextcloud/axios": "^2.0.0",
"@nextcloud/browser-storage": "^0.1.1",
Expand All @@ -50,47 +51,50 @@
"@nextcloud/l10n": "^1.6.0",
"@nextcloud/logger": "^2.2.1",
"@nextcloud/router": "^2.0.0",
"click-outside-vue3": "^4.0.1",
"debounce": "1.2.1",
"emoji-mart-vue-fast": "^11.1.1",
"escape-html": "^1.0.3",
"floating-vue": "^1.0.0-beta.18",
"floating-vue": "^2.0.0-beta.19",
"focus-trap": "^7.0.0",
"hammerjs": "^2.0.8",
"linkify-string": "^4.0.0",
"md5": "^2.3.0",
"splitpanes": "^2.4.1",
"splitpanes": "^3.1.1",
"string-length": "^5.0.1",
"striptags": "^3.2.0",
"tributejs": "^5.1.3",
"v-click-outside": "^3.2.0",
"vue": "^2.7.8",
"vue-color": "^2.8.1",
"vue": "^3.2.38",
"vue-datepicker-next": "^1.0.2",
"vue-material-design-icons": "^5.1.2",
"vue-multiselect": "^2.1.6",
"vue2-datepicker": "^3.11.0"
"vue-multiselect": "^3.0.0-alpha.2"
},
"peerDependencies": {
"vue": "^3.2.38"
},
"engines": {
"node": "^16.0.0",
"npm": "^7.0.0 || ^8.0.0"
},
"devDependencies": {
"@cypress/vue": "^2.2.4",
"@cypress/webpack-dev-server": "^1.8.4",
"@cypress/vue": "^4.2.0",
"@cypress/webpack-dev-server": "^2.3.0",
"@cypress/webpack-preprocessor": "5.13.0",
"@fontsource/roboto": "^4.5.8",
"@nextcloud/babel-config": "^1.0.0",
"@nextcloud/browserslist-config": "^2.3.0",
"@nextcloud/eslint-config": "^8.1.2",
"@nextcloud/eslint-config": "github:nextcloud/eslint-config#8fe45614b68e95639b64d6d3bac2d6821c1bb1af",
"@nextcloud/stylelint-config": "^2.1.2",
"@vue/test-utils": "^1.3.0",
"@vue/vue2-jest": "^29.0.0",
"@vue/compiler-sfc": "^3.2.38",
"@vue/test-utils": "^2.0.2",
"@vue/vue3-jest": "^29.0.0",
"babel-jest": "^29.0.1",
"babel-loader": "^8.2.5",
"babel-loader-exclude-node-modules-except": "^1.0.3",
"css-loader": "~6.7.1",
"cypress": "^9.7.0",
"cypress-visual-regression": "^1.5.0",
"eslint-plugin-cypress": "^2.11.1",
"babel-loader-exclude-node-modules-except": "^1.2.1",
"css-loader": "^6.7.1",
"cypress": "^10.7.0",
"cypress-visual-regression": "^1.7.0",
"eslint-plugin-cypress": "^2.12.1",
"file-loader": "^6.2.0",
"gettext-extractor": "^3.5.4",
"gettext-parser": "^6.0.0",
Expand All @@ -107,9 +111,9 @@
"style-loader": "^3.3.1",
"url-loader": "^4.1.1",
"vue-eslint-parser": "^9.0.3",
"vue-loader": "^15.10.0",
"vue-styleguidist": "~4.54.1",
"vue-template-compiler": "^2.7.9",
"vue-loader": "^17.0.0",
"vue-styleguidist": "^4.54.1",
"vue-template-compiler": "^2.7.10",
"webpack": "^5.74.0",
"webpack-cli": "^4.10.0",
"webpack-merge": "^5.8.0",
Expand All @@ -121,13 +125,16 @@
"vue"
],
"testEnvironment": "jsdom",
"testEnvironmentOptions": {
"customExportConditions": ["node", "node-addons"]
},
"transform": {
"^.+\\.js$": "babel-jest",
"^.+\\.vue$": "@vue/vue2-jest",
"^.+\\.vue$": "@vue/vue3-jest",
".+\\.(css|styl|less|sass|scss|png|jpg|ttf|woff|woff2)$": "jest-transform-stub"
},
"transformIgnorePatterns": [
"/node_modules/(?!vue-material-design-icons)"
"/node_modules/(?!(.*vue-material-design-icons|.*vue-multiselect))"
],
"snapshotSerializers": [
"<rootDir>/node_modules/jest-serializer-vue"
Expand Down
3 changes: 1 addition & 2 deletions src/components/NcActionInput/NcActionInput.vue
Original file line number Diff line number Diff line change
Expand Up @@ -80,8 +80,7 @@ For the multiselect component, all events will be passed through. Please see the
:disabled="disabled"
:class="{ focusable: isFocusable }"
class="action-input__multi"
v-bind="$attrs"
v-on="$listeners" />
v-bind="$attrs" />

<template v-else>
<input :id="id" type="submit" class="action-input__submit">
Expand Down
2 changes: 1 addition & 1 deletion src/components/NcActionRouter/NcActionRouter.vue
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@
class="action-router focusable"
:aria-label="ariaLabel"
rel="nofollow noreferrer noopener"
@click.native="onClick">
@click="onClick">
<!-- @slot Manually provide icon -->
<slot name="icon">
<span :class="[isIconUrl ? 'action-router__icon--url' : icon]"
Expand Down
198 changes: 81 additions & 117 deletions src/components/NcActions/NcActions.vue
Original file line number Diff line number Diff line change
Expand Up @@ -521,9 +521,10 @@ import Tooltip from '../../directives/Tooltip/index.js'
import GenRandomId from '../../utils/GenRandomId.js'
import { t } from '../../l10n.js'

import Vue from 'vue'
import DotsHorizontal from 'vue-material-design-icons/DotsHorizontal.vue'

import { h, Fragment, resolveComponent, withDirectives, warn } from 'vue'

const focusableSelector = '.focusable'

/**
Expand Down Expand Up @@ -711,6 +712,9 @@ export default {
const componentName = action?.componentOptions?.Ctor?.extendOptions?.name ?? action?.componentOptions?.tag
return ['NcActionButton', 'NcActionLink', 'NcActionRouter'].includes(componentName)
},
isAction(vnode) {
return vnode?.type?.name?.startsWith?.('NcAction')
},

// MENU STATE MANAGEMENT
openMenu(e) {
Expand Down Expand Up @@ -892,25 +896,32 @@ export default {
/**
* The render function to display the component
*
* @param {Function} h The function to create VNodes
* @return {VNodes} The created VNodes
*/
render(h) {
/**
* Filter the Actions, so that we only get allowed components.
* This also ensure that we don't get 'text' elements, which would
* become problematic later on.
*/
const actions = (this.$slots.default || []).filter(
action => action?.componentOptions?.tag
)
render() {
const actions = []
// We have to iterate over all slot elements
this.$slots.default?.().forEach(vnode => {
if (this.isAction(vnode)) {
actions.push(vnode)
return
}
// If we encounter a Fragment, we have to check its children too
if (vnode?.type === Fragment) {
vnode?.children?.forEach?.(child => {
if (this.isAction(child)) {
actions.push(child)
}
})
}
})

/**
* Filter and list actions that are allowed to be displayed inline
*/
let inlineActions = actions.filter(this.isValidSingleAction)
if (this.forceMenu && inlineActions.length > 0 && this.inline > 0) {
Vue.util.warn('Specifying forceMenu will ignore any inline actions rendering.')
warn('Specifying forceMenu will ignore any inline actions rendering.')
inlineActions = []
}

Expand All @@ -926,53 +937,39 @@ export default {
* @return {Function} the vue render function
*/
const renderInlineAction = (action) => {
const icon = action?.data?.scopedSlots?.icon()?.[0] || h('span', { class: ['icon', action?.componentOptions?.propsData?.icon] })
const icon = action?.children?.icon?.()?.[0] || h('span', { class: ['icon', action?.componentOptions?.propsData?.icon] })
const title = this.forceTitle ? this.menuTitle : ''
const clickListener = action?.componentOptions?.listeners?.click
const clickListener = action?.props?.onClick

return h('NcButton',
return withDirectives(h(resolveComponent('NcButton'),
{
class: [
'action-item action-item--single',
action?.data?.staticClass,
action?.data?.class,
],
attrs: {
'aria-label': action?.componentOptions?.propsData?.ariaLabel || action?.componentOptions?.children?.[0]?.text,
},
props: {
// If it has a title, we use a secondary button
type: this.type || (title ? 'secondary' : 'tertiary'),
disabled: this.disabled || action?.componentOptions?.propsData?.disabled,
...action?.componentOptions?.propsData,
},
directives: [{
name: 'tooltip',
value: action?.componentOptions?.children?.[0]?.text,
modifiers: {
auto: true,
'aria-label': action?.componentOptions?.propsData?.ariaLabel || action?.componentOptions?.children?.[0]?.text,
// If it has a title, we use a secondary button
type: this.type || (title ? 'secondary' : 'tertiary'),
disabled: this.disabled || action?.componentOptions?.propsData?.disabled,
...action?.componentOptions?.propsData,
onFocus: this.onFocus,
onBlur: this.onBlur,
// If we have a click listener,
// we bind it to execute on click and forward the click event
...(!!clickListener && {
onClick: (event) => {
if (clickListener) {
clickListener(event)
}
},

}],
on: {
focus: this.onFocus,
blur: this.onBlur,
// If we have a click listener,
// we bind it to execute on click and forward the click event
...(!!clickListener && {
click: (event) => {
if (clickListener) {
clickListener(event)
}
},
}),
},
}),
},
[
h('template', { slot: 'icon' }, [icon]),
title,
],
)
{
default: () => title,
icon: () => icon,
},
), [[Tooltip, action.children.default?.()?.[0]?.children?.trim(), '', { auto: true }]])
}

/**
Expand All @@ -982,92 +979,59 @@ export default {
* @return {Function} the vue render function
*/
const renderActionsPopover = (actions) => {
const triggerIcon = this.$slots.icon?.[0] || (
const triggerIcon = this.$slots.icon?.()?.[0] || (
this.defaultIcon
? h('span', { class: ['icon', this.defaultIcon] })
: h('DotsHorizontal', {
props: {
size: 20,
},
})
: h(resolveComponent('DotsHorizontal'), { size: 20 })
)
return h('NcPopover',
return h(resolveComponent('NcPopover'),
{
ref: 'popover',
props: {
delay: 0,
handleResize: true,
shown: this.opened,
placement: this.placement,
boundary: this.boundariesElement,
container: this.container,
popoverBaseClass: 'action-item__popper',
},
// For some reason the popover component
// does not react to props given under the 'props' key,
// so we use both 'attrs' and 'props'
attrs: {
delay: 0,
handleResize: true,
shown: this.opened,
placement: this.placement,
boundary: this.boundariesElement,
container: this.container,
popoverBaseClass: 'action-item__popper',
},
on: {
show: this.openMenu,
'after-show': this.onOpen,
hide: this.closeMenu,
},
delay: 0,
handleResize: true,
shown: this.opened,
placement: this.placement,
boundary: this.boundariesElement,
container: this.container,
popoverBaseClass: 'action-item__popper',
onShow: this.openMenu,
onAfterShow: this.onOpen,
onHide: this.closeMenu,
},
[
h('NcButton', {
{
trigger: () => h(resolveComponent('NcButton'), {
class: 'action-item__menutoggle',
props: {
type: this.triggerBtnType,
disabled: this.disabled,
},
slot: 'trigger',
type: this.triggerBtnType,
disabled: this.disabled,
ref: 'menuButton',
attrs: {
'aria-haspopup': 'menu',
'aria-label': this.ariaLabel,
'aria-controls': this.opened ? this.randomId : null,
'aria-expanded': this.opened.toString(),
},
on: {
focus: this.onFocus,
blur: this.onBlur,
},
}, [
h('template', { slot: 'icon' }, [triggerIcon]),
this.menuTitle,
]),
h('div', {
'aria-haspopup': 'menu',
'aria-label': this.ariaLabel,
'aria-controls': this.opened ? this.randomId : null,
'aria-expanded': this.opened.toString(),
onFocus: this.onFocus,
onBlur: this.onBlur,
}, {
icon: () => triggerIcon,
default: () => this.menuTitle,
}),
default: () => h('div', {
class: {
open: this.opened,
},
attrs: {
tabindex: '-1',
},
on: {
keydown: this.onKeydown,
mousemove: this.onMouseFocusAction,
},
tabindex: '-1',
onKeydown: this.onKeydown,
onMousemove: this.onMouseFocusAction,
ref: 'menu',
}, [
h('ul', {
attrs: {
id: this.randomId,
tabindex: '-1',
role: 'menu',
},
id: this.randomId,
tabindex: '-1',
role: 'menu',
}, [
actions,
]),
]),
],
},
)
}

Expand Down
Loading

0 comments on commit a9bbe06

Please sign in to comment.