@globalbrain/sefirot 2.0.0-draft.8 → 2.1.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/README.md +6 -6
- package/lib/components/SAvatar.vue +17 -17
- package/lib/components/SButton.vue +520 -276
- 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 +190 -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 +4 -3
- package/lib/components/SInputCheckboxes.vue +74 -0
- package/lib/components/SInputDate.vue +182 -0
- package/lib/components/SInputDropdown.vue +159 -157
- package/lib/components/SInputDropdownItem.vue +46 -48
- package/lib/components/SInputDropdownItemAvatar.vue +99 -0
- package/lib/components/SInputDropdownItemText.vue +79 -16
- package/lib/components/SInputFile.vue +56 -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 +7 -6
- package/lib/components/SInputSwitch.vue +193 -0
- package/lib/components/SInputSwitches.vue +88 -0
- package/lib/components/SInputText.vue +207 -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 +33 -57
- package/lib/components/SMount.vue +19 -0
- package/lib/components/SSheet.vue +50 -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 +58 -47
- package/lib/components/{SPortalSnackbars.vue → SSnackbars.vue} +17 -20
- package/lib/components/{icons/SIconPreloader.vue → SSpinner.vue} +5 -4
- package/lib/components/SStep.vue +107 -0
- package/lib/components/SSteps.vue +59 -0
- package/lib/components/STable.vue +242 -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 +103 -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 +5 -9
- 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 +59 -37
- package/CHANGELOG.md +0 -47
- package/lib/.DS_Store +0 -0
- package/lib/components/.DS_Store +0 -0
- 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/SInputDropdownItemUserTag.vue +0 -100
- package/lib/components/SPortalModals.vue +0 -74
- package/lib/components/icons/.DS_Store +0 -0
- package/lib/components/icons/SIconActivity.vue +0 -5
- package/lib/components/icons/SIconArrowDown.vue +0 -5
- package/lib/components/icons/SIconArrowLeft.vue +0 -5
- package/lib/components/icons/SIconArrowRight.vue +0 -5
- package/lib/components/icons/SIconArrowUp.vue +0 -5
- package/lib/components/icons/SIconBarChart.vue +0 -7
- package/lib/components/icons/SIconBriefcase.vue +0 -5
- package/lib/components/icons/SIconBuilding.vue +0 -5
- package/lib/components/icons/SIconCalendar.vue +0 -5
- package/lib/components/icons/SIconCheck.vue +0 -5
- package/lib/components/icons/SIconCheckCircle.vue +0 -6
- package/lib/components/icons/SIconCheckCircleThin.vue +0 -6
- package/lib/components/icons/SIconCheckSquare.vue +0 -6
- package/lib/components/icons/SIconChevronDown.vue +0 -5
- package/lib/components/icons/SIconChevronLeft.vue +0 -5
- package/lib/components/icons/SIconChevronRight.vue +0 -5
- package/lib/components/icons/SIconChevronUp.vue +0 -5
- package/lib/components/icons/SIconClock.vue +0 -6
- package/lib/components/icons/SIconCode.vue +0 -6
- package/lib/components/icons/SIconDatabase.vue +0 -5
- package/lib/components/icons/SIconDollarSign.vue +0 -5
- package/lib/components/icons/SIconDownload.vue +0 -6
- package/lib/components/icons/SIconDownloadCloud.vue +0 -6
- package/lib/components/icons/SIconEdit.vue +0 -6
- package/lib/components/icons/SIconEdit2.vue +0 -5
- package/lib/components/icons/SIconEdit3.vue +0 -6
- package/lib/components/icons/SIconEdit3Off.vue +0 -6
- package/lib/components/icons/SIconExternalLink.vue +0 -6
- package/lib/components/icons/SIconEye.vue +0 -6
- package/lib/components/icons/SIconFile.vue +0 -5
- package/lib/components/icons/SIconFilePlus.vue +0 -6
- package/lib/components/icons/SIconFileText.vue +0 -8
- package/lib/components/icons/SIconFlag.vue +0 -5
- package/lib/components/icons/SIconGitBranch.vue +0 -5
- package/lib/components/icons/SIconGitCommit.vue +0 -5
- package/lib/components/icons/SIconGitPullRequest.vue +0 -6
- package/lib/components/icons/SIconGlobe.vue +0 -5
- package/lib/components/icons/SIconGrab.vue +0 -10
- package/lib/components/icons/SIconGrid.vue +0 -8
- package/lib/components/icons/SIconHome.vue +0 -5
- package/lib/components/icons/SIconImage.vue +0 -6
- package/lib/components/icons/SIconInbox.vue +0 -5
- package/lib/components/icons/SIconInfo.vue +0 -7
- package/lib/components/icons/SIconLayout.vue +0 -5
- package/lib/components/icons/SIconList.vue +0 -10
- package/lib/components/icons/SIconLock.vue +0 -5
- package/lib/components/icons/SIconLogout.vue +0 -6
- package/lib/components/icons/SIconMail.vue +0 -6
- package/lib/components/icons/SIconMapPin.vue +0 -6
- package/lib/components/icons/SIconMoon.vue +0 -5
- package/lib/components/icons/SIconMoreHorizontal.vue +0 -7
- package/lib/components/icons/SIconMoreVertical.vue +0 -7
- package/lib/components/icons/SIconPauseFill.vue +0 -6
- package/lib/components/icons/SIconPlayCircle.vue +0 -6
- package/lib/components/icons/SIconPlayFill.vue +0 -5
- package/lib/components/icons/SIconPlus.vue +0 -5
- package/lib/components/icons/SIconPlusCircle.vue +0 -8
- package/lib/components/icons/SIconPlusOff.vue +0 -7
- package/lib/components/icons/SIconPreloaderDark.vue +0 -52
- package/lib/components/icons/SIconPreloaderLight.vue +0 -52
- package/lib/components/icons/SIconProgress.vue +0 -5
- package/lib/components/icons/SIconRadio.vue +0 -6
- package/lib/components/icons/SIconSave.vue +0 -5
- package/lib/components/icons/SIconSearch.vue +0 -5
- package/lib/components/icons/SIconSend.vue +0 -5
- package/lib/components/icons/SIconSettings.vue +0 -6
- package/lib/components/icons/SIconShare2.vue +0 -5
- package/lib/components/icons/SIconSkipBackFill.vue +0 -6
- package/lib/components/icons/SIconSliders.vue +0 -12
- package/lib/components/icons/SIconSun.vue +0 -13
- package/lib/components/icons/SIconTelescope.vue +0 -5
- package/lib/components/icons/SIconTrash.vue +0 -5
- package/lib/components/icons/SIconTrash2.vue +0 -7
- package/lib/components/icons/SIconTrash2Off.vue +0 -6
- package/lib/components/icons/SIconTrello.vue +0 -7
- package/lib/components/icons/SIconUser.vue +0 -6
- package/lib/components/icons/SIconUsers.vue +0 -8
- package/lib/components/icons/SIconWarning.vue +0 -7
- package/lib/components/icons/SIconX.vue +0 -5
- package/lib/components/icons/SIconXCircle.vue +0 -6
- package/lib/components/icons/SIconXCircleThin.vue +0 -6
- package/lib/components/icons/SIconXSquare.vue +0 -6
- package/lib/components/icons/SIconZap.vue +0 -5
- 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,101 @@
|
|
|
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 IconCaretDown from '@iconify-icons/ph/caret-down'
|
|
3
|
+
import IconCaretUp from '@iconify-icons/ph/caret-up'
|
|
4
|
+
import xor from 'lodash-es/xor'
|
|
5
|
+
import { computed } from 'vue'
|
|
6
|
+
import type { DropdownSectionFilter } from '../composables/Dropdown'
|
|
47
7
|
import { useFlyout } from '../composables/Flyout'
|
|
48
|
-
import {
|
|
49
|
-
import
|
|
50
|
-
import SIconChevronDown from './icons/SIconChevronDown.vue'
|
|
8
|
+
import { Validatable } from '../composables/Validation'
|
|
9
|
+
import { isArray } from '../support/Utils'
|
|
51
10
|
import SDropdown from './SDropdown.vue'
|
|
11
|
+
import SIcon from './SIcon.vue'
|
|
52
12
|
import SInputBase from './SInputBase.vue'
|
|
53
13
|
import SInputDropdownItem from './SInputDropdownItem.vue'
|
|
54
14
|
|
|
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
|
-
})
|
|
15
|
+
export type Size = 'mini' | 'small' | 'medium'
|
|
16
|
+
export type PrimitiveValue = string | number | boolean | null
|
|
17
|
+
export type ArrayValue = (string | number | boolean)[]
|
|
18
|
+
export type OptionValue = string | number | boolean
|
|
19
|
+
|
|
20
|
+
export type Option = OptionText | OptionAvatar
|
|
72
21
|
|
|
73
|
-
|
|
22
|
+
export interface OptionBase {
|
|
23
|
+
type?: 'text' | 'avatar'
|
|
24
|
+
value: OptionValue
|
|
25
|
+
}
|
|
74
26
|
|
|
75
|
-
|
|
27
|
+
export interface OptionText extends OptionBase {
|
|
28
|
+
type?: 'text'
|
|
29
|
+
label: string
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export interface OptionAvatar extends OptionBase {
|
|
33
|
+
type: 'avatar'
|
|
34
|
+
label: string
|
|
35
|
+
image?: string | null
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
const props = defineProps<{
|
|
39
|
+
size?: Size
|
|
40
|
+
label?: string
|
|
41
|
+
note?: string
|
|
42
|
+
help?: string
|
|
43
|
+
placeholder?: string
|
|
44
|
+
noSearch?: boolean
|
|
45
|
+
nullable?: boolean
|
|
46
|
+
closeOnClick?: boolean
|
|
47
|
+
options: Option[]
|
|
48
|
+
disabled?: boolean
|
|
49
|
+
modelValue: PrimitiveValue | ArrayValue
|
|
50
|
+
validation?: Validatable
|
|
51
|
+
}>()
|
|
52
|
+
|
|
53
|
+
const emit = defineEmits<{
|
|
54
|
+
(e: 'update:modelValue', value: PrimitiveValue | ArrayValue): void
|
|
55
|
+
}>()
|
|
56
|
+
|
|
57
|
+
const { container, isOpen, open } = useFlyout()
|
|
76
58
|
|
|
77
59
|
const classes = computed(() => [
|
|
78
|
-
props.size,
|
|
60
|
+
props.size ?? 'small',
|
|
79
61
|
{ disabled: props.disabled }
|
|
80
62
|
])
|
|
81
63
|
|
|
82
|
-
const
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
closeOnClick: props.closeOnClick,
|
|
90
|
-
selected: computed(() => props.modelValue),
|
|
91
|
-
callback: handleCallback
|
|
92
|
-
})
|
|
64
|
+
const dropdownOptions = computed<DropdownSectionFilter[]>(() => [{
|
|
65
|
+
type: 'filter',
|
|
66
|
+
search: props.noSearch === undefined ? true : !props.noSearch,
|
|
67
|
+
selected: props.modelValue,
|
|
68
|
+
options: props.options,
|
|
69
|
+
onClick: handleSelect
|
|
70
|
+
}])
|
|
93
71
|
|
|
94
72
|
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
|
-
}
|
|
73
|
+
if (isArray(props.modelValue)) {
|
|
74
|
+
return props.options.filter((o) => (props.modelValue as ArrayValue).includes(o.value))
|
|
116
75
|
}
|
|
117
76
|
|
|
118
|
-
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
async function handleOpen(): Promise<void> {
|
|
122
|
-
if (!props.disabled) {
|
|
123
|
-
open()
|
|
77
|
+
const item = props.options.find((o) => o.value === props.modelValue)
|
|
124
78
|
|
|
125
|
-
|
|
79
|
+
return item ? [item] : []
|
|
80
|
+
})
|
|
126
81
|
|
|
127
|
-
|
|
82
|
+
const hasSelected = computed(() => {
|
|
83
|
+
return selected.value.length > 0
|
|
84
|
+
})
|
|
128
85
|
|
|
129
|
-
|
|
130
|
-
|
|
86
|
+
async function handleOpen() {
|
|
87
|
+
!props.disabled && open()
|
|
131
88
|
}
|
|
132
89
|
|
|
133
|
-
function
|
|
134
|
-
props.validation
|
|
90
|
+
function handleSelect(value: OptionValue) {
|
|
91
|
+
props.validation?.$touch()
|
|
135
92
|
|
|
136
|
-
isArray(props.modelValue) ? handleArray(
|
|
93
|
+
isArray(props.modelValue) ? handleArray(value) : handlePrimitive(value)
|
|
137
94
|
}
|
|
138
95
|
|
|
139
|
-
function handlePrimitive(value:
|
|
140
|
-
if (
|
|
141
|
-
emit('update:modelValue', value)
|
|
142
|
-
|
|
143
|
-
return
|
|
96
|
+
function handlePrimitive(value: OptionValue) {
|
|
97
|
+
if (value !== props.modelValue) {
|
|
98
|
+
return emit('update:modelValue', value)
|
|
144
99
|
}
|
|
145
100
|
|
|
146
101
|
if (props.nullable) {
|
|
@@ -148,8 +103,8 @@ function handlePrimitive(value: unknown): void {
|
|
|
148
103
|
}
|
|
149
104
|
}
|
|
150
105
|
|
|
151
|
-
function handleArray(value:
|
|
152
|
-
const difference =
|
|
106
|
+
function handleArray(value: OptionValue) {
|
|
107
|
+
const difference = xor(props.modelValue as ArrayValue, [value])
|
|
153
108
|
|
|
154
109
|
if (!props.nullable && difference.length === 0) {
|
|
155
110
|
return
|
|
@@ -157,76 +112,113 @@ function handleArray(value: unknown[]): void {
|
|
|
157
112
|
|
|
158
113
|
emit('update:modelValue', difference)
|
|
159
114
|
}
|
|
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
115
|
</script>
|
|
167
116
|
|
|
117
|
+
<template>
|
|
118
|
+
<SInputBase
|
|
119
|
+
class="SInputDropdown"
|
|
120
|
+
:class="classes"
|
|
121
|
+
:label="label"
|
|
122
|
+
:note="note"
|
|
123
|
+
:help="help"
|
|
124
|
+
:validation="validation"
|
|
125
|
+
>
|
|
126
|
+
<div class="container" ref="container">
|
|
127
|
+
<div
|
|
128
|
+
class="box"
|
|
129
|
+
role="button"
|
|
130
|
+
tabindex="0"
|
|
131
|
+
@click="handleOpen"
|
|
132
|
+
@keydown.down.prevent
|
|
133
|
+
@keyup.enter="handleOpen"
|
|
134
|
+
@keyup.down="handleOpen"
|
|
135
|
+
>
|
|
136
|
+
<div class="box-content">
|
|
137
|
+
<SInputDropdownItem
|
|
138
|
+
v-if="hasSelected"
|
|
139
|
+
:items="selected"
|
|
140
|
+
:disabled="disabled ?? false"
|
|
141
|
+
@remove="handleSelect"
|
|
142
|
+
/>
|
|
143
|
+
|
|
144
|
+
<div v-else class="box-placeholder">{{ placeholder }}</div>
|
|
145
|
+
</div>
|
|
146
|
+
|
|
147
|
+
<div class="box-icon">
|
|
148
|
+
<SIcon :icon="IconCaretUp" class="box-icon-svg up" />
|
|
149
|
+
<SIcon :icon="IconCaretDown" class="box-icon-svg down" />
|
|
150
|
+
</div>
|
|
151
|
+
</div>
|
|
152
|
+
|
|
153
|
+
<div v-if="isOpen" class="dropdown">
|
|
154
|
+
<SDropdown :sections="dropdownOptions" />
|
|
155
|
+
</div>
|
|
156
|
+
</div>
|
|
157
|
+
</SInputBase>
|
|
158
|
+
</template>
|
|
159
|
+
|
|
168
160
|
<style lang="postcss" scoped>
|
|
169
161
|
.SInputDropdown.mini {
|
|
170
|
-
.
|
|
162
|
+
.box {
|
|
171
163
|
min-height: 32px;
|
|
172
164
|
}
|
|
173
165
|
|
|
174
|
-
.
|
|
166
|
+
.box-content {
|
|
175
167
|
padding: 3px 30px 3px 12px;
|
|
176
168
|
line-height: 24px;
|
|
177
169
|
font-size: 14px;
|
|
178
170
|
}
|
|
179
171
|
|
|
180
|
-
.
|
|
172
|
+
.box-icon {
|
|
181
173
|
top: 3px;
|
|
182
174
|
right: 8px;
|
|
183
175
|
}
|
|
184
176
|
}
|
|
185
177
|
|
|
186
178
|
.SInputDropdown.small {
|
|
187
|
-
.
|
|
179
|
+
.box {
|
|
188
180
|
min-height: 40px;
|
|
189
181
|
}
|
|
190
182
|
|
|
191
|
-
.
|
|
192
|
-
padding:
|
|
183
|
+
.box-content {
|
|
184
|
+
padding: 5px 30px 5px 8px;
|
|
193
185
|
line-height: 24px;
|
|
194
|
-
font-size:
|
|
186
|
+
font-size: 16px;
|
|
195
187
|
}
|
|
196
188
|
|
|
197
|
-
.
|
|
189
|
+
.box-icon {
|
|
198
190
|
top: 7px;
|
|
199
191
|
right: 8px;
|
|
200
192
|
}
|
|
201
193
|
}
|
|
202
194
|
|
|
203
195
|
.SInputDropdown.medium {
|
|
204
|
-
.
|
|
196
|
+
.box {
|
|
205
197
|
height: 48px;
|
|
206
198
|
}
|
|
207
199
|
|
|
208
|
-
.
|
|
200
|
+
.box-content {
|
|
209
201
|
padding: 11px 44px 11px 16px;
|
|
210
202
|
line-height: 24px;
|
|
211
203
|
font-size: 16px;
|
|
212
204
|
}
|
|
213
205
|
|
|
214
|
-
.
|
|
206
|
+
.box-icon {
|
|
215
207
|
top: 11px;
|
|
216
208
|
right: 12px;
|
|
217
209
|
}
|
|
218
210
|
}
|
|
219
211
|
|
|
220
212
|
.SInputDropdown.disabled {
|
|
221
|
-
.
|
|
222
|
-
background-color: var(--
|
|
213
|
+
.box {
|
|
214
|
+
background-color: var(--c-bg);
|
|
223
215
|
cursor: not-allowed;
|
|
224
216
|
|
|
225
|
-
&:hover { border-color: var(--
|
|
226
|
-
&:focus:not(:focus-visible) { border-color: var(--
|
|
217
|
+
&:hover { border-color: var(--c-divider); }
|
|
218
|
+
&:focus:not(:focus-visible) { border-color: var(--c-divider); }
|
|
227
219
|
}
|
|
228
220
|
|
|
229
|
-
.
|
|
221
|
+
.box-icon {
|
|
230
222
|
cursor: not-allowed;
|
|
231
223
|
}
|
|
232
224
|
}
|
|
@@ -237,53 +229,63 @@ function getDifference(source: unknown[], value: unknown[]): unknown[] {
|
|
|
237
229
|
}
|
|
238
230
|
}
|
|
239
231
|
|
|
240
|
-
.
|
|
232
|
+
.container {
|
|
241
233
|
position: relative;
|
|
242
234
|
}
|
|
243
235
|
|
|
244
|
-
.
|
|
236
|
+
.box {
|
|
245
237
|
position: relative;
|
|
246
|
-
border: 1px solid var(--
|
|
247
|
-
border-radius:
|
|
238
|
+
border: 1px solid var(--c-divider);
|
|
239
|
+
border-radius: 6px;
|
|
248
240
|
width: 100%;
|
|
249
241
|
color: var(--input-text);
|
|
242
|
+
background-color: var(--c-bg);
|
|
250
243
|
cursor: pointer;
|
|
251
244
|
transition: border-color .25s, background-color .25s;
|
|
252
245
|
|
|
253
246
|
&:hover {
|
|
254
|
-
border-color: var(--
|
|
247
|
+
border-color: var(--c-black);
|
|
255
248
|
}
|
|
256
249
|
|
|
257
|
-
&:focus
|
|
258
|
-
|
|
259
|
-
|
|
250
|
+
&:focus,
|
|
251
|
+
&:hover.focus {
|
|
252
|
+
border-color: var(--c-info);
|
|
260
253
|
}
|
|
261
254
|
|
|
255
|
+
.dark &:hover {
|
|
256
|
+
border-color: var(--c-gray);
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
.dark &:focus,
|
|
260
|
+
.dark &:hover:focus {
|
|
261
|
+
border-color: var(--c-info);
|
|
262
|
+
}
|
|
262
263
|
}
|
|
263
264
|
|
|
264
|
-
.
|
|
265
|
+
.box-placeholder {
|
|
266
|
+
padding: 2px 4px;
|
|
265
267
|
font-weight: 500;
|
|
266
|
-
color: var(--
|
|
268
|
+
color: var(--c-text-3);
|
|
267
269
|
}
|
|
268
270
|
|
|
269
|
-
.
|
|
271
|
+
.box-icon {
|
|
270
272
|
position: absolute;
|
|
271
273
|
z-index: 10;
|
|
272
274
|
cursor: pointer;
|
|
273
275
|
}
|
|
274
276
|
|
|
275
|
-
.
|
|
277
|
+
.box-icon-svg {
|
|
276
278
|
display: block;
|
|
277
279
|
width: 14px;
|
|
278
280
|
height: 14px;
|
|
279
|
-
|
|
281
|
+
color: var(--c-text-2);
|
|
280
282
|
}
|
|
281
283
|
|
|
282
|
-
.
|
|
284
|
+
.box-icon-svg.up {
|
|
283
285
|
margin-bottom: -4px;
|
|
284
286
|
}
|
|
285
287
|
|
|
286
|
-
.
|
|
288
|
+
.dropdown {
|
|
287
289
|
position: absolute;
|
|
288
290
|
top: calc(100% + 8px);
|
|
289
291
|
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>
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import IconX from '@iconify-icons/ph/x'
|
|
3
|
+
import SAvatar from './SAvatar.vue'
|
|
4
|
+
import SIcon from './SIcon.vue'
|
|
5
|
+
|
|
6
|
+
defineProps<{
|
|
7
|
+
label: string
|
|
8
|
+
image?: string | null
|
|
9
|
+
value: string | number | boolean
|
|
10
|
+
disabled: boolean
|
|
11
|
+
}>()
|
|
12
|
+
|
|
13
|
+
defineEmits<{
|
|
14
|
+
(e: 'remove', value: string | number | boolean): void
|
|
15
|
+
}>()
|
|
16
|
+
</script>
|
|
17
|
+
|
|
18
|
+
<template>
|
|
19
|
+
<div class="SInputDropdownItemAvatar" :class="{ disabled }">
|
|
20
|
+
<div class="user">
|
|
21
|
+
<div class="avatar">
|
|
22
|
+
<SAvatar size="nano" :avatar="image" :name="label" />
|
|
23
|
+
</div>
|
|
24
|
+
<p class="name">{{ label }}</p>
|
|
25
|
+
</div>
|
|
26
|
+
|
|
27
|
+
<div v-if="!disabled" class="remove" role="button" @click="$emit('remove', value)">
|
|
28
|
+
<div class="remove-box">
|
|
29
|
+
<SIcon :icon="IconX" class="remove-icon" />
|
|
30
|
+
</div>
|
|
31
|
+
</div>
|
|
32
|
+
</div>
|
|
33
|
+
</template>
|
|
34
|
+
|
|
35
|
+
<style lang="postcss" scoped>
|
|
36
|
+
.SInputDropdownItemAvatar {
|
|
37
|
+
display: flex;
|
|
38
|
+
border: 1px solid var(--c-divider-light);
|
|
39
|
+
border-radius: 14px;
|
|
40
|
+
padding: 0;
|
|
41
|
+
background-color: var(--c-bg-mute);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
.SInputDropdownItemUserAvatar.disabled {
|
|
45
|
+
padding: 0 10px 0 0;
|
|
46
|
+
background-color: var(--c-gray-light-4);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
.user {
|
|
50
|
+
display: flex;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
.avatar {
|
|
54
|
+
padding: 3px 0 0 3px;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
.name {
|
|
58
|
+
margin: 0 0 0 8px;
|
|
59
|
+
line-height: 26px;
|
|
60
|
+
font-size: 12px;
|
|
61
|
+
font-weight: 500;
|
|
62
|
+
white-space: nowrap;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
.remove {
|
|
66
|
+
display: flex;
|
|
67
|
+
justify-content: center;
|
|
68
|
+
align-items: center;
|
|
69
|
+
margin-left: 2px;
|
|
70
|
+
width: 26px;
|
|
71
|
+
height: 26px;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
.remove-box {
|
|
75
|
+
display: flex;
|
|
76
|
+
justify-content: center;
|
|
77
|
+
align-items: center;
|
|
78
|
+
border-radius: 50%;
|
|
79
|
+
width: 20px;
|
|
80
|
+
height: 20px;
|
|
81
|
+
color: var(--c-text-2);
|
|
82
|
+
transition: color 0.25s, background-color 0.25s;
|
|
83
|
+
|
|
84
|
+
.remove:hover & {
|
|
85
|
+
color: var(--c-text-1);
|
|
86
|
+
background-color: var(--c-gray-light-3)
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
.dark .remove:hover & {
|
|
90
|
+
color: var(--c-text-1);
|
|
91
|
+
background-color: var(--c-gray-dark-3)
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
.remove-icon {
|
|
96
|
+
width: 12px;
|
|
97
|
+
height: 12px;
|
|
98
|
+
}
|
|
99
|
+
</style>
|