@globalbrain/sefirot 2.0.0-draft.7 → 2.0.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/LICENSE.md +1 -1
- package/README.md +6 -6
- package/lib/components/SAvatar.vue +17 -17
- package/lib/components/SButton.vue +512 -267
- package/lib/components/SButtonGroup.vue +149 -0
- package/lib/components/SDropdown.vue +26 -150
- package/lib/components/SDropdownSection.vue +48 -0
- package/lib/components/SDropdownSectionFilter.vue +189 -0
- package/lib/components/SDropdownSectionFilterItem.vue +21 -0
- package/lib/components/SDropdownSectionFilterItemAvatar.vue +31 -0
- package/lib/components/SDropdownSectionFilterItemText.vue +20 -0
- package/lib/components/SDropdownSectionMenu.vue +39 -0
- package/lib/components/SIcon.vue +13 -0
- package/lib/components/SInputBase.vue +31 -31
- package/lib/components/SInputCheckbox.vue +1 -1
- package/lib/components/SInputCheckboxes.vue +74 -0
- package/lib/components/SInputDate.vue +182 -0
- package/lib/components/SInputDropdown.vue +158 -157
- package/lib/components/SInputDropdownItem.vue +46 -48
- package/lib/components/{SInputDropdownItemUserTag.vue → SInputDropdownItemAvatar.vue} +43 -44
- package/lib/components/SInputDropdownItemText.vue +79 -16
- package/lib/components/SInputFile.vue +55 -60
- package/lib/components/SInputHMS.vue +120 -110
- package/lib/components/SInputNumber.vue +38 -9
- package/lib/components/SInputRadio.vue +39 -36
- package/lib/components/SInputRadios.vue +40 -53
- package/lib/components/SInputSelect.vue +3 -3
- package/lib/components/SInputSwitch.vue +193 -0
- package/lib/components/SInputSwitches.vue +88 -0
- package/lib/components/SInputText.vue +206 -62
- package/lib/components/SInputTextarea.vue +46 -32
- package/lib/components/SInputYMD.vue +123 -126
- package/lib/components/SMarkdown.vue +52 -0
- package/lib/components/SModal.vue +25 -63
- package/lib/components/SMount.vue +19 -0
- package/lib/components/SSheet.vue +49 -55
- package/lib/components/SSheetFooter.vue +1 -1
- package/lib/components/SSheetFooterAction.vue +24 -17
- package/lib/components/SSheetFooterActions.vue +1 -4
- package/lib/components/SSheetForm.vue +15 -0
- package/lib/components/SSheetMedium.vue +8 -10
- package/lib/components/SSheetTitle.vue +7 -14
- package/lib/components/SSnackbar.vue +55 -45
- package/lib/components/{SPortalSnackbars.vue → SSnackbars.vue} +17 -20
- package/lib/components/SStep.vue +106 -0
- package/lib/components/SSteps.vue +59 -0
- package/lib/components/STable.vue +241 -0
- package/lib/components/STableCell.vue +82 -0
- package/lib/components/STableCellAvatar.vue +69 -0
- package/lib/components/STableCellAvatars.vue +93 -0
- package/lib/components/STableCellDay.vue +40 -0
- package/lib/components/STableCellPill.vue +84 -0
- package/lib/components/STableCellText.vue +102 -0
- package/lib/components/STableColumn.vue +255 -0
- package/lib/components/STableFooter.vue +115 -0
- package/lib/components/STableHeader.vue +74 -0
- package/lib/components/STableItem.vue +38 -0
- package/lib/components/STooltip.vue +112 -0
- package/lib/composables/Dropdown.ts +40 -99
- package/lib/composables/Form.ts +21 -18
- package/lib/composables/Grid.ts +117 -0
- package/lib/composables/Markdown.ts +138 -0
- package/lib/composables/Step.ts +7 -0
- package/lib/composables/Table.ts +103 -0
- package/lib/composables/Tooltip.ts +91 -0
- package/lib/composables/Validation.ts +6 -7
- package/lib/composables/markdown/LinkPlugin.ts +45 -0
- package/lib/mixins/Sheet.ts +5 -3
- package/lib/stores/Snackbars.ts +48 -0
- package/lib/{assets/styles → styles}/base.css +0 -0
- package/lib/{assets/styles → styles}/bootstrap.css +1 -0
- package/lib/{assets/styles → styles}/variables.css +55 -48
- package/lib/support/Day.ts +8 -0
- package/lib/support/Num.ts +3 -0
- package/lib/support/Time.ts +5 -2
- package/lib/support/Utils.ts +4 -3
- package/lib/types/shims.d.ts +3 -0
- package/lib/validation/validators/requiredYmd.ts +1 -1
- package/lib/validation/validators/ymd.ts +4 -4
- package/package.json +62 -43
- package/CHANGELOG.md +0 -41
- package/lib/components/SDialog.vue +0 -140
- package/lib/components/SDropdownItem.vue +0 -78
- package/lib/components/SDropdownItemText.vue +0 -22
- package/lib/components/SDropdownItemUser.vue +0 -40
- package/lib/components/SInputDropdownItemTextTag.vue +0 -94
- package/lib/components/SInputDropdownItemUser.vue +0 -41
- package/lib/components/SPortalModals.vue +0 -74
- package/lib/composables/Dialog.ts +0 -38
- package/lib/composables/Modal.ts +0 -34
- package/lib/composables/Snackbar.ts +0 -18
- package/lib/store/Sefirot.ts +0 -17
- package/lib/store/dialog/index.ts +0 -42
- package/lib/store/modal/index.ts +0 -61
- package/lib/store/snackbars/index.ts +0 -70
|
@@ -1,146 +1,100 @@
|
|
|
1
|
-
<template>
|
|
2
|
-
<SInputBase
|
|
3
|
-
class="SInputDropdown"
|
|
4
|
-
:class="classes"
|
|
5
|
-
:label="label"
|
|
6
|
-
:note="note"
|
|
7
|
-
:help="help"
|
|
8
|
-
:validation="validation"
|
|
9
|
-
>
|
|
10
|
-
<div ref="container" class="SInputDropdown-container">
|
|
11
|
-
<div
|
|
12
|
-
class="SInputDropdown-box"
|
|
13
|
-
role="button"
|
|
14
|
-
tabindex="0"
|
|
15
|
-
@click="handleOpen"
|
|
16
|
-
@keydown.down.prevent
|
|
17
|
-
@keyup.enter="handleOpen"
|
|
18
|
-
@keyup.down="handleOpen"
|
|
19
|
-
>
|
|
20
|
-
<div class="SInputDropdown-box-content">
|
|
21
|
-
<SInputDropdownItem
|
|
22
|
-
v-if="hasSelected"
|
|
23
|
-
:item="selected"
|
|
24
|
-
:disabled="disabled"
|
|
25
|
-
@remove="handleCallback"
|
|
26
|
-
/>
|
|
27
|
-
|
|
28
|
-
<span v-else class="SInputDropdown-box-placeholder">{{ placeholder }}</span>
|
|
29
|
-
</div>
|
|
30
|
-
|
|
31
|
-
<div class="SInputDropdown-box-icon">
|
|
32
|
-
<SIconChevronUp class="SInputDropdown-box-icon-svg up" />
|
|
33
|
-
<SIconChevronDown class="SInputDropdown-box-icon-svg down" />
|
|
34
|
-
</div>
|
|
35
|
-
</div>
|
|
36
|
-
|
|
37
|
-
<div v-if="isOpen" class="SInputDropdown-dropdown">
|
|
38
|
-
<SDropdown :options="dropdownOptions" @close="close" />
|
|
39
|
-
</div>
|
|
40
|
-
</div>
|
|
41
|
-
</SInputBase>
|
|
42
|
-
</template>
|
|
43
|
-
|
|
44
1
|
<script setup lang="ts">
|
|
45
|
-
import
|
|
46
|
-
import {
|
|
2
|
+
import xor from 'lodash-es/xor'
|
|
3
|
+
import { computed } from 'vue'
|
|
4
|
+
import type { DropdownSectionFilter } from '../composables/Dropdown'
|
|
47
5
|
import { useFlyout } from '../composables/Flyout'
|
|
48
|
-
import {
|
|
49
|
-
import
|
|
50
|
-
import SIconChevronDown from './icons/SIconChevronDown.vue'
|
|
6
|
+
import { Validatable } from '../composables/Validation'
|
|
7
|
+
import { isArray } from '../support/Utils'
|
|
51
8
|
import SDropdown from './SDropdown.vue'
|
|
52
9
|
import SInputBase from './SInputBase.vue'
|
|
53
10
|
import SInputDropdownItem from './SInputDropdownItem.vue'
|
|
11
|
+
import SIconChevronDown from './icons/SIconChevronDown.vue'
|
|
12
|
+
import SIconChevronUp from './icons/SIconChevronUp.vue'
|
|
54
13
|
|
|
55
|
-
type Size = 'mini' | 'small' | 'medium'
|
|
56
|
-
type
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
note: { type: String, default: null },
|
|
62
|
-
help: { type: String, default: null },
|
|
63
|
-
placeholder: { type: String, default: null },
|
|
64
|
-
search: { type: [Boolean, Object] as PropType<boolean | Search>, default: false },
|
|
65
|
-
options: { type: Array as PropType<Item[]>, required: true },
|
|
66
|
-
nullable: { type: Boolean, default: true },
|
|
67
|
-
closeOnClick: { type: Boolean, default: false },
|
|
68
|
-
disabled: { type: Boolean, default: false },
|
|
69
|
-
modelValue: { type: [String, Number, Boolean, Array, Object] as PropType<Value>, default: null },
|
|
70
|
-
validation: { type: Object as PropType<any>, default: null }
|
|
71
|
-
})
|
|
14
|
+
export type Size = 'mini' | 'small' | 'medium'
|
|
15
|
+
export type PrimitiveValue = string | number | boolean | null
|
|
16
|
+
export type ArrayValue = (string | number | boolean)[]
|
|
17
|
+
export type OptionValue = string | number | boolean
|
|
18
|
+
|
|
19
|
+
export type Option = OptionText | OptionAvatar
|
|
72
20
|
|
|
73
|
-
|
|
21
|
+
export interface OptionBase {
|
|
22
|
+
type?: 'text' | 'avatar'
|
|
23
|
+
value: OptionValue
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export interface OptionText extends OptionBase {
|
|
27
|
+
type?: 'text'
|
|
28
|
+
label: string
|
|
29
|
+
}
|
|
74
30
|
|
|
75
|
-
|
|
31
|
+
export interface OptionAvatar extends OptionBase {
|
|
32
|
+
type: 'avatar'
|
|
33
|
+
label: string
|
|
34
|
+
image?: string | null
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
const props = defineProps<{
|
|
38
|
+
size?: Size
|
|
39
|
+
label?: string
|
|
40
|
+
note?: string
|
|
41
|
+
help?: string
|
|
42
|
+
placeholder?: string
|
|
43
|
+
noSearch?: boolean
|
|
44
|
+
nullable?: boolean
|
|
45
|
+
closeOnClick?: boolean
|
|
46
|
+
options: Option[]
|
|
47
|
+
disabled?: boolean
|
|
48
|
+
modelValue: PrimitiveValue | ArrayValue
|
|
49
|
+
validation?: Validatable
|
|
50
|
+
}>()
|
|
51
|
+
|
|
52
|
+
const emit = defineEmits<{
|
|
53
|
+
(e: 'update:modelValue', value: PrimitiveValue | ArrayValue): void
|
|
54
|
+
}>()
|
|
55
|
+
|
|
56
|
+
const { container, isOpen, open } = useFlyout()
|
|
76
57
|
|
|
77
58
|
const classes = computed(() => [
|
|
78
|
-
props.size,
|
|
59
|
+
props.size ?? 'small',
|
|
79
60
|
{ disabled: props.disabled }
|
|
80
61
|
])
|
|
81
62
|
|
|
82
|
-
const
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
closeOnClick: props.closeOnClick,
|
|
90
|
-
selected: computed(() => props.modelValue),
|
|
91
|
-
callback: handleCallback
|
|
92
|
-
})
|
|
63
|
+
const dropdownOptions = computed<DropdownSectionFilter[]>(() => [{
|
|
64
|
+
type: 'filter',
|
|
65
|
+
search: props.noSearch === undefined ? true : !props.noSearch,
|
|
66
|
+
selected: props.modelValue,
|
|
67
|
+
options: props.options,
|
|
68
|
+
onClick: handleSelect
|
|
69
|
+
}])
|
|
93
70
|
|
|
94
71
|
const selected = computed(() => {
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
: props.options.find(o => isEqual(o.value, props.modelValue))
|
|
98
|
-
})
|
|
99
|
-
|
|
100
|
-
const hasSelected = computed(() => {
|
|
101
|
-
return isArray(selected.value)
|
|
102
|
-
? selected.value.length > 0
|
|
103
|
-
: !isNullish(selected.value) && selected.value.value !== ''
|
|
104
|
-
})
|
|
105
|
-
|
|
106
|
-
function createDropdownSearchOptions(): UseDropdownSearchOptions | undefined {
|
|
107
|
-
if (props.search === false) {
|
|
108
|
-
return undefined
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
if (props.search === true) {
|
|
112
|
-
return {
|
|
113
|
-
placeholder: 'Search items',
|
|
114
|
-
missing: 'No items found.'
|
|
115
|
-
}
|
|
72
|
+
if (isArray(props.modelValue)) {
|
|
73
|
+
return props.options.filter((o) => (props.modelValue as ArrayValue).includes(o.value))
|
|
116
74
|
}
|
|
117
75
|
|
|
118
|
-
|
|
119
|
-
}
|
|
76
|
+
const item = props.options.find((o) => o.value === props.modelValue)
|
|
120
77
|
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
open()
|
|
124
|
-
|
|
125
|
-
await nextTick()
|
|
78
|
+
return item ? [item] : []
|
|
79
|
+
})
|
|
126
80
|
|
|
127
|
-
|
|
81
|
+
const hasSelected = computed(() => {
|
|
82
|
+
return selected.value.length > 0
|
|
83
|
+
})
|
|
128
84
|
|
|
129
|
-
|
|
130
|
-
|
|
85
|
+
async function handleOpen() {
|
|
86
|
+
!props.disabled && open()
|
|
131
87
|
}
|
|
132
88
|
|
|
133
|
-
function
|
|
134
|
-
props.validation
|
|
89
|
+
function handleSelect(value: OptionValue) {
|
|
90
|
+
props.validation?.$touch()
|
|
135
91
|
|
|
136
|
-
isArray(props.modelValue) ? handleArray(
|
|
92
|
+
isArray(props.modelValue) ? handleArray(value) : handlePrimitive(value)
|
|
137
93
|
}
|
|
138
94
|
|
|
139
|
-
function handlePrimitive(value:
|
|
140
|
-
if (
|
|
141
|
-
emit('update:modelValue', value)
|
|
142
|
-
|
|
143
|
-
return
|
|
95
|
+
function handlePrimitive(value: OptionValue) {
|
|
96
|
+
if (value !== props.modelValue) {
|
|
97
|
+
return emit('update:modelValue', value)
|
|
144
98
|
}
|
|
145
99
|
|
|
146
100
|
if (props.nullable) {
|
|
@@ -148,8 +102,8 @@ function handlePrimitive(value: unknown): void {
|
|
|
148
102
|
}
|
|
149
103
|
}
|
|
150
104
|
|
|
151
|
-
function handleArray(value:
|
|
152
|
-
const difference =
|
|
105
|
+
function handleArray(value: OptionValue) {
|
|
106
|
+
const difference = xor(props.modelValue as ArrayValue, [value])
|
|
153
107
|
|
|
154
108
|
if (!props.nullable && difference.length === 0) {
|
|
155
109
|
return
|
|
@@ -157,76 +111,113 @@ function handleArray(value: unknown[]): void {
|
|
|
157
111
|
|
|
158
112
|
emit('update:modelValue', difference)
|
|
159
113
|
}
|
|
160
|
-
|
|
161
|
-
function getDifference(source: unknown[], value: unknown[]): unknown[] {
|
|
162
|
-
return source
|
|
163
|
-
.filter(item => !isEqual(item, value))
|
|
164
|
-
.concat(source.includes(value) ? [] : [value])
|
|
165
|
-
}
|
|
166
114
|
</script>
|
|
167
115
|
|
|
116
|
+
<template>
|
|
117
|
+
<SInputBase
|
|
118
|
+
class="SInputDropdown"
|
|
119
|
+
:class="classes"
|
|
120
|
+
:label="label"
|
|
121
|
+
:note="note"
|
|
122
|
+
:help="help"
|
|
123
|
+
:validation="validation"
|
|
124
|
+
>
|
|
125
|
+
<div class="container" ref="container">
|
|
126
|
+
<div
|
|
127
|
+
class="box"
|
|
128
|
+
role="button"
|
|
129
|
+
tabindex="0"
|
|
130
|
+
@click="handleOpen"
|
|
131
|
+
@keydown.down.prevent
|
|
132
|
+
@keyup.enter="handleOpen"
|
|
133
|
+
@keyup.down="handleOpen"
|
|
134
|
+
>
|
|
135
|
+
<div class="box-content">
|
|
136
|
+
<SInputDropdownItem
|
|
137
|
+
v-if="hasSelected"
|
|
138
|
+
:items="selected"
|
|
139
|
+
:disabled="disabled ?? false"
|
|
140
|
+
@remove="handleSelect"
|
|
141
|
+
/>
|
|
142
|
+
|
|
143
|
+
<div v-else class="box-placeholder">{{ placeholder }}</div>
|
|
144
|
+
</div>
|
|
145
|
+
|
|
146
|
+
<div class="box-icon">
|
|
147
|
+
<SIconChevronUp class="box-icon-svg up" />
|
|
148
|
+
<SIconChevronDown class="box-icon-svg down" />
|
|
149
|
+
</div>
|
|
150
|
+
</div>
|
|
151
|
+
|
|
152
|
+
<div v-if="isOpen" class="dropdown">
|
|
153
|
+
<SDropdown :sections="dropdownOptions" />
|
|
154
|
+
</div>
|
|
155
|
+
</div>
|
|
156
|
+
</SInputBase>
|
|
157
|
+
</template>
|
|
158
|
+
|
|
168
159
|
<style lang="postcss" scoped>
|
|
169
160
|
.SInputDropdown.mini {
|
|
170
|
-
.
|
|
161
|
+
.box {
|
|
171
162
|
min-height: 32px;
|
|
172
163
|
}
|
|
173
164
|
|
|
174
|
-
.
|
|
165
|
+
.box-content {
|
|
175
166
|
padding: 3px 30px 3px 12px;
|
|
176
167
|
line-height: 24px;
|
|
177
168
|
font-size: 14px;
|
|
178
169
|
}
|
|
179
170
|
|
|
180
|
-
.
|
|
171
|
+
.box-icon {
|
|
181
172
|
top: 3px;
|
|
182
173
|
right: 8px;
|
|
183
174
|
}
|
|
184
175
|
}
|
|
185
176
|
|
|
186
177
|
.SInputDropdown.small {
|
|
187
|
-
.
|
|
178
|
+
.box {
|
|
188
179
|
min-height: 40px;
|
|
189
180
|
}
|
|
190
181
|
|
|
191
|
-
.
|
|
192
|
-
padding:
|
|
182
|
+
.box-content {
|
|
183
|
+
padding: 5px 30px 5px 8px;
|
|
193
184
|
line-height: 24px;
|
|
194
|
-
font-size:
|
|
185
|
+
font-size: 16px;
|
|
195
186
|
}
|
|
196
187
|
|
|
197
|
-
.
|
|
188
|
+
.box-icon {
|
|
198
189
|
top: 7px;
|
|
199
190
|
right: 8px;
|
|
200
191
|
}
|
|
201
192
|
}
|
|
202
193
|
|
|
203
194
|
.SInputDropdown.medium {
|
|
204
|
-
.
|
|
195
|
+
.box {
|
|
205
196
|
height: 48px;
|
|
206
197
|
}
|
|
207
198
|
|
|
208
|
-
.
|
|
199
|
+
.box-content {
|
|
209
200
|
padding: 11px 44px 11px 16px;
|
|
210
201
|
line-height: 24px;
|
|
211
202
|
font-size: 16px;
|
|
212
203
|
}
|
|
213
204
|
|
|
214
|
-
.
|
|
205
|
+
.box-icon {
|
|
215
206
|
top: 11px;
|
|
216
207
|
right: 12px;
|
|
217
208
|
}
|
|
218
209
|
}
|
|
219
210
|
|
|
220
211
|
.SInputDropdown.disabled {
|
|
221
|
-
.
|
|
222
|
-
background-color: var(--
|
|
212
|
+
.box {
|
|
213
|
+
background-color: var(--c-bg);
|
|
223
214
|
cursor: not-allowed;
|
|
224
215
|
|
|
225
|
-
&:hover { border-color: var(--
|
|
226
|
-
&:focus:not(:focus-visible) { border-color: var(--
|
|
216
|
+
&:hover { border-color: var(--c-divider); }
|
|
217
|
+
&:focus:not(:focus-visible) { border-color: var(--c-divider); }
|
|
227
218
|
}
|
|
228
219
|
|
|
229
|
-
.
|
|
220
|
+
.box-icon {
|
|
230
221
|
cursor: not-allowed;
|
|
231
222
|
}
|
|
232
223
|
}
|
|
@@ -237,53 +228,63 @@ function getDifference(source: unknown[], value: unknown[]): unknown[] {
|
|
|
237
228
|
}
|
|
238
229
|
}
|
|
239
230
|
|
|
240
|
-
.
|
|
231
|
+
.container {
|
|
241
232
|
position: relative;
|
|
242
233
|
}
|
|
243
234
|
|
|
244
|
-
.
|
|
235
|
+
.box {
|
|
245
236
|
position: relative;
|
|
246
|
-
border: 1px solid var(--
|
|
247
|
-
border-radius:
|
|
237
|
+
border: 1px solid var(--c-divider);
|
|
238
|
+
border-radius: 6px;
|
|
248
239
|
width: 100%;
|
|
249
240
|
color: var(--input-text);
|
|
241
|
+
background-color: var(--c-bg);
|
|
250
242
|
cursor: pointer;
|
|
251
243
|
transition: border-color .25s, background-color .25s;
|
|
252
244
|
|
|
253
245
|
&:hover {
|
|
254
|
-
border-color: var(--
|
|
246
|
+
border-color: var(--c-black);
|
|
255
247
|
}
|
|
256
248
|
|
|
257
|
-
&:focus
|
|
258
|
-
|
|
259
|
-
|
|
249
|
+
&:focus,
|
|
250
|
+
&:hover.focus {
|
|
251
|
+
border-color: var(--c-info);
|
|
260
252
|
}
|
|
261
253
|
|
|
254
|
+
.dark &:hover {
|
|
255
|
+
border-color: var(--c-gray);
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
.dark &:focus,
|
|
259
|
+
.dark &:hover:focus {
|
|
260
|
+
border-color: var(--c-info);
|
|
261
|
+
}
|
|
262
262
|
}
|
|
263
263
|
|
|
264
|
-
.
|
|
264
|
+
.box-placeholder {
|
|
265
|
+
padding: 2px 4px;
|
|
265
266
|
font-weight: 500;
|
|
266
|
-
color: var(--
|
|
267
|
+
color: var(--c-text-3);
|
|
267
268
|
}
|
|
268
269
|
|
|
269
|
-
.
|
|
270
|
+
.box-icon {
|
|
270
271
|
position: absolute;
|
|
271
272
|
z-index: 10;
|
|
272
273
|
cursor: pointer;
|
|
273
274
|
}
|
|
274
275
|
|
|
275
|
-
.
|
|
276
|
+
.box-icon-svg {
|
|
276
277
|
display: block;
|
|
277
278
|
width: 14px;
|
|
278
279
|
height: 14px;
|
|
279
|
-
fill: var(--
|
|
280
|
+
fill: var(--c-text-2);
|
|
280
281
|
}
|
|
281
282
|
|
|
282
|
-
.
|
|
283
|
+
.box-icon-svg.up {
|
|
283
284
|
margin-bottom: -4px;
|
|
284
285
|
}
|
|
285
286
|
|
|
286
|
-
.
|
|
287
|
+
.dropdown {
|
|
287
288
|
position: absolute;
|
|
288
289
|
top: calc(100% + 8px);
|
|
289
290
|
left: 0;
|
|
@@ -1,63 +1,61 @@
|
|
|
1
|
-
<template>
|
|
2
|
-
<div class="SInputDropdownItem">
|
|
3
|
-
<div v-for="(i, index) in arrayItem" :key="index" class="item">
|
|
4
|
-
<component
|
|
5
|
-
:is="component(i)"
|
|
6
|
-
:mute="shouldMute(i)"
|
|
7
|
-
:item="i"
|
|
8
|
-
:disabled="disabled"
|
|
9
|
-
@remove="$emit('remove', i)"
|
|
10
|
-
/>
|
|
11
|
-
</div>
|
|
12
|
-
</div>
|
|
13
|
-
</template>
|
|
14
|
-
|
|
15
1
|
<script setup lang="ts">
|
|
16
|
-
import
|
|
17
|
-
import { isArray } from '../support/Utils'
|
|
2
|
+
import SInputDropdownItemAvatar from './SInputDropdownItemAvatar.vue'
|
|
18
3
|
import SInputDropdownItemText from './SInputDropdownItemText.vue'
|
|
19
|
-
import SInputDropdownItemTextTag from './SInputDropdownItemTextTag.vue'
|
|
20
|
-
import SInputDropdownItemUser from './SInputDropdownItemUser.vue'
|
|
21
|
-
import SInputDropdownItemUserTag from './SInputDropdownItemUserTag.vue'
|
|
22
|
-
|
|
23
|
-
const props = defineProps({
|
|
24
|
-
item: { type: [Object, Array] as PropType<any>, default: null },
|
|
25
|
-
disabled: { type: Boolean, default: false }
|
|
26
|
-
})
|
|
27
|
-
|
|
28
|
-
defineEmits(['remove'])
|
|
29
|
-
|
|
30
|
-
const isItemArray = computed(() => isArray(props.item))
|
|
31
4
|
|
|
32
|
-
|
|
33
|
-
return isArray(props.item) ? props.item : [props.item]
|
|
34
|
-
})
|
|
5
|
+
export type Item = ItemText | ItemAvatar
|
|
35
6
|
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
if (item.type === 'user') {
|
|
42
|
-
return isItemArray.value ? SInputDropdownItemUserTag : SInputDropdownItemUser
|
|
43
|
-
}
|
|
7
|
+
export interface ItemBase {
|
|
8
|
+
type?: 'text' | 'avatar'
|
|
9
|
+
value: string | number | boolean
|
|
10
|
+
}
|
|
44
11
|
|
|
45
|
-
|
|
12
|
+
export interface ItemText extends ItemBase {
|
|
13
|
+
type?: 'text'
|
|
14
|
+
label: string
|
|
46
15
|
}
|
|
47
16
|
|
|
48
|
-
|
|
49
|
-
|
|
17
|
+
export interface ItemAvatar extends ItemBase {
|
|
18
|
+
type: 'avatar'
|
|
19
|
+
label: string
|
|
20
|
+
image?: string | null
|
|
50
21
|
}
|
|
22
|
+
|
|
23
|
+
defineProps<{
|
|
24
|
+
items: Item[]
|
|
25
|
+
disabled: boolean
|
|
26
|
+
}>()
|
|
27
|
+
|
|
28
|
+
defineEmits<{
|
|
29
|
+
(e: 'remove', value: string | number | boolean): void
|
|
30
|
+
}>()
|
|
51
31
|
</script>
|
|
52
32
|
|
|
53
|
-
<
|
|
33
|
+
<template>
|
|
34
|
+
<div class="SInputDropdownItem">
|
|
35
|
+
<div v-for="(item, index) in items" :key="index" class="item">
|
|
36
|
+
<SInputDropdownItemText
|
|
37
|
+
v-if="item.type === 'text' || item.type === undefined"
|
|
38
|
+
:label="item.label"
|
|
39
|
+
:value="item.value"
|
|
40
|
+
:disabled="disabled"
|
|
41
|
+
@remove="(v) => $emit('remove', v)"
|
|
42
|
+
/>
|
|
43
|
+
<SInputDropdownItemAvatar
|
|
44
|
+
v-if="item.type === 'avatar'"
|
|
45
|
+
:label="item.label"
|
|
46
|
+
:image="item.image"
|
|
47
|
+
:value="item.value"
|
|
48
|
+
:disabled="disabled"
|
|
49
|
+
@remove="(v) => $emit('remove', v)"
|
|
50
|
+
/>
|
|
51
|
+
</div>
|
|
52
|
+
</div>
|
|
53
|
+
</template>
|
|
54
|
+
|
|
55
|
+
<style scoped lang="postcss">
|
|
54
56
|
.SInputDropdownItem {
|
|
55
57
|
display: flex;
|
|
56
58
|
flex-wrap: wrap;
|
|
57
|
-
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
.item {
|
|
61
|
-
padding: 2px;
|
|
59
|
+
gap: 4px;
|
|
62
60
|
}
|
|
63
61
|
</style>
|
|
@@ -1,14 +1,29 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import SAvatar from './SAvatar.vue'
|
|
3
|
+
import SIconX from './icons/SIconX.vue'
|
|
4
|
+
|
|
5
|
+
defineProps<{
|
|
6
|
+
label: string
|
|
7
|
+
image?: string | null
|
|
8
|
+
value: string | number | boolean
|
|
9
|
+
disabled: boolean
|
|
10
|
+
}>()
|
|
11
|
+
|
|
12
|
+
defineEmits<{
|
|
13
|
+
(e: 'remove', value: string | number | boolean): void
|
|
14
|
+
}>()
|
|
15
|
+
</script>
|
|
16
|
+
|
|
1
17
|
<template>
|
|
2
|
-
<div class="
|
|
18
|
+
<div class="SInputDropdownItemAvatar" :class="{ disabled }">
|
|
3
19
|
<div class="user">
|
|
4
20
|
<div class="avatar">
|
|
5
|
-
<SAvatar size="nano" :avatar="
|
|
21
|
+
<SAvatar size="nano" :avatar="image" :name="label" />
|
|
6
22
|
</div>
|
|
7
|
-
|
|
8
|
-
<p class="name">{{ item.name }}</p>
|
|
23
|
+
<p class="name">{{ label }}</p>
|
|
9
24
|
</div>
|
|
10
25
|
|
|
11
|
-
<div v-if="!disabled" class="remove" role="button" @click="$emit('remove')">
|
|
26
|
+
<div v-if="!disabled" class="remove" role="button" @click="$emit('remove', value)">
|
|
12
27
|
<div class="remove-box">
|
|
13
28
|
<SIconX class="remove-icon" />
|
|
14
29
|
</div>
|
|
@@ -16,49 +31,34 @@
|
|
|
16
31
|
</div>
|
|
17
32
|
</template>
|
|
18
33
|
|
|
19
|
-
<script setup lang="ts">
|
|
20
|
-
import { PropType } from 'vue'
|
|
21
|
-
import { UserItem } from '../composables/Dropdown'
|
|
22
|
-
import SIconX from './icons/SIconX.vue'
|
|
23
|
-
import SAvatar from './SAvatar.vue'
|
|
24
|
-
|
|
25
|
-
defineProps({
|
|
26
|
-
item: { type: Object as PropType<UserItem>, required: true },
|
|
27
|
-
disabled: { type: Boolean, default: false }
|
|
28
|
-
})
|
|
29
|
-
|
|
30
|
-
defineEmits(['remove'])
|
|
31
|
-
</script>
|
|
32
|
-
|
|
33
34
|
<style lang="postcss" scoped>
|
|
34
|
-
.
|
|
35
|
+
.SInputDropdownItemAvatar {
|
|
35
36
|
display: flex;
|
|
36
|
-
border
|
|
37
|
-
|
|
38
|
-
|
|
37
|
+
border: 1px solid var(--c-divider-light);
|
|
38
|
+
border-radius: 14px;
|
|
39
|
+
padding: 0;
|
|
40
|
+
background-color: var(--c-bg-mute);
|
|
39
41
|
}
|
|
40
42
|
|
|
41
|
-
.
|
|
43
|
+
.SInputDropdownItemUserAvatar.disabled {
|
|
42
44
|
padding: 0 10px 0 0;
|
|
43
45
|
background-color: var(--c-gray-light-4);
|
|
44
46
|
}
|
|
45
47
|
|
|
46
|
-
.dark .SInputDropdownItemUserTag {
|
|
47
|
-
background-color: var(--c-black-mute);
|
|
48
|
-
}
|
|
49
|
-
|
|
50
48
|
.user {
|
|
51
49
|
display: flex;
|
|
52
50
|
}
|
|
53
51
|
|
|
54
52
|
.avatar {
|
|
55
|
-
padding:
|
|
53
|
+
padding: 3px 0 0 3px;
|
|
56
54
|
}
|
|
57
55
|
|
|
58
56
|
.name {
|
|
59
|
-
|
|
57
|
+
margin: 0 0 0 8px;
|
|
58
|
+
line-height: 26px;
|
|
60
59
|
font-size: 12px;
|
|
61
60
|
font-weight: 500;
|
|
61
|
+
white-space: nowrap;
|
|
62
62
|
}
|
|
63
63
|
|
|
64
64
|
.remove {
|
|
@@ -66,19 +66,8 @@ defineEmits(['remove'])
|
|
|
66
66
|
justify-content: center;
|
|
67
67
|
align-items: center;
|
|
68
68
|
margin-left: 2px;
|
|
69
|
-
width:
|
|
70
|
-
height:
|
|
71
|
-
|
|
72
|
-
&:hover .remove-box {
|
|
73
|
-
color: var(--c-text-1);
|
|
74
|
-
background-color: var(--c-gray-light-4)
|
|
75
|
-
}
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
.dark .remove {
|
|
79
|
-
&:hover .remove-box {
|
|
80
|
-
background-color: var(--c-gray-dark-2)
|
|
81
|
-
}
|
|
69
|
+
width: 26px;
|
|
70
|
+
height: 26px;
|
|
82
71
|
}
|
|
83
72
|
|
|
84
73
|
.remove-box {
|
|
@@ -89,7 +78,17 @@ defineEmits(['remove'])
|
|
|
89
78
|
width: 20px;
|
|
90
79
|
height: 20px;
|
|
91
80
|
color: var(--c-text-2);
|
|
92
|
-
transition: color .25s, background-color .25s;
|
|
81
|
+
transition: color 0.25s, background-color 0.25s;
|
|
82
|
+
|
|
83
|
+
.remove:hover & {
|
|
84
|
+
color: var(--c-text-1);
|
|
85
|
+
background-color: var(--c-gray-light-3)
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
.dark .remove:hover & {
|
|
89
|
+
color: var(--c-text-1);
|
|
90
|
+
background-color: var(--c-gray-dark-3)
|
|
91
|
+
}
|
|
93
92
|
}
|
|
94
93
|
|
|
95
94
|
.remove-icon {
|