Skip to content

Commit 4fec858

Browse files
committed
fix(toast): fix typo of position prop, adding examples on docs
1 parent 13649a7 commit 4fec858

File tree

12 files changed

+230
-39
lines changed

12 files changed

+230
-39
lines changed

.vitepress/components/Example.vue

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,7 @@ const expanded = ref(false)
7171
flex-direction: column;
7272
outline: 0;
7373
font-size: 14px;
74+
background: var(--gray-a2);
7475
}
7576
.vp-ExampleAction {
7677
width: 100%;

.vitepress/custom/Layout.vue

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ const isActiveLink = (item: DefaultTheme.SidebarItem, link: string) => {
3333
<script setup lang="ts">
3434
import { computed, toRefs } from 'vue'
3535
import { useData, useRoute } from 'vitepress'
36-
import { ThemeProvider, ToastProvider } from '#components'
36+
import { ThemeProvider } from '#components'
3737
import Navbar, { type NavbarItem } from './Navbar.vue'
3838
import Doc from './Doc.vue'
3939
@@ -59,6 +59,5 @@ const activeSidebar = computed(() => {
5959
<ThemeProvider>
6060
<Navbar :items="sidebar" />
6161
<Doc :sidebar="activeSidebar" />
62-
<ToastProvider />
6362
</ThemeProvider>
6463
</template>

.vitepress/theme/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ export default {
1010
Layout,
1111
async enhanceApp({ app }) {
1212
app.component('Example', Example)
13+
app.component('ExampleCode', Example)
1314
app.component('PropsTable', PropsTable)
1415
Object.keys(components).forEach((name) => {
1516
app.component(name, components[name as 'Button'])

docs/content/components/toast.md

Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,4 +6,121 @@ source: https://github.com/typlog/ui/tree/main/src/components/toggtoastle
66
reka: https://reka-ui.com/docs/components/toast
77
---
88

9+
<script setup>
10+
import { ref } from 'vue'
11+
import { ToastProvider, Button, toast } from '#components'
12+
13+
const size = ref('1')
14+
const position = ref('bottom-right')
15+
16+
const changePosition = (value) => {
17+
position.value = value
18+
toast(`Position changed to: ${value}`)
19+
}
20+
21+
const changeSize = (value) => {
22+
size.value = value
23+
toast(`Size changed to: ${value}`)
24+
}
25+
</script>
26+
27+
<ToastProvider :size="size" :position="position" />
28+
929
<Example name="toast/Overview.vue" variant="full" />
30+
31+
## Provider
32+
33+
To use the `toast` module, you need to set up the `ToastProvider` first. Simply
34+
place it within the `ThemeProvider` – its position doesn't matter, and it will
35+
function as expected.
36+
37+
```vue
38+
<script setup>
39+
import { ThemeProvider, ToastProvider } from '@typlog/ui'
40+
</script>
41+
<template>
42+
<ThemeProvider>
43+
<ToastProvider />
44+
</ThemeProvider>
45+
</template>
46+
```
47+
48+
### Position
49+
50+
You can customize the position of toast messages using the `position` prop on `ToastProvider`.
51+
By default, toasts appear in the bottom-right corner.
52+
53+
<ExampleCode name="Position" variant="full">
54+
55+
<div class="flex flex-wrap items-center gap-4">
56+
<Button @click="changePosition('top-left')" variant="surface">Top left</Button>
57+
<Button @click="changePosition('top-right')" variant="surface">Top right</Button>
58+
<Button @click="changePosition('bottom-left')" variant="surface">Bottom left</Button>
59+
<Button @click="changePosition('bottom-right')" variant="surface">Bottom right</Button>
60+
</div>
61+
62+
<template #source>
63+
64+
<div class="language-vue">
65+
<pre class="shiki"><code>&lt;ToastProvider
66+
<span style="color: var(--red-10)">position="{{ position }}"</span>
67+
/&gt;
68+
</code></pre>
69+
</div>
70+
71+
</template>
72+
73+
</ExampleCode>
74+
75+
76+
### Size
77+
78+
You can customize the size of toast messages using one of the three available `size` options.
79+
80+
<ExampleCode name="Size" variant="full">
81+
82+
<div class="flex flex-wrap items-center gap-4">
83+
<Button @click="changeSize('1')" variant="surface">Size 1</Button>
84+
<Button @click="changeSize('2')" variant="surface">Size 2</Button>
85+
<Button @click="changeSize('3')" variant="surface">Size 3</Button>
86+
</div>
87+
88+
<template #source>
89+
90+
<div class="language-vue">
91+
<pre class="shiki"><code>&lt;ToastProvider
92+
<span style="color: var(--red-10)">size="{{ size }}"</span>
93+
/&gt;
94+
</code></pre>
95+
</div>
96+
97+
</template>
98+
99+
</ExampleCode>
100+
101+
## Examples
102+
103+
### Methods
104+
105+
<div class="flex flex-wrap items-center gap-4 not-prose">
106+
<Button @click="toast.info('A info message')">
107+
<code>toast.info</code>
108+
</Button>
109+
<Button @click="toast.success('A success message')" color="green">
110+
<code>toast.success</code>
111+
</Button>
112+
<Button @click="toast.warning('A warning message')" color="orange">
113+
<code>toast.warning</code>
114+
</Button>
115+
<Button @click="toast.error('A error message')" color="red">
116+
<code>toast.error</code>
117+
</Button>
118+
</div>
119+
120+
### Promise
121+
122+
<Example name="toast/Promise.vue" />
123+
124+
### Description
125+
126+
<Example name="toast/Description.vue" variant="full" />

docs/examples/toast/Action.vue

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
<script setup lang="ts">
2+
import { toast, Button } from '#components'
3+
4+
const onClick = () => {
5+
toast({
6+
title: 'A message with action.',
7+
action: {
8+
label: 'Undo',
9+
onClick: () => console.log('undo'),
10+
},
11+
})
12+
}
13+
</script>
14+
15+
<template>
16+
<Button @click="onClick">Action</Button>
17+
</template>
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
<script setup lang="ts">
2+
import { toast, Button } from '#components'
3+
4+
const onClick = () => {
5+
const now = new Date().toLocaleDateString('en-US', {
6+
year: 'numeric',
7+
month: 'long',
8+
day: '2-digit',
9+
weekday: 'short',
10+
hour: '2-digit',
11+
minute: '2-digit',
12+
})
13+
toast({
14+
title: 'A new event with description.',
15+
description: now,
16+
})
17+
}
18+
</script>
19+
20+
<template>
21+
<Button @click="onClick">Description</Button>
22+
</template>

docs/examples/toast/Overview.vue

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -6,14 +6,7 @@ const count = ref(0)
66
77
const onClick = () => {
88
count.value += 1
9-
toast.info({
10-
title: `You clicked ${count.value} times`,
11-
description: 'This is a description',
12-
action: {
13-
label: 'Undo',
14-
onClick: () => console.log('undo'),
15-
},
16-
})
9+
toast(`You have received ${count.value} events.`)
1710
}
1811
</script>
1912

docs/examples/toast/Promise.vue

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
<script setup lang="ts">
2+
import { toast, Button } from '#components'
3+
4+
const successFn = () => new Promise((resolve) => setTimeout(resolve, 2000))
5+
const errorFn = () => new Promise((_, reject) => setTimeout(reject, 2000))
6+
7+
const onClickSuccess = () => {
8+
toast.promise(successFn, {
9+
loading: 'Fetching data ....',
10+
success: () => {
11+
return 'You have a new message.'
12+
},
13+
})
14+
}
15+
16+
const onClickError = () => {
17+
toast.promise(errorFn, {
18+
loading: 'Fetching data ....',
19+
success: () => {
20+
return 'You have a new message.'
21+
},
22+
error: () => {
23+
return 'You have a new error.'
24+
},
25+
})
26+
}
27+
</script>
28+
29+
<template>
30+
<div class="flex items-center gap-4">
31+
<Button variant="soft" @click="onClickSuccess">With success</Button>
32+
<Button color="red" variant="soft" @click="onClickError">With error</Button>
33+
</div>
34+
</template>

src/components/toast/ToastItem.vue

Lines changed: 6 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ const CATEGORY_COLORS: Record<MessageCategory, ColorType> = {
2121
loading: 'gray',
2222
info: 'indigo',
2323
success: 'green',
24-
warning: 'amber',
24+
warning: 'orange',
2525
error: 'red',
2626
}
2727
</script>
@@ -41,10 +41,10 @@ const props = defineProps<ToastItemProps>()
4141
const toastRef = useTemplateRef<InstanceType<typeof ToastRoot>>('toastRef')
4242
const paused = ref(false)
4343
44-
const state = useToastManager()
44+
const manager = useToastManager()
4545
4646
const styleVars = computed(() => {
47-
const heights = state.messages.value.slice(0, props.index).map(item => item.height || 60)
47+
const heights = manager.messages.value.slice(0, props.index).map(item => item.height || 60)
4848
const offsetY = heights.reduce((sum, num) => sum + num, 0)
4949
return {'--toast-index': props.index, '--toast-offset-y': offsetY + 'px'}
5050
})
@@ -68,7 +68,7 @@ const categoryColor = computed(() => {
6868
const onOpenChange = (open: boolean) => {
6969
if (open === false) {
7070
setTimeout(() => {
71-
state.remove(props.message.id)
71+
manager.remove(props.message.id)
7272
}, 500)
7373
}
7474
}
@@ -83,7 +83,7 @@ const onResume = () => {
8383
8484
onMounted(() => {
8585
const el = toastRef.value!.$el as HTMLLIElement
86-
state.update(props.message.id, {height: el.clientHeight})
86+
manager.update(props.message.id, {height: el.clientHeight})
8787
})
8888
</script>
8989

@@ -94,7 +94,6 @@ onMounted(() => {
9494
class="ui-ToastItem"
9595
:duration="message.duration"
9696
:data-expanded="paused"
97-
:data-invisible="index > 2"
9897
:style="styleVars"
9998
@update:open="onOpenChange"
10099
@pause="onPause"
@@ -157,10 +156,6 @@ onMounted(() => {
157156
--toast-collapse-scale: calc(max(0, 1 - (var(--toast-index) * 0.06)));
158157
}
159158
160-
.ui-ToastItem:where([data-invisible="true"]) {
161-
opacity: 0;
162-
}
163-
164159
.ui-ToastItem:where([data-swipe="move"]) {
165160
transition: none;
166161
}
@@ -192,7 +187,7 @@ onMounted(() => {
192187
:where(.ui-ToastViewport[data-y-position="bottom"]) .ui-ToastItem:where([data-expanded="false"]) {
193188
transform:
194189
translateX(var(--reka-toast-swipe-move-x, 0px))
195-
translateY(calc(var(--reka-toast-swipe-move-y, 0px) + (min(var(--toast-index), 10) * -20%)))
190+
translateY(calc(var(--reka-toast-swipe-move-y, 0px) + var(--toast-offset-y) * -0.2))
196191
scale(var(--toast-collapse-scale));
197192
}
198193

src/components/toast/ToastProvider.vue

Lines changed: 13 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import type { ToastProviderProps as RekaToastProviderProps } from 'reka-ui'
33
44
export interface ToastProviderProps extends RekaToastProviderProps {
55
size?: '1' | '2' | '3'
6-
postion?: 'top-left' | 'top-right' | 'bottom-left' | 'bottom-right'
6+
position?: 'top-left' | 'top-right' | 'bottom-left' | 'bottom-right'
77
}
88
</script>
99

@@ -25,18 +25,18 @@ defineOptions({
2525
2626
const props = withDefaults(defineProps<ToastProviderProps>(), {
2727
size: '1',
28-
postion: 'bottom-right',
29-
offset: '1rem',
28+
position: 'bottom-right',
3029
})
3130
3231
const forwarded = useForwardPropsWithout(props, ['position', 'size'])
32+
const manager = useToastManager()
3333
3434
const yPosition = computed(() => {
35-
return props.postion.split('-')[0] as 'top' | 'bottom'
35+
return props.position.split('-')[0] as 'top' | 'bottom'
3636
})
3737
3838
const xPosition = computed(() => {
39-
return props.postion.split('-')[1] as 'left' | 'right'
39+
return props.position.split('-')[1] as 'left' | 'right'
4040
})
4141
4242
const swipeDirection = computed(() => {
@@ -46,7 +46,10 @@ const swipeDirection = computed(() => {
4646
return xPosition.value
4747
})
4848
49-
const { messages } = useToastManager()
49+
const messages = computed(() => {
50+
// only show latest 3 messages
51+
return manager.messages.value.slice(0, 3)
52+
})
5053
</script>
5154

5255
<template>
@@ -102,19 +105,19 @@ const { messages } = useToastManager()
102105
}
103106
.ui-ToastViewport:where(.r-size-1) {
104107
--toast-width: 300px;
105-
--toast-gap: var(--space-4);
108+
--toast-gap: var(--space-2);
106109
--toast-title-font-size: var(--font-size-2);
107110
--toast-description-font-size: var(--font-size-1);
108111
}
109112
.ui-ToastViewport:where(.r-size-2) {
110113
--toast-width: 340px;
111-
--toast-gap: var(--space-5);
114+
--toast-gap: var(--space-3);
112115
--toast-title-font-size: var(--font-size-3);
113-
--toast-description-font-size: var(--font-size-2);
116+
--toast-description-font-size: var(--font-size-1);
114117
}
115118
.ui-ToastViewport:where(.r-size-3) {
116119
--toast-width: 380px;
117-
--toast-gap: var(--space-6);
120+
--toast-gap: var(--space-4);
118121
--toast-title-font-size: var(--font-size-4);
119122
--toast-description-font-size: var(--font-size-3);
120123
}

0 commit comments

Comments
 (0)