@indielayer/ui 1.9.3 → 1.10.0

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 (95) hide show
  1. package/docs/components/menu/DocsMenu.vue +1 -0
  2. package/docs/pages/component/form/usage.vue +2 -0
  3. package/docs/pages/component/menu/usage.vue +2 -0
  4. package/docs/pages/component/select/index.vue +7 -0
  5. package/docs/pages/component/select/multiple.vue +42 -0
  6. package/docs/pages/component/select/usage.vue +8 -12
  7. package/docs/pages/component/table/virtual.vue +19 -6
  8. package/docs/pages/component/toggle/index.vue +1 -1
  9. package/docs/pages/component/tooltip/index.vue +1 -1
  10. package/docs/pages/component/upload/index.vue +29 -0
  11. package/docs/pages/component/upload/usage.vue +115 -0
  12. package/docs/search/components.json +1 -1
  13. package/lib/common/icons.d.ts +2 -0
  14. package/lib/common/icons.js +17 -15
  15. package/lib/components/checkbox/Checkbox.vue2.js +9 -9
  16. package/lib/components/datepicker/Datepicker.vue.d.ts +4 -4
  17. package/lib/components/datepicker/Datepicker.vue.js +1 -1
  18. package/lib/components/drawer/Drawer.vue.js +1 -17
  19. package/lib/components/form/Form.vue.d.ts +4 -4
  20. package/lib/components/form/Form.vue.js +34 -34
  21. package/lib/components/formGroup/FormGroup.vue.d.ts +1 -1
  22. package/lib/components/formGroup/FormGroup.vue.js +39 -37
  23. package/lib/components/index.d.ts +1 -0
  24. package/lib/components/index.js +68 -66
  25. package/lib/components/label/theme/Label.base.theme.js +7 -7
  26. package/lib/components/menu/Menu.vue.d.ts +2 -0
  27. package/lib/components/menu/MenuItem.vue.d.ts +15 -3
  28. package/lib/components/menu/MenuItem.vue.js +1 -1
  29. package/lib/components/menu/MenuItem.vue2.js +43 -37
  30. package/lib/components/modal/Modal.vue.d.ts +4 -4
  31. package/lib/components/modal/Modal.vue.js +38 -34
  32. package/lib/components/notifications/Notifications.vue.d.ts +15 -0
  33. package/lib/components/notifications/Notifications.vue.js +149 -127
  34. package/lib/components/progress/Progress.vue.d.ts +4 -4
  35. package/lib/components/progress/Progress.vue.js +7 -7
  36. package/lib/components/scroll/Scroll.vue2.js +1 -1
  37. package/lib/components/select/Select.vue.d.ts +43 -1
  38. package/lib/components/select/Select.vue.js +358 -258
  39. package/lib/components/select/theme/Select.base.theme.js +1 -0
  40. package/lib/components/tab/Tab.vue.js +1 -1
  41. package/lib/components/tab/TabGroup.vue.js +2 -2
  42. package/lib/components/table/TableCell.vue.d.ts +1 -1
  43. package/lib/components/tag/Tag.vue.js +23 -21
  44. package/lib/components/textarea/Textarea.vue.js +1 -1
  45. package/lib/components/upload/Upload.vue.d.ts +195 -0
  46. package/lib/components/upload/Upload.vue.js +264 -0
  47. package/lib/components/upload/Upload.vue2.js +4 -0
  48. package/lib/components/upload/__tests__/Upload.spec.d.ts +1 -0
  49. package/lib/components/upload/index.d.ts +2 -0
  50. package/lib/components/upload/theme/Upload.base.theme.d.ts +3 -0
  51. package/lib/components/upload/theme/Upload.base.theme.js +8 -0
  52. package/lib/components/upload/theme/Upload.carbon.theme.d.ts +3 -0
  53. package/lib/components/upload/theme/Upload.carbon.theme.js +5 -0
  54. package/lib/composables/useVirtualList.js +56 -53
  55. package/lib/index.js +43 -41
  56. package/lib/index.umd.js +4 -4
  57. package/lib/node_modules/.pnpm/@vueuse_core@11.1.0_vue@3.5.10_typescript@5.2.2_/node_modules/@vueuse/core/index.js +501 -0
  58. package/lib/node_modules/.pnpm/@vueuse_shared@11.1.0_vue@3.5.10_typescript@5.2.2_/node_modules/@vueuse/shared/index.js +96 -0
  59. package/lib/theme.d.ts +2 -1
  60. package/lib/themes/base/components.d.ts +1 -0
  61. package/lib/themes/base/components.js +23 -21
  62. package/lib/themes/carbon/components.d.ts +1 -0
  63. package/lib/themes/carbon/components.js +23 -21
  64. package/lib/version.d.ts +1 -1
  65. package/lib/version.js +1 -1
  66. package/package.json +3 -3
  67. package/src/common/icons.ts +2 -0
  68. package/src/components/checkbox/Checkbox.vue +5 -5
  69. package/src/components/drawer/Drawer.vue +0 -16
  70. package/src/components/form/Form.vue +10 -4
  71. package/src/components/formGroup/FormGroup.vue +2 -0
  72. package/src/components/index.ts +1 -0
  73. package/src/components/label/theme/Label.base.theme.ts +7 -5
  74. package/src/components/menu/Menu.vue +2 -0
  75. package/src/components/menu/MenuItem.vue +8 -6
  76. package/src/components/modal/Modal.vue +6 -1
  77. package/src/components/notifications/Notifications.vue +34 -4
  78. package/src/components/progress/Progress.vue +2 -2
  79. package/src/components/select/Select.vue +165 -67
  80. package/src/components/select/theme/Select.base.theme.ts +2 -0
  81. package/src/components/tag/Tag.vue +11 -9
  82. package/src/components/upload/Upload.vue +365 -0
  83. package/src/components/upload/__tests__/Upload.spec.ts +11 -0
  84. package/src/components/upload/index.ts +2 -0
  85. package/src/components/upload/theme/Upload.base.theme.ts +9 -0
  86. package/src/components/upload/theme/Upload.carbon.theme.ts +7 -0
  87. package/src/composables/useInputtable.ts +1 -1
  88. package/src/composables/useVirtualList.ts +8 -5
  89. package/src/theme.ts +2 -0
  90. package/src/themes/base/components.ts +1 -0
  91. package/src/themes/carbon/components.ts +1 -0
  92. package/src/version.ts +1 -1
  93. package/volar.d.ts +1 -0
  94. package/lib/node_modules/.pnpm/@vueuse_core@10.2.0_vue@3.5.10_typescript@5.2.2_/node_modules/@vueuse/core/index.js +0 -412
  95. package/lib/node_modules/.pnpm/@vueuse_shared@10.2.0_vue@3.5.10_typescript@5.2.2_/node_modules/@vueuse/shared/index.js +0 -90
