@teammodlr/ui-kit 3.0.0-beta.9 → 3.0.1

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 (110) hide show
  1. package/lib/components/cardcontextmenu/CardContextMenu.vue.d.ts +4 -2
  2. package/lib/components/checkbox/Checkbox.vue.d.ts +4 -4
  3. package/lib/components/clearbutton/ClearButton.vue.d.ts +9 -0
  4. package/lib/components/clearbutton/style/ClearButton.css.d.ts +2 -0
  5. package/lib/components/clearbutton/style/index.d.ts +1 -0
  6. package/lib/components/colorpicker/ColorPicker.vue.d.ts +6 -4
  7. package/lib/components/colorpicker/style/ColorPicker.css.d.ts +1 -0
  8. package/lib/components/dialog/Dialog.vue.d.ts +14 -6
  9. package/lib/components/dialog/style/Dialog.css.d.ts +2 -0
  10. package/lib/components/drawer/Drawer.vue.d.ts +146 -0
  11. package/lib/components/drawer/style/Drawer.css.d.ts +33 -0
  12. package/lib/components/drawer/style/index.d.ts +1 -0
  13. package/lib/components/dropdown/Dropdown.vue.d.ts +4 -2
  14. package/lib/components/form/Form.vue.d.ts +4 -2
  15. package/lib/components/hovercard/HoverCard.vue.d.ts +124 -0
  16. package/lib/components/hovercard/style/HoverCard.css.d.ts +3 -0
  17. package/lib/components/hovercard/style/index.d.ts +1 -0
  18. package/lib/components/index.d.ts +3 -0
  19. package/lib/components/input/Input.vue.d.ts +20 -5
  20. package/lib/components/input/style/Input.css.d.ts +4 -0
  21. package/lib/components/modal/Modal.vue.d.ts +11 -4
  22. package/lib/components/pagination/Pagination.vue.d.ts +6 -3
  23. package/lib/components/paneldialog/PanelDialog.vue.d.ts +175 -0
  24. package/lib/components/paneldialog/style/PanelDialog.css.d.ts +8 -0
  25. package/lib/components/paneldialog/style/index.d.ts +1 -0
  26. package/lib/components/popover/Popover.vue.d.ts +28 -2
  27. package/lib/components/radio/Radio.vue.d.ts +5 -5
  28. package/lib/components/radiobutton/RadioButton.vue.d.ts +4 -4
  29. package/lib/components/radiobuttongroup/RadioButtonGroup.vue.d.ts +4 -2
  30. package/lib/components/select/Select.vue.d.ts +94 -91
  31. package/lib/components/select/style/Select.css.d.ts +9 -1
  32. package/lib/components/slider/Slider.vue.d.ts +6 -3
  33. package/lib/components/switch/Switch.vue.d.ts +4 -4
  34. package/lib/components/tab/Tab.vue.d.ts +10 -2
  35. package/lib/components/tab/TabGroup.vue.d.ts +6 -3
  36. package/lib/components/table/Table.vue.d.ts +4 -2
  37. package/lib/components/textarea/Textarea.vue.d.ts +16 -5
  38. package/lib/components/textarea/style/Textarea.css.d.ts +2 -0
  39. package/lib/components/tree/Tree.vue.d.ts +6 -3
  40. package/lib/composables/useInput.d.ts +9 -2
  41. package/lib/index.cjs.js +3 -3
  42. package/lib/index.es.js +8526 -6393
  43. package/lib/style.css +1 -1
  44. package/lib/tsconfig.app.tsbuildinfo +1 -0
  45. package/lib/tsconfig.vitest.tsbuildinfo +1 -0
  46. package/package.json +7 -4
  47. package/src/components/cardcontextmenu/CardContextMenu.vue +3 -1
  48. package/src/components/cardcontextmenu/style/Dropdown.css.ts +7 -0
  49. package/src/components/clearbutton/ClearButton.vue +41 -0
  50. package/src/components/clearbutton/style/ClearButton.css.ts +37 -0
  51. package/src/components/clearbutton/style/index.ts +1 -0
  52. package/src/components/colorpicker/ColorPicker.vue +12 -12
  53. package/src/components/colorpicker/examples/basic.vue +8 -17
  54. package/src/components/colorpicker/style/ColorPicker.css.ts +6 -1
  55. package/src/components/dialog/Dialog.vue +12 -6
  56. package/src/components/dialog/style/Dialog.css.ts +30 -0
  57. package/src/components/drawer/Drawer.vue +280 -0
  58. package/src/components/drawer/examples/basic.vue +15 -0
  59. package/src/components/drawer/examples/custom-title.vue +21 -0
  60. package/src/components/drawer/examples/index.stories.ts +24 -0
  61. package/src/components/drawer/examples/index.ts +7 -0
  62. package/src/components/drawer/examples/no-mask.vue +15 -0
  63. package/src/components/drawer/examples/no-outside-close.vue +15 -0
  64. package/src/components/drawer/examples/placements.vue +28 -0
  65. package/src/components/drawer/examples/with-footer.vue +21 -0
  66. package/src/components/drawer/examples/with-trigger.vue +13 -0
  67. package/src/components/drawer/style/Drawer.css.ts +208 -0
  68. package/src/components/drawer/style/index.ts +1 -0
  69. package/src/components/dropdown/Dropdown.vue +4 -2
  70. package/src/components/form/Form.vue +3 -3
  71. package/src/components/hovercard/HoverCard.vue +165 -0
  72. package/src/components/hovercard/style/HoverCard.css.ts +175 -0
  73. package/src/components/hovercard/style/index.ts +1 -0
  74. package/src/components/index.ts +3 -0
  75. package/src/components/input/Input.vue +52 -4
  76. package/src/components/input/examples/clearable.vue +18 -0
  77. package/src/components/input/examples/index.stories.ts +3 -1
  78. package/src/components/input/examples/index.ts +1 -0
  79. package/src/components/input/style/Input.css.ts +19 -0
  80. package/src/components/messageprovider/MessageProvider.vue +33 -7
  81. package/src/components/modal/Modal.vue +28 -11
  82. package/src/components/pagination/Pagination.vue +4 -1
  83. package/src/components/paneldialog/PanelDialog.vue +509 -0
  84. package/src/components/paneldialog/examples/basic.vue +36 -0
  85. package/src/components/paneldialog/examples/index.stories.ts +22 -0
  86. package/src/components/paneldialog/examples/index.ts +2 -0
  87. package/src/components/paneldialog/examples/modal.vue +31 -0
  88. package/src/components/paneldialog/style/PanelDialog.css.ts +90 -0
  89. package/src/components/paneldialog/style/index.ts +1 -0
  90. package/src/components/popover/Popover.vue +9 -2
  91. package/src/components/radiobuttongroup/RadioButtonGroup.vue +3 -1
  92. package/src/components/select/Select.vue +211 -111
  93. package/src/components/select/examples/clearable.vue +18 -0
  94. package/src/components/select/examples/fill.vue +52 -0
  95. package/src/components/select/examples/index.stories.ts +4 -1
  96. package/src/components/select/examples/index.ts +3 -0
  97. package/src/components/select/examples/remote.vue +54 -0
  98. package/src/components/select/style/Select.css.ts +140 -24
  99. package/src/components/slider/Slider.vue +4 -1
  100. package/src/components/tab/Tab.vue +4 -2
  101. package/src/components/tab/TabGroup.vue +4 -4
  102. package/src/components/tab/style/Tab.css.ts +6 -0
  103. package/src/components/table/Table.vue +3 -3
  104. package/src/components/textarea/Textarea.vue +40 -4
  105. package/src/components/textarea/examples/clearable.vue +16 -0
  106. package/src/components/textarea/examples/index.stories.ts +2 -1
  107. package/src/components/textarea/examples/index.ts +1 -0
  108. package/src/components/textarea/style/Textarea.css.ts +10 -0
  109. package/src/components/tree/Tree.vue +4 -1
  110. package/src/composables/useInput.ts +10 -2
