Skip to content

Commit

Permalink
fix(snackbar): add type definition
Browse files Browse the repository at this point in the history
  • Loading branch information
BeADre committed Dec 10, 2020
1 parent a76a0be commit a3283ff
Show file tree
Hide file tree
Showing 5 changed files with 152 additions and 125 deletions.
10 changes: 1 addition & 9 deletions packages/varlet-ui/src/snackbar-core/SnackbarCore.vue
Original file line number Diff line number Diff line change
Expand Up @@ -35,15 +35,7 @@
</template>

<script lang="ts">
import {
defineComponent,
reactive,
computed,
watch,
ref,
Ref,
onMounted,
} from 'vue'
import { defineComponent, reactive, watch, ref, Ref, onMounted } from 'vue'
import Loading from '../loading'
import Button from '../button'
import { useZIndex } from '../context/zIndex'
Expand Down
5 changes: 3 additions & 2 deletions packages/varlet-ui/src/snackbar/Snackbar.vue
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,11 @@
</template>

<script>
import { defineComponent } from 'vue'
import SnackbarCore from '../snackbar-core'
import { props, emits } from '../snackbar-core/propsEmits'
export default {
export default defineComponent({
name: 'VarSnackbar',
components: {
[SnackbarCore.name]: SnackbarCore,
Expand All @@ -39,5 +40,5 @@ export default {
update,
}
},
}
})
</script>
6 changes: 3 additions & 3 deletions packages/varlet-ui/src/snackbar/example/index.vue
Original file line number Diff line number Diff line change
Expand Up @@ -147,7 +147,7 @@
<script lang="ts">
import { defineComponent, ref, Ref, reactive, toRefs } from 'vue'
import Button from '../../button'
import Snackbar from '..'
import Snackbar, { SnackbarType } from '..'
export default defineComponent({
name: 'SnackbarExample',
Expand All @@ -174,7 +174,7 @@ export default defineComponent({
}
const create = (type: any) => {
const snackbar = Snackbar({
const snackbar: any = Snackbar({
content: "Hello, I'm a snackbar-core",
type,
})
Expand All @@ -183,7 +183,7 @@ export default defineComponent({
}, 1000)
}
const createMethod = (type: any) => {
const createMethod = (type: SnackbarType) => {
Snackbar[type]({
content: "Hello, I'm a snackbar-core",
forbidClick: type === 'loading',
Expand Down
254 changes: 144 additions & 110 deletions packages/varlet-ui/src/snackbar/index.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,17 @@
import { h, reactive, TransitionGroup } from 'vue'
import { h, reactive, TransitionGroup, App, RendererElement } from 'vue'
import VarSnackbarCore from '../snackbar-core'
import VarSnackbar from './Snackbar.vue'
import { mountInstance } from '../utils/components'
import { isBasicObject } from '../utils/shared'
import { isBaseObject } from '../utils/shared'

type SnackbarHandel = {
clear: () => void
}

export type SnackbarType = 'success' | 'warning' | 'info' | 'error' | 'loading'

interface SnackbarOptions {
type?: 'loading' | 'success' | 'error' | 'warning' | 'info'
type?: SnackbarType
content?: string
position?: 'top' | 'center' | 'bottom'
loadingType?: string
Expand All @@ -23,106 +29,139 @@ interface SnackbarOptions {
onClosed?: () => void
}

const TransitionGroupHost = {
setup() {
return () => {
const snackbarList = Snackbar.instances.map(
({ id, reactiveSnackOptions, _update }: any) => {
if (reactiveSnackOptions.forbidClick) {
const transitionGroupEl = document.querySelector(
'.var-transition-group'
)
;(transitionGroupEl as HTMLElement).classList.add(
'var-pointer-auto'
)
}
return h(VarSnackbarCore, {
...reactiveSnackOptions,
...{
key: id,
style: {
position: 'relative',
top: getTop(reactiveSnackOptions.position),
},
_update,
'onUpdate:show': (value: boolean) => {
reactiveSnackOptions.show = value
},
},
})
}
)

return h(
TransitionGroup,
{
...transitionGroupProps,
onAfterLeave: removeInstance,
},
snackbarList
)
}
},
interface UniqSnackbarOptions {
id: number
reactiveSnackOptions: SnackbarOptions
_update?: string
}

const Snackbar: any = function (options: SnackbarOptions): any {
const snackOptions: SnackbarOptions = isBasicObject(options) ? options : {}
const reactiveSnackOptions: SnackbarOptions = reactive<SnackbarOptions>(
snackOptions
)
reactiveSnackOptions.show = true

const api = {
clear() {
reactiveSnackOptions.show = false
}
}

if (!Snackbar.isMount) {
Snackbar.isMount = true
mountInstance(TransitionGroupHost)
}
interface Snackbar {
(options: SnackbarOptions): SnackbarHandel
install(app: App): void
allowMultiple(bool: boolean): void
success(options: SnackbarOptions | string): void
warning(options: SnackbarOptions | string): void
info(options: SnackbarOptions | string): void
error(options: SnackbarOptions | string): void
loading(options: SnackbarOptions | string): void
isAllowMultiple: boolean
isMount: boolean | undefined
uniqSnackbarOptions: UniqSnackbarOptions[]
Component: RendererElement
}

const transitionGroupProps: any = {
name: 'var-snackbar-fade',
tag: 'div',
class: 'var-transition-group',
afterEnter: 'onOpened',
afterLeave: 'onClosed',
}

const id = Date.now()
const { length } = Snackbar.instances

if (length === 0) {
Snackbar.instances.push({
id,
reactiveSnackOptions,
})
return api
}

if (!Snackbar.isAllowMultiple) {
Snackbar.instances[0].reactiveSnackOptions = {
...Snackbar.instances[0].reactiveSnackOptions,
...reactiveSnackOptions,
}
Snackbar.instances[0]._update = `update-${id}`
} else {
Snackbar.instances.push({
id,
reactiveSnackOptions,
})
}

return api
const TransitionGroupHost = {
setup() {
return () => {
const snackbarList = Snackbar.uniqSnackbarOptions.map(
({ id, reactiveSnackOptions, _update }: UniqSnackbarOptions) => {
if (reactiveSnackOptions.forbidClick) {
const transitionGroupEl = document.querySelector(
'.var-transition-group'
)
;(transitionGroupEl as HTMLElement).classList.add(
'var-pointer-auto'
)
}
if (Snackbar.isAllowMultiple) reactiveSnackOptions.position = 'top'
return h(VarSnackbarCore, {
...reactiveSnackOptions,
...{
key: id,
'data-id': id,
style: {
position: 'relative',
top: getTop(reactiveSnackOptions.position),
},
_update,
'onUpdate:show': (value: boolean) => {
reactiveSnackOptions.show = value
},
},
})
}
)

return h(
TransitionGroup,
{
...transitionGroupProps,
onAfterLeave: removeUniqOption,
},
snackbarList
)
}
},
}

;['success', 'warning', 'info', 'error', 'loading'].forEach((type: any) => {
Snackbar[type] = (options: SnackbarOptions | string) => {
if (typeof options === 'string') {
options = {
content: options,
type,
const Snackbar: Snackbar = <Snackbar>(
function (options: SnackbarOptions = {}): SnackbarHandel {
const snackOptions: SnackbarOptions = isBaseObject(options) ? options : {}
const reactiveSnackOptions: SnackbarOptions = reactive<SnackbarOptions>(
snackOptions
)
reactiveSnackOptions.show = true

const api = {
clear() {
reactiveSnackOptions.show = false
},
}

if (!Snackbar.isMount) {
Snackbar.isMount = true
mountInstance(TransitionGroupHost)
}

const id = Date.now()
const { length } = Snackbar.uniqSnackbarOptions
const uniqSnackbarOptionItem: UniqSnackbarOptions = {
id,
reactiveSnackOptions,
}

if (length === 0) {
Snackbar.uniqSnackbarOptions.push(uniqSnackbarOptionItem)
return api
}

if (!Snackbar.isAllowMultiple) {
Snackbar.uniqSnackbarOptions[0].reactiveSnackOptions = {
...Snackbar.uniqSnackbarOptions[0].reactiveSnackOptions,
...reactiveSnackOptions,
}
Snackbar.uniqSnackbarOptions[0]._update = `update-${id}`
} else {
options.type = type
Snackbar.uniqSnackbarOptions.push(uniqSnackbarOptionItem)
}

return api
}
)

;(['success', 'warning', 'info', 'error', 'loading'] as const).forEach(
(type) => {
Snackbar[type] = (options: SnackbarOptions | string): SnackbarHandel => {
if (typeof options === 'string') {
options = {
content: options,
type,
}
} else {
options.type = type
}
return Snackbar(options)
}
return Snackbar(options)
}
})
)

Snackbar.install = function (app: any) {
app.component(VarSnackbar.name, VarSnackbar)
Expand All @@ -134,30 +173,25 @@ Snackbar.allowMultiple = function (bool = false) {

Snackbar.isAllowMultiple = true

Snackbar.instances = reactive([]) as any[]
Snackbar.isMount = false

Snackbar.Component = VarSnackbar
Snackbar.uniqSnackbarOptions = reactive<UniqSnackbarOptions[]>([])

const transitionGroupProps = {
name: 'var-snackbar-fade',
tag: 'div',
class: 'var-transition-group',
afterEnter: 'onOpened',
afterLeave: 'onClosed',
}
Snackbar.Component = VarSnackbar

function removeInstance(element: any) {
function removeUniqOption(element: HTMLElement): void {
element.parentElement &&
element.parentElement.classList.remove('var-pointer-auto')
const { key } = element.__vueParentComponent.vnode
for (let i = 0; i < Snackbar.instances.length; i++) {
if (Snackbar.instances[i].id === key) Snackbar.instances.splice(i, 1)
const id = element.getAttribute('data-id')
for (let i = 0; i < Snackbar.uniqSnackbarOptions.length; i++) {
if (Snackbar.uniqSnackbarOptions[i].id === +(id as string))
Snackbar.uniqSnackbarOptions.splice(i, 1)
}
}

function getTop(postion: string) {
if (postion === 'center') return '45%'
if (postion === 'bottom') return '85%'
function getTop(position = 'top'): string {
if (position === 'center') return '45%'
if (position === 'bottom') return '85%'
return '5%'
}

Expand Down
2 changes: 1 addition & 1 deletion packages/varlet-ui/src/utils/shared.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
export const isString = (val: unknown): val is string => typeof val === 'string'

export const isBasicObject = (val: unknown) =>
export const isBaseObject = (val: unknown) =>
Object.prototype.toString.call(val) === '[object Object]'

0 comments on commit a3283ff

Please sign in to comment.