@@ -16,11 +16,11 @@ import { default as L } from "../../components/divider/theme/Divider.carbon.them
16
16
  import { default as w } from "../../components/drawer/theme/Drawer.carbon.theme.js";
17
17
  import { default as R } from "../../components/form/theme/Form.carbon.theme.js";
18
18
  import { default as N } from "../../components/formGroup/theme/FormGroup.carbon.theme.js";
19
- import { default as j } from "../../components/icon/theme/Icon.carbon.theme.js";
20
- import { default as y } from "../../components/image/theme/Image.carbon.theme.js";
21
- import { default as E } from "../../components/input/theme/Input.carbon.theme.js";
22
- import { default as K } from "../../components/inputFooter/theme/InputFooter.carbon.theme.js";
23
- import { default as U } from "../../components/label/theme/Label.carbon.theme.js";
19
+ import { default as U } from "../../components/icon/theme/Icon.carbon.theme.js";
20
+ import { default as q } from "../../components/image/theme/Image.carbon.theme.js";
21
+ import { default as z } from "../../components/input/theme/Input.carbon.theme.js";
22
+ import { default as J } from "../../components/inputFooter/theme/InputFooter.carbon.theme.js";
23
+ import { default as O } from "../../components/label/theme/Label.carbon.theme.js";
24
24
  import { default as W } from "../../components/link/theme/Link.carbon.theme.js";