@@ -0,0 +1,175 @@
1
+ import { globalKeyframes, globalStyle, style } from '@vanilla-extract/css';
2
+ import { themeVars } from '../../../styles/theme.css';
3
+
4
+ const slideFadeOutTopAnimation = 'hover-card-slide-fade-out-top';
5
+ globalKeyframes(slideFadeOutTopAnimation, {
6
+ from: {
7
+ opacity: 1,
8
+ transform: 'translateY(0) scale(1)'
9
+ },
10
+ to: {
11
+ opacity: 0,
12
+ transform: 'translateY(6px) scale(0.98)'
13
+ }
14
+ });
15
+
16
+ const slideFadeOutBottomAnimation = 'hover-card-slide-fade-out-bottom';
17
+ globalKeyframes(slideFadeOutBottomAnimation, {
18
+ from: {
19
+ opacity: 1,
20
+ transform: 'translateY(0) scale(1)'
21
+ },
22
+ to: {
23
+ opacity: 0,
24
+ transform: 'translateY(-6px) scale(0.98)'
25
+ }
26
+ });
27
+
28
+ const slideFadeOutLeftAnimation = 'hover-card-slide-fade-out-left';
29
+ globalKeyframes(slideFadeOutLeftAnimation, {
30
+ from: {
31
+ opacity: 1,
32
+ transform: 'translateX(0) scale(1)'
33
+ },
34
+ to: {
35
+ opacity: 0,
36
+ transform: 'translateX(6px) scale(0.98)'
37
+ }
38
+ });
39
+
40
+ const slideFadeOutRightAnimation = 'hover-card-slide-fade-out-right';
41
+ globalKeyframes(slideFadeOutRightAnimation, {
42
+ from: {
43
+ opacity: 1,
44
+ transform: 'translateX(0) scale(1)'
45
+ },
46
+ to: {
47
+ opacity: 0,
48
+ transform: 'translateX(-6px) scale(0.98)'
49
+ }
50
+ });
51
+
52
+ const slideFadeTopAnimation = 'hover-card-slide-fade-top';
53
+ globalKeyframes(slideFadeTopAnimation, {
54
+ from: {
55
+ opacity: 0,
56
+ transform: 'translateY(6px) scale(0.98)'
57
+ },
58
+ to: {
59
+ opacity: 1,
60
+ transform: 'translateY(0) scale(1)'
61
+ }
62
+ });
63
+
64
+ const slideFadeBottomAnimation = 'hover-card-slide-fade-bottom';
65
+ globalKeyframes(slideFadeBottomAnimation, {
66
+ from: {
67
+ opacity: 0,
68
+ transform: 'translateY(-6px) scale(0.98)'
69
+ },
70
+ to: {
71
+ opacity: 1,
72
+ transform: 'translateY(0) scale(1)'
73
+ }
74
+ });
75
+
76
+ const slideFadeLeftAnimation = 'hover-card-slide-fade-left';
77
+ globalKeyframes(slideFadeLeftAnimation, {
78
+ from: {
79
+ opacity: 0,
80
+ transform: 'translateX(6px) scale(0.98)'
81
+ },
82
+ to: {
83
+ opacity: 1,
84
+ transform: 'translateX(0) scale(1)'
85
+ }
86
+ });
87
+
88
+ const slideFadeRightAnimation = 'hover-card-slide-fade-right';
89
+ globalKeyframes(slideFadeRightAnimation, {
90
+ from: {
91
+ opacity: 0,
92
+ transform: 'translateX(-6px) scale(0.98)'
93
+ },
94
+ to: {
95
+ opacity: 1,
96
+ transform: 'translateX(0) scale(1)'
97
+ }
98
+ });
99
+
100
+ export const content = style({
101
+ backgroundColor: '#ffffff',
102
+ borderRadius: '5px',
103
+ padding: '5px',
104
+ zIndex: 4000,
105
+ boxSizing: 'border-box',
106
+ position: 'relative',
107
+ minWidth: '130px',
108
+ maxWidth: '350px',
109
+ border: `1px solid ${themeVars.color.gray[300]}`,
110
+ boxShadow: themeVars.shadow.md,
111
+ transformOrigin: 'var(--reka-hover-card-content-transform-origin)',
112
+ willChange: 'transform, opacity',
113
+ outline: 'none',
114
+ selectors: {
115
+ '&[data-state="open"]': {
116
+ animationDuration: '0.16s',
117
+ animationTimingFunction: 'cubic-bezier(0.16, 1, 0.3, 1)',
118
+ animationFillMode: 'both'
119
+ },
120
+ '&[data-state="closed"]': {
121
+ animationDuration: '0.12s',
122
+ animationTimingFunction: 'ease-out',
123
+ animationFillMode: 'both'
124
+ },
125
+ '&[data-state="closed"][data-side="top"]': {
126
+ animationName: slideFadeOutTopAnimation
127
+ },
128
+ '&[data-state="closed"][data-side="bottom"]': {
129
+ animationName: slideFadeOutBottomAnimation
130
+ },
131
+ '&[data-state="closed"][data-side="left"]': {
132
+ animationName: slideFadeOutLeftAnimation
133
+ },
134
+ '&[data-state="closed"][data-side="right"]': {
135
+ animationName: slideFadeOutRightAnimation
136
+ },
137
+ '&[data-state="open"][data-side="top"]': {
138
+ animationName: slideFadeTopAnimation
139
+ },
140
+ '&[data-state="open"][data-side="bottom"]': {
141
+ animationName: slideFadeBottomAnimation
142
+ },
143
+ '&[data-state="open"][data-side="left"]': {
144
+ animationName: slideFadeLeftAnimation
145
+ },
146
+ '&[data-state="open"][data-side="right"]': {
147
+ animationName: slideFadeRightAnimation
148
+ }
149
+ }
150
+ });
151
+
152
+ export const arrow = style({
153
+ fill: '#ffffff'
154
+ });
155
+
156
+ globalStyle(`${arrow} path`, {
157
+ fill: '#ffffff',
158
+ stroke: themeVars.color.gray[300],
159
+ strokeWidth: '1px'
160
+ });
161
+
162
+ export const dark = style({
163
+ backgroundColor: themeVars.color.gray[900],
164
+ border: `1px solid ${themeVars.color.gray[800]}`,
165
+ color: themeVars.color.gray[100]
166
+ });
167
+
168
+ globalStyle(`${dark} ${arrow}`, {
169
+ fill: themeVars.color.gray[900]
170
+ });
171
+
172
+ globalStyle(`${dark} ${arrow} path`, {
173
+ fill: themeVars.color.gray[900],
174
+ stroke: themeVars.color.gray[800]
175
+ });
@@ -0,0 +1 @@
1
+ export * from './HoverCard.css';
@@ -54,6 +54,9 @@ export { default as MVirtualScroll } from './virtualscroll/VirtualScroll.vue';
54
54
  export { default as MConfirm } from './confirm/Confirm.vue';
