Skip to content

Commit

Permalink
chore(lib): update NotificationNotice
Browse files Browse the repository at this point in the history
- `NotificationNotice` migrates to Vue 3. Changes sufficient to render
  the documentation page of `Notice` are made. Scss is also slightly
  changed. A commit of updates on the documentation page will follow
  this commit.
- In `src/components/notification/NotificationNotice.vue`,
    - `v-bind="$options.propsData"` is replaced with
      `v-bind="$attrs"` because there is no way to pass
      `$options` via the `h` (createElement) function on Vue 3.
      `$attrs` contains necessary props because `NoticeMixin` is
      replaced with `NoticeMixinSubset` (see below).
    - Adds a `duration` prop because `NoticeMixinSubset` does not
      include it. `duration` is explicitly given to `<b-notification>`
      because it is not included in `$attrs`.
    - `<b-notification>` tag is duplicated to tell two cases, with or
      without a default slot. `<slot v-if... />` did not work. It set
      a comment node as the default slot.
    - `duration` is given to `<b-notification>`.
    - `model-value` of `<b-notification>` syncs with `isActive` to do
      animation.
    - `Notification` is explicitly registered, because
      `NotificationNotice` will be mounted on a brand-new Vue app.
    - Removes `$destroy` because Vue 3 no longer provides it.
    - Lists the "close" event in `emits`.
- In `src/components/notification/Notification.vue`,
    - `Progress` is explicitly registered, because `Notification` may be
      embedded in `NotificationNotice` which is programmatically opened.
- In `src/components/notification/index.js`,
    - A component instance of `NotificationNotice` is obtained by
      mounting a brand-new Vue app created by `createApp` instead of
      directly newing a `Vue.extend`ed component. Because the latter
      is no longer supported by Vue 3. A brand-new `$buefy` global
      property is added to the new Vue app so that
      `globalNoticeInterval` is available.
    - `createApp` does not actually returns an instance of
      `NotificationNotice` but another component that wraps
      `NotificationNotice`. It exposes the `close` function so that
      it can be programmatically closed. It also calls an `onClose`
      function specified to props when it is closed.
    - A mounted app unmounts itself when the `Notice` is closed.
- In a new file `src/components/notification/NoticeMixinSubset.js`,
    - `NoticeMixinSubset` copies `NoticeMixin` but excludes the
      following props not used by `NoticeMixin` itself,
        - `type`
        - `message`
        - `duration`

      By excluding these props, they are passed through to
      `Notification` from `NotificationNotice.`
- In `src/utils/NoticeMixin.js`,
    - `emits` lists "click", and "close" events.
- In `src/scss/utils/_animation.scss`,
    - `.fade-ender` --> `.fade-enter-from`, to conform to Vue 3.
    - Other classes related to animation are not used in the
      documentation page but also renamed,
          - `.zoom-in-enter` --> `.zoom-in-enter-from`
          - `.zoom-out-enter` --> `.zoom-out-enter-from`
          - `.slide-next-enter` --> `.slide-next-enter-from`
          - `.slide-prev-enter` --> `.slide-prev-enter-from`
          - `.slide-down-enter` --> `.slide-down-enter-from`
          - `.slide-up-enter` --> `.slide-up-enter-from`
          - `.slide-enter` --> `.slide-enter-from`
- Common,
    - ESLint fix is applied.
  • Loading branch information
kikuomax committed Jul 7, 2023
1 parent 5bc62ff commit 8213633
Show file tree
Hide file tree
Showing 6 changed files with 123 additions and 36 deletions.
24 changes: 24 additions & 0 deletions src/components/notification/NoticeMixinSubset.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import NoticeMixin from '../../utils/NoticeMixin.js'

// drops props not used by `NoticeMixin` itself
// - type
// - message
// - duration
const {
queue,
indefinite,
pauseOnHover,
position,
container
} = NoticeMixin.props

export default {
...NoticeMixin,
props: {
queue,
indefinite,
pauseOnHover,
position,
container
}
}
12 changes: 10 additions & 2 deletions src/components/notification/Notification.vue
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,8 @@
:pack="iconPack"
:size="newIconSize"
both
aria-hidden/>
aria-hidden
/>
</div>
<div class="media-content">
<template v-if="$slots.default">
Expand All @@ -37,16 +38,23 @@
:value="remainingTime - 1"
:max="duration / 1000 - 1"
:type="type"
:rounded="false"/>
:rounded="false"
/>
</article>
</transition>
</template>

