@xen-orchestra/web-core 0.8.0 → 0.9.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.
@@ -1,141 +1,170 @@
1
- <!-- WIP -->
1
+ <!-- v5 -->
2
2
  <template>
3
- <div class="ui-input">
4
- <VtsIcon :icon accent="current" class="before" />
5
- <input :id v-model.trim="modelValue" class="typo p1-regular input" type="search" v-bind="attrs" />
6
- <VtsIcon
7
- v-if="!attrs.disabled && modelValue"
8
- :icon="faXmark"
9
- class="after"
10
- accent="info"
11
- @click="modelValue = ''"
12
- />
3
+ <div class="ui-input" :class="toVariants({ accent })">
4
+ <UiLabel v-if="slots.default || label" :accent="labelAccent" :required :icon="labelIcon" :href :for="id">
5
+ <slot>{{ label }}</slot>
6
+ </UiLabel>
7
+ <div>
8
+ <VtsIcon :icon accent="current" class="before" />
9
+ <input :id v-model.trim="modelValue" class="typo p1-regular input text-ellipsis" :type :disabled v-bind="attrs" />
10
+ <VtsIcon
11
+ v-if="!attrs.disabled && modelValue && clearable"
12
+ :icon="faXmark"
13
+ class="after"
14
+ accent="info"
15
+ @click="modelValue = ''"
16
+ />
17
+ </div>
18
+ <UiInfo v-if="slots.info || info" :accent>
19
+ <slot name="info">{{ info }}</slot>
20
+ </UiInfo>
13
21
  </div>
14
22
  </template>
15
23
 
16
24
  <script lang="ts" setup>
17
25
  import VtsIcon from '@core/components/icon/VtsIcon.vue'
18
- import { uniqueId } from '@core/utils/unique-id.util'
26
+ import UiInfo from '@core/components/ui/info/UiInfo.vue'
27
+ import UiLabel from '@core/components/ui/label/UiLabel.vue'
28
+ import { toVariants } from '@core/utils/to-variants.util'
19
29
  import type { IconDefinition } from '@fortawesome/fontawesome-common-types'
20
30
  import { faXmark } from '@fortawesome/free-solid-svg-icons'
21
- import { computed, useAttrs } from 'vue'
31
+ import { computed, useAttrs, useId } from 'vue'
32
+
33
+ type InputAccent = 'info' | 'warning' | 'danger'
34
+ type InputType = 'text' | 'number' | 'password' | 'search'
22
35
 
23
36
  defineOptions({
24
37
  inheritAttrs: false,
25
38
  })
26
39
 
