@globalbrain/sefirot 4.11.0 → 4.12.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.
- package/lib/components/SDescFile.vue +1 -1
- package/lib/components/SDescItem.vue +11 -1
- package/lib/components/SDescLabel.vue +67 -6
- package/lib/components/SInputBase.vue +41 -18
- package/lib/components/SInputDropdown.vue +49 -29
- package/lib/components/SInputDropdownItem.vue +255 -25
- package/lib/components/SInputNumber.vue +16 -25
- package/lib/components/SInputText.vue +19 -23
- package/lib/components/SInputTextarea.vue +19 -23
- package/lib/composables/Error.ts +3 -1
- package/lib/styles/variables.css +2 -0
- package/package.json +1 -1
- package/lib/components/SInputDropdownItemAvatar.vue +0 -175
- package/lib/components/SInputDropdownItemText.vue +0 -154
|
@@ -29,7 +29,17 @@ const labelWidth = computed(() => {
|
|
|
29
29
|
}
|
|
30
30
|
|
|
31
31
|
.SDesc.row > .SDescItem {
|
|
32
|
-
|
|
32
|
+
& {
|
|
33
|
+
grid-template-columns: var(--desc-label-width, v-bind(labelWidth)) minmax(0, 1fr);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
& > :deep(.SDescLabel) {
|
|
37
|
+
height: 24px;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
& > :deep(.SDescLabel > .value) {
|
|
41
|
+
line-height: 24px;
|
|
42
|
+
}
|
|
33
43
|
}
|
|
34
44
|
|
|
35
45
|
.SDesc.divider > .SDescItem:not(:has(> .SDescFile)) {
|
|
@@ -1,7 +1,40 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
|
-
|
|
2
|
+
import { type Component } from 'vue'
|
|
3
|
+
import { type ActionList } from './SActionList.vue'
|
|
4
|
+
import SActionMenu from './SActionMenu.vue'
|
|
5
|
+
import SButton, { type Mode, type Tooltip } from './SButton.vue'
|
|
6
|
+
|
|
7
|
+
export interface Props {
|
|
3
8
|
value?: string | null
|
|
4
|
-
|
|
9
|
+
actions?: Action[]
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export type Action = ActionButton | ActionMenu
|
|
13
|
+
|
|
14
|
+
export interface ActionBase {
|
|
15
|
+
type?: 'button' | 'menu'
|
|
16
|
+
mode?: Mode
|
|
17
|
+
icon: Component
|
|
18
|
+
loading?: boolean
|
|
19
|
+
disabled?: boolean
|
|
20
|
+
tooltip?: string | Tooltip
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export interface ActionButton extends ActionBase {
|
|
24
|
+
type?: 'button'
|
|
25
|
+
onClick(): void
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export interface ActionMenu extends ActionBase {
|
|
29
|
+
type: 'menu'
|
|
30
|
+
options: ActionList
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
defineProps<Props>()
|
|
34
|
+
|
|
35
|
+
function isActionButton(action: Action): action is ActionButton {
|
|
36
|
+
return (action.type ?? 'button') === 'button'
|
|
37
|
+
}
|
|
5
38
|
</script>
|
|
6
39
|
|
|
7
40
|
<template>
|
|
@@ -10,19 +43,47 @@ defineProps<{
|
|
|
10
43
|
<slot v-if="$slots.default" />
|
|
11
44
|
<template v-else>{{ value }}</template>
|
|
12
45
|
</div>
|
|
46
|
+
<div v-if="actions?.length" class="actions">
|
|
47
|
+
<template v-for="action, index in actions" :key="index">
|
|
48
|
+
<SButton
|
|
49
|
+
v-if="isActionButton(action)"
|
|
50
|
+
type="text"
|
|
51
|
+
size="mini"
|
|
52
|
+
:mode="action.mode ?? 'mute'"
|
|
53
|
+
:icon="action.icon"
|
|
54
|
+
:loading="action.loading"
|
|
55
|
+
:disabled="action.disabled"
|
|
56
|
+
:tooltip="action.tooltip"
|
|
57
|
+
@click="action.onClick"
|
|
58
|
+
/>
|
|
59
|
+
<SActionMenu
|
|
60
|
+
v-else
|
|
61
|
+
type="text"
|
|
62
|
+
size="mini"
|
|
63
|
+
:mode="action.mode ?? 'mute'"
|
|
64
|
+
:icon="action.icon"
|
|
65
|
+
:loading="action.loading"
|
|
66
|
+
:disabled="action.disabled"
|
|
67
|
+
:tooltip="action.tooltip"
|
|
68
|
+
:options="[{ type: 'menu', options: action.options }]"
|
|
69
|
+
/>
|
|
70
|
+
</template>
|
|
71
|
+
</div>
|
|
13
72
|
</div>
|
|
14
73
|
</template>
|
|
15
74
|
|
|
16
75
|
<style scoped lang="postcss">
|
|
17
76
|
.SDescLabel {
|
|
18
77
|
display: flex;
|
|
19
|
-
|
|
78
|
+
gap: 16px;
|
|
79
|
+
height: 28px;
|
|
20
80
|
}
|
|
21
81
|
|
|
22
82
|
.value {
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
font-
|
|
83
|
+
flex-grow: 1;
|
|
84
|
+
line-height: 28px;
|
|
85
|
+
font-size: 14px;
|
|
86
|
+
font-weight: 400;
|
|
26
87
|
color: var(--c-text-2);
|
|
27
88
|
white-space: nowrap;
|
|
28
89
|
overflow: hidden;
|
|
@@ -4,9 +4,8 @@ import { type Component, computed, unref, useSlots } from 'vue'
|
|
|
4
4
|
import { type Validatable } from '../composables/Validation'
|
|
5
5
|
import STooltip from './STooltip.vue'
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
const props = defineProps<{
|
|
7
|
+
export interface Props {
|
|
8
|
+
size?: Size
|
|
10
9
|
name?: string
|
|
11
10
|
label?: string
|
|
12
11
|
info?: string
|
|
@@ -16,11 +15,24 @@ const props = defineProps<{
|
|
|
16
15
|
checkText?: string
|
|
17
16
|
checkColor?: Color
|
|
18
17
|
validation?: Validatable
|
|
18
|
+
warning?: string
|
|
19
19
|
hideError?: boolean
|
|
20
|
-
|
|
20
|
+
hideWarning?: boolean
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export type Size = 'mini' | 'small' | 'medium'
|
|
24
|
+
export type Color = 'neutral' | 'mute' | 'info' | 'success' | 'warning' | 'danger'
|
|
25
|
+
|
|
26
|
+
const props = defineProps<Props>()
|
|
21
27
|
|
|
22
28
|
const slots = useSlots()
|
|
23
29
|
|
|
30
|
+
const classes = computed(() => [
|
|
31
|
+
props.size ?? 'small',
|
|
32
|
+
{ 'has-error': error.value?.has },
|
|
33
|
+
{ 'has-warning': props.warning }
|
|
34
|
+
])
|
|
35
|
+
|
|
24
36
|
const hasInfo = computed(() => {
|
|
25
37
|
return slots.info || props.info
|
|
26
38
|
})
|
|
@@ -53,7 +65,7 @@ function getErrorMsg(validation: Validatable) {
|
|
|
53
65
|
</script>
|
|
54
66
|
|
|
55
67
|
<template>
|
|
56
|
-
<div class="SInputBase" :class="
|
|
68
|
+
<div class="SInputBase" :class="classes">
|
|
57
69
|
<label v-if="label" class="label" :for="name">
|
|
58
70
|
<span class="label-text">{{ label }}</span>
|
|
59
71
|
|
|
@@ -76,8 +88,9 @@ function getErrorMsg(validation: Validatable) {
|
|
|
76
88
|
|
|
77
89
|
<div class="help">
|
|
78
90
|
<slot name="before-help" />
|
|
79
|
-
<p v-if="error?.show" class="help-error">{{ error.msg }}</p>
|
|
80
|
-
<p v-if="
|
|
91
|
+
<p v-if="error?.show" class="help-value help-error">{{ error.msg }}</p>
|
|
92
|
+
<p v-if="warning && !hideWarning" class="help-value help-warning">{{ warning }}</p>
|
|
93
|
+
<p v-if="help" class="help-value help-text">{{ help }}</p>
|
|
81
94
|
</div>
|
|
82
95
|
</div>
|
|
83
96
|
</template>
|
|
@@ -102,12 +115,19 @@ function getErrorMsg(validation: Validatable) {
|
|
|
102
115
|
.label-text { font-size: var(--input-label-font-size, var(--input-medium-label-font-size)); }
|
|
103
116
|
}
|
|
104
117
|
|
|
105
|
-
.SInputBase.has-error
|
|
118
|
+
.SInputBase.has-error,
|
|
119
|
+
.SInputBase.has-warning.has-error {
|
|
106
120
|
.label-text {
|
|
107
121
|
color: var(--input-error-text-color);
|
|
108
122
|
}
|
|
109
123
|
}
|
|
110
124
|
|
|
125
|
+
.SInputBase.has-warning {
|
|
126
|
+
.label-text {
|
|
127
|
+
color: var(--input-warning-text-color);
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
|
|
111
131
|
.label {
|
|
112
132
|
display: flex;
|
|
113
133
|
align-items: flex-start;
|
|
@@ -118,7 +138,7 @@ function getErrorMsg(validation: Validatable) {
|
|
|
118
138
|
}
|
|
119
139
|
|
|
120
140
|
.label-text {
|
|
121
|
-
font-weight:
|
|
141
|
+
font-weight: 400;
|
|
122
142
|
color: var(--input-label-color);
|
|
123
143
|
transition: color 0.25s;
|
|
124
144
|
}
|
|
@@ -173,29 +193,32 @@ function getErrorMsg(validation: Validatable) {
|
|
|
173
193
|
position: relative;
|
|
174
194
|
}
|
|
175
195
|
|
|
176
|
-
.help-
|
|
196
|
+
.help-value {
|
|
177
197
|
width: 100%;
|
|
178
198
|
max-width: 65ch;
|
|
179
199
|
margin: 0;
|
|
180
200
|
padding: 6px 0 0 0;
|
|
181
|
-
line-height:
|
|
201
|
+
line-height: 20px;
|
|
182
202
|
font-size: 12px;
|
|
183
203
|
font-weight: 400;
|
|
184
|
-
color: var(--input-error-text-color);
|
|
185
204
|
transition: opacity 0.25s, transform 0.25s;
|
|
186
205
|
}
|
|
187
206
|
|
|
207
|
+
.help-error {
|
|
208
|
+
color: var(--input-error-text-color);
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
.help-warning {
|
|
212
|
+
color: var(--input-warning-text-color);
|
|
213
|
+
}
|
|
214
|
+
|
|
188
215
|
.help-text {
|
|
189
|
-
max-width: 65ch;
|
|
190
|
-
margin: 0;
|
|
191
|
-
padding: 6px 0 0;
|
|
192
|
-
line-height: 20px;
|
|
193
|
-
font-size: 12px;
|
|
194
|
-
font-weight: 400;
|
|
195
216
|
color: var(--c-text-2);
|
|
196
217
|
}
|
|
197
218
|
|
|
219
|
+
.help-error + .help-warning,
|
|
198
220
|
.help-error + .help-text,
|
|
221
|
+
.help-warning + .help-text,
|
|
199
222
|
.help-text + .help-error,
|
|
200
223
|
.help-text + .help-text {
|
|
201
224
|
padding: 0;
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
|
-
import IconCaretDown from '~icons/ph/caret-down
|
|
3
|
-
import IconCaretUp from '~icons/ph/caret-up
|
|
2
|
+
import IconCaretDown from '~icons/ph/caret-down'
|
|
3
|
+
import IconCaretUp from '~icons/ph/caret-up'
|
|
4
4
|
import xor from 'lodash-es/xor'
|
|
5
5
|
import { type Component, computed, ref } from 'vue'
|
|
6
6
|
import { type DropdownSectionFilter, useManualDropdownPosition } from '../composables/Dropdown'
|
|
7
7
|
import { useFlyout } from '../composables/Flyout'
|
|
8
|
+
import { useTrans } from '../composables/Lang'
|
|
8
9
|
import { type Validatable } from '../composables/Validation'
|
|
9
10
|
import SDropdown from './SDropdown.vue'
|
|
10
11
|
import SInputBase from './SInputBase.vue'
|
|
@@ -52,13 +53,19 @@ const props = defineProps<{
|
|
|
52
53
|
nullable?: boolean
|
|
53
54
|
closeOnClick?: boolean
|
|
54
55
|
disabled?: boolean
|
|
55
|
-
modelValue: PrimitiveValue | ArrayValue
|
|
56
56
|
validation?: Validatable
|
|
57
57
|
}>()
|
|
58
58
|
|
|
59
|
-
const
|
|
60
|
-
|
|
61
|
-
}
|
|
59
|
+
const model = defineModel<PrimitiveValue | ArrayValue>({ required: true })
|
|
60
|
+
|
|
61
|
+
const { t } = useTrans({
|
|
62
|
+
en: {
|
|
63
|
+
ph: 'Select items'
|
|
64
|
+
},
|
|
65
|
+
ja: {
|
|
66
|
+
ph: '項目を選択してください'
|
|
67
|
+
}
|
|
68
|
+
})
|
|
62
69
|
|
|
63
70
|
const container = ref<any>(null)
|
|
64
71
|
|
|
@@ -73,28 +80,28 @@ const classes = computed(() => [
|
|
|
73
80
|
const dropdownOptions = computed<DropdownSectionFilter[]>(() => [{
|
|
74
81
|
type: 'filter',
|
|
75
82
|
search: props.noSearch === undefined ? true : !props.noSearch,
|
|
76
|
-
selected:
|
|
83
|
+
selected: model.value,
|
|
77
84
|
options: props.options,
|
|
78
85
|
onClick: handleSelect
|
|
79
86
|
}])
|
|
80
87
|
|
|
81
88
|
const selected = computed(() => {
|
|
82
|
-
if (Array.isArray(
|
|
83
|
-
return props.options.filter((o) => (
|
|
89
|
+
if (Array.isArray(model.value)) {
|
|
90
|
+
return props.options.filter((o) => (model.value as ArrayValue).includes(o.value))
|
|
84
91
|
}
|
|
85
92
|
|
|
86
|
-
const item = props.options.find((o) => o.value ===
|
|
93
|
+
const item = props.options.find((o) => o.value === model.value)
|
|
87
94
|
|
|
88
|
-
return item
|
|
95
|
+
return item ?? null
|
|
89
96
|
})
|
|
90
97
|
|
|
91
98
|
const hasSelected = computed(() => {
|
|
92
|
-
return selected.value.length > 0
|
|
99
|
+
return Array.isArray(selected.value) ? selected.value.length > 0 : !!selected.value
|
|
93
100
|
})
|
|
94
101
|
|
|
95
102
|
const removable = computed(() => {
|
|
96
|
-
if (Array.isArray(
|
|
97
|
-
return props.nullable || selected.value.length > 1
|
|
103
|
+
if (Array.isArray(model.value)) {
|
|
104
|
+
return props.nullable || (selected.value as Option[]).length > 1
|
|
98
105
|
}
|
|
99
106
|
|
|
100
107
|
return !!props.nullable
|
|
@@ -110,27 +117,25 @@ async function handleOpen() {
|
|
|
110
117
|
function handleSelect(value: OptionValue) {
|
|
111
118
|
props.validation?.$touch()
|
|
112
119
|
|
|
113
|
-
Array.isArray(
|
|
120
|
+
Array.isArray(model.value) ? handleArray(value) : handlePrimitive(value)
|
|
114
121
|
}
|
|
115
122
|
|
|
116
123
|
function handlePrimitive(value: OptionValue) {
|
|
117
|
-
if (value !==
|
|
118
|
-
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
if (props.nullable) {
|
|
122
|
-
emit('update:modelValue', null)
|
|
124
|
+
if (value !== model.value) {
|
|
125
|
+
model.value = value
|
|
126
|
+
} else if (props.nullable) {
|
|
127
|
+
model.value = null
|
|
123
128
|
}
|
|
124
129
|
}
|
|
125
130
|
|
|
126
131
|
function handleArray(value: OptionValue) {
|
|
127
|
-
const difference = xor(
|
|
132
|
+
const difference = xor(model.value as ArrayValue, [value])
|
|
128
133
|
|
|
129
134
|
if (!props.nullable && difference.length === 0) {
|
|
130
135
|
return
|
|
131
136
|
}
|
|
132
137
|
|
|
133
|
-
|
|
138
|
+
model.value = difference
|
|
134
139
|
}
|
|
135
140
|
</script>
|
|
136
141
|
|
|
@@ -160,14 +165,14 @@ function handleArray(value: OptionValue) {
|
|
|
160
165
|
<div class="box-content">
|
|
161
166
|
<SInputDropdownItem
|
|
162
167
|
v-if="hasSelected"
|
|
163
|
-
:
|
|
168
|
+
:item="selected!"
|
|
164
169
|
:size="size ?? 'small'"
|
|
165
170
|
:removable="removable"
|
|
166
171
|
:disabled="disabled ?? false"
|
|
167
172
|
@remove="handleSelect"
|
|
168
173
|
/>
|
|
169
174
|
|
|
170
|
-
<div v-else class="box-placeholder">{{ placeholder }}</div>
|
|
175
|
+
<div v-else class="box-placeholder">{{ placeholder ?? t.ph }}</div>
|
|
171
176
|
</div>
|
|
172
177
|
|
|
173
178
|
<div class="box-icon">
|
|
@@ -187,6 +192,7 @@ function handleArray(value: OptionValue) {
|
|
|
187
192
|
<style scoped lang="postcss">
|
|
188
193
|
.container {
|
|
189
194
|
position: relative;
|
|
195
|
+
width: 100%;
|
|
190
196
|
}
|
|
191
197
|
|
|
192
198
|
.box {
|
|
@@ -209,6 +215,8 @@ function handleArray(value: OptionValue) {
|
|
|
209
215
|
.box-content {
|
|
210
216
|
display: flex;
|
|
211
217
|
align-items: center;
|
|
218
|
+
flex-grow: 1;
|
|
219
|
+
max-width: 100%;
|
|
212
220
|
}
|
|
213
221
|
|
|
214
222
|
.box-placeholder {
|
|
@@ -250,11 +258,15 @@ function handleArray(value: OptionValue) {
|
|
|
250
258
|
}
|
|
251
259
|
|
|
252
260
|
.box-content {
|
|
253
|
-
padding:
|
|
261
|
+
padding: 0 30px 0 0;
|
|
254
262
|
line-height: 24px;
|
|
255
263
|
font-size: var(--input-font-size, var(--input-mini-font-size));
|
|
256
264
|
}
|
|
257
265
|
|
|
266
|
+
.box-placeholder {
|
|
267
|
+
padding-left: 10px;
|
|
268
|
+
}
|
|
269
|
+
|
|
258
270
|
.box-icon {
|
|
259
271
|
top: 3px;
|
|
260
272
|
right: 8px;
|
|
@@ -267,11 +279,15 @@ function handleArray(value: OptionValue) {
|
|
|
267
279
|
}
|
|
268
280
|
|
|
269
281
|
.box-content {
|
|
270
|
-
padding:
|
|
282
|
+
padding: 0 30px 0 0;
|
|
271
283
|
line-height: 24px;
|
|
272
284
|
font-size: var(--input-font-size, var(--input-small-font-size));
|
|
273
285
|
}
|
|
274
286
|
|
|
287
|
+
.box-placeholder {
|
|
288
|
+
padding-left: 12px;
|
|
289
|
+
}
|
|
290
|
+
|
|
275
291
|
.box-icon {
|
|
276
292
|
top: 7px;
|
|
277
293
|
right: 8px;
|
|
@@ -280,15 +296,19 @@ function handleArray(value: OptionValue) {
|
|
|
280
296
|
|
|
281
297
|
.SInputDropdown.medium {
|
|
282
298
|
.box {
|
|
283
|
-
height: 48px;
|
|
299
|
+
min-height: 48px;
|
|
284
300
|
}
|
|
285
301
|
|
|
286
302
|
.box-content {
|
|
287
|
-
padding:
|
|
303
|
+
padding: 0 40px 0 0;
|
|
288
304
|
line-height: 24px;
|
|
289
305
|
font-size: var(--input-font-size, var(--input-medium-font-size));
|
|
290
306
|
}
|
|
291
307
|
|
|
308
|
+
.box-placeholder {
|
|
309
|
+
padding-left: 16px;
|
|
310
|
+
}
|
|
311
|
+
|
|
292
312
|
.box-icon {
|
|
293
313
|
top: 11px;
|
|
294
314
|
right: 12px;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
|
-
import
|
|
3
|
-
import
|
|
2
|
+
import IconX from '~icons/ph/x'
|
|
3
|
+
import SAvatar from './SAvatar.vue'
|
|
4
4
|
|
|
5
5
|
export type Item = ItemText | ItemAvatar
|
|
6
6
|
|
|
@@ -23,47 +23,277 @@ export interface ItemAvatar extends ItemBase {
|
|
|
23
23
|
export type Size = 'mini' | 'small' | 'medium'
|
|
24
24
|
|
|
25
25
|
defineProps<{
|
|
26
|
-
|
|
26
|
+
item: Item | Item[]
|
|
27
27
|
size: Size
|
|
28
28
|
removable: boolean
|
|
29
29
|
disabled: boolean
|
|
30
30
|
}>()
|
|
31
31
|
|
|
32
32
|
defineEmits<{
|
|
33
|
-
|
|
33
|
+
remove: [value: any]
|
|
34
34
|
}>()
|
|
35
35
|
</script>
|
|
36
36
|
|
|
37
37
|
<template>
|
|
38
|
-
<div class="SInputDropdownItem">
|
|
39
|
-
<div v-
|
|
40
|
-
<
|
|
41
|
-
v-if="
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
38
|
+
<div class="SInputDropdownItem" :class="[size, { disabled }]">
|
|
39
|
+
<div v-if="Array.isArray(item)" class="many">
|
|
40
|
+
<template v-for="i, index in item" :key="index">
|
|
41
|
+
<div v-if="i.type === undefined || i.type === 'text'" class="many-text">
|
|
42
|
+
<div class="many-text-value">{{ i.label }}</div>
|
|
43
|
+
<button v-if="removable" class="many-text-close" @click.stop="$emit('remove', i.value)">
|
|
44
|
+
<IconX class="many-text-close-icon" />
|
|
45
|
+
</button>
|
|
46
|
+
</div>
|
|
47
|
+
<div v-else-if="i.type === 'avatar'" class="many-avatar">
|
|
48
|
+
<div class="many-avatar-body">
|
|
49
|
+
<div class="many-avatar-image"><SAvatar size="fill" :avatar="i.image" /></div>
|
|
50
|
+
<div class="many-avatar-name">{{ i.label }}</div>
|
|
51
|
+
</div>
|
|
52
|
+
<button v-if="removable" class="many-avatar-close" @click.stop="$emit('remove', i.value)">
|
|
53
|
+
<IconX class="many-avatar-close-icon" />
|
|
54
|
+
</button>
|
|
55
|
+
</div>
|
|
56
|
+
</template>
|
|
57
|
+
</div>
|
|
58
|
+
<div v-else class="one">
|
|
59
|
+
<div v-if="item.type === undefined || item.type === 'text'" class="one-text">
|
|
60
|
+
<div class="one-text-value">{{ item.label }}</div>
|
|
61
|
+
</div>
|
|
62
|
+
<div v-else-if="item.type === 'avatar'" class="one-avatar">
|
|
63
|
+
<div class="one-avatar-image"><SAvatar size="fill" :avatar="item.image" /></div>
|
|
64
|
+
<div class="one-avatar-name">{{ item.label }}</div>
|
|
65
|
+
</div>
|
|
66
|
+
<button v-if="removable" class="one-close" @click.stop="$emit('remove', item.value)">
|
|
67
|
+
<IconX class="one-close-icon" />
|
|
68
|
+
</button>
|
|
59
69
|
</div>
|
|
60
70
|
</div>
|
|
61
71
|
</template>
|
|
62
72
|
|
|
63
73
|
<style scoped lang="postcss">
|
|
64
74
|
.SInputDropdownItem {
|
|
75
|
+
flex-grow: 1;
|
|
76
|
+
width: 100%;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
.many {
|
|
65
80
|
display: flex;
|
|
66
81
|
flex-wrap: wrap;
|
|
67
82
|
gap: 4px;
|
|
68
83
|
}
|
|
84
|
+
|
|
85
|
+
.many-text {
|
|
86
|
+
display: flex;
|
|
87
|
+
align-items: center;
|
|
88
|
+
gap: 4px;
|
|
89
|
+
border: 1px solid var(--c-divider);
|
|
90
|
+
border-radius: 12px;
|
|
91
|
+
padding: 0 10px;
|
|
92
|
+
height: 24px;
|
|
93
|
+
|
|
94
|
+
&:has(.many-text-close) {
|
|
95
|
+
padding-right: 4px;
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
.many-text-value {
|
|
100
|
+
line-height: 20px;
|
|
101
|
+
font-size: 12px;
|
|
102
|
+
font-weight: 400;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
.many-text-close {
|
|
106
|
+
display: flex;
|
|
107
|
+
justify-content: center;
|
|
108
|
+
align-items: center;
|
|
109
|
+
width: 16px;
|
|
110
|
+
height: 16px;
|
|
111
|
+
color: var(--c-text-2);
|
|
112
|
+
|
|
113
|
+
&:hover {
|
|
114
|
+
color: var(--c-text-1);
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
.many-text-close-icon {
|
|
119
|
+
width: 14px;
|
|
120
|
+
height: 14px;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
.many-avatar {
|
|
124
|
+
display: flex;
|
|
125
|
+
align-items: center;
|
|
126
|
+
gap: 4px;
|
|
127
|
+
border: 1px solid var(--c-divider);
|
|
128
|
+
border-radius: 12px;
|
|
129
|
+
padding: 1px 8px 1px 1px;
|
|
130
|
+
height: 24px;
|
|
131
|
+
|
|
132
|
+
&:has(.many-avatar-close) {
|
|
133
|
+
gap: 6px;
|
|
134
|
+
padding-right: 4px;
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
.many-avatar-body {
|
|
139
|
+
display: flex;
|
|
140
|
+
align-items: center;
|
|
141
|
+
gap: 6px;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
.many-avatar-image {
|
|
145
|
+
width: 20px;
|
|
146
|
+
height: 20px;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
.many-avatar-name {
|
|
150
|
+
line-height: 20px;
|
|
151
|
+
font-size: 12px;
|
|
152
|
+
font-weight: 400;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
.many-avatar-close {
|
|
156
|
+
display: flex;
|
|
157
|
+
justify-content: center;
|
|
158
|
+
align-items: center;
|
|
159
|
+
width: 16px;
|
|
160
|
+
height: 16px;
|
|
161
|
+
color: var(--c-text-2);
|
|
162
|
+
|
|
163
|
+
&:hover {
|
|
164
|
+
color: var(--c-text-1);
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
.many-avatar-close-icon {
|
|
169
|
+
width: 14px;
|
|
170
|
+
height: 14px;
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
.one {
|
|
174
|
+
display: flex;
|
|
175
|
+
align-items: center;
|
|
176
|
+
justify-content: space-between;
|
|
177
|
+
gap: 8px;
|
|
178
|
+
width: 100%;
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
.one-text {
|
|
182
|
+
flex-grow: 1;
|
|
183
|
+
max-width: 100%;
|
|
184
|
+
overflow: hidden;
|
|
185
|
+
white-space: nowrap;
|
|
186
|
+
text-overflow: ellipsis;
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
.one-text-value {
|
|
190
|
+
max-width: 100%;
|
|
191
|
+
overflow: hidden;
|
|
192
|
+
white-space: nowrap;
|
|
193
|
+
text-overflow: ellipsis;
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
.one-avatar {
|
|
197
|
+
display: flex;
|
|
198
|
+
align-items: center;
|
|
199
|
+
flex-grow: 1;
|
|
200
|
+
max-width: 100%;
|
|
201
|
+
overflow: hidden;
|
|
202
|
+
white-space: nowrap;
|
|
203
|
+
text-overflow: ellipsis;
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
.one-avatar-image {
|
|
207
|
+
flex-shrink: 0;
|
|
208
|
+
width: 20px;
|
|
209
|
+
height: 20px;
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
.one-avatar-name {
|
|
213
|
+
flex-grow: 1;
|
|
214
|
+
max-width: 100%;
|
|
215
|
+
line-height: 24px;
|
|
216
|
+
font-size: 14px;
|
|
217
|
+
font-weight: 400;
|
|
218
|
+
overflow: hidden;
|
|
219
|
+
white-space: nowrap;
|
|
220
|
+
text-overflow: ellipsis;
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
.one-close {
|
|
224
|
+
display: flex;
|
|
225
|
+
justify-content: center;
|
|
226
|
+
align-items: center;
|
|
227
|
+
flex-shrink: 0;
|
|
228
|
+
width: 16px;
|
|
229
|
+
height: 16px;
|
|
230
|
+
color: var(--c-text-2);
|
|
231
|
+
transition: color 0.25s;
|
|
232
|
+
|
|
233
|
+
&:hover {
|
|
234
|
+
color: var(--c-text-1);
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
.one-close-icon {
|
|
239
|
+
width: 16px;
|
|
240
|
+
height: 16px;
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
.SInputDropdownItem.mini {
|
|
244
|
+
.many {
|
|
245
|
+
padding: 3px 0 3px 3px;
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
.one-text {
|
|
249
|
+
padding-left: 10px;
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
.one-text-value {
|
|
253
|
+
font-size: var(--input-font-size, var(--input-mini-font-size));
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
.one-avatar {
|
|
257
|
+
gap: 6px;
|
|
258
|
+
padding-left: 7px;
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
.SInputDropdownItem.small {
|
|
263
|
+
.many {
|
|
264
|
+
padding: 7px 0 7px 7px;
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
.one-text {
|
|
268
|
+
padding-left: 12px;
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
.one-text-value {
|
|
272
|
+
font-size: var(--input-font-size, var(--input-small-font-size));
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
.one-avatar {
|
|
276
|
+
gap: 8px;
|
|
277
|
+
padding-left: 10px;
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
.SInputDropdownItem.medium {
|
|
282
|
+
.many {
|
|
283
|
+
padding: 11px 0 11px 11px;
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
.one-text {
|
|
287
|
+
padding-left: 16px;
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
.one-text-value {
|
|
291
|
+
font-size: var(--input-font-size, var(--input-medium-font-size));
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
.one-avatar {
|
|
295
|
+
gap: 8px;
|
|
296
|
+
padding-left: 12px;
|
|
297
|
+
}
|
|
298
|
+
}
|
|
69
299
|
</style>
|
|
@@ -1,41 +1,30 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
|
-
import {
|
|
3
|
-
import { type Validatable } from '../composables/Validation'
|
|
2
|
+
import { computed } from 'vue'
|
|
4
3
|
import { isString } from '../support/Utils'
|
|
4
|
+
import { type Props as BaseProps } from './SInputBase.vue'
|
|
5
5
|
import SInputText from './SInputText.vue'
|
|
6
6
|
|
|
7
|
-
export
|
|
8
|
-
export type Align = 'left' | 'center' | 'right'
|
|
9
|
-
export type CheckColor = 'neutral' | 'mute' | 'info' | 'success' | 'warning' | 'danger'
|
|
10
|
-
export type TextColor = 'neutral' | 'info' | 'success' | 'warning' | 'danger'
|
|
11
|
-
|
|
12
|
-
const props = defineProps<{
|
|
13
|
-
size?: Size
|
|
14
|
-
name?: string
|
|
15
|
-
label?: string
|
|
16
|
-
info?: string
|
|
17
|
-
note?: string
|
|
18
|
-
help?: string
|
|
7
|
+
export interface Props extends BaseProps {
|
|
19
8
|
placeholder?: string
|
|
20
9
|
unitBefore?: any
|
|
21
10
|
unitAfter?: any
|
|
22
|
-
checkIcon?: Component
|
|
23
|
-
checkText?: string
|
|
24
|
-
checkColor?: CheckColor
|
|
25
11
|
textColor?: TextColor | ((value: number | null) => TextColor)
|
|
26
|
-
align?: Align
|
|
27
12
|
separator?: boolean
|
|
13
|
+
align?: Align
|
|
28
14
|
disabled?: boolean
|
|
29
15
|
value?: number | null
|
|
30
16
|
modelValue?: number | null
|
|
31
17
|
displayValue?: string | null
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export type Align = 'left' | 'center' | 'right'
|
|
21
|
+
export type TextColor = 'neutral' | 'info' | 'success' | 'warning' | 'danger'
|
|
22
|
+
|
|
23
|
+
const props = defineProps<Props>()
|
|
35
24
|
|
|
36
25
|
const emit = defineEmits<{
|
|
37
|
-
|
|
38
|
-
|
|
26
|
+
'update:model-value': [value: number | null]
|
|
27
|
+
'input': [value: number | null]
|
|
39
28
|
}>()
|
|
40
29
|
|
|
41
30
|
const _value = computed(() => {
|
|
@@ -86,8 +75,8 @@ function emitUpdate(value: string | null) {
|
|
|
86
75
|
<template>
|
|
87
76
|
<SInputText
|
|
88
77
|
class="SInputNumber"
|
|
89
|
-
:name="name"
|
|
90
78
|
:size="size"
|
|
79
|
+
:name="name"
|
|
91
80
|
type="number"
|
|
92
81
|
:label="label"
|
|
93
82
|
:note="note"
|
|
@@ -102,10 +91,12 @@ function emitUpdate(value: string | null) {
|
|
|
102
91
|
:text-color="_textColor"
|
|
103
92
|
:align="align"
|
|
104
93
|
:disabled="disabled"
|
|
105
|
-
:hide-error="hideError"
|
|
106
94
|
:display-value="displayValue"
|
|
107
95
|
:model-value="_value == null ? null : String(_value)"
|
|
108
96
|
:validation="validation"
|
|
97
|
+
:warning="warning"
|
|
98
|
+
:hide-error="hideError"
|
|
99
|
+
:hide-warning="hideWarning"
|
|
109
100
|
@update:model-value="emitUpdate"
|
|
110
101
|
@input="emitUpdate"
|
|
111
102
|
>
|
|
@@ -1,51 +1,36 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
2
|
import { type Component, computed, ref } from 'vue'
|
|
3
|
-
import { type Validatable } from '../composables/Validation'
|
|
4
3
|
import { isString } from '../support/Utils'
|
|
5
|
-
import SInputBase from './SInputBase.vue'
|
|
6
|
-
|
|
7
|
-
export interface Props {
|
|
8
|
-
size?: Size
|
|
9
|
-
name?: string
|
|
10
|
-
label?: string
|
|
11
|
-
info?: string
|
|
12
|
-
note?: string
|
|
13
|
-
help?: string
|
|
4
|
+
import SInputBase, { type Props as BaseProps } from './SInputBase.vue'
|
|
5
|
+
|
|
6
|
+
export interface Props extends BaseProps {
|
|
14
7
|
type?: string
|
|
15
8
|
placeholder?: string
|
|
16
9
|
unitBefore?: Component | string
|
|
17
10
|
unitAfter?: Component | string
|
|
18
|
-
checkIcon?: Component
|
|
19
|
-
checkText?: string
|
|
20
|
-
checkColor?: CheckColor
|
|
21
11
|
textColor?: TextColor | ((value: string | null) => TextColor)
|
|
22
12
|
align?: Align
|
|
23
13
|
disabled?: boolean
|
|
24
14
|
modelValue: string | null
|
|
25
15
|
displayValue?: string | null
|
|
26
|
-
hideError?: boolean
|
|
27
|
-
validation?: Validatable
|
|
28
16
|
}
|
|
29
17
|
|
|
30
|
-
export type Size = 'mini' | 'small' | 'medium'
|
|
31
18
|
export type Align = 'left' | 'center' | 'right'
|
|
32
|
-
export type CheckColor = 'neutral' | 'mute' | 'info' | 'success' | 'warning' | 'danger'
|
|
33
19
|
export type TextColor = 'neutral' | 'info' | 'success' | 'warning' | 'danger'
|
|
34
20
|
|
|
35
21
|
const props = defineProps<Props>()
|
|
36
22
|
|
|
37
23
|
const emit = defineEmits<{
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
24
|
+
'update:model-value': [value: string | null]
|
|
25
|
+
'input': [value: string | null]
|
|
26
|
+
'blur': [value: string | null]
|
|
27
|
+
'enter': [value: string | null]
|
|
42
28
|
}>()
|
|
43
29
|
|
|
44
30
|
const input = ref<HTMLElement | null>(null)
|
|
45
31
|
const isFocused = ref(false)
|
|
46
32
|
|
|
47
33
|
const classes = computed(() => [
|
|
48
|
-
props.size ?? 'small',
|
|
49
34
|
props.align ?? 'left',
|
|
50
35
|
{ disabled: props.disabled }
|
|
51
36
|
])
|
|
@@ -116,6 +101,7 @@ function getValue(e: Event | FocusEvent | KeyboardEvent): string | null {
|
|
|
116
101
|
<SInputBase
|
|
117
102
|
class="SInputText"
|
|
118
103
|
:class="classes"
|
|
104
|
+
:size="size"
|
|
119
105
|
:name="name"
|
|
120
106
|
:label="label"
|
|
121
107
|
:note="note"
|
|
@@ -124,8 +110,10 @@ function getValue(e: Event | FocusEvent | KeyboardEvent): string | null {
|
|
|
124
110
|
:check-icon="checkIcon"
|
|
125
111
|
:check-text="checkText"
|
|
126
112
|
:check-color="checkColor"
|
|
127
|
-
:hide-error="hideError"
|
|
128
113
|
:validation="validation"
|
|
114
|
+
:warning="warning"
|
|
115
|
+
:hide-error="hideError"
|
|
116
|
+
:hide-warning="hideWarning"
|
|
129
117
|
>
|
|
130
118
|
<div class="box" :class="{ focus: isFocused }" @click="focus">
|
|
131
119
|
<div v-if="$slots['addon-before']" class="addon before">
|
|
@@ -349,6 +337,14 @@ function getValue(e: Event | FocusEvent | KeyboardEvent): string | null {
|
|
|
349
337
|
}
|
|
350
338
|
}
|
|
351
339
|
|
|
340
|
+
.SInputText.has-warning {
|
|
341
|
+
.box,
|
|
342
|
+
.box:hover,
|
|
343
|
+
.box:focus {
|
|
344
|
+
border-color: var(--input-warning-border-color);
|
|
345
|
+
}
|
|
346
|
+
}
|
|
347
|
+
|
|
352
348
|
.box {
|
|
353
349
|
position: relative;
|
|
354
350
|
display: flex;
|
|
@@ -1,42 +1,29 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
|
-
import {
|
|
3
|
-
import { type
|
|
4
|
-
import SInputBase from './SInputBase.vue'
|
|
2
|
+
import { computed, ref } from 'vue'
|
|
3
|
+
import SInputBase, { type Props as BaseProps } from './SInputBase.vue'
|
|
5
4
|
import SInputSegments from './SInputSegments.vue'
|
|
6
5
|
|
|
7
|
-
export
|
|
8
|
-
export type Color = 'neutral' | 'mute' | 'info' | 'success' | 'warning' | 'danger'
|
|
9
|
-
|
|
10
|
-
const props = withDefaults(defineProps<{
|
|
11
|
-
size?: Size
|
|
12
|
-
name?: string
|
|
13
|
-
label?: string
|
|
14
|
-
info?: string
|
|
15
|
-
note?: string
|
|
16
|
-
help?: string
|
|
17
|
-
checkIcon?: Component
|
|
18
|
-
checkText?: string
|
|
19
|
-
checkColor?: Color
|
|
6
|
+
export interface Props extends BaseProps {
|
|
20
7
|
placeholder?: string
|
|
21
8
|
disabled?: boolean
|
|
22
9
|
rows?: number | 'fill'
|
|
23
10
|
autoResize?: boolean | number
|
|
24
11
|
value?: string | null
|
|
25
12
|
modelValue?: string | null
|
|
26
|
-
hideError?: boolean
|
|
27
|
-
validation?: Validatable
|
|
28
13
|
preview?: (value: string | null) => string
|
|
29
14
|
previewLabel?: string
|
|
30
15
|
writeLabel?: string
|
|
31
|
-
}
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
const props = withDefaults(defineProps<Props>(), {
|
|
32
19
|
size: 'small',
|
|
33
20
|
rows: 3
|
|
34
21
|
})
|
|
35
22
|
|
|
36
23
|
const emit = defineEmits<{
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
24
|
+
'update:model-value': [value: string | null]
|
|
25
|
+
'input': [value: string | null]
|
|
26
|
+
'blur': [value: string | null]
|
|
40
27
|
}>()
|
|
41
28
|
|
|
42
29
|
const sizePaddingYDict = {
|
|
@@ -93,6 +80,7 @@ const isPreview = ref(false)
|
|
|
93
80
|
<SInputBase
|
|
94
81
|
class="SInputTextarea"
|
|
95
82
|
:class="classes"
|
|
83
|
+
:size="size"
|
|
96
84
|
:name="name"
|
|
97
85
|
:label="label"
|
|
98
86
|
:note="note"
|
|
@@ -101,8 +89,10 @@ const isPreview = ref(false)
|
|
|
101
89
|
:check-icon="checkIcon"
|
|
102
90
|
:check-text="checkText"
|
|
103
91
|
:check-color="checkColor"
|
|
104
|
-
:hide-error="hideError"
|
|
105
92
|
:validation="validation"
|
|
93
|
+
:warning="warning"
|
|
94
|
+
:hide-error="hideError"
|
|
95
|
+
:hide-warning="hideWarning"
|
|
106
96
|
>
|
|
107
97
|
<div class="box">
|
|
108
98
|
<div v-if="preview !== undefined" class="control">
|
|
@@ -248,4 +238,10 @@ const isPreview = ref(false)
|
|
|
248
238
|
border-color: var(--input-error-border-color);
|
|
249
239
|
}
|
|
250
240
|
}
|
|
241
|
+
|
|
242
|
+
.SInputTextarea.has-warning {
|
|
243
|
+
.box {
|
|
244
|
+
border-color: var(--input-warning-border-color);
|
|
245
|
+
}
|
|
246
|
+
}
|
|
251
247
|
</style>
|
package/lib/composables/Error.ts
CHANGED
|
@@ -143,7 +143,9 @@ function formatProps(props: Record<string, unknown>): string {
|
|
|
143
143
|
const ignoreErrors = [
|
|
144
144
|
/Network Error/,
|
|
145
145
|
/Non-Error (?:exception|promise rejection) captured/,
|
|
146
|
-
/ResizeObserver loop
|
|
146
|
+
/ResizeObserver loop/,
|
|
147
|
+
/Can't find variable: gmo/,
|
|
148
|
+
/\[Cloudflare Turnstile\] Error: (?:10[2-46]|1106[02]|[36]00)/
|
|
147
149
|
]
|
|
148
150
|
|
|
149
151
|
export function useErrorHandler({
|
package/lib/styles/variables.css
CHANGED
|
@@ -858,6 +858,8 @@
|
|
|
858
858
|
--input-focus-border-color: var(--c-border-info-1);
|
|
859
859
|
--input-error-text-color: var(--c-text-danger-1);
|
|
860
860
|
--input-error-border-color: var(--c-border-danger-1);
|
|
861
|
+
--input-warning-text-color: var(--c-text-warning-1);
|
|
862
|
+
--input-warning-border-color: var(--c-border-warning-1);
|
|
861
863
|
--input-disabled-border-color: var(--c-border-mute-1);
|
|
862
864
|
--input-disabled-value-color: var(--c-text-1);
|
|
863
865
|
--input-disabled-bg-color: var(--c-bg-mute-1);
|
package/package.json
CHANGED
|
@@ -1,175 +0,0 @@
|
|
|
1
|
-
<script setup lang="ts">
|
|
2
|
-
import IconX from '~icons/ph/x-bold'
|
|
3
|
-
import SAvatar from './SAvatar.vue'
|
|
4
|
-
|
|
5
|
-
export type Size = 'mini' | 'small' | 'medium'
|
|
6
|
-
|
|
7
|
-
defineProps<{
|
|
8
|
-
size: Size
|
|
9
|
-
label: string
|
|
10
|
-
image?: string | null
|
|
11
|
-
value: any
|
|
12
|
-
removable: boolean
|
|
13
|
-
disabled: boolean
|
|
14
|
-
}>()
|
|
15
|
-
|
|
16
|
-
defineEmits<{
|
|
17
|
-
(e: 'remove', value: any): void
|
|
18
|
-
}>()
|
|
19
|
-
|
|
20
|
-
const avatarSizeDict = {
|
|
21
|
-
mini: 'nano',
|
|
22
|
-
small: 'mini',
|
|
23
|
-
medium: 'mini'
|
|
24
|
-
} as const
|
|
25
|
-
</script>
|
|
26
|
-
|
|
27
|
-
<template>
|
|
28
|
-
<div class="SInputDropdownItemAvatar" :class="[size, { disabled, removable }]">
|
|
29
|
-
<div class="user">
|
|
30
|
-
<div class="avatar">
|
|
31
|
-
<SAvatar :size="avatarSizeDict[size]" :avatar="image" :name="label" />
|
|
32
|
-
</div>
|
|
33
|
-
<p class="name">{{ label }}</p>
|
|
34
|
-
</div>
|
|
35
|
-
|
|
36
|
-
<div v-if="!disabled && removable" class="remove" role="button" @click="$emit('remove', value)">
|
|
37
|
-
<div class="remove-box">
|
|
38
|
-
<IconX class="remove-icon" />
|
|
39
|
-
</div>
|
|
40
|
-
</div>
|
|
41
|
-
</div>
|
|
42
|
-
</template>
|
|
43
|
-
|
|
44
|
-
<style lang="postcss" scoped>
|
|
45
|
-
.SInputDropdownItemAvatar {
|
|
46
|
-
display: flex;
|
|
47
|
-
align-items: center;
|
|
48
|
-
border: 1px solid var(--c-border-mute-1);
|
|
49
|
-
background-color: var(--c-bg-mute-1);
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
.user {
|
|
53
|
-
display: flex;
|
|
54
|
-
align-items: center;
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
.avatar {
|
|
58
|
-
display: flex;
|
|
59
|
-
align-items: center;
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
.name {
|
|
63
|
-
font-size: 12px;
|
|
64
|
-
font-weight: 500;
|
|
65
|
-
white-space: nowrap;
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
.remove {
|
|
69
|
-
display: flex;
|
|
70
|
-
justify-content: center;
|
|
71
|
-
align-items: center;
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
.remove-box {
|
|
75
|
-
display: flex;
|
|
76
|
-
justify-content: center;
|
|
77
|
-
align-items: center;
|
|
78
|
-
border-radius: 50%;
|
|
79
|
-
color: var(--c-text-2);
|
|
80
|
-
transition: color 0.25s, background-color 0.25s;
|
|
81
|
-
|
|
82
|
-
.remove:hover & {
|
|
83
|
-
color: var(--c-text-1);
|
|
84
|
-
background-color: var(--c-bg-mute-2)
|
|
85
|
-
}
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
.SInputDropdownItemAvatar.mini {
|
|
89
|
-
gap: 2px;
|
|
90
|
-
border-radius: 12px;
|
|
91
|
-
padding: 0 8px 0 0;
|
|
92
|
-
height: 24px;
|
|
93
|
-
|
|
94
|
-
.avatar {
|
|
95
|
-
padding: 0 0 0 1px;
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
.name {
|
|
99
|
-
margin-left: 6px;
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
.remove {
|
|
103
|
-
width: 23px;
|
|
104
|
-
height: 23px;
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
.remove-box {
|
|
108
|
-
width: 20px;
|
|
109
|
-
height: 20px;
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
.remove-icon {
|
|
113
|
-
width: 12px;
|
|
114
|
-
height: 12px;
|
|
115
|
-
}
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
.SInputDropdownItemAvatar.small {
|
|
119
|
-
border-radius: 14px;
|
|
120
|
-
padding: 0 12px 0 0;
|
|
121
|
-
height: 28px;
|
|
122
|
-
|
|
123
|
-
.avatar {
|
|
124
|
-
padding: 0 0 0 1px;
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
.name {
|
|
128
|
-
margin-left: 6px;
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
.remove {
|
|
132
|
-
width: 26px;
|
|
133
|
-
height: 26px;
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
.remove-box {
|
|
137
|
-
width: 20px;
|
|
138
|
-
height: 20px;
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
.remove-icon {
|
|
142
|
-
width: 12px;
|
|
143
|
-
height: 12px;
|
|
144
|
-
}
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
.SInputDropdownItemAvatar.medium {
|
|
148
|
-
border-radius: 16px;
|
|
149
|
-
padding: 0 12px 0 0;
|
|
150
|
-
height: 32px;
|
|
151
|
-
|
|
152
|
-
.avatar {
|
|
153
|
-
padding: 0 0 0 4px;
|
|
154
|
-
}
|
|
155
|
-
|
|
156
|
-
.name {
|
|
157
|
-
margin-left: 6px;
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
.remove {
|
|
161
|
-
width: 26px;
|
|
162
|
-
height: 26px;
|
|
163
|
-
}
|
|
164
|
-
|
|
165
|
-
.remove-box {
|
|
166
|
-
width: 20px;
|
|
167
|
-
height: 20px;
|
|
168
|
-
}
|
|
169
|
-
|
|
170
|
-
.remove-icon {
|
|
171
|
-
width: 12px;
|
|
172
|
-
height: 12px;
|
|
173
|
-
}
|
|
174
|
-
}
|
|
175
|
-
</style>
|
|
@@ -1,154 +0,0 @@
|
|
|
1
|
-
<script setup lang="ts">
|
|
2
|
-
import IconX from '~icons/ph/x-bold'
|
|
3
|
-
|
|
4
|
-
export type Size = 'mini' | 'small' | 'medium'
|
|
5
|
-
|
|
6
|
-
defineProps<{
|
|
7
|
-
size: Size
|
|
8
|
-
label: string
|
|
9
|
-
value: any
|
|
10
|
-
removable: boolean
|
|
11
|
-
disabled: boolean
|
|
12
|
-
}>()
|
|
13
|
-
|
|
14
|
-
defineEmits<{
|
|
15
|
-
(e: 'remove', value: any): void
|
|
16
|
-
}>()
|
|
17
|
-
</script>
|
|
18
|
-
|
|
19
|
-
<template>
|
|
20
|
-
<div class="SInputDropdownItemText" :class="[size, { disabled, removable }]">
|
|
21
|
-
<p class="text">{{ label }}</p>
|
|
22
|
-
|
|
23
|
-
<div v-if="!disabled && removable" class="remove" role="button" @click.stop="$emit('remove', value)">
|
|
24
|
-
<div class="remove-box">
|
|
25
|
-
<IconX class="remove-icon" />
|
|
26
|
-
</div>
|
|
27
|
-
</div>
|
|
28
|
-
</div>
|
|
29
|
-
</template>
|
|
30
|
-
|
|
31
|
-
<style lang="postcss" scoped>
|
|
32
|
-
.SInputDropdownItemText {
|
|
33
|
-
display: flex;
|
|
34
|
-
align-items: center;
|
|
35
|
-
border: 1px solid var(--c-border-mute-1);
|
|
36
|
-
background-color: var(--c-bg-mute-1);
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
.text {
|
|
40
|
-
margin: 0;
|
|
41
|
-
line-height: 20px;
|
|
42
|
-
font-size: 12px;
|
|
43
|
-
font-weight: 500;
|
|
44
|
-
white-space: nowrap;
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
.remove {
|
|
48
|
-
display: flex;
|
|
49
|
-
justify-content: center;
|
|
50
|
-
align-items: center;
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
.remove-box {
|
|
54
|
-
display: flex;
|
|
55
|
-
justify-content: center;
|
|
56
|
-
align-items: center;
|
|
57
|
-
border-radius: 50%;
|
|
58
|
-
color: var(--c-text-2);
|
|
59
|
-
transition: color 0.25s, background-color 0.25s;
|
|
60
|
-
|
|
61
|
-
.remove:hover & {
|
|
62
|
-
color: var(--c-text-1);
|
|
63
|
-
background-color: var(--c-bg-mute-3);
|
|
64
|
-
}
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
.SInputDropdownItemText.mini {
|
|
68
|
-
gap: 2px;
|
|
69
|
-
border-radius: 12px;
|
|
70
|
-
padding: 0 8px;
|
|
71
|
-
height: 24px;
|
|
72
|
-
|
|
73
|
-
&.removable {
|
|
74
|
-
padding: 0 0 0 8px;
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
&.disabled {
|
|
78
|
-
padding: 0 10px;
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
.remove {
|
|
82
|
-
width: 23px;
|
|
83
|
-
height: 23px;
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
.remove-box {
|
|
87
|
-
width: 20px;
|
|
88
|
-
height: 20px;
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
.remove-icon {
|
|
92
|
-
width: 12px;
|
|
93
|
-
height: 12px;
|
|
94
|
-
}
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
.SInputDropdownItemText.small {
|
|
98
|
-
border-radius: 14px;
|
|
99
|
-
padding: 0 12px;
|
|
100
|
-
height: 28px;
|
|
101
|
-
|
|
102
|
-
&.removable {
|
|
103
|
-
padding: 0 0 0 12px;
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
&.disabled {
|
|
107
|
-
padding: 0 12px;
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
.remove {
|
|
111
|
-
width: 26px;
|
|
112
|
-
height: 26px;
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
.remove-box {
|
|
116
|
-
width: 20px;
|
|
117
|
-
height: 20px;
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
.remove-icon {
|
|
121
|
-
width: 12px;
|
|
122
|
-
height: 12px;
|
|
123
|
-
}
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
.SInputDropdownItemText.medium {
|
|
127
|
-
border-radius: 16px;
|
|
128
|
-
padding: 0 12px;
|
|
129
|
-
height: 32px;
|
|
130
|
-
|
|
131
|
-
&.removable {
|
|
132
|
-
padding: 0 0 0 12px;
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
&.disabled {
|
|
136
|
-
padding: 0 12px;
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
.remove {
|
|
140
|
-
width: 26px;
|
|
141
|
-
height: 26px;
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
.remove-box {
|
|
145
|
-
width: 20px;
|
|
146
|
-
height: 20px;
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
.remove-icon {
|
|
150
|
-
width: 12px;
|
|
151
|
-
height: 12px;
|
|
152
|
-
}
|
|
153
|
-
}
|
|
154
|
-
</style>
|