Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft: refact(KtToaster): to ts #723

Draft
wants to merge 1 commit into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
53 changes: 39 additions & 14 deletions packages/documentation/pages/usage/components/toaster.vue
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,12 @@ Toasters can deliver messages that the user needs to pay attention to without in

![Toaster Structure](~/assets/img/toaster_structure.png)

1. Type Color: Depends on the type of toaster. There are three colors:
1. Type Color: Depends on the type of toaster. It uses the Kotti Color Tokens for success, error, warning:

- `Green-500`: for success information
- `Orange-500`: for warning message
- `Red-500`: for fail/alert message
- `var(--support-error)`: for type `error`
- `var(--support-info)`: for type `info`
- `var(--support-success)`: for type `success`
- `var(--support-warning)`: for type `warning`

2. Message: Keep the message short and easy to understand, since the toaster disappears automatically after a few seconds.

Expand All @@ -26,15 +27,19 @@ Since `Kotti-UI 1.0.0`, [vue-yodify](https://github.com/3YOURMIND/vue-yodify) is
<div class="element-example">
<KtToaster/>
<KtButton
@click="$yodify({ text: 'Wow very looooooooooooong text, and it breaks the line!', type: 'success' })"
@click="notify('Info message', Type.INFO)"
v-text="'Info Message'"
/>
<KtButton
@click="notify('Wow very looooooooooooong text, and it breaks the line!', Type.SUCCESS)"
v-text="'Success Long Message'"
/>
<KtButton
@click="$yodify({ text: 'Error message', type: 'error' })"
@click="notify('Error message', Type.ERROR)"
v-text="'Error Message'"
/>
<KtButton
@click="$yodify({ text: 'Warning message', type: 'warning' })"
@click="notify('Warning message', Type.WARNING)"
v-text="'Warning Message'"
/>
</div>
Expand All @@ -59,17 +64,28 @@ this.$yodify({
})
```

Or within Vue's setup hook

```js
const root = getCurrentInstance()
root.$yodify({
text: 'This was successful :)',
type: 'success', // optional, default
duration: 3000,
})
```

### Attributes

| Attribute | Description | Type | Accepted values | Default |
| :--------- | :------------------------------------------ | :------- | :---------------------------- | :-------- |
| `duration` | duration after which the toaster disappears | `Number` | — | `3000` |
| `text` | text message in the toaster | `String` | — | — |
| `type` | define the type of the toaster | `String` | `success`, `error`, `warning` | `success` |
| Attribute | Description | Type | Accepted values | Default |
| :--------- | :------------------------------------------ | :------- | :------------------------------------ | :-------- |
| `duration` | duration after which the toaster disappears | `Number` | — | `3000` |
| `text` | text message in the toaster | `String` | — | — |
| `type` | define the type of the toaster | `String` | `error`, `info`, `success`, `warning` | `success` |
</template>

<script lang="ts">
import { KtToaster } from '@3yourmind/kotti-ui'
import { Kotti, KtToaster } from '@3yourmind/kotti-ui'
import { defineComponent } from '@vue/composition-api'

import ComponentInfo from '~/components/ComponentInfo.vue'
Expand All @@ -79,9 +95,18 @@ export default defineComponent({
components: {
ComponentInfo,
},
setup() {
setup(_, setupContext) {
const root = setupContext.root

return {
Type: Kotti.Toaster.Type,
component: KtToaster,
notify: (
text: Kotti.Toaster.Notification['text'],
type: Kotti.Toaster.Type,
) => {
root?.$yodify({ text, type })
},
}
},
})
Expand Down
14 changes: 8 additions & 6 deletions packages/kotti-ui/source/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,7 @@ import { KtTag } from './kotti-tag'
export * from './kotti-tag'
import { KtToaster } from './kotti-toaster'
export * from './kotti-toaster'
import { KottiToaster } from './kotti-toaster/types'
import { KtUserMenu } from './kotti-user-menu'
export * from './kotti-user-menu'
export * from './types'
Expand Down Expand Up @@ -166,14 +167,15 @@ export default {
Vue.prototype.$yodify = function ({
duration = DEFAULT_YODIFY_DURATION,
text,
type = 'success',
}: {
duration: number
text: string
type: 'success' | 'error'
}) {
type = KottiToaster.Type.SUCCESS,
}: KottiToaster.Notification) {
const notification = { duration, text, type }

console.log('inside yodify function assignment')
console.log('root', this.$root)
console.log('root.$yodifyBuffer', this.$root.$yodifyBuffer)
console.log('root.$yodify', this.$root.$yodify)

// buffer notifications if vue isn't ready
if (!this.$root) Vue.prototype.$yodifyBuffer.push(notification)
else this.$root.$emit('vue-yodify', notification)
Expand Down
228 changes: 138 additions & 90 deletions packages/kotti-ui/source/kotti-toaster/KtToaster.vue
Original file line number Diff line number Diff line change
Expand Up @@ -11,132 +11,180 @@
<div class="vue-yodify__content" v-text="notification.text" />
<div
class="vue-yodify__close"
@click="deleteNotification(notification.id)"
@click="deleteNotificationById(notification.id)"
>
<i class="yoco" v-text="'close'" />
</div>
</div>
</div>
</template>

<script>
<script lang="ts">
import { Yoco } from '@3yourmind/yoco'
import { TimeConversion } from '@metatypes/units'
import {
getCurrentInstance,
defineComponent,
onUnmounted,
ref,
onMounted,
onBeforeMount,
} from '@vue/composition-api'

import { isBrowser } from '../utilities'

import { DEFAULT_YODIFY_NOTIFICATION_DURATION_IN_SECONDS } from './constants'
import { KottiToaster } from './types'
import { generateId, notId } from './utilities.js'

const DEFAULT_DURATION_IN_SECONDS = 3

export default {
export default defineComponent({
name: 'KtToaster',
data() {
return { queue: [] }
},
created() {
let notification
while ((notification = this.$yodifyBuffer.pop()))
this.addNotification(notification)
setup() {
const root = getCurrentInstance()

this.$root.$on('vue-yodify', this.addNotification)
},
beforeDestroy() {
this.$root.$off('vue-yodify', this.addNotification)
},
methods: {
addNotification({
const yodifyBuffer =
// @ts-expect-error see usage of `Vue.prototype.$yodifyBuffer = []` on root index file
(root?.$yodifyBuffer as Array<KottiToaster.NotificationInternal>) ?? []

const queue = ref<Array<KottiToaster.NotificationInternal>>([])

const addNotification = ({
id = generateId(),
text,
type,
duration = DEFAULT_DURATION_IN_SECONDS *
duration = DEFAULT_YODIFY_NOTIFICATION_DURATION_IN_SECONDS *
TimeConversion.MILLISECONDS_PER_SECOND,
}) {
this.queue.push({ id, text, type })
}: KottiToaster.NotificationInternal) => {
debugger
queue.value.push({ id, text, type })

if (isBrowser)
window.setTimeout(() => this.deleteNotification(id), duration)
},
deleteNotification(id) {
this.queue = this.queue.filter(notId({ id }))
},
iconClass(notificationStatus) {
return `vue-yodify__icon vue-yodify__icon--${notificationStatus}`
},
iconText(type) {
if (type === 'error') return 'circle_cross'
if (type === 'warning') return 'circle_attention'
return 'circle_check'
},
window.setTimeout(() => deleteNotificationById(id), duration)
}

const deleteNotificationById = (
id: NonNullable<KottiToaster.NotificationInternal['id']>,
) => {
queue.value = queue.value.filter((notification) =>
notId(id)(notification?.id),
)
}

onBeforeMount(() => {
if (!root) throw new Error('Root is undefined')

root.$on('vue-yodify', addNotification)
})

onMounted(() => {
let notification
while ((notification = yodifyBuffer.pop())) {
addNotification(notification)
}
})

onUnmounted(() => {
if (root) root.$off('vue-yodify', addNotification)
})

return {
addNotification,
deleteNotificationById,
iconClass: (type: KottiToaster.Type) =>
`vue-yodify__icon vue-yodify__icon--${type}`,
iconText: (type: KottiToaster.Type) => {
switch (type) {
case KottiToaster.Type.ERROR:
return Yoco.Icon.CIRCLE_CROSS
case KottiToaster.Type.WARNING:
return Yoco.Icon.CIRCLE_ATTENTION
case KottiToaster.Type.SUCCESS:
default:
return Yoco.Icon.CIRCLE_CHECK
}
},
queue,
yodifyBuffer,
}
},
}
})
</script>

<style lang="scss" scoped>
// reset some commonly overwritten styles
.vue-yodify,
.vue-yodify * {
box-sizing: initial;
line-height: initial;
}

.vue-yodify {
position: fixed;
top: 0;
right: 0.8rem;
z-index: 9999;
}

.vue-yodify__notification {
display: flex;
justify-content: space-between;
width: 448px;
margin: 1.2rem 0;
overflow: hidden;
background-color: white;
border-radius: 0.2rem;
box-shadow: 0 0.1rem 0.4rem rgba(0, 0, 0, 0.24);
}

.vue-yodify__icon,
.vue-yodify__close {
display: flex;
flex: 0 0 2rem;
align-items: center;
justify-content: center;
min-height: 2rem;
}
.vue-yodify__icon {
&--success {
background: #64ad13;
}
&--error {
background: #d91919;
}
&--warning {
background: #ff7800;
&__notification {
display: flex;
justify-content: space-between;
width: 448px;
margin: 1.2rem 0;
overflow: hidden;
background-color: var(--white);
border-radius: 0.2rem;
box-shadow: 0 0.1rem 0.4rem rgba(0, 0, 0, 0.24);
}
.yoco {
font-size: 1rem;
color: #ffffff;

&__icon,
&__close {
display: flex;
flex: 0 0 2rem;
align-items: center;
justify-content: center;
min-height: 2rem;
}
}
.vue-yodify__content {
display: flex;
flex: 1;
align-items: center;
height: 100%;
min-height: 1.2rem;
padding: 0.4rem;
}
.vue-yodify__close {
.yoco {
font-size: 1rem;
color: #8a8a8a;

&__icon {
.yoco {
font-size: 1rem;
color: var(--white);
}

&--info {
background: var(--support-info);
}

&--error {
background: var(--support-error);
}
&--success {
background: var(--support-success);
}

&--warning {
background: var(--support-warning);
}
}
&:hover {
cursor: pointer;
background-color: rgba(0, 0, 0, 0.1);

&__content {
display: flex;
flex: 1;
align-items: center;
height: 100%;
min-height: 1.2rem;
padding: 0.4rem;
}
}

// reset some commonly overwritten styles
.vue-yodify,
.vue-yodify * {
box-sizing: initial;
line-height: initial;
&__close {
.yoco {
font-size: 1rem;
color: #8a8a8a;
}
&:hover {
cursor: pointer;
background-color: rgba(0, 0, 0, 0.1);
}
}
}

// support for mobile device
Expand Down
1 change: 1 addition & 0 deletions packages/kotti-ui/source/kotti-toaster/constants.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export const DEFAULT_YODIFY_NOTIFICATION_DURATION_IN_SECONDS = 3
Loading