@xen-orchestra/web-core 0.51.0 → 0.53.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 (52) hide show
  1. package/lib/assets/css/_reset.pcss +8 -1
  2. package/lib/components/column/VtsColumn.vue +5 -1
  3. package/lib/components/columns/VtsColumns.vue +17 -8
  4. package/lib/components/console/VtsRemoteConsole.vue +25 -19
  5. package/lib/components/form/VtsForm.vue +15 -0
  6. package/lib/components/{quick-info-column/VtsQuickInfoColumn.vue → key-value-list/VtsKeyValueList.vue} +3 -3
  7. package/lib/components/key-value-pair/VtsKeyValuePair.vue +48 -0
  8. package/lib/components/key-value-row/VtsKeyValueRow.vue +45 -0
  9. package/lib/components/status/VtsStatus.vue +1 -7
  10. package/lib/components/table/cells/VtsTagCell.vue +2 -4
  11. package/lib/components/tabular-key-value-list/VtsTabularKeyValueList.vue +29 -0
  12. package/lib/components/tabular-key-value-row/VtsTabularKeyValueRow.vue +42 -0
  13. package/lib/components/tag/VtsTag.vue +30 -0
  14. package/lib/components/ui/chip/UiChip.vue +52 -29
  15. package/lib/components/ui/info/UiInfo.vue +17 -6
  16. package/lib/components/ui/link/UiLink.vue +6 -2
  17. package/lib/components/ui/tag/UiTag.vue +10 -17
  18. package/lib/components/ui/tag/UiTertiaryTag.vue +39 -0
  19. package/lib/icons/action-icons.ts +1 -1
  20. package/lib/locales/cs.json +0 -1
  21. package/lib/locales/da.json +0 -1
  22. package/lib/locales/de.json +0 -1
  23. package/lib/locales/en.json +15 -1
  24. package/lib/locales/es.json +0 -1
  25. package/lib/locales/fr.json +15 -1
  26. package/lib/locales/nl.json +0 -1
  27. package/lib/locales/pt-BR.json +0 -1
  28. package/lib/locales/pt.json +0 -1
  29. package/lib/locales/ru.json +0 -1
  30. package/lib/locales/sk.json +0 -1
  31. package/lib/locales/sv.json +0 -1
  32. package/lib/locales/zh-Hans.json +0 -1
  33. package/lib/packages/form-validation/README.md +273 -0
  34. package/lib/packages/form-validation/custom-rules/out-of-range.rule.ts +15 -0
  35. package/lib/packages/form-validation/index.ts +8 -0
  36. package/lib/packages/form-validation/merge-validation-configs.ts +46 -0
  37. package/lib/packages/form-validation/types.ts +104 -0
  38. package/lib/packages/form-validation/use-form-validation.ts +196 -0
  39. package/lib/packages/modal/types.ts +1 -2
  40. package/lib/packages/remote-resource/define-remote-resource.ts +2 -1
  41. package/lib/packages/remote-resource/types.ts +1 -3
  42. package/lib/packages/request/define-request.ts +1 -2
  43. package/lib/packages/validated-form/README.md +389 -0
  44. package/lib/packages/validated-form/index.ts +2 -0
  45. package/lib/packages/validated-form/use-multi-step-validated-form.ts +203 -0
  46. package/lib/packages/validated-form/use-validated-form.ts +180 -0
  47. package/lib/utils/parse-tag.util.ts +22 -0
  48. package/package.json +11 -8
  49. package/tsconfig.json +2 -3
  50. package/lib/components/quick-info-row/VtsQuickInfoRow.vue +0 -59
  51. package/lib/components/ui/chip/ChipIcon.vue +0 -21
  52. package/lib/components/ui/chip/ChipRemoveIcon.vue +0 -16
@@ -25,7 +25,10 @@ h5,
25
25
  h6,
26
26
  p,
27
27
  ol,