25
25
  import { default as Y } from "../../components/loader/theme/Loader.carbon.theme.js";
26
26
  import { default as _ } from "../../components/menu/theme/Menu.carbon.theme.js";
@@ -43,12 +43,13 @@ import { default as Le } from "../../components/tab/theme/Tab.carbon.theme.js";
43
43
  import { default as we } from "../../components/tab/theme/TabGroup.carbon.theme.js";
44
44
  import { default as Re } from "../../components/table/theme/Table.carbon.theme.js";
45
45
  import { default as Ne } from "../../components/table/theme/TableCell.carbon.theme.js";
46
- import { default as je } from "../../components/table/theme/TableHead.carbon.theme.js";
47
- import { default as ye } from "../../components/table/theme/TableHeader.carbon.theme.js";
48
- import { default as Ee } from "../../components/table/theme/TableRow.carbon.theme.js";
49
- import { default as Ke } from "../../components/tag/theme/Tag.carbon.theme.js";
50
- import { default as Ue } from "../../components/textarea/theme/Textarea.carbon.theme.js";
46
+ import { default as Ue } from "../../components/table/theme/TableHead.carbon.theme.js";
47
+ import { default as qe } from "../../components/table/theme/TableHeader.carbon.theme.js";
48
+ import { default as ze } from "../../components/table/theme/TableRow.carbon.theme.js";
49
+ import { default as Je } from "../../components/tag/theme/Tag.carbon.theme.js";
50
+ import { default as Oe } from "../../components/textarea/theme/Textarea.carbon.theme.js";
51
51
  import { default as We } from "../../components/toggle/theme/Toggle.carbon.theme.js";