55
55
  export { default as MConfirmProvider } from './confirm/ConfirmProvider.vue';
56
56
  export { default as MDialog } from './dialog/Dialog.vue';
57
+ export { default as MPanelDialog } from './paneldialog/PanelDialog.vue';
57
58
  export { default as MDialogProvider } from './dialogprovider/DialogProvider.vue';
59
+ export { default as MDrawer } from './drawer/Drawer.vue';
58
60
  export { default as MTree } from './tree/Tree.vue';
59
61
  export { default as MPopover } from './popover/Popover.vue';
62
+ export { default as MHoverCard } from './hovercard/HoverCard.vue';
@@ -20,9 +20,10 @@
20
20
  :type="inputType"
21
21
  :placeholder="placeholder"
22
22
  :name="name"
23
- :value="modelValue || ''"
23
+ :value="currentValue"
24
24
  :readonly="readonly"
25
25
  v-on="inputListeners"
26
+ @input="onNativeInput"
26
27
  :class="inputComputedClasses"
27
28
  v-bind="$attrs"
28
29
  :disabled="disabled || loading"
@@ -32,6 +33,7 @@
32
33
  <div v-if="hasSuffix" :class="style.suffix">
33
34
  <slot name="suffix" />
34
35
  </div>
36
+ <MClearButton v-if="showClear" :class="clearClasses" @clear="onClear" />
35
37
  <div v-if="hasRightIcon" :class="style.rightIcon">