27
- defineProps<{
40
+ const { accent, id = useId() } = defineProps<{
41
+ accent: InputAccent
42
+ label?: string
43
+ info?: string
44
+ id?: string
45
+ disabled?: boolean
46
+ clearable?: boolean
47
+ href?: string
48
+ required?: boolean
49
+ labelIcon?: IconDefinition
28
50
  icon?: IconDefinition
51
+ type?: InputType
29
52
  }>()
30
53
 
31
- const modelValue = defineModel<string>({ required: true })
54
+ const modelValue = defineModel<string | number>({ required: true })
55
+
56
+ const slots = defineSlots<{
57
+ default?(): any
58
+ info?(): any
59
+ }>()
32
60
 
33
61
  const attrs = useAttrs()
34
62
 
35
- const id = computed(() => uniqueId('input-'))
63
+ const labelAccent = computed(() => (accent === 'info' ? 'neutral' : accent))
36
64
  </script>
37
65
 
38
66
  <style lang="postcss" scoped>
39
- /* COLOR VARIANTS */
40
- .input {
41
- & {
42
- --border-color: var(--color-neutral-border);
43
- --background-color: var(--color-neutral-background-primary);
67
+ /* IMPLEMENTATION */
68
+ .ui-input {
69
+ position: relative;
70
+ display: flex;
71
+ flex-direction: column;
72
+ gap: 0.4rem;
73
+
74
+ .input {
75
+ border-radius: 0.4rem;
76
+ border-width: 0.1rem;
77
+ border-style: solid;
78
+ background-color: var(--color-neutral-background-primary);
79
+ color: var(--color-neutral-txt-primary);
80
+ height: 4rem;
81
+ outline: none;
82
+ width: 100%;
83
+ padding-block: 0.8rem;
84
+ padding-inline: 1.6rem;
85
+
86
+ &::placeholder {
87
+ color: var(--color-neutral-txt-secondary);
88
+ }
89
+
90
+ &:focus {
91
+ border-width: 0.2rem;
92
+ }
93
+
94
+ &:has(+ .after) {
95
+ padding-inline-end: 4.8rem;
96
+ }
44
97
  }
45
98
 
46
- &:is(:hover, :focus-visible) {
47
- --border-color: var(--color-info-item-hover);
48
- --background-color: var(--color-neutral-background-primary);
49
- }
99
+ /* VARIANT */
50
100
 
51
- &:focus {
52
- --border-color: var(--color-info-item-base);
53
- --background-color: var(--color-neutral-background-primary);
54
- }
101
+ &.accent--info {
102
+ .input {
103
+ border-color: var(--color-neutral-border);
55
104
 
56
- &:active {
57
- --border-color: var(--color-info-item-active);
58
- --background-color: var(--color-neutral-background-primary);
59
- }
105
+ &:hover {
106
+ border-color: var(--color-info-item-hover);
107
+ }
60
108
 
61
- &:disabled {
62
- --border-color: var(--color-neutral-border);
63
- --background-color: var(--color-neutral-background-disabled);
64
- }
65
- }
109
+ &:focus {
110
+ border-color: var(--color-info-item-base);
111
+ }
66
112
 
67
- /* BORDER VARIANTS */
68
- .input {
69
- --border-width: 0.1rem;
113
+ &:active {
114
+ border-color: var(--color-info-item-active);
115
+ }
70
116
 
71
- &:is(:hover, :focus-visible) {
72
- --border-width: 0.1rem;
117
+ &:disabled {
118
+ border-color: var(--color-neutral-border);
119
+ background-color: var(--color-neutral-background-disabled);
120
+ }
121
+ }
73
122
  }
74
123
 
75
- &:focus {
76
- --border-width: 0.2rem;
77
- }
124
+ &.accent--warning {
125
+ .input {
126
+ border-color: var(--color-warning-item-base);
78
127
 
79
- &:active {
80
- --border-width: 0.1rem;
128
+ &:disabled {
129
+ border-color: var(--color-neutral-border);
130
+ background-color: var(--color-neutral-background-disabled);
131
+ }
132
+ }
81
133
  }
82
134
 
83
- &:disabled {
84
- --border-width: 0.1rem;
135
+ &.accent--danger {
136
+ .input {
137
+ border-color: var(--color-danger-item-base);
138
+
139
+ &:disabled {
140
+ border-color: var(--color-neutral-border);
141
+ background-color: var(--color-neutral-background-disabled);
142
+ }
143
+ }
85
144
  }
86
- }
87
145
 
88
- /* IMPLEMENTATION */
89
- .ui-input {
90
- position: relative;
146
+ /* ICON POSITION */
91
147
 
92
148
  .before + .input {
93
149
  padding-inline-start: 4.8rem;
94
150
  }
95
- }
96
-
97
- .input {
98
- border: var(--border-width) solid var(--border-color);
99
- border-radius: 0.8rem;
100
- outline: none;
101
- width: 100%;
102
- height: 4rem;
103
- padding: 0.8rem 1.6rem;
104
- color: var(--color-neutral-txt-primary);
105
- background-color: var(--background-color);
106
-
107
- &:has(+ .after) {
108
- padding-inline-end: 4.8rem;
109
- }
110
151
 
111
- &:disabled {
112
- cursor: not-allowed;
152
+ .before,
153
+ .after {
154
+ position: absolute;
155
+ inset-block: 1.2rem;
113
156
  }
114
157
 
115
- &::placeholder {
158
+ .before {
116
159
  color: var(--color-neutral-txt-secondary);
160
+ inset-inline-start: 1.6rem;
161
+ pointer-events: none;
162
+ z-index: 1;
117
163
  }
118
164
 
119
- &[type='search']::-webkit-search-cancel-button {
120
- display: none;
165
+ .after {
166
+ inset-inline-end: 1.6rem;
167
+ cursor: pointer;
121
168
  }
122
169
  }
123
-
124
- .before,
125
- .after {
126
- position: absolute;
127
- inset-block: 1.2rem;
128
- }
129
-
130
- .before {
131
- color: var(--color-neutral-txt-secondary);
132
- inset-inline-start: 1.6rem;
133
- pointer-events: none;
134
- z-index: 1;
135
- }
136
-
137
- .after {
138
- inset-inline-end: 1.6rem;
139
- cursor: pointer;
140
- }
141
170
  </style>
@@ -7,6 +7,8 @@
7
7
  <UiInput
8
8
  :id
9
9
  v-model="value"
10
+ type="text"
11
+ accent="info"
10
12
  :aria-label="uiStore.isMobile ? $t('core.query-search-bar.label') : undefined"
11
13
  :icon="uiStore.isDesktop ? faMagnifyingGlass : undefined"
12
14
  :placeholder="$t('core.query-search-bar.placeholder')"
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@xen-orchestra/web-core",
3
3
  "type": "module",
4
- "version": "0.8.0",
4
+ "version": "0.9.0",
5
5
  "private": false,
6
6
  "exports": {
7
7
  "./*": {