28
- ul {
28
+ ul,
29
+ dl,
30
+ dt,
31
+ dd {
29
32
  margin: 0;
30
33
  padding: 0;
31
34
  font-weight: inherit;
@@ -36,6 +39,10 @@ ul {
36
39
  list-style: none;
37
40
  }
38
41
 
42
+ dd {
43
+ margin-inline-start: 0;
44
+ }
45
+
39
46
  img {
40
47
  max-width: 100%;
41
48
  height: auto;
@@ -13,9 +13,13 @@ defineSlots<{
13
13
  <style lang="postcss" scoped>
14
14
  .vts-column {
15
15
  flex: 1;
16
- flex-basis: 0;
17
16
  display: flex;
18
17
  flex-direction: column;
19
18
  gap: 0.8rem;
19
+ min-width: 0;
20
+
21
+ @container vts-columns (max-width: 90rem) {
22
+ flex-basis: 100%;
23
+ }
20
24
  }
21
25
  </style>
@@ -1,16 +1,16 @@
1
1
  <template>
2
- <div class="vts-columns" :class="{ mobile: uiStore.isSmall }">
2
+ <div class="vts-columns" :class="{ 'extra-space-around': extraSpaceAround }">
3
3
  <component :is="nodes[index - 1] ?? VtsColumn" v-for="index of columns" :key="index" />
4
4
  </div>
5
5
  </template>
6
6
 
7
7
  <script lang="ts" setup>
8
8
  import VtsColumn from '@core/components/column/VtsColumn.vue'
9
- import { useUiStore } from '@core/stores/ui.store.ts'
10
9
  import { computed } from 'vue'
11
10
 
12
11
  const { columns: _columns = 2 } = defineProps<{
13
12
  columns?: number
13
+ extraSpaceAround?: boolean
14
14
  }>()
15
15
 
16
16
  const slots = defineSlots<{
@@ -20,19 +20,28 @@ const slots = defineSlots<{
20
20
  const nodes = computed(() => slots.default())
21
21
 
22
22
  const columns = computed(() => Math.max(_columns, nodes.value.length))
23
-
24
- const uiStore = useUiStore()
25
23
  </script>
26
24
 
27
25
  <style lang="postcss" scoped>
28
26
  .vts-columns {
27
+ container-type: inline-size;
28
+ container-name: vts-columns;
29
29
  display: flex;
30
+ flex-wrap: wrap;
30
31
  gap: 0.8rem;
31
- padding: 0.8rem;
32
- flex-direction: row;
33
32
 
34
- &.mobile {
35
- flex-direction: column;
33
+ &.extra-space-around {
34
+ margin: 0.8rem;
35
+ }
36
+
37
+ & > * {
38
+ flex: 1 0 0;
39
+ }
40
+
41
+ @container vts-columns (max-width: 60rem) {
42
+ & > * {
43
+ flex-basis: 100%;
44
+ }
36
45
  }
37
46
  }
38
47
  </style>
@@ -8,14 +8,15 @@
8
8
  <script lang="ts" setup>
9
9
  import VtsStateHero from '@core/components/state-hero/VtsStateHero.vue'
10
10
  import { useUiStore } from '@core/stores/ui.store'
11
- import VncClient from '@novnc/novnc/lib/rfb'
11
+ import type NoVncClient from '@novnc/novnc/lib/rfb'
12
+ import _RFB from '@novnc/novnc/lib/rfb'
12
13
  import { whenever } from '@vueuse/core'
13
14
  import { promiseTimeout } from '@vueuse/shared'
14
15
  import { fibonacci } from 'iterable-backoff'
15
- import { onBeforeUnmount, ref, useTemplateRef, watchEffect } from 'vue'
16
+ import { onBeforeUnmount, ref, useTemplateRef, watch } from 'vue'
16
17
  import { useI18n } from 'vue-i18n'
17
18
 
18
- const props = defineProps<{
19
+ const { url, isConsoleAvailable } = defineProps<{
19
20
  url: URL
20
21
  isConsoleAvailable: boolean
21
22
  }>()
@@ -30,23 +31,24 @@ const FIBONACCI_MS_ARRAY: number[] = Array.from(fibonacci().toMs().take(N_TOTAL_
30
31
  const consoleContainer = useTemplateRef<HTMLDivElement | null>('console-container')
31
32
  const isReady = ref(false)
32
33
 
33
- let vncClient: VncClient | undefined
34
+ // See https://rolldown.rs/in-depth/bundling-cjs#ambiguous-default-import-from-cjs-modules
35
+ const VncClient = typeof _RFB === 'object' && _RFB !== null && (_RFB as any).__esModule ? (_RFB as any).default : _RFB
36
+
37
+ let vncClient: NoVncClient | undefined
34
38
  let nConnectionAttempts = 0
35
39
 
36
40
  function handleDisconnectionEvent() {
37
41
  clearVncClient()
38
- if (props.isConsoleAvailable) {
42
+ if (isConsoleAvailable) {
39
43
  nConnectionAttempts++
40
44
 
41
45
  if (nConnectionAttempts > N_TOTAL_TRIES) {
42
- console.error('The number of reconnection attempts has been exceeded for:', props.url)
46
+ console.error('The number of reconnection attempts has been exceeded for:', url)
43
47
  return
44
48
  }
45
49
 
46
50
  console.error(
47
- `Connection lost for the remote console: ${props.url}. New attempt in ${
48
- FIBONACCI_MS_ARRAY[nConnectionAttempts - 1]
49
- }ms`
51
+ `Connection lost for the remote console: ${url}. New attempt in ${FIBONACCI_MS_ARRAY[nConnectionAttempts - 1]}ms`
50
52
  )
51
53
  createVncConnection()
52
54
  }
@@ -80,9 +82,9 @@ async function createVncConnection() {
80
82
  }
81
83
  }
82
84
 
83
- vncClient = new VncClient(consoleContainer.value!, props.url.toString(), {
85
+ vncClient = new VncClient(consoleContainer.value!, url.toString(), {
84
86
  wsProtocols: ['binary'],
85
- })
87
+ }) as NoVncClient
86
88
  vncClient.scaleViewport = true
87
89
  vncClient.background = 'transparent'
88
90
 
@@ -114,16 +116,20 @@ whenever(
114
116
  }
115
117
  )
116
118
 
117
- watchEffect(() => {
118
- if (consoleContainer.value === null || !props.isConsoleAvailable) {
119
- return
120
- }
119
+ watch(
120
+ [consoleContainer, () => isConsoleAvailable, () => url.toString()],
121
+ ([container, isAvailable]) => {
122
+ if (container === null || !isAvailable) {
123
+ return
124
+ }
121
125
 
122
- nConnectionAttempts = 0
126
+ nConnectionAttempts = 0
123
127
 
124
- clearVncClient()
125
- createVncConnection()
126
- })
128
+ clearVncClient()
129
+ createVncConnection()
130
+ },
131
+ { immediate: true }
132
+ )
127
133
 
128
134
  onBeforeUnmount(() => {
129
135
  clearVncClient()
@@ -0,0 +1,15 @@
1
+ <template>
2
+ <form novalidate @submit.prevent="emit('submit')">
3
+ <slot />
4
+ </form>
5
+ </template>
6
+
7
+ <script lang="ts" setup>
8
+ const emit = defineEmits<{
9
+ submit: []
10
+ }>()
11
+
12
+ defineSlots<{
13
+ default(): any
14
+ }>()
15
+ </script>
@@ -1,11 +1,11 @@
1
1
  <template>
2
- <div class="vts-quick-info-column">
2
+ <dl class="vts-key-value-list">
3
3
  <slot />
4
- </div>
4
+ </dl>
5
5
  </template>
6
6
 
7
7
  <style lang="postcss" scoped>
8
- .vts-quick-info-column {
8
+ .vts-key-value-list {
9
9
  display: flex;
10
10
  flex-direction: column;
11
11
  gap: 1.6rem;
@@ -0,0 +1,48 @@
1
+ <template>
2
+ <dt class="typo-body-regular label">
3
+ <slot name="label">
4
+ {{ label }}
5
+ </slot>
6
+ </dt>
7
+ <dd class="typo-body-regular value">
8
+ <span v-tooltip class="text-ellipsis">
9
+ <slot name="value">
10
+ {{ value }}
11
+ </slot>
12
+ </span>
13
+ </dd>
14
+ </template>
15
+
16
+ <script lang="ts" setup>
17
+ import { vTooltip } from '@core/directives/tooltip.directive'
18
+
19
+ defineProps<{
20
+ label?: string
21
+ value?: string
22
+ }>()
23
+
24
+ defineSlots<{
25
+ label?(): any
26
+ value?(): any
27
+ }>()
28
+ </script>
29
+
30
+ <style lang="postcss" scoped>
31
+ .label {
32
+ color: var(--color-neutral-txt-secondary);
33
+ }
34
+
35
+ .value {
36
+ color: var(--color-neutral-txt-primary);
37
+ display: flex;
38
+ align-items: center;
39
+ gap: 0.8rem;
40
+ min-width: 0;
41
+
42
+ .text-ellipsis {
43
+ &:empty::before {
44
+ content: '-';
45
+ }
46
+ }
47
+ }
48
+ </style>
@@ -0,0 +1,45 @@
1
+ <template>
2
+ <div class="vts-key-value-row" :class="{ mobile: uiStore.isSmallOrMedium }">
3
+ <VtsKeyValuePair :label :value>
4
+ <template v-if="slots.label" #label>
5
+ <slot name="label" />
6
+ </template>
7
+ <template v-if="slots.value" #value>
8
+ <slot name="value" />
9
+ </template>
10
+ </VtsKeyValuePair>
11
+ </div>
12
+ </template>
13
+
14
+ <script lang="ts" setup>
15
+ import VtsKeyValuePair from '@core/components/key-value-pair/VtsKeyValuePair.vue'
16
+ import { useUiStore } from '@core/stores/ui.store.ts'
17
+
18
+ defineProps<{
19
+ label?: string
20
+ value?: string
21
+ }>()
22
+
23
+ const slots = defineSlots<{
24
+ label?(): any
25
+ value?(): any
26
+ }>()
27
+
28
+ const uiStore = useUiStore()
29
+ </script>
30
+
31
+ <style lang="postcss" scoped>
32
+ .vts-key-value-row {
33
+ display: flex;
34
+ gap: 2.4rem;
35
+
36
+ &.mobile {
37
+ flex-direction: column;
38
+ gap: 0.8rem;
39
+ }
40
+
41
+ :deep(dt) {
42
+ flex-shrink: 0;
43
+ }
44
+ }
45
+ </style>
@@ -1,5 +1,5 @@
1
1
  <template>
2
- <UiInfo v-tooltip="iconOnly ? currentStatus.text : false" class="vts-status" :accent="currentStatus.accent">
2
+ <UiInfo v-tooltip="iconOnly ? currentStatus.text : false" :accent="currentStatus.accent">
3
3
  <template v-if="!iconOnly">{{ currentStatus.text }}</template>
4
4
  </UiInfo>
5
5
  </template>
@@ -62,9 +62,3 @@ const currentStatus = useMapper<Status, { text: string; accent: InfoAccent }>(
62
62
  false
63
63
  )
64
64
  </script>
65
-
66
- <style lang="postcss" scoped>
67
- .vts-status {
68
- align-items: center;
69
- }
70
- </style>
@@ -1,16 +1,14 @@
1
1
  <template>
2
2
  <UiTableCell>
3
3
  <UiTagsList>
4
- <UiTag v-for="tagItem of tags" :key="tagItem" accent="info" variant="secondary">
5
- {{ tagItem }}
6
- </UiTag>
4
+ <VtsTag v-for="tagItem of tags" :key="tagItem" :value="tagItem" />
7
5
  </UiTagsList>
8
6
  </UiTableCell>
9
7
  </template>
10
8
 
11
9
  <script setup lang="ts">
10
+ import VtsTag from '@core/components/tag/VtsTag.vue'
12
11
  import UiTableCell from '@core/components/ui/table-cell/UiTableCell.vue'
13
- import UiTag from '@core/components/ui/tag/UiTag.vue'
14
12
  import UiTagsList from '@core/components/ui/tag/UiTagsList.vue'
15
13
  import type { MaybeArray } from '@core/types/utility.type'
16
14
  import { toArray } from '@core/utils/to-array.utils'
@@ -0,0 +1,29 @@
1
+ <template>
2
+ <dl class="vts-tabular-key-value-list" :class="{ 'full-height': fullHeight }">
3
+ <slot />
4
+ </dl>
5
+ </template>
6
+
7
+ <script lang="ts" setup>
8
+ defineProps<{
9
+ fullHeight?: boolean
10
+ }>()
11
+ </script>
12
+
13
+ <style lang="postcss" scoped>
14
+ .vts-tabular-key-value-list {
15
+ container-type: inline-size;
16
+ container-name: vts-tabular-key-value-list;
17
+ display: grid;
18
+ grid-template-columns: minmax(min-content, 20rem) 1fr;
19
+ row-gap: 1.6rem;
20
+ column-gap: 2.4rem;
21
+ align-items: start;
22
+ align-self: flex-start;
23
+ width: 100%;
24
+
25
+ &.full-height {
26
+ height: 100%;
27
+ }
28
+ }
29
+ </style>
@@ -0,0 +1,42 @@
1
+ <template>
2
+ <div class="vts-tabular-key-value-row">
3
+ <VtsKeyValuePair :label :value>
4
+ <template v-if="slots.label" #label>
5
+ <slot name="label" />
6
+ </template>
7
+ <template v-if="slots.value" #value>
8
+ <slot name="value" />
9
+ </template>
10
+ </VtsKeyValuePair>
11
+ </div>
12
+ </template>
13
+
14
+ <script lang="ts" setup>
15
+ import VtsKeyValuePair from '@core/components/key-value-pair/VtsKeyValuePair.vue'
16
+
17
+ defineProps<{
18
+ label?: string
19
+ value?: string
20
+ }>()
21
+
22
+ const slots = defineSlots<{
23
+ label?(): any
24
+ value?(): any
25
+ }>()
26
+ </script>
27
+
28
+ <style lang="postcss" scoped>
29
+ .vts-tabular-key-value-row {
30
+ display: grid;
31
+ grid-template-columns: subgrid;
32
+ grid-column: span 2;
33
+ align-items: start;
34
+
35
+ @container vts-tabular-key-value-list (max-width: 40rem) {
36
+ display: flex;
37
+ flex-direction: column;
38
+ align-items: stretch;
39
+ gap: 0.8rem;
40
+ }
41
+ }
42
+ </style>
@@ -0,0 +1,30 @@
1
+ <template>
2
+ <UiTertiaryTag v-if="parsedTag" :accent>
3
+ <template #term>{{ parsedTag.term }}</template>
4
+ {{ parsedTag.label }}
5
+ </UiTertiaryTag>
6
+ <UiTag v-else :accent :variant>
7
+ {{ value }}
8
+ </UiTag>
9
+ </template>
10
+
11
+ <script lang="ts" setup>
12
+ import UiTag, { type TagAccent } from '@core/components/ui/tag/UiTag.vue'
13
+ import UiTertiaryTag from '@core/components/ui/tag/UiTertiaryTag.vue'
14
+ import { parseTag } from '@core/utils/parse-tag.util'
15
+ import { computed } from 'vue'
16
+
17
+ type TagVariant = 'primary' | 'secondary'
18
+
19
+ const {
20
+ value,
21
+ accent = 'info',
22
+ variant = 'secondary',
23
+ } = defineProps<{
24
+ value: string
25
+ accent?: TagAccent
26
+ variant?: TagVariant
27
+ }>()
28
+
29
+ const parsedTag = computed(() => parseTag(value))
30
+ </script>
@@ -1,31 +1,28 @@
1
- <!-- v4 -->
1
+ <!-- v8 -->
2
2
  <template>
3
- <span :class="classNames" class="ui-chip typo-body-regular-small" @click="emit('edit')">
4
- <ChipIcon :disabled :icon />
5
- <span class="content text-ellipsis">
3
+ <span :class="classNames" class="ui-chip typo-body-regular-small">
4
+ <span class="text-ellipsis">
6
5
  <slot />
7
6
  </span>
8
- <ChipRemoveIcon v-if="!disabled" :accent @click.stop="emit('remove')" />
7
+ <button v-if="!disabled" class="icon" type="button" @click.stop="emit('remove')">
8
+ <VtsIcon name="action:close-cancel-clear" size="medium" />
9
+ </button>
9
10
  </span>
10
11
  </template>
11
12
 
12
13
  <script lang="ts" setup>
13
- import ChipIcon from '@core/components/ui/chip/ChipIcon.vue'
14
- import ChipRemoveIcon from '@core/components/ui/chip/ChipRemoveIcon.vue'
15
- import type { IconName } from '@core/icons'
14
+ import VtsIcon from '@core/components/icon/VtsIcon.vue'
16
15
  import { toVariants } from '@core/utils/to-variants.util'
17
16
  import { computed } from 'vue'
18
17
 
19
18
  export type ChipAccent = 'info' | 'success' | 'warning' | 'danger'
20
19
 
21
- const props = defineProps<{
20
+ const { accent, disabled } = defineProps<{
22
21
  accent: ChipAccent
23
- icon?: IconName
24
22
  disabled?: boolean
25
23
  }>()
26
24
 
27
25
  const emit = defineEmits<{
28
- edit: []
29
26
  remove: []
30
27
  }>()
31
28
 
@@ -36,8 +33,8 @@ defineSlots<{
36
33
  const classNames = computed(() => {
37
34
  return [
38
35
  toVariants({
39
- accent: props.accent,
40
- muted: props.disabled,
36
+ accent,
37
+ muted: disabled,
41
38
  }),
42
39
  ]
43
40
  })
@@ -45,37 +42,51 @@ const classNames = computed(() => {
45
42
 
46
43
  <style lang="postcss" scoped>
47
44
  .ui-chip {
48
- display: flex;
45
+ display: inline-flex;
49
46
  align-items: center;
50
- gap: 0.8rem;
51
- padding: 0.4rem 0.8rem;
47
+ gap: 0.4rem;
48
+ padding: 0.4rem 1.2rem;
52
49
  border-radius: 10rem;
53
50
  color: var(--color-neutral-txt-primary);
54
- cursor: pointer;
55
51
  min-height: 2.4rem;
56
52
  vertical-align: middle;
57
53
  white-space: nowrap;
58
- min-width: 0;
59
54
 
60
55
  &.muted {
61
56
  color: var(--color-neutral-txt-secondary);
62
57
  pointer-events: none;
63
58
  }
64
59
 
65
- .content {
66
- line-height: 1.6rem;
60
+ .icon {
61
+ border-radius: 0 10rem 10rem 0;
62
+ padding: 0.4rem;
63
+ margin: -0.4rem -1.2rem -0.4rem 0;
64
+ align-self: stretch;
65
+ display: flex;
66
+ align-items: center;
67
+ justify-content: center;
68
+ cursor: pointer;
69
+ background-color: transparent;
70
+ border: none;
67
71
  }
68
72
 
73
+ .icon:focus-visible {
74
+ outline: 0.2rem solid var(--color-brand-txt-base);
75
+ outline-offset: 0.2rem;
76
+ }
69
77
  /* COLOR VARIANTS */
70
-
71
78
  &.accent--info {
72
79
  background-color: var(--color-info-background-selected);
73
80
 
74
- &:is(:hover, :focus-visible) {
81
+ .icon {
82
+ color: var(--color-info-txt-hover);
83
+ }
84
+
85
+ .icon:hover {
75
86
  background-color: var(--color-info-background-hover);
76
87
  }
77
88
 
78
- &:active {
89
+ .icon:active {
79
90
  background-color: var(--color-info-background-active);
80
91
  }
81
92
 
@@ -87,11 +98,15 @@ const classNames = computed(() => {
87
98
  &.accent--success {
88
99
  background-color: var(--color-success-background-selected);
89
100
 
90
- &:is(:hover, :focus-visible) {
101
+ .icon {
102
+ color: var(--color-success-txt-hover);
103
+ }
104
+
105
+ .icon:hover {
91
106
  background-color: var(--color-success-background-hover);
92
107
  }
93
108
 
94
- &:active {
109
+ .icon:active {
95
110
  background-color: var(--color-success-background-active);
96
111
  }
97
112
 
@@ -103,11 +118,15 @@ const classNames = computed(() => {
103
118
  &.accent--warning {
104
119
  background-color: var(--color-warning-background-selected);
105
120
 
106
- &:is(:hover, :focus-visible) {
121
+ .icon {
122
+ color: var(--color-warning-txt-hover);
123
+ }
124
+
125
+ .icon:hover {
107
126
  background-color: var(--color-warning-background-hover);
108
127
  }
109
128
 
110
- &:active {
129
+ .icon:active {
111
130
  background-color: var(--color-warning-background-active);
112
131
  }
113
132
 
@@ -119,11 +138,15 @@ const classNames = computed(() => {
119
138
  &.accent--danger {
120
139
  background-color: var(--color-danger-background-selected);
121
140
 
122
- &:is(:hover, :focus-visible) {
141
+ .icon {
142
+ color: var(--color-danger-txt-hover);
143
+ }
144
+
145
+ .icon:hover {
123
146
  background-color: var(--color-danger-background-hover);
124
147
  }
125
148
 
126
- &:active {
149
+ .icon:active {
127
150
  background-color: var(--color-danger-background-active);
128
151
  }
129
152
 
@@ -1,8 +1,8 @@
1
- <!-- v4 -->
1
+ <!-- v6 -->
2
2
  <template>
3
3
  <div class="ui-info">
4
- <VtsIcon class="icon" :name="icon" size="medium" />
5
- <p v-tooltip="!wrap" class="typo-body-regular-small label" :class="{ 'text-ellipsis': !wrap }">
4
+ <VtsIcon class="icon" :name="icon" :size />
5
+ <p v-tooltip="!wrap" class="label" :class="[textSize, { 'text-ellipsis': !wrap }]">
6
6
  <slot />
7
7
  </p>
8
8
  </div>
@@ -15,10 +15,12 @@ import type { IconName } from '@core/icons'
15
15
  import { useMapper } from '@core/packages/mapper'
16
16
 
17
17
  export type InfoAccent = 'info' | 'success' | 'warning' | 'danger' | 'muted'
18
+ type Size = 'small' | 'medium'
18
19
 
19
- const { accent } = defineProps<{
20
+ const { accent, size = 'medium' } = defineProps<{
20
21
  accent: InfoAccent
21
22
  wrap?: boolean
23
+ size?: Size
22
24
  }>()
23
25
 
24
26
  defineSlots<{
@@ -36,16 +38,25 @@ const icon = useMapper<InfoAccent, IconName>(
36
38
  },
37
39
  'muted'
38
40
  )
41
+
42
+ const textSize = useMapper<Size, any>(
43
+ () => size,
44
+ {
45
+ small: 'typo-body-regular-small',
46
+ medium: 'typo-body-regular',
47
+ },
48
+ 'medium'
49
+ )
39
50
  </script>
40
51
 
41
52
  <style lang="postcss" scoped>
42
53
  .ui-info {
43
- align-items: start;
54
+ align-items: baseline;
44
55
  display: flex;
45
56
  gap: 0.8rem;
46
57
 
47
58
  .icon {
48
- font-size: 1.6rem;
59
+ transform: translateY(0.2ex);
49
60
  }
50
61
 
51
62
  .label:empty {