@teammodlr/ui-kit 2.3.23 → 3.0.0-beta.11

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (111) hide show
  1. package/lib/components/avatar/Avatar.vue.d.ts +2 -2
  2. package/lib/components/badge/style/Badge.css.d.ts +2 -2
  3. package/lib/components/button/Button.vue.d.ts +7 -4
  4. package/lib/components/button/style/Button.css.d.ts +3 -3
  5. package/lib/components/cardcontextmenu/CardContextMenu.vue.d.ts +5 -8
  6. package/lib/components/cardcontextmenu/CardContextMenuItem.vue.d.ts +11 -2
  7. package/lib/components/cardcontextmenu/CardContextMenuTriggerProvider.vue.d.ts +2 -0
  8. package/lib/components/cardcontextmenu/style/Dropdown.css.d.ts +2 -1
  9. package/lib/components/cardcontextmenu/symbol.d.ts +1 -0
  10. package/lib/components/checkbox/Checkbox.vue.d.ts +15 -4
  11. package/lib/components/collapse/CollapseItem.vue.d.ts +3 -2
  12. package/lib/components/colorpicker/ColorPicker.vue.d.ts +8 -9
  13. package/lib/components/confirm/Confirm.vue.d.ts +9 -0
  14. package/lib/components/confirm/props.d.ts +4 -0
  15. package/lib/components/dialog/Dialog.vue.d.ts +13 -5
  16. package/lib/components/dialogprovider/DialogProvider.vue.d.ts +1 -0
  17. package/lib/components/dialogprovider/types.d.ts +1 -0
  18. package/lib/components/dropdown/Dropdown.vue.d.ts +3 -1
  19. package/lib/components/dropdown/DropdownItem.vue.d.ts +11 -1
  20. package/lib/components/dropdown/DropdownSeperator.vue.d.ts +1 -0
  21. package/lib/components/dropdown/DropdownTriggerProvider.vue.d.ts +2 -0
  22. package/lib/components/dropdown/style/Dropdown.css.d.ts +2 -1
  23. package/lib/components/dropdown/symbol.d.ts +2 -0
  24. package/lib/components/image/Image.vue.d.ts +1 -1
  25. package/lib/components/index.d.ts +1 -0
  26. package/lib/components/messageprovider/Message.vue.d.ts +1 -1
  27. package/lib/components/messageprovider/MessageProvider.vue.d.ts +24 -24
  28. package/lib/components/messageprovider/style/Message.css.d.ts +1 -1
  29. package/lib/components/messageprovider/style/Toaster.css.d.ts +1 -0
  30. package/lib/components/messageprovider/types.d.ts +5 -0
  31. package/lib/components/modal/Modal.vue.d.ts +18 -6
  32. package/lib/components/popover/Popover.vue.d.ts +113 -0
  33. package/lib/components/popover/style/Popover.css.d.ts +4 -0
  34. package/lib/components/popover/style/index.d.ts +1 -0
  35. package/lib/components/radio/Radio.vue.d.ts +2 -0
  36. package/lib/components/radiobuttongroup/RadioButtonGroup.vue.d.ts +1 -0
  37. package/lib/components/select/Select.vue.d.ts +20 -11
  38. package/lib/components/switch/Switch.vue.d.ts +2 -0
  39. package/lib/components/tab/Tab.vue.d.ts +5 -2
  40. package/lib/components/tab/TabGroup.vue.d.ts +8 -3
  41. package/lib/components/textarea/Textarea.vue.d.ts +2 -1
  42. package/lib/components/tooltip/Tooltip.vue.d.ts +5 -20
  43. package/lib/components/tooltip/TooltipTrigger.vue.d.ts +1 -10
  44. package/lib/components/tree/Tree.vue.d.ts +3 -3
  45. package/lib/components/tree/TreeNode.vue.d.ts +26 -12
  46. package/lib/components/tree/types.d.ts +5 -5
  47. package/lib/index.cjs.js +5 -14
  48. package/lib/index.es.js +16893 -12185
  49. package/lib/style.css +1 -1
  50. package/package.json +12 -6
  51. package/src/components/avatar/Avatar.vue +32 -24
  52. package/src/components/button/Button.vue +24 -5
  53. package/src/components/cardcontextmenu/CardContextMenu.vue +68 -95
  54. package/src/components/cardcontextmenu/CardContextMenuItem.vue +40 -50
  55. package/src/components/cardcontextmenu/CardContextMenuSeperator.vue +9 -7
  56. package/src/components/cardcontextmenu/CardContextMenuTriggerProvider.vue +15 -0
  57. package/src/components/cardcontextmenu/style/Dropdown.css.ts +155 -2
  58. package/src/components/cardcontextmenu/symbol.ts +3 -0
  59. package/src/components/checkbox/Checkbox.vue +37 -12
  60. package/src/components/checkbox/style/Checkbox.css.ts +6 -6
  61. package/src/components/collapse/CollapseItem.vue +46 -21
  62. package/src/components/collapse/style/Collapse.css.ts +5 -1
  63. package/src/components/colorpicker/ColorPicker.vue +77 -46
  64. package/src/components/confirm/Confirm.vue +15 -8
  65. package/src/components/confirm/props.ts +4 -0
  66. package/src/components/dialog/Dialog.vue +183 -37
  67. package/src/components/dialog/style/Dialog.css.ts +15 -1
  68. package/src/components/dialogprovider/types.ts +1 -0
  69. package/src/components/dropdown/Dropdown.vue +46 -3
  70. package/src/components/dropdown/DropdownItem.vue +55 -25
  71. package/src/components/dropdown/DropdownSeperator.vue +19 -11
  72. package/src/components/dropdown/DropdownTriggerProvider.vue +15 -0
  73. package/src/components/dropdown/examples/context.vue +2 -2
  74. package/src/components/dropdown/style/Dropdown.css.ts +173 -4
  75. package/src/components/dropdown/symbol.ts +4 -0
  76. package/src/components/form/examples/basic.vue +19 -8
  77. package/src/components/index.ts +1 -0
  78. package/src/components/messageprovider/MessageProvider.vue +143 -90
  79. package/src/components/messageprovider/examples/basic.vue +3 -1
  80. package/src/components/messageprovider/examples/index.stories.ts +37 -1
  81. package/src/components/messageprovider/style/Toaster.css.ts +24 -0
  82. package/src/components/messageprovider/types.ts +10 -0
  83. package/src/components/modal/Modal.vue +142 -67
  84. package/src/components/modal/style/Modal.css.ts +26 -2
  85. package/src/components/popover/Popover.vue +155 -0
  86. package/src/components/popover/examples/arrow.vue +47 -0
  87. package/src/components/popover/examples/basic.vue +15 -0
  88. package/src/components/popover/examples/index.stories.ts +19 -0
  89. package/src/components/popover/examples/index.ts +4 -0
  90. package/src/components/popover/examples/placement.vue +59 -0
  91. package/src/components/popover/examples/variant.vue +30 -0
  92. package/src/components/popover/style/Popover.css.ts +203 -0
  93. package/src/components/popover/style/index.ts +1 -0
  94. package/src/components/radio/Radio.vue +31 -17
  95. package/src/components/radiobutton/RadioButton.vue +15 -2
  96. package/src/components/radiobuttongroup/RadioButtonGroup.vue +11 -4
  97. package/src/components/select/Select.vue +301 -153
  98. package/src/components/select/examples/basic.vue +1 -1
  99. package/src/components/slider/Slider.vue +1 -1
  100. package/src/components/switch/Switch.vue +30 -10
  101. package/src/components/switch/style/Switch.css.ts +3 -5
  102. package/src/components/tab/Tab.vue +29 -20
  103. package/src/components/tab/TabGroup.vue +29 -38
  104. package/src/components/textarea/Textarea.vue +8 -4
  105. package/src/components/tooltip/Tooltip.vue +52 -141
  106. package/src/components/tooltip/TooltipTrigger.vue +14 -17
  107. package/src/components/tooltip/style/Tooltip.css.ts +148 -29
  108. package/src/components/tree/Tree.vue +138 -100
  109. package/src/components/tree/TreeNode.vue +105 -98
  110. package/src/components/tree/types.ts +4 -4
  111. package/src/styles/transitions.css.ts +36 -16