36
38
  <slot name="icon-right" />
37
39
  </div>
@@ -52,14 +54,17 @@ import {
52
54
  defineComponent,
53
55
  ref,
54
56
  computed,
55
- toRef
57
+ toRef,
58
+ watch
56
59
  } from "vue";
57
60
  import { useInput } from "../../composables/useInput";
58
61
  import { useInteractive } from "../../composables/useInteractive";
62
+ import MClearButton from '../clearbutton/ClearButton.vue';
59
63
  import * as style from './style';
60
64
 
61
65
  export default defineComponent({
62
66
  name: 'MInput',
67
+ components: { MClearButton },
63
68
  props: {
64
69
  ...useInput.props(),
65
70
  ...useInteractive.props(),
@@ -100,11 +105,15 @@ export default defineComponent({
100
105
  default: false
101
106
  },
102
107
  error: {
103
- type: String,
108
+ type: String as PropType<string | null>,
104
109
  default: ''
105
110
  },
111
+ clearable: {
112
+ type: Boolean,
113
+ default: false
114
+ },
106
115
  },
107
- emits: useInput.emits(),
116
+ emits: [...useInput.emits(), 'clear'],
108
117
  setup(props, { slots, emit, expose }) {
109
118
  const element = ref<HTMLInputElement|null>(null);
110
119
  const { focus, blur } = useInteractive(element);
@@ -170,6 +179,8 @@ export default defineComponent({
170
179
  [style.disabled]: disabled.value || loading.value,
171
180
  [style.hasLeftIcon]: hasLeftIcon.value,
172
181
  [style.hasRightIcon]: hasRightIcon.value,
182
+ [style.hasClear]: props.clearable,
183
+ [style.hasClearAndRightIcon]: props.clearable && hasRightIcon.value,
173
184
  }
174
185
  ];
175
186
 
@@ -193,8 +204,41 @@ export default defineComponent({
193
204
  return formError.value || props.error;
194
205
  });
195
206
 
207
+ // Tracks typed text so clearable works without v-model
208
+ const internalValue = ref<any>(props.modelValue ?? '');
209
+ watch(() => props.modelValue, value => {
210
+ internalValue.value = value ?? '';
211
+ });
212
+
213
+ const currentValue = computed(() => {
214
+ const value = props.modelValue !== undefined ? props.modelValue : internalValue.value;
215
+ return value || '';
216
+ });
217
+
218
+ const onNativeInput = (event: Event) => {
219
+ internalValue.value = (event.target as HTMLInputElement).value;
220
+ };
221
+
222
+ const showClear = computed(() => {
223
+ return props.clearable
224
+ && !disabled.value
225
+ && !loading.value
226
+ && !props.readonly
227
+ && currentValue.value !== '';
228
+ });
229
+
230
+ const clearClasses = computed(() => {
231
+ return [
232
+ style.clear,
233
+ { [style.clearWithRightIcon]: hasRightIcon.value }
234
+ ];
235
+ });
236
+
196
237
  const onClear = () => {
238
+ internalValue.value = '';
197
239
  emit('update:modelValue', '');
240
+ emit('clear');
241
+ focus();
198
242
  };
199
243
 
200
244
  expose({
@@ -220,6 +264,10 @@ export default defineComponent({
220
264
  hasHelpMessage,
221
265
  inputError,
222
266
  style,
267
+ showClear,
268
+ clearClasses,
269
+ currentValue,
270
+ onNativeInput,
223
271
 
224
272
  onClear,
225
273
  validate,
@@ -0,0 +1,18 @@
1
+ <template>
2
+ <div style="display: flex; flex-direction: column; gap: 12px; max-width: 320px;">
3
+ <MInput v-model="value" placeholder="Type something..." clearable />
4
+ <MInput v-model="value" placeholder="With a right icon" clearable>
5
+ <template #icon-right>
6
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor" style="width: 20px; height: 20px;">
7
+ <path fill-rule="evenodd" d="M18 10a8 8 0 11-16 0 8 8 0 0116 0zm-7-4a1 1 0 11-2 0 1 1 0 012 0zM9 9a.75.75 0 000 1.5h.253a.25.25 0 01.244.304l-.459 2.066A1.75 1.75 0 0010.747 15H11a.75.75 0 000-1.5h-.253a.25.25 0 01-.244-.304l.459-2.066A1.75 1.75 0 009.253 9H9z" clip-rule="evenodd" />
8
+ </svg>
9
+ </template>
10
+ </MInput>
11
+ </div>
12
+ </template>
13
+
14
+ <script lang="ts" setup>
15
+ import { ref } from 'vue';
16
+
17
+ const value = ref('Clear me');
18
+ </script>
@@ -5,7 +5,8 @@ import {
5
5
  MInputPrefix,
6
6
  MInputLeftIcon,
7
7
  MInputRightIcon,
8
- MInputSizes
8
+ MInputSizes,
9
+ MInputClearable
9
10
  } from './index';
10
11
 
11
12
  import { createStory, sizeArgType } from '../../../__storybook__';
@@ -24,3 +25,4 @@ export const Prefix = createStory(MInputPrefix);
24
25
  export const Sizes = createStory(MInputSizes);
25
26
  export const LeftIcon = createStory(MInputLeftIcon);
26
27
  export const RightIcon = createStory(MInputRightIcon);
28
+ export const Clearable = createStory(MInputClearable);
@@ -4,3 +4,4 @@ export { default as MInputPrefix } from './prefix.vue';
4
4
  export { default as MInputSizes } from './sizes.vue';
5
5
  export { default as MInputLeftIcon } from './left-icon.vue';
6
6
  export { default as MInputRightIcon } from './right-icon.vue';
7
+ export { default as MInputClearable } from './clearable.vue';
@@ -251,6 +251,25 @@ export const hasRightIcon = style({
251
251
  paddingRight: '2.25rem'
252
252
  });
253
253
 
254
+ export const hasClear = style({
255
+ paddingRight: '1.75rem'
256
+ });
257
+
258
+ export const hasClearAndRightIcon = style({
259
+ paddingRight: '4rem'
260
+ });
261
+
262
+ export const clear = style({
263
+ position: 'absolute',
264
+ top: '50%',
265
+ right: themeVars.space[1],
266
+ transform: 'translateY(-50%)'
267
+ });
268
+
269
+ export const clearWithRightIcon = style({
270
+ right: '2.25rem'
271
+ });
272
+
254
273
  export const prefix = style({
255
274
  pointerEvents: 'none',
256
275
  marginRight: themeVars.space[3],
@@ -64,7 +64,7 @@ export default defineComponent({
64
64
  },
65
65
  },
66
66
  setup(props) {
67
- const activeMessages = new Map<string, { stop: () => void; closed: boolean; onClose?: () => void }>();
67
+ const activeMessages = new Map<string, { stop: () => void; closed: boolean; currentId: string; onClose?: () => void }>();
68
68
 
69
69
  const sonnerPosition = computed(() => placementMap[props.placement]);
70
70
 
@@ -100,9 +100,9 @@ export default defineComponent({
100
100
  return timeout ?? props.timeout;
101
101
  }
102
102
 
103
- function syncToast(message: PrivateMessageReactive) {
103
+ function createToast(message: PrivateMessageReactive, sonnerId: string) {
104
104
  const options: ExternalToast = {
105
- id: message.id,
105
+ id: sonnerId,
106
106
  duration: normalizeDuration(message.timeout),
107
107
  closeButton: message.closeButton ?? message.closable,
108
108
  richColors: message.richColors,
@@ -133,6 +133,23 @@ export default defineComponent({
133
133
  }
134
134
  }
135
135
 
136
+ function syncToast(message: PrivateMessageReactive) {
137
+ const active = activeMessages.get(message.id);
138
+ if (!active) {
139
+ return;
140
+ }
141
+
142
+ const oldId = active.currentId;
143
+ const newId = Math.random().toString(16).slice(2, 14);
144
+ active.currentId = newId;
145
+
146
+ toast.dismiss(oldId);
147
+
148
+ requestAnimationFrame(() => {
149
+ createToast(message, newId);
150
+ });
151
+ }
152
+
136
153
  function closeMessage(id: string, invokeOnClose: boolean) {
137
154
  const active = activeMessages.get(id);
138
155
  if (!active || active.closed) {
@@ -164,20 +181,29 @@ export default defineComponent({
164
181
  type: options.type,
165
182
  onClose: options.onClose,
166
183
  destroy: () => {
184
+ const active = activeMessages.get(id);
185
+ const sonnerId = active?.currentId ?? id;
167
186
  closeMessage(id, false);
168
- toast.dismiss(id);
187
+ toast.dismiss(sonnerId);
169
188
  },
170
189
  }) as PrivateMessageReactive;
171
190
 
191
+ const sonnerId = Math.random().toString(16).slice(2, 14);
192
+ activeMessages.set(id, { stop: () => {}, closed: false, currentId: sonnerId, onClose: options.onClose });
193
+
172
194
  const stop = watch(
173
195
  () => [message.content, message.type, message.timeout, message.closable, message.closeButton, message.richColors, sonnerPosition.value],
174
- () => {
175
- syncToast(message);
196
+ (_, oldVal) => {
197
+ if (!oldVal) {
198
+ createToast(message, activeMessages.get(id)!.currentId);
199
+ } else {
200
+ syncToast(message);
201
+ }
176
202
  },
177
203
  { immediate: true }
178
204
  );
179
205
 
180
- activeMessages.set(id, { stop, closed: false, onClose: options.onClose });
206
+ activeMessages.get(id)!.stop = stop;
181
207
 
182
208
  return message;
183
209
  }
@@ -6,7 +6,8 @@
6
6
  <DialogOverlay v-if="isOpen" force-mount :class="style.mask" :style="{ zIndex }" />
7
7
  </Transition>
8
8
  <Transition appear type="animation" :enter-active-class="modalScale.enterActive" :leave-active-class="modalScale.leaveActive"
9
- :enter-from-class="modalScale.enterFrom" :leave-to-class="modalScale.leaveTo">
9
+ :enter-from-class="modalScale.enterFrom" :leave-to-class="modalScale.leaveTo"
10
+ @after-leave="handleAfterLeave">
10
11
  <div tabIndex="-1" v-if="isOpen" ref="wrapperRef"
11
12
  :class="computedWrapperClasses" :style="computedWrapperStyles">
12
13
  <DialogContent
@@ -73,6 +74,7 @@ import {
73
74
  computed,
74
75
  defineComponent,
75
76
  nextTick,
77
+ onBeforeUnmount,
76
78
  provide,
77
79
  ref,
78
80
  shallowRef,
@@ -144,7 +146,13 @@ export default defineComponent({
144
146
  default: true
145
147
  }
146
148
  },
147
- emits: ['open', 'close', 'update:open'],
149
+ emits: {
150
+ open: () => true,
151
+ close: (_e?: MouseEvent | KeyboardEvent) => true,
152
+ 'update:open': (_value: boolean) => true,
153
+ // Fired once the leave animation has finished and the modal is out of the DOM
154
+ 'after-leave': () => true
155
+ },
148
156
  setup(props, { emit, slots }) {
149
157
  const { nextZIndex } = useZIndex();
150
158
 
@@ -302,7 +310,6 @@ export default defineComponent({
302
310
 
303
311
  const close = (e: MouseEvent | KeyboardEvent | undefined) => {
304
312
  props.onClose?.(e);
305
- ownerScrollbarClose();
306
313
  emit('close', e);
307
314
  isOpen.value = false;
308
315
  };
@@ -330,14 +337,26 @@ export default defineComponent({
330
337
  }
331
338
 
332
339
  function ownerScrollbarClose() {
333
- setTimeout(() => {
334
- let documentElement = window.document.documentElement;
340
+ let documentElement = window.document.documentElement;
335
341
 
336
- documentElement.style.overflow = 'visible';
337
- documentElement.style.paddingRight = '0px';
338
- }, 250);
342
+ documentElement.style.overflow = 'visible';
343
+ documentElement.style.paddingRight = '0px';
339
344
  }
340
345
 
346
+ // Runs when the leave transition actually completes, so the scroll lock
347
+ // can't drift from the animation duration.
348
+ const handleAfterLeave = () => {
349
+ ownerScrollbarClose();
350
+ emit('after-leave');
351
+ };
352
+
353
+ // Unmounted while open: there is no leave transition, so release the lock here
354
+ onBeforeUnmount(() => {
355
+ if (isOpen.value) {
356
+ ownerScrollbarClose();
357
+ }
358
+ });
359
+
341
360
  watch(
342
361
  () => isOpen.value,
343
362
  (newValue, oldValue) => {
@@ -346,9 +365,6 @@ export default defineComponent({
346
365
  ownerScrollbarOpen();
347
366
  zIndex.value = props.zIndex ?? nextZIndex();
348
367
  emit('open');
349
- } else if (!newValue && oldValue) {
350
- // Closing
351
- ownerScrollbarClose();
352
368
  }
353
369
  },
354
370
  { immediate: true }
@@ -362,6 +378,7 @@ export default defineComponent({
362
378
  onInteractOutside,
363
379
  handleOpenChange,
364
380
  handleOpenAutoFocus,
381
+ handleAfterLeave,
365
382
  target,
366
383
  bodyRef,
367
384
  style,
@@ -126,7 +126,10 @@ export default defineComponent({
126
126
  default: false
127
127
  }
128
128
  },
129
- emits: ['update:page', 'update:pageSize'],
129
+ emits: {
130
+ 'update:page': (_page: number) => true,
131
+ 'update:pageSize': (_pageSize: number) => true
132
+ },
130
133
  setup(props, { emit }) {
131
134
  const realTotal = computed(() => {
132
135
  return props.total || 0;