<script>
import Progress from '../progress/Progress.vue'
import MessageMixin from '../../utils/MessageMixin'
export default {
name: 'BNotification',
components: {
// directly registers Progress
// in case Notification is programmatically opened
[Progress.name]: Progress
},
mixins: [MessageMixin],
props: {
position: String,
Expand Down
31 changes: 27 additions & 4 deletions src/components/notification/NotificationNotice.vue
Original file line number Diff line number Diff line change
@@ -1,24 +1,48 @@
<template>
<b-notification
v-bind="$options.propsData"
v-if="$slots.default != null"
ref="notification"
:position="position"
:model-value="isActive"
v-bind="$attrs"
:duration="duration"
@click="click"
@close="close"
@mouseenter="pause"
@mouseleave="removePause"
>
<slot />
</b-notification>
<b-notification
v-else
ref="notification"
:position="position"
:model-value="isActive"
v-bind="$attrs"
:duration="duration"
@click="click"
@close="close"
@mouseenter="pause"
@mouseleave="removePause"
/>
</template>

<script>
import config from '../../utils/config'
import NoticeMixin from '../../utils/NoticeMixin'
import { removeElement } from '../../utils/helpers'
import NoticeMixinSubset from './NoticeMixinSubset'
import Notification from './Notification'
export default {
name: 'BNotificationNotice',
mixins: [NoticeMixin],
components: {
[Notification.name]: Notification
},
mixins: [NoticeMixinSubset],
props: {
duration: Number
},
emits: ['close'],
data() {
return {
newDuration: this.duration || config.defaultNotificationDuration
Expand All @@ -33,7 +57,6 @@ export default {
// Timeout for the animation complete before destroying
setTimeout(() => {
this.$destroy()
removeElement(this.$el)
}, 150)
}
Expand Down
73 changes: 52 additions & 21 deletions src/components/notification/index.js
Original file line number Diff line number Diff line change
@@ -1,15 +1,14 @@
import { createApp, h as createElement } from 'vue'

import Notification from './Notification.vue'
import NotificationNotice from './NotificationNotice.vue'

import config, { VueInstance } from '../../utils/config'
import config from '../../utils/config'
import { merge } from '../../utils/helpers'
import { use, registerComponent, registerComponentProgrammatic } from '../../utils/plugins'

let localVueInstance

const NotificationProgrammatic = {
open(params) {
let parent
if (typeof params === 'string') {
params = {
message: params
Expand All @@ -20,37 +19,69 @@ const NotificationProgrammatic = {
position: config.defaultNotificationPosition || 'is-top-right'
}
if (params.parent) {
parent = params.parent
delete params.parent
}
let onClose
if (typeof params.onClose === 'function') {
onClose = params.onClose
delete params.onClose
}
let slot
if (Array.isArray(params.message)) {
slot = params.message
delete params.message
}
// fix animation
params.active = false
const propsData = merge(defaultParam, params)
const vm = typeof window !== 'undefined' && window.Vue ? window.Vue : localVueInstance || VueInstance
const NotificationNoticeComponent = vm.extend(NotificationNotice)
const component = new NotificationNoticeComponent({
parent,
el: document.createElement('div'),
propsData
const container = document.createElement('div')
const vueInstance = createApp({
data() {
return {
noticeVNode: null
}
},
methods: {
close() {
const notice =
this.noticeVNode?.component?.expose ||
this.noticeVNode?.component?.proxy
notice?.close()
}
},
render() {
this.noticeVNode = createElement(
NotificationNotice,
{
...propsData,
onClose: () => {
if (onClose != null) {
onClose()
}
// waits for a while in favor of animation
setTimeout(() => {
vueInstance.unmount()
}, 150)
}
},
slot != null ? { default: () => slot } : undefined
)
return this.noticeVNode
}
})
if (slot) {
component.$slots.default = slot
component.$forceUpdate()
}
// fix animation
component.$children[0].isActive = true
return component
// workaround for an error that
// $buefy.globalNoticeInterval is not defined
vueInstance.use({
install: (Vue) => {
Vue.config.globalProperties.$buefy = {
globalNoticeInterval: null
}
}
})
return vueInstance.mount(container)
}
}

const Plugin = {
install(Vue) {
localVueInstance = Vue
registerComponent(Vue, Notification)
registerComponentProgrammatic(Vue, 'notification', NotificationProgrammatic)
}
Expand Down
18 changes: 9 additions & 9 deletions src/scss/utils/_animations.scss
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@
.fade-leave-active {
transition: opacity $speed-slow $easing;
}
.fade-enter,
.fade-enter-from,
.fade-leave-to {
opacity: 0;
}
Expand All @@ -103,7 +103,7 @@
transition: transform $speed-slow $easing;
}
}
.zoom-in-enter,
.zoom-in-enter-from,
.zoom-in-leave-active {
opacity: 0;
.animation-content,
Expand All @@ -122,7 +122,7 @@
transition: transform $speed-slow $easing;
}
}
.zoom-out-enter,
.zoom-out-enter-from,
.zoom-out-leave-active {
opacity: 0;
.animation-content,
Expand All @@ -138,12 +138,12 @@
.slide-prev-leave-active {
transition: transform $speed-slower cubic-bezier(0.785, 0.135, 0.150, 0.860);
}
.slide-prev-leave-to, .slide-next-enter {
.slide-prev-leave-to, .slide-next-enter-from {
transform: translate3d(-100%, 0, 0);
position: absolute;
width: 100%;
}
.slide-prev-enter, .slide-next-leave-to {
.slide-prev-enter-from, .slide-next-leave-to {
transform: translate3d(100%, 0, 0);
position: absolute;
width: 100%;
Expand All @@ -155,12 +155,12 @@
.slide-up-leave-active {
transition: transform $speed-slower cubic-bezier(0.785, 0.135, 0.150, 0.860);
}
.slide-up-leave-to, .slide-down-enter {
.slide-up-leave-to, .slide-down-enter-from {
transform: translate3d(0, -100%, 0);
position: absolute;
height: 100%;
}
.slide-up-enter, .slide-down-leave-to {
.slide-up-enter-from, .slide-down-leave-to {
transform: translate3d(0, 100%, 0);
position: absolute;
height: 100%;
Expand All @@ -173,11 +173,11 @@
transition: $speed-slow $easing;
transition-timing-function: cubic-bezier(0, 1, 0.5, 1);
}
.slide-enter-to, .slide-leave {
.slide-enter-to, .slide-leave-from {
max-height: 100px;
overflow: hidden;
}
.slide-enter, .slide-leave-to {
.slide-enter-from, .slide-leave-to {
overflow: hidden;
max-height: 0;
}
1 change: 1 addition & 0 deletions src/utils/NoticeMixin.js
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ export default {
},
container: String
},
emits: ['click', 'close'],
data() {
return {
isActive: false,
Expand Down

0 comments on commit 8213633

Please sign in to comment.