@@ -2,7 +2,7 @@
2
2
  <div>
3
3
 
4
4
 
5
- <MDropdown v-model:open="isOpen" :style="{ top: `199px`, left: `9px` }">
5
+ <MDropdown contextMenu v-model:open="isOpen" :style="{ top: `199px`, left: `9px` }">
6
6
  <div style="background: #eee; width: 500px; height: 500px;">
7
7
  </div>
8
8
  <template #menu>
@@ -47,7 +47,7 @@
47
47
 
48
48
  <script lang="ts" setup>
49
49
  import { ref } from 'vue';
50
- const isOpen = ref(true);
50
+ const isOpen = ref(false);
51
51
  const handleClick = () => {
52
52
  alert('hi');
53
53
  }
@@ -1,6 +1,112 @@
1
- import { createVar, style, styleVariants } from '@vanilla-extract/css';
1
+ import { createVar, globalKeyframes, style, styleVariants } from '@vanilla-extract/css';
2
2
  import { themeVars } from '../../../styles/theme.css';
3
3
 
4
+ const menuFadeOutAnimation = 'dropdown-fade-out';
5
+ globalKeyframes(menuFadeOutAnimation, {
6
+ from: {
7
+ opacity: 1
8
+ },
9
+ to: {
10
+ opacity: 0
11
+ }
12
+ });
13
+
14
+ const menuSlideFadeOutTopAnimation = 'dropdown-slide-fade-out-top';
15
+ globalKeyframes(menuSlideFadeOutTopAnimation, {
16
+ from: {
17
+ opacity: 1,
18
+ transform: 'translateY(0) scale(1)'
19
+ },
20
+ to: {
21
+ opacity: 0,
22
+ transform: 'translateY(6px) scale(0.98)'
23
+ }
24
+ });
25
+
26
+ const menuSlideFadeOutBottomAnimation = 'dropdown-slide-fade-out-bottom';
27
+ globalKeyframes(menuSlideFadeOutBottomAnimation, {
28
+ from: {
29
+ opacity: 1,
30
+ transform: 'translateY(0) scale(1)'
31
+ },
32
+ to: {
33
+ opacity: 0,
34
+ transform: 'translateY(-6px) scale(0.98)'
35
+ }
36
+ });
37
+
38
+ const menuSlideFadeOutLeftAnimation = 'dropdown-slide-fade-out-left';
39
+ globalKeyframes(menuSlideFadeOutLeftAnimation, {
40
+ from: {
41
+ opacity: 1,
42
+ transform: 'translateX(0) scale(1)'
43
+ },
44
+ to: {
45
+ opacity: 0,
46
+ transform: 'translateX(6px) scale(0.98)'
47
+ }
48
+ });
49
+
50
+ const menuSlideFadeOutRightAnimation = 'dropdown-slide-fade-out-right';
51
+ globalKeyframes(menuSlideFadeOutRightAnimation, {
52
+ from: {
53
+ opacity: 1,
54
+ transform: 'translateX(0) scale(1)'
55
+ },
56
+ to: {
57
+ opacity: 0,
58
+ transform: 'translateX(-6px) scale(0.98)'
59
+ }
60
+ });
61
+
62
+ const menuSlideFadeTopAnimation = 'dropdown-slide-fade-top';
63
+ globalKeyframes(menuSlideFadeTopAnimation, {
64
+ from: {
65
+ opacity: 0,
66
+ transform: 'translateY(6px) scale(0.98)'
67
+ },
68
+ to: {
69
+ opacity: 1,
70
+ transform: 'translateY(0) scale(1)'
71
+ }
72
+ });
73
+
74
+ const menuSlideFadeBottomAnimation = 'dropdown-slide-fade-bottom';
75
+ globalKeyframes(menuSlideFadeBottomAnimation, {
76
+ from: {
77
+ opacity: 0,
78
+ transform: 'translateY(-6px) scale(0.98)'
79
+ },
80
+ to: {
81
+ opacity: 1,
82
+ transform: 'translateY(0) scale(1)'
83
+ }
84
+ });
85
+
86
+ const menuSlideFadeLeftAnimation = 'dropdown-slide-fade-left';
87
+ globalKeyframes(menuSlideFadeLeftAnimation, {
88
+ from: {
89
+ opacity: 0,
90
+ transform: 'translateX(6px) scale(0.98)'
91
+ },
92
+ to: {
93
+ opacity: 1,
94
+ transform: 'translateX(0) scale(1)'
95
+ }
96
+ });
97
+
98
+ const menuSlideFadeRightAnimation = 'dropdown-slide-fade-right';
99
+ globalKeyframes(menuSlideFadeRightAnimation, {
100
+ from: {
101
+ opacity: 0,
102
+ transform: 'translateX(-6px) scale(0.98)'
103
+ },
104
+ to: {
105
+ opacity: 1,
106
+ transform: 'translateX(0) scale(1)'
107
+ }
108
+ });
109
+
4
110
  export const menu = style({
5
111
  backgroundColor: '#ffffff',
6
112
  borderRadius: '5px',
@@ -12,7 +118,45 @@ export const menu = style({
12
118
  maxWidth: '350px',
13
119
  border: `1px solid ${themeVars.color.gray[300]}`,
14
120
  boxShadow: themeVars.shadow.md,
15
- overflow: 'auto'
121
+ overflow: 'auto',
122
+ transformOrigin: 'var(--reka-dropdown-menu-content-transform-origin)',
123
+ willChange: 'transform, opacity',
124
+ selectors: {
125
+ '&[data-state="open"]': {
126
+ animationDuration: '0.16s',
127
+ animationTimingFunction: 'cubic-bezier(0.16, 1, 0.3, 1)',
128
+ animationFillMode: 'both'
129
+ },
130
+ '&[data-state="closed"]': {
131
+ animationDuration: '0.12s',
132
+ animationTimingFunction: 'ease-out',
133
+ animationFillMode: 'both'
134
+ },
135
+ '&[data-state="closed"][data-side="top"]': {
136
+ animationName: menuSlideFadeOutTopAnimation
137
+ },
138
+ '&[data-state="closed"][data-side="bottom"]': {
139
+ animationName: menuSlideFadeOutBottomAnimation
140
+ },
141
+ '&[data-state="closed"][data-side="left"]': {
142
+ animationName: menuSlideFadeOutLeftAnimation
143
+ },
144
+ '&[data-state="closed"][data-side="right"]': {
145
+ animationName: menuSlideFadeOutRightAnimation
146
+ },
147
+ '&[data-state="open"][data-side="top"]': {
148
+ animationName: menuSlideFadeTopAnimation
149
+ },
150
+ '&[data-state="open"][data-side="bottom"]': {
151
+ animationName: menuSlideFadeBottomAnimation
152
+ },
153
+ '&[data-state="open"][data-side="left"]': {
154
+ animationName: menuSlideFadeLeftAnimation
155
+ },
156
+ '&[data-state="open"][data-side="right"]': {
157
+ animationName: menuSlideFadeRightAnimation
158
+ }
159
+ }
16
160
  });
17
161
 
18
162
  export const menuItems = style({
@@ -33,8 +177,8 @@ export const menuItem = style({
33
177
  },
34
178
  display: 'grid',
35
179
  alignItems: 'center',
36
- gridTemplateAreas: '"icon name kbd"',
37
- gridTemplateColumns: '16px 1fr auto',
180
+ gridTemplateAreas: '"icon name kbd arrow"',
181
+ gridTemplateColumns: '16px 1fr auto auto',
38
182
  gridTemplateRows: '16px',
39
183
  columnGap: themeVars.space['1.5'],
40
184
  rowGap: themeVars.space['0.5'],
@@ -53,6 +197,22 @@ export const menuItem = style({
53
197
  backgroundColor: vars.backgroundColor,
54
198
  color: vars.color,
55
199
  outline: 'none'
200
+ },
201
+ ':focus': {
202
+ vars: {
203
+ [vars.backgroundColor]: themeVars.color.gray[150],
204
+ },
205
+ backgroundColor: vars.backgroundColor,
206
+ outline: 'none'
207
+ },
208
+ selectors: {
209
+ '&[aria-expanded="true"]': {
210
+ vars: {
211
+ [vars.backgroundColor]: themeVars.color.gray[150],
212
+ },
213
+ backgroundColor: vars.backgroundColor,
214
+ outline: 'none'
215
+ }
56
216
  }
57
217
  });
58
218
 
@@ -144,6 +304,15 @@ export const menuItemIcon = style({
144
304
  opacity: 0.8
145
305
  });
146
306
 
307
+ export const menuItemIconRight = style({
308
+ gridArea: 'arrow',
309
+ flexShrink: 0,
310
+ display: 'flex',
311
+ alignItems: 'center',
312
+ opacity: 0.8,
313
+ marginLeft: themeVars.space[2]
314
+ });
315
+
147
316
  export const menuSeperator = style({
148
317
  height: '1px',
149
318
  backgroundColor: themeVars.color.gray[200],
@@ -1,9 +1,13 @@
1
1
  import type { InjectionKey } from 'vue';
2
2
 
3
3
  export interface DropdownState {
4
+ contextMenu: boolean;
4
5
  handleSelect: (labels: string[]) => void;
5
6
  isOpen: boolean;
6
7
  }
7
8
 
8
9
  export const DROPDOWN_STATE: InjectionKey<DropdownState> =
9
10
  Symbol('DROPDOWN_STATE');
11
+
12
+ export const DROPDOWN_TRIGGER_STATE: InjectionKey<boolean> =
13
+ Symbol('DROPDOWN_TRIGGER_STATE');
@@ -2,17 +2,17 @@
2
2
  <MForm @submit="onSubmit" :loading="loading">
3
3
  <MInput
4
4
  label="Email"
5
- placeholder="Email Address"
6
- name="email"
7
- v-model="email"
5
+ placeholder="Email Address"
6
+ name="email"
7
+ v-model="email"
8
8
  :rules="[rules.isRequired, rules.isEmail]"
9
9
  />
10
10
 
11
11
  <MInput
12
12
  label="Name"
13
- placeholder="Name"
14
- name="name"
15
- v-model="name"
13
+ placeholder="Name"
14
+ name="name"
15
+ v-model="name"
16
16
  :rules="[rules.isRequired]"
17
17
  />
18
18
 
@@ -23,9 +23,20 @@
23
23
  :option-value="'id'"
24
24
  :option-label="'name'"
25
25
  :rules="[rules.isRequired]"
26
+ searchable
27
+ multiple
26
28
  />
27
29
 
28
- <MCheckbox
30
+ <MSelect
31
+ label="Option"
32
+ v-model="option"
33
+ :options="options"
34
+ :option-value="'id'"
35
+ :option-label="'name'"
36
+ :rules="[rules.isRequired]"
37
+ multiple
38
+ />
39
+ <!-- <MCheckbox
29
40
  label="Agree to terms"
30
41
  v-model="agree"
31
42
  :rules="[rules.isRequired]"
@@ -33,7 +44,7 @@
33
44
  Something here!
34
45
  </MCheckbox>
35
46
 
36
- <MColorPicker />
47
+ <MColorPicker /> -->
37
48
 
38
49
 
39
50
  <MButton type="submit" color="blue">Submit</MButton>
@@ -56,3 +56,4 @@ export { default as MConfirmProvider } from './confirm/ConfirmProvider.vue';
56
56
  export { default as MDialog } from './dialog/Dialog.vue';
57
57
  export { default as MDialogProvider } from './dialogprovider/DialogProvider.vue';
58
58
  export { default as MTree } from './tree/Tree.vue';
59
+ export { default as MPopover } from './popover/Popover.vue';
@@ -1,77 +1,73 @@
1
1
  <template>
2
2
  <slot />
3
- <template v-if="messageList.length > 0">
4
- <Teleport to="body">
5
- <transition
6
- type="animation"
7
- :enter-active-class="modalScale.enterActive"
8
- :leave-active-class="modalScale.leaveActive"
9
- :enter-from-class="modalScale.enterFrom"
10
- :leave-to-class="modalScale.leaveTo">
11
- <div :class="classes">
12
- <MMessage
13
- v-for="message in messageList"
14
- :key="message.key"
15
- :internalKey="message.key"
16
- :variant="message.type"
17
- :content="message.content"
18
- :timeout="message.timeout ?? timeout"
19
- ref="messageRefs"
20
- :on-internal-after-leave="onInternalAfterLeave" />
21
- </div>
22
- </transition>
23
- </Teleport>
24
- </template>
3
+ <Toaster
4
+ :class="style.toaster"
5
+ :position="sonnerPosition"
6
+ :duration="timeout"
7
+ :visible-toasts="max"
8
+ :close-button-position="closeButtonPosition"
9
+ />
25
10
  </template>
26
11
 
27
12
  <script lang="ts">
28
- import {
29
- ref,
30
- reactive,
31
- defineComponent,
32
- provide,
33
- computed
34
- } from 'vue';
13
+ import 'vue-sonner/style.css';
14
+
15
+ import { computed, defineComponent, provide, reactive, watch } from 'vue';
16
+ import { Toaster, toast } from 'vue-sonner';
17
+ import type { ExternalToast } from 'vue-sonner';
35
18
  import type {
36
- MessageType,
37
- MessageReactive,
38
- MessageOptions,
39
- MessageApiInjection,
40
19
  ContentType,
41
- MessagePlacement
20
+ MessageApiInjection,
21
+ MessageCloseButtonPosition,
22
+ MessageOptions,
23
+ MessagePlacement,
24
+ MessageReactive,
25
+ MessageType,
42
26
  } from './types';
43
27
  import type { PropType } from 'vue';
44
- import MMessage from './Message.vue';
45
- import * as style from './style';
46
- import { modalScale } from '../../styles/transitions.css';
28
+ import * as style from './style/Toaster.css';
47
29
 
48
30
  interface PrivateMessageReactive extends MessageReactive {
49
- key: string;
31
+ id: string;
50
32
  }
51
33
 
52
- interface PrivateMessageRef extends MessageReactive {
53
- key: string;
54
- hide: () => void;
55
- }
34
+ const placementMap: Record<MessagePlacement, ExternalToast['position']> = {
35
+ top: 'top-center',
36
+ 'top-left': 'top-left',
37
+ 'top-right': 'top-right',
38
+ bottom: 'bottom-center',
39
+ 'bottom-left': 'bottom-left',
40
+ 'bottom-right': 'bottom-right',
41
+ };
56
42
 
57
43
  export default defineComponent({
58
44
  name: 'MMessageProvider',
59
45
  components: {
60
- MMessage
46
+ Toaster,
61
47
  },
62
48
  props: {
63
49
  placement: {
64
50
  type: String as PropType<MessagePlacement>,
65
- default: 'top'
51
+ default: 'top',
66
52
  },
67
53
  timeout: {
68
54
  type: Number,
69
- default: 3000
70
- }
55
+ default: 3000,
56
+ },
57
+ max: {
58
+ type: Number,
59
+ default: 999,
60
+ },
61
+ closeButtonPosition: {
62
+ type: String as PropType<MessageCloseButtonPosition>,
63
+ default: 'top-right',
64
+ },
71
65
  },
72
- setup(props, { slots }) {
73
- const messageListRef = ref<PrivateMessageReactive[]>([]);
74
- const messageRefs = ref<Record<string, PrivateMessageRef>>({});
66
+ setup(props) {
67
+ const activeMessages = new Map<string, { stop: () => void; closed: boolean; onClose?: () => void }>();
68
+
69
+ const sonnerPosition = computed(() => placementMap[props.placement]);
70
+
75
71
  const api: MessageApiInjection = {
76
72
  create(content: ContentType, options?: MessageOptions) {
77
73
  return create(content, { type: 'default', ...options });
@@ -91,62 +87,119 @@ export default defineComponent({
91
87
  loading(content: ContentType, options?: MessageOptions) {
92
88
  return create(content, { ...options, type: 'loading' });
93
89
  },
94
- destroyAll
90
+ destroyAll,
95
91
  };
96
92
 
97
93
  provide('m-message', api);
94
+
95
+ function normalizeDuration(timeout?: number): number {
96
+ if (timeout === 0) {
97
+ return Infinity;
98
+ }
99
+
100
+ return timeout ?? props.timeout;
101
+ }
102
+
103
+ function syncToast(message: PrivateMessageReactive, isUpdate = false) {
104
+ const options: ExternalToast = {
105
+ id: message.id,
106
+ duration: normalizeDuration(message.timeout),
107
+ closeButton: message.closeButton ?? message.closable,
108
+ richColors: message.richColors,
109
+ position: sonnerPosition.value,
110
+ onDismiss: () => closeMessage(message.id, true),
111
+ onAutoClose: () => closeMessage(message.id, true),
112
+ };
113
+
114
+ if (isUpdate) {
115
+ toast.dismiss(message.id);
116
+ }
117
+
118
+ switch (message.type) {
119
+ case 'success':
120
+ toast.success(message.content, options);
121
+ break;
122
+ case 'info':
123
+ toast.info(message.content, options);
124
+ break;
125
+ case 'warning':
126
+ toast.warning(message.content, options);
127
+ break;
128
+ case 'error':
129
+ toast.error(message.content, options);
130
+ break;
131
+ case 'loading':
132
+ toast.loading(message.content, options);
133
+ break;
134
+ default:
135
+ toast(message.content, options);
136
+ break;
137
+ }
138
+ }
139
+
140
+ function closeMessage(id: string, invokeOnClose: boolean) {
141
+ const active = activeMessages.get(id);
142
+ if (!active || active.closed) {
143
+ return;
144
+ }
145
+
146
+ active.closed = true;
147
+ active.stop();
148
+
149
+ if (invokeOnClose) {
150
+ active.onClose?.();
151
+ }
152
+
153
+ activeMessages.delete(id);
154
+ }
155
+
98
156
  function create(
99
157
  content: ContentType,
100
158
  options: MessageOptions & { type: MessageType }
101
159
  ): MessageReactive {
102
- const key = Math.random()
103
- .toString(16)
104
- .slice(2, 2 + 12);
105
- const messageReactive = reactive({
106
- ...options,
160
+ const id = Math.random().toString(16).slice(2, 14);
161
+ const message = reactive({
162
+ id,
107
163
  content,
108
- key,
164
+ timeout: options.timeout,
165
+ closable: options.closable,
166
+ closeButton: options.closeButton,
167
+ richColors: options.richColors,
168
+ type: options.type,
169
+ onClose: options.onClose,
109
170
  destroy: () => {
110
- messageRefs.value[key].hide();
111
- }
112
- });
171
+ closeMessage(id, false);
172
+ toast.dismiss(id);
173
+ },
174
+ }) as PrivateMessageReactive;
175
+
176
+ const stop = watch(
177
+ () => [message.content, message.type, message.timeout, message.closable, message.closeButton, message.richColors, sonnerPosition.value],
178
+ (newVal, oldVal) => {
179
+ syncToast(message, !!oldVal);
180
+ },
181
+ { immediate: true }
182
+ );
113
183
 
114
- messageListRef.value.push(messageReactive);
115
- return messageReactive;
184
+ activeMessages.set(id, { stop, closed: false, onClose: options.onClose });
185
+
186
+ return message;
116
187
  }
117
188
 
118
189
  function destroyAll(): void {
119
- //@ts-ignore
120
- Object.values(messageRefs.value).forEach(messageRef => {
121
- messageRef.hide();
122
- });
123
- }
190
+ for (const [id, active] of activeMessages.entries()) {
191
+ active.closed = true;
192
+ active.stop();
193
+ }
124
194
 
125
- function onInternalAfterLeave(key: string): void {
126
- messageListRef.value = messageListRef.value.filter(
127
- message => message.key !== key
128
- );
129
- delete messageRefs.value[key];
195
+ activeMessages.clear();
196
+ toast.dismiss();
130
197
  }
131
198
 
132
- const classes = computed(() => {
133
- return [
134
- style.wrapper,
135
- // @ts-ignore
136
- [style.placement[props.placement]]
137
- ];
138
- });
139
-
140
- return Object.assign(
141
- {
142
- messageRefs,
143
- messageList: messageListRef,
144
- onInternalAfterLeave,
145
- classes,
146
- modalScale
147
- },
148
- api
149
- );
150
- }
199
+ return {
200
+ sonnerPosition,
201
+ style,
202
+ };
203
+ },
151
204
  });
152
205
  </script>
@@ -37,13 +37,15 @@ function updateNumber() {
37
37
  msg.content = `Saved Successfully`;
38
38
  msg.type = 'success';
39
39
  msg.timeout = 3000;
40
+ msg.closable = true
40
41
  }
41
42
  }
42
43
 
43
44
 
44
45
  const showSuccess = () => {
45
46
  message.success(`Hello World`, {
46
- timeout: 3000
47
+ timeout: 3000,
48
+ richColors: true,
47
49
  });
48
50
  };
49
51
 
@@ -1,6 +1,15 @@
1
1
  import MMessageProvider from '../MessageProvider.vue';
2
2
  import { MMessageProviderBasic } from './index';
3
3
 
4
+ const placementOptions = [
5
+ 'top',
6
+ 'top-left',
7
+ 'top-right',
8
+ 'bottom',
9
+ 'bottom-left',
10
+ 'bottom-right'
11
+ ];
12
+
4
13
  const Template = (args: any) => ({
5
14
  components: {
6
15
  MMessageProvider,
@@ -20,7 +29,34 @@ const Template = (args: any) => ({
20
29
 
21
30
  export default {
22
31
  component: MMessageProvider,
23
- title: 'Components/MessageProvider'
32
+ title: 'Components/MessageProvider',
33
+ args: {
34
+ placement: 'top',
35
+ timeout: 3000,
36
+ max: 5,
37
+ closeButtonPosition: 'top-right'
38
+ },
39
+ argTypes: {
40
+ placement: {
41
+ control: 'select',
42
+ options: placementOptions
43
+ },
44
+ closeButtonPosition: {
45
+ control: 'select',
46
+ options: [
47
+ 'top-left',
48
+ 'top-right',
49
+ 'bottom-left',
50
+ 'bottom-right'
51
+ ]
52
+ },
53
+ timeout: {
54
+ control: 'number'
55
+ },
56
+ max: {
57
+ control: 'number'
58
+ }
59
+ }
24
60
  };
25
61
 
26
62
  export const Primary = Template.bind({});
@@ -0,0 +1,24 @@
1
+ import { globalStyle, style } from '@vanilla-extract/css';
2
+ import { themeVars } from '../../../styles/theme.css';
3
+
4
+ export const toaster = style({});
5
+
6
+ globalStyle(`${toaster} [data-sonner-toast][data-type='success'] [data-icon]`, {
7
+ color: themeVars.color.green[500]
8
+ });
9
+
10
+ globalStyle(`${toaster} [data-sonner-toast][data-type='error'] [data-icon]`, {
11
+ color: themeVars.color.red[500]
12
+ });
13
+
14
+ globalStyle(`${toaster} [data-sonner-toast][data-type='warning'] [data-icon]`, {
15
+ color: themeVars.color.amber[500]
16
+ });
17
+
18
+ globalStyle(`${toaster} [data-sonner-toast][data-type='info'] [data-icon]`, {
19
+ color: themeVars.color.blue[500]
20
+ });
21
+
22
+ globalStyle(`${toaster} [data-sonner-toast][data-type='loading'] [data-icon]`, {
23
+ color: themeVars.color.gray[500]
24
+ });