52
+ import { default as Ye } from "../../components/upload/theme/Upload.carbon.theme.js";
52
53
  export {
53
54
  a as Accordion,
54
55
  t as AccordionItem,
@@ -68,11 +69,11 @@ export {
68
69
  w as Drawer,
69
70
  R as Form,
70
71
  N as FormGroup,
71
- j as Icon,
72
- y as Image,
73
- E as Input,
74
- K as InputFooter,
75
- U as Label,
72
+ U as Icon,
73
+ q as Image,
74
+ z as Input,
75
+ J as InputFooter,
76
+ O as Label,
76
77
  W as Link,
77
78
  Y as Loader,
78
79
  _ as Menu,
@@ -95,10 +96,11 @@ export {
95
96
  we as TabGroup,
96
97
  Re as Table,
97
98
  Ne as TableCell,
98
- je as TableHead,
99
- ye as TableHeader,
100
- Ee as TableRow,
101
- Ke as Tag,
102
- Ue as Textarea,
103
- We as Toggle
99
+ Ue as TableHead,
100
+ qe as TableHeader,
101
+ ze as TableRow,
102
+ Je as Tag,
103
+ Oe as Textarea,
104
+ We as Toggle,
105
+ Ye as Upload
104
106
  };
package/lib/version.d.ts CHANGED
@@ -1,2 +1,2 @@
1
- declare const _default: "1.9.3";
1
+ declare const _default: "1.10.0";
2
2
  export default _default;
package/lib/version.js CHANGED
@@ -1,4 +1,4 @@
1
- const e = "1.9.3";
1
+ const e = "1.10.0";
2
2
  export {
3
3
  e as default
4
4
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@indielayer/ui",
3
- "version": "1.9.3",
3
+ "version": "1.10.0",
4
4
  "description": "Indielayer UI Components with Tailwind CSS build for Vue 3",
5
5
  "author": {
6
6
  "name": "João Teixeira",
@@ -58,7 +58,7 @@
58
58
  "@vue/test-utils": "^2.4.0",
59
59
  "@vue/tsconfig": "^0.4.0",
60
60
  "@vuepic/vue-datepicker": "^8.3.2",
61
- "@vueuse/core": "^10.2.0",
61
+ "@vueuse/core": "^11.1.0",
62
62
  "autoprefixer": "^10.4.0",
63
63
  "c8": "^7.12.0",
64
64
  "clean-css": "^5.3.0",
@@ -96,7 +96,7 @@
96
96
  "access": "public"
97
97
  },
98
98
  "scripts": {
99
- "dev": "vite dev --mode docs",
99
+ "dev": "vite dev --mode docs --open",
100
100
  "build": "pnpm generate && vite build",
101
101
  "build:docs": "pnpm build --mode docs",
102
102
  "build:prod": "pnpm build && pnpm gen:types",
@@ -16,3 +16,5 @@ export const externalIcon = '<line x1="7" y1="17" x2="17" y2="7" /><polyline poi
16
16
  export const stepperPristineIcon = '<path d="M7.5 4.21v.01M4.21 7.5v.01M3 12v.01m1.21 4.49v.01m3.29 3.28v.01M12 21v.01m4.5-1.22v.01m3.29-3.3v.01M21 12v.01M19.79 7.5v.01m-3.29-3.3v.01M12 3v.01"/>'
17
17
  export const stepperIncompleteIcon = '<svg focusable="false" preserveAspectRatio="xMidYMid meet" fill="currentColor" viewBox="0 0 32 32" aria-hidden="true" xmlns="http://www.w3.org/2000/svg"><path d="M23.7642 6.8593l1.2851-1.5315A13.976 13.976 0 0020.8672 2.887l-.6836 1.8776A11.9729 11.9729 0 0123.7642 6.8593zM27.81 14l1.9677-.4128A13.8888 13.8888 0 0028.14 9.0457L26.4087 10A12.52 12.52 0 0127.81 14zM20.1836 27.2354l.6836 1.8776a13.976 13.976 0 004.1821-2.4408l-1.2851-1.5315A11.9729 11.9729 0 0120.1836 27.2354zM26.4087 22L28.14 23a14.14 14.14 0 001.6382-4.5872L27.81 18.0659A12.1519 12.1519 0 0126.4087 22zM16 30V2a14 14 0 000 28z"></path></svg>'
18
18
  export const chevronDownIcon = '<path d="M19 9l-7 7-7-7" />'
19
+ export const uploadIcon = '<path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"></path><polyline points="17 8 12 3 7 8"></polyline><line x1="12" y1="3" x2="12" y2="15"></line>'
20
+ export const fileIcon = '<path d="M13 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V9z"></path><polyline points="13 2 13 9 20 9"></polyline>'
@@ -24,15 +24,15 @@ export default {
24
24
  </script>
25
25
 
26
26
  <script setup lang="ts">
27
- import { ref, watch, type ExtractPublicPropTypes, type Ref, unref, nextTick } from 'vue'
28
- import { useTheme, type ThemeComponent } from '../../composables/useTheme'
29
- import { useCommon } from '../../composables/useCommon'
27
+ import { ref, unref, watch, type ExtractPublicPropTypes, type Ref } from 'vue'
30
28
  import { useColors } from '../../composables/useColors'
31
- import { useInteractive } from '../../composables/useInteractive'
29
+ import { useCommon } from '../../composables/useCommon'
32
30
  import { useInputtable } from '../../composables/useInputtable'
31
+ import { useInteractive } from '../../composables/useInteractive'
32
+ import { useTheme, type ThemeComponent } from '../../composables/useTheme'
33
33
 
34
- import XSpinner from '../spinner/Spinner.vue'
35
34
  import XInputFooter from '../inputFooter/InputFooter.vue'
35
+ import XSpinner from '../spinner/Spinner.vue'
36
36
 
37
37
  const props = defineProps(checkboxProps)
38
38
 
@@ -87,22 +87,6 @@ function onKeyDown(event: KeyboardEvent) {
87
87
  }
88
88
 
89
89
  const { lengthX, lengthY } = useSwipe(drawerRef, {
90
- // passive: false,
91
- // onSwipe(e: TouchEvent) {
92
- // if (lengthX.value < 0) {
93
- // const length = Math.abs(lengthX.value)
94
- // left.value = `${length}px`
95
- // } else {
96
- // left.value = '0'
97
- // }
98
- // },
99
- // onSwipeEnd(e: TouchEvent, direction: UseSwipeDirection) {
100
- // if (lengthX.value < 0 && props.width && (Math.abs(lengthX.value) / props.width) >= 0.5) {
101
- // left.value = '100%'
102
- // } else {
103
- // left.value = '0'
104
- // }
105
- // },
106
90
  onSwipeEnd(e: TouchEvent, direction: UseSwipeDirection) {
107
91
  if (detached.value) {
108
92
  if (
@@ -10,7 +10,7 @@ const formProps = {
10
10
  },
11
11
  disabled: Boolean,
12
12
  errors: {
13
- type: [Array, Object] as PropType<[FormError[], FormError]>,
13
+ type: [Array, Object] as PropType<FormError[] | FormError>,
14
14
  default: () => ([]),
15
15
  },
16
16
  title: String,
@@ -86,16 +86,22 @@ onMounted(async () => {
86
86
 
87
87
  watch(() => props.errors, (errors) => {
88
88
  if (errors) nextTick(() => {
89
- if (Array.isArray(errors)) errors.forEach((error: any) => {
89
+ if (Array.isArray(errors)) errors.forEach((error: FormError, index) => {
90
90
  const input = inputs.find((i) => i.name === error.field)
91
91
 
92
- if (input) input.setError(error.msg)
92
+ if (input) {
93
+ input.setError(error.msg)
94
+ if (index === 0 && input.focus) input.focus()
95
+ }
93
96
  })
94
97
 
95
98
  else {
96
99
  const input = inputs.find((i) => i.name === (errors as FormError).field)
97
100
 
98
- if (input) input.setError((errors as FormError).msg)
101
+ if (input) {
102
+ input.setError((errors as FormError).msg)
103
+ if (input.focus) input.focus()
104
+ }
99
105
  }
100
106
  })
101
107
  })
@@ -73,6 +73,8 @@ function focus() {
73
73
  inputs[0]?.focus()
74
74
  }
75
75
 
76
+ function blur() {}
77
+
76
78
  const emit = defineEmits(useInputtable.emits())
77
79
 
78
80
  const {
@@ -42,3 +42,4 @@ export * from './textarea'
42
42
  export * from './themeProvider'
43
43
  export * from './toggle'
44
44
  export * from './tooltip'
45
+ export * from './upload'
@@ -12,12 +12,14 @@ const theme: LabelTheme = {
12
12
  },
13
13
 
14
14
  label: ({ props }) => {
15
- const classes = 'flex items-center gap-2 font-medium text-secondary-800 dark:text-secondary-200 mb-1'
15
+ const classes = ['flex items-center gap-2 font-medium text-secondary-800 dark:text-secondary-200 mb-1']
16
16
 
17
- if (props.size === 'xs') return classes + ' text-xs'
18
- else if (props.size === 'sm') return classes + ' text-sm'
19
- else if (props.size === 'lg') return classes + ' text-lg'
20
- else if (props.size === 'xl') return classes + ' text-xl'
17
+ if (props.size === 'xs') classes.push('text-xs')
18
+ else if (props.size === 'sm') classes.push('text-sm')
19
+ else if (props.size === 'lg') classes.push('text-lg')
20
+ else if (props.size === 'xl') classes.push('text-xl')
21
+
22
+ if (props.required) classes.push('[&_span]:after:content-["*"] [&_span]:after:ml-0.5 [&_span]:after:text-error-500')
21
23
 
22
24
  return classes
23
25
  },
@@ -43,6 +43,8 @@ export type MenuArrayItem = {
43
43
  disabled?: boolean;
44
44
  active?: boolean;
45
45
  attrs?: Record<string, unknown>;
46
+ prefix?: string;
47
+ suffix?: string;
46
48
  onClick?: (e: MouseEvent) => void;
47
49
  }
48
50
 
@@ -1,7 +1,7 @@
1
1
  <script lang="ts">
2
2
  const menuItemProps = {
3
3
  ...useCommon.props(),
4
- ...useColors.props('primary'),
4
+ ...useColors.props('secondary'),
5
5
  item: {
6
6
  type: Object as PropType<MenuArrayItem>,
7
7
  default: () => {},
@@ -32,6 +32,8 @@ const menuItemProps = {
32
32
  selected: Boolean,
33
33
  disabled: Boolean,
34
34
  minimal: Boolean,
35
+ prefix: String,
36
+ suffix: String,
35
37
  }
36
38
 
37
39
  export type MenuItemProps = ExtractPublicPropTypes<typeof menuItemProps>
@@ -148,20 +150,20 @@ const { styles, classes, className } = useTheme('MenuItem', {}, computedProps, {
148
150
  :alt="computedProps.label"
149
151
  @click="onItemClick"
150
152
  >
151
- <span v-if="$slots.prefix" class="mr-2 shrink-0">
152
- <slot name="prefix"></slot>
153
+ <span v-if="$slots.prefix || computedProps.prefix" class="mr-2 shrink-0">
154
+ <slot name="prefix" :item="computedProps">{{ computedProps.prefix }}</slot>
153
155
  </span>
154
156
  <x-icon v-else-if="computedProps.icon" :size="computedProps.size" :icon="computedProps.icon" class="mr-2"/>
155
157
 
156
158
  <span v-if="!minimal" class="flex-1 truncate">
157
- <slot>{{ computedProps.label }}</slot>
159
+ <slot :item="computedProps">{{ computedProps.label }}</slot>
158
160
  </span>
159
161
 
160
162
  <span class="ml-1 shrink-0">
161
163
  <x-spinner v-if="computedProps.loading" :size="computedProps.size" />
162
164
  <template v-else>
163
- <span v-if="$slots.suffix">
164
- <slot name="suffix"></slot>
165
+ <span v-if="$slots.suffix || computedProps.suffix">
166
+ <slot name="suffix" :item="computedProps">{{ computedProps.suffix }}</slot>
165
167
  </span>
166
168
  <x-icon v-else-if="computedProps.iconRight" :size="computedProps.size" :icon="computedProps.iconRight"/>
167
169
  </template>
@@ -41,7 +41,7 @@ const modalProps = {
41
41
  default: true,
42
42
  },
43
43
  formErrors: {
44
- type: [Array, Object] as PropType<[FormError[], FormError]>,
44
+ type: [Array, Object] as PropType<FormError[] | FormError>,
45
45
  default: () => ([]),
46
46
  },
47
47
  persistent: Boolean,
@@ -112,6 +112,8 @@ async function checkVisibiliy() {
112
112
  const val = props.modelValue
113
113
 
114
114
  if (val) {
115
+ const scrollbarWidth = window.innerWidth - document.documentElement.clientWidth
116
+
115
117
  value.value = val
116
118
 
117
119
  await nextTick()
@@ -121,11 +123,14 @@ async function checkVisibiliy() {
121
123
  await nextTick()
122
124
 
123
125
  initFocusTrap(modalRef)
126
+
127
+ document.body.style.paddingRight = `${scrollbarWidth}px`
124
128
  document.body.style.overflow = 'hidden'
125
129
  } else {
126
130
  visible.value = val
127
131
  value.value = val
128
132
  clearFocusTrap()
133
+ document.body.style.paddingRight = ''
129
134
  document.body.style.overflow = 'auto'
130
135
  }
131
136
  }
@@ -19,6 +19,10 @@ const notificationsProps = {
19
19
  type: Boolean,
20
20
  default: true,
21
21
  },
22
+ pauseOnHover: {
23
+ type: Boolean,
24
+ default: true,
25
+ },
22
26
  injectKey: {
23
27
  type: [Symbol, String],
24
28
  default: injectNotificationKey,
@@ -47,6 +51,8 @@ export type NotificationEvent = {
47
51
  title?: string;
48
52
  style?: string;
49
53
  message?: string;
54
+ timer?: ReturnType<typeof setTimeout>;
55
+ timerStart?: number;
50
56
  timeout?: number;
51
57
  removable?: boolean;
52
58
  align?: NotificationsAlign;
@@ -209,11 +215,18 @@ function add(notification: NotificationEvent) {
209
215
 
210
216
  merged.style = Object.keys(cssVariables).map((key) => `${key}: ${cssVariables[key]}`).join(';')
211
217
 
212
- notifications.value.push(merged)
218
+ if (merged.timeout) {
219
+ const timer = setTimer(merged, merged.timeout)
213
220
 
214
- listRef.value?.scrollTo({ top: 0, behavior: 'smooth' })
221
+ merged.timer = timer
222
+ merged.timerStart = Date.now()
223
+ }
224
+
225
+ notifications.value.push(merged)
215
226
 
216
- if (merged.timeout) setTimer(merged, merged.timeout)
227
+ setTimeout(() => {
228
+ listRef.value?.scrollTo({ top: 0, behavior: 'smooth' })
229
+ }, 0)
217
230
  }
218
231
 
219
232
  function remove(event: NotificationEvent) {
@@ -221,11 +234,26 @@ function remove(event: NotificationEvent) {
221
234
  }
222
235
 
223
236
  function setTimer(notification: NotificationEvent, timeout: number) {
224
- setTimeout(() => {
237
+ return setTimeout(() => {
225
238
  remove(notification)
226
239
  }, timeout)
227
240
  }
228
241
 
242
+ function pause(notification: NotificationEvent) {
243
+ if (props.pauseOnHover && notification.timer) {
244
+ clearTimeout(notification.timer)
245
+ notification.timer = undefined
246
+ }
247
+ }
248
+
249
+ function resume(notification: NotificationEvent) {
250
+ if (props.pauseOnHover && notification.timeout && notification.timerStart) {
251
+ const remaining = Math.max(notification.timeout - (Date.now() - notification.timerStart), 1000)
252
+
253
+ notification.timer = setTimer(notification, remaining)
254
+ }
255
+ }
256
+
229
257
  const { styles, classes, className } = useTheme('Notifications', {}, props)
230
258
 
231
259
  defineExpose({ log, info, success, warn, warning: warn, error })
@@ -273,6 +301,8 @@ defineExpose({ log, info, success, warn, warning: warn, error })
273
301
  'mt-2': internalPosition === 'top',
274
302
  }]"
275
303
  :style="notification.style"
304
+ @mouseenter="pause(notification)"
305
+ @mouseleave="resume(notification)"
276
306
  >
277
307
  <x-icon
278
308
  v-if="notification.icon"
@@ -2,7 +2,7 @@
2
2
  const progressProps = {
3
3
  ...useColors.props('primary'),
4
4
  percentage: {
5
- type: Number,
5
+ type: [Number, String],
6
6
  default: 0,
7
7
  validator: (value: number) => value >= 0 && value <= 100,
8
8
  },
@@ -56,7 +56,7 @@ const { styles, classes, className } = useTheme('Progress', {}, props)
56
56
  class="absolute h-full bg-secondary-100 dark:bg-secondary-700 right-0 top-0"
57
57
  :class="{ 'duration-150 transition-[width]': animate }"
58
58
  :style="{
59
- width: `${100 - percentage}%`
59
+ width: `${100 - Number(percentage)}%`
60
60
  }"
61
61
  ></div>
62
62
  </div>