@opendesign-plus-test/components 0.0.1-rc.50 → 0.0.1-rc.51
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/dist/chunk-OElCookieNotice.cjs.js +1 -1
- package/dist/chunk-OElCookieNotice.es.js +68 -48
- package/dist/components/OHeaderSearch.vue.d.ts +814 -534
- package/dist/components/OThemeSwitcher.vue.d.ts +5 -2
- package/dist/components/activity/index.d.ts +2 -2
- package/dist/components/meeting/index.d.ts +3 -3
- package/dist/components/search/OSearchInput.vue.d.ts +1003 -0
- package/dist/components/search/composables/useImageSearch.d.ts +48 -0
- package/dist/components/search/composables/useKeywordHighlight.d.ts +2 -0
- package/dist/components/search/composables/useSearchHistory.d.ts +14 -0
- package/dist/components/search/index.d.ts +590 -0
- package/dist/components/search/internal/HighlightText.vue.d.ts +9 -0
- package/dist/components/search/internal/SearchImageInput.vue.d.ts +716 -0
- package/dist/components/search/internal/SearchPanel.vue.d.ts +100 -0
- package/dist/components/search/types.d.ts +20 -0
- package/dist/components.cjs.js +42 -42
- package/dist/components.css +1 -1
- package/dist/components.es.js +11517 -10501
- package/dist/index.d.ts +1 -0
- package/package.json +4 -2
- package/src/assets/svg-icons/icon-delete-hover.svg +4 -0
- package/src/assets/svg-icons/icon-delete.svg +5 -1
- package/src/assets/svg-icons/icon-image-close.svg +4 -0
- package/src/assets/svg-icons/icon-image-upload.svg +3 -0
- package/src/assets/svg-icons/icon-image-zoomin.svg +3 -0
- package/src/assets/svg-icons/icon-refresh.svg +3 -0
- package/src/components/OHeaderSearch.vue +437 -415
- package/src/components/OThemeSwitcher.vue +27 -51
- package/src/components/activity/OActivityApproval.vue +6 -10
- package/src/components/activity/OActivityForm.vue +3 -5
- package/src/components/activity/{OActivityMyCalendar.vue → OMyActivityCalendar.vue} +21 -43
- package/src/components/activity/index.ts +4 -4
- package/src/components/events/OEventsApply.vue +1 -2
- package/src/components/events/OEventsCalendar.vue +5 -7
- package/src/components/events/OEventsList.vue +4 -6
- package/src/components/meeting/OMeetingCalendar.vue +12 -15
- package/src/components/meeting/OMeetingForm.vue +10 -16
- package/src/components/meeting/OMeetingPlayback.vue +8 -32
- package/src/components/meeting/{OMeetingMyCalendar.vue → OMyMeetingCalendar.vue} +38 -73
- package/src/components/meeting/{OMeetingSigCalendar.vue → OSigMeetingCalendar.vue} +3 -6
- package/src/components/meeting/components/OMeetingCalendarList.vue +3 -3
- package/src/components/meeting/components/OMeetingCalendarSelector.vue +1 -1
- package/src/components/meeting/components/OMeetingPlaybackSubtitles.vue +9 -10
- package/src/components/meeting/components/OMeetingPlaybackVideo.vue +6 -6
- package/src/components/meeting/components/{OMeetingSigAside.vue → OSigMeetingAside.vue} +1 -1
- package/src/components/meeting/config.ts +1 -1
- package/src/components/meeting/index.ts +8 -8
- package/src/components/search/OSearchInput.vue +463 -0
- package/src/components/search/composables/useImageSearch.ts +157 -0
- package/src/components/search/composables/useKeywordHighlight.ts +30 -0
- package/src/components/search/composables/useSearchHistory.ts +75 -0
- package/src/components/search/index.ts +23 -0
- package/src/components/search/internal/HighlightText.vue +37 -0
- package/src/components/search/internal/SearchImageInput.vue +488 -0
- package/src/components/search/internal/SearchPanel.vue +430 -0
- package/src/components/search/types.ts +25 -0
- package/src/i18n/en.ts +12 -2
- package/src/i18n/zh.ts +10 -0
- package/src/index.ts +1 -0
- package/vite.config.ts +5 -1
- package/src/assets/styles/element-plus.scss +0 -204
- /package/dist/components/activity/{OActivityMyCalendar.vue.d.ts → OMyActivityCalendar.vue.d.ts} +0 -0
- /package/dist/components/meeting/{OMeetingMyCalendar.vue.d.ts → OMyMeetingCalendar.vue.d.ts} +0 -0
- /package/dist/components/meeting/{OMeetingSigCalendar.vue.d.ts → OSigMeetingCalendar.vue.d.ts} +0 -0
- /package/dist/components/meeting/components/{OMeetingSigAside.vue.d.ts → OSigMeetingAside.vue.d.ts} +0 -0
|
@@ -264,7 +264,7 @@ defineExpose({
|
|
|
264
264
|
min-height: calc(var(--layout-content-min-height) - 104px);
|
|
265
265
|
background-color: var(--o-color-fill2);
|
|
266
266
|
position: relative;
|
|
267
|
-
border-radius: var(--
|
|
267
|
+
border-radius: var(--o-radius-xs);
|
|
268
268
|
overflow: hidden;
|
|
269
269
|
|
|
270
270
|
.video-placeholder {
|
|
@@ -443,7 +443,7 @@ defineExpose({
|
|
|
443
443
|
width: calc(100% + 5em);
|
|
444
444
|
max-height: 22em;
|
|
445
445
|
padding: 8px 16px;
|
|
446
|
-
border-radius: var(--
|
|
446
|
+
border-radius: var(--o-radius-xs);
|
|
447
447
|
margin-left: -2.5em;
|
|
448
448
|
background-color: var(--o-color-info2);
|
|
449
449
|
box-shadow: 0 3px 9px 0 rgba(var(--o-kleinblue-10), 0.08);
|
|
@@ -509,7 +509,7 @@ defineExpose({
|
|
|
509
509
|
input {
|
|
510
510
|
order: 1;
|
|
511
511
|
margin-right: 12px;
|
|
512
|
-
border-radius:
|
|
512
|
+
border-radius: 4px;
|
|
513
513
|
cursor: inherit;
|
|
514
514
|
position: relative;
|
|
515
515
|
top: -1px;
|
|
@@ -598,7 +598,7 @@ defineExpose({
|
|
|
598
598
|
}
|
|
599
599
|
|
|
600
600
|
.vjs-volume-control {
|
|
601
|
-
border-radius: var(--
|
|
601
|
+
border-radius: var(--o-radius-xs);
|
|
602
602
|
background-color: var(--o-color-info2);
|
|
603
603
|
box-shadow: 0 3px 9px 0 rgba(var(--o-kleinblue-10), 0.08);
|
|
604
604
|
backdrop-filter: blur(13.59);
|
|
@@ -647,7 +647,7 @@ defineExpose({
|
|
|
647
647
|
left: 0;
|
|
648
648
|
|
|
649
649
|
div {
|
|
650
|
-
border-radius:
|
|
650
|
+
border-radius: 4px;
|
|
651
651
|
}
|
|
652
652
|
|
|
653
653
|
.vjs-progress-holder {
|
|
@@ -692,7 +692,7 @@ defineExpose({
|
|
|
692
692
|
width: fit-content !important;
|
|
693
693
|
color: var(--o-color-info1-inverse) !important;
|
|
694
694
|
background-color: rgba(0, 0, 0, 0.4) !important;
|
|
695
|
-
border-radius: var(--
|
|
695
|
+
border-radius: var(--o-radius-xs);
|
|
696
696
|
display: block !important;
|
|
697
697
|
padding: var(--o-gap-1) var(--o-gap-4);
|
|
698
698
|
@include tip1;
|
|
@@ -7,7 +7,7 @@ import IconSummit from '~icons/meeting/icon-summit.svg';
|
|
|
7
7
|
export const TYPE_COLOR_MAP = {
|
|
8
8
|
summit: 'rgba(var(--o-orange-6))',
|
|
9
9
|
events: 'rgba(var(--o-cyan-6))',
|
|
10
|
-
meeting: 'rgba(var(--o-
|
|
10
|
+
meeting: 'rgba(var(--o-deep-blue-6))',
|
|
11
11
|
};
|
|
12
12
|
|
|
13
13
|
export const INTERVAL_DAY = 0;
|
|
@@ -2,8 +2,8 @@ import type { App } from 'vue';
|
|
|
2
2
|
import _OMeetingCalendar from './OMeetingCalendar.vue';
|
|
3
3
|
import _OMeetingForm from './OMeetingForm.vue';
|
|
4
4
|
import _OMeetingPlayback from './OMeetingPlayback.vue';
|
|
5
|
-
import
|
|
6
|
-
import
|
|
5
|
+
import _OSigMeetingCalendar from './OSigMeetingCalendar.vue';
|
|
6
|
+
import _OMyMeetingCalendar from './OMyMeetingCalendar.vue';
|
|
7
7
|
|
|
8
8
|
const OMeetingCalendar = Object.assign(_OMeetingCalendar, {
|
|
9
9
|
install(app: App) {
|
|
@@ -22,15 +22,15 @@ const OMeetingPlayback = Object.assign(_OMeetingPlayback, {
|
|
|
22
22
|
},
|
|
23
23
|
});
|
|
24
24
|
|
|
25
|
-
const
|
|
25
|
+
const OSigMeetingCalendar = Object.assign(_OSigMeetingCalendar, {
|
|
26
26
|
install(app: App) {
|
|
27
|
-
app.component('
|
|
27
|
+
app.component('OSigMeetingCalendar', _OSigMeetingCalendar);
|
|
28
28
|
},
|
|
29
29
|
});
|
|
30
30
|
|
|
31
|
-
const
|
|
31
|
+
const OMyMeetingCalendar = Object.assign(_OMyMeetingCalendar, {
|
|
32
32
|
install(app: App) {
|
|
33
|
-
app.component('
|
|
33
|
+
app.component('OMyMeetingCalendar', _OMyMeetingCalendar);
|
|
34
34
|
},
|
|
35
35
|
});
|
|
36
36
|
|
|
@@ -38,8 +38,8 @@ export {
|
|
|
38
38
|
OMeetingCalendar,
|
|
39
39
|
OMeetingForm,
|
|
40
40
|
OMeetingPlayback,
|
|
41
|
-
|
|
42
|
-
|
|
41
|
+
OSigMeetingCalendar,
|
|
42
|
+
OMyMeetingCalendar,
|
|
43
43
|
};
|
|
44
44
|
|
|
45
45
|
export * from './types';
|
|
@@ -0,0 +1,463 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import { computed, ref, toRef, watch } from 'vue';
|
|
3
|
+
import { onClickOutside, useDebounceFn } from '@vueuse/core';
|
|
4
|
+
|
|
5
|
+
import SearchImageInput from './internal/SearchImageInput.vue';
|
|
6
|
+
import SearchPanel from './internal/SearchPanel.vue';
|
|
7
|
+
import { useSearchHistory } from './composables/useSearchHistory';
|
|
8
|
+
import { useI18n } from '@/i18n';
|
|
9
|
+
import type {
|
|
10
|
+
OSearchPayload,
|
|
11
|
+
OSearchRecommendItem,
|
|
12
|
+
OSearchUploadImageFn,
|
|
13
|
+
} from './types';
|
|
14
|
+
|
|
15
|
+
export interface OSearchInputPropsT {
|
|
16
|
+
modelValue?: string;
|
|
17
|
+
imageUrl?: string;
|
|
18
|
+
size?: 'small' | 'medium' | 'large';
|
|
19
|
+
placeholder?: string;
|
|
20
|
+
imagePlaceholder?: string;
|
|
21
|
+
|
|
22
|
+
/** ---- Image search ---- */
|
|
23
|
+
enableImageSearch?: boolean;
|
|
24
|
+
uploadImage?: OSearchUploadImageFn;
|
|
25
|
+
maxImageSize?: number;
|
|
26
|
+
imageUploadTooltip?: string;
|
|
27
|
+
|
|
28
|
+
/** ---- Recommendation lists (controlled by parent) ---- */
|
|
29
|
+
suggestItems?: OSearchRecommendItem[];
|
|
30
|
+
onestepItems?: OSearchRecommendItem[];
|
|
31
|
+
suggestTitle?: string;
|
|
32
|
+
onestepTitle?: string;
|
|
33
|
+
noDataText?: string;
|
|
34
|
+
/** When true, show "no data" placeholder for empty suggest while typing */
|
|
35
|
+
showSuggestEmpty?: boolean;
|
|
36
|
+
highlightKeyword?: boolean;
|
|
37
|
+
debounce?: number;
|
|
38
|
+
|
|
39
|
+
/** ---- History ---- */
|
|
40
|
+
enableHistory?: boolean;
|
|
41
|
+
historyItems?: string[];
|
|
42
|
+
maxHistoryCount?: number;
|
|
43
|
+
storeHistory?: boolean;
|
|
44
|
+
storageKey?: string;
|
|
45
|
+
historyTitle?: string;
|
|
46
|
+
/** Auto-record history on search; default true */
|
|
47
|
+
autoSaveHistory?: boolean;
|
|
48
|
+
|
|
49
|
+
/** ---- "Did you mean" list (below input) ---- */
|
|
50
|
+
suggestList?: string[];
|
|
51
|
+
suggestListLabel?: string;
|
|
52
|
+
/** When true, render suggestList items as HTML (with v-html on inert string) */
|
|
53
|
+
allowHtmlInSuggest?: boolean;
|
|
54
|
+
|
|
55
|
+
/** ---- Misc ---- */
|
|
56
|
+
clearable?: boolean;
|
|
57
|
+
closeOnSearch?: boolean;
|
|
58
|
+
closeOnClickOutside?: boolean;
|
|
59
|
+
/** Show dropdown on focus even when empty (history) */
|
|
60
|
+
openOnFocus?: boolean;
|
|
61
|
+
/** Always show image as inline thumbnail inside the input; never expand preview below */
|
|
62
|
+
alwaysInlineThumbnail?: boolean;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
const props = withDefaults(defineProps<OSearchInputPropsT>(), {
|
|
66
|
+
modelValue: '',
|
|
67
|
+
imageUrl: '',
|
|
68
|
+
size: 'large',
|
|
69
|
+
enableImageSearch: false,
|
|
70
|
+
maxImageSize: 10 * 1024 * 1024,
|
|
71
|
+
suggestItems: () => [],
|
|
72
|
+
onestepItems: () => [],
|
|
73
|
+
showSuggestEmpty: true,
|
|
74
|
+
highlightKeyword: true,
|
|
75
|
+
debounce: 300,
|
|
76
|
+
enableHistory: true,
|
|
77
|
+
historyItems: () => [],
|
|
78
|
+
maxHistoryCount: 6,
|
|
79
|
+
storeHistory: false,
|
|
80
|
+
storageKey: 'search-history',
|
|
81
|
+
autoSaveHistory: true,
|
|
82
|
+
suggestList: () => [],
|
|
83
|
+
allowHtmlInSuggest: false,
|
|
84
|
+
clearable: true,
|
|
85
|
+
closeOnSearch: true,
|
|
86
|
+
closeOnClickOutside: true,
|
|
87
|
+
openOnFocus: true,
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
const emit = defineEmits<{
|
|
91
|
+
(e: 'update:modelValue', val: string): void;
|
|
92
|
+
(e: 'update:imageUrl', url: string): void;
|
|
93
|
+
(e: 'update:historyItems', items: string[]): void;
|
|
94
|
+
(e: 'focus'): void;
|
|
95
|
+
(e: 'blur'): void;
|
|
96
|
+
(e: 'input', val: string): void;
|
|
97
|
+
(e: 'clear'): void;
|
|
98
|
+
(e: 'search', payload: OSearchPayload): void;
|
|
99
|
+
(e: 'recommend-click', item: OSearchRecommendItem): void;
|
|
100
|
+
(e: 'onestep-click', item: OSearchRecommendItem): void;
|
|
101
|
+
(e: 'history-click', val: string): void;
|
|
102
|
+
(e: 'suggest-list-click', val: string): void;
|
|
103
|
+
(e: 'delete-history', items: string[]): void;
|
|
104
|
+
(e: 'delete-history-item', val: string): void;
|
|
105
|
+
(e: 'image-upload-start', file: File): void;
|
|
106
|
+
(e: 'image-upload-success', url: string, file: File): void;
|
|
107
|
+
(e: 'image-upload-error', error: unknown, file: File): void;
|
|
108
|
+
(e: 'image-validate-error', reason: 'size' | 'type', file: File): void;
|
|
109
|
+
}>();
|
|
110
|
+
|
|
111
|
+
const { t } = useI18n();
|
|
112
|
+
|
|
113
|
+
const inputRef = ref<InstanceType<typeof SearchImageInput>>();
|
|
114
|
+
const wrapperRef = ref<HTMLElement | null>(null);
|
|
115
|
+
|
|
116
|
+
const innerValue = computed({
|
|
117
|
+
get: () => props.modelValue,
|
|
118
|
+
set: (val: string) => emit('update:modelValue', val),
|
|
119
|
+
});
|
|
120
|
+
|
|
121
|
+
const isFocus = ref(false);
|
|
122
|
+
const isPreviewOpen = ref(false);
|
|
123
|
+
const justClosedPreview = ref(false);
|
|
124
|
+
const hasInternalImage = ref(false);
|
|
125
|
+
|
|
126
|
+
const showDropdown = computed(() => {
|
|
127
|
+
if (!isFocus.value) return false;
|
|
128
|
+
if (props.imageUrl || hasInternalImage.value) return false;
|
|
129
|
+
const hasSuggest =
|
|
130
|
+
!!innerValue.value &&
|
|
131
|
+
(props.suggestItems.length > 0 || props.onestepItems.length > 0 || props.showSuggestEmpty);
|
|
132
|
+
const hasHistory = props.enableHistory && history.items.value.length > 0 && !innerValue.value;
|
|
133
|
+
if (hasSuggest) return true;
|
|
134
|
+
if (props.openOnFocus && hasHistory) return true;
|
|
135
|
+
return false;
|
|
136
|
+
});
|
|
137
|
+
|
|
138
|
+
// history
|
|
139
|
+
const historyItemsRef = toRef(props, 'historyItems');
|
|
140
|
+
const storageKeyRef = toRef(props, 'storageKey');
|
|
141
|
+
const storeHistoryRef = toRef(props, 'storeHistory');
|
|
142
|
+
const maxHistoryRef = toRef(props, 'maxHistoryCount');
|
|
143
|
+
|
|
144
|
+
const history = useSearchHistory({
|
|
145
|
+
initial: historyItemsRef,
|
|
146
|
+
storageKey: storageKeyRef,
|
|
147
|
+
storeHistory: storeHistoryRef,
|
|
148
|
+
maxHistoryCount: maxHistoryRef,
|
|
149
|
+
onChange: (items) => emit('update:historyItems', items),
|
|
150
|
+
});
|
|
151
|
+
|
|
152
|
+
// debounced input event
|
|
153
|
+
const emitInputDebounced = useDebounceFn((val: string) => {
|
|
154
|
+
emit('input', val);
|
|
155
|
+
}, () => props.debounce);
|
|
156
|
+
|
|
157
|
+
watch(innerValue, (val) => {
|
|
158
|
+
emitInputDebounced(val);
|
|
159
|
+
});
|
|
160
|
+
|
|
161
|
+
// click outside
|
|
162
|
+
onClickOutside(wrapperRef, () => {
|
|
163
|
+
if (!props.closeOnClickOutside) return;
|
|
164
|
+
if (isPreviewOpen.value || justClosedPreview.value) return;
|
|
165
|
+
isFocus.value = false;
|
|
166
|
+
});
|
|
167
|
+
|
|
168
|
+
const handleFocus = () => {
|
|
169
|
+
isFocus.value = true;
|
|
170
|
+
emit('focus');
|
|
171
|
+
};
|
|
172
|
+
|
|
173
|
+
const handleBlur = () => {
|
|
174
|
+
emit('blur');
|
|
175
|
+
};
|
|
176
|
+
|
|
177
|
+
const runSearch = async () => {
|
|
178
|
+
if (inputRef.value?.getIsUploading?.()) {
|
|
179
|
+
await inputRef.value.awaitUpload?.();
|
|
180
|
+
}
|
|
181
|
+
const keyword = innerValue.value.trim();
|
|
182
|
+
const imageUrl = inputRef.value?.getUploadedUrl?.() || props.imageUrl;
|
|
183
|
+
|
|
184
|
+
if (!keyword && !imageUrl) return;
|
|
185
|
+
|
|
186
|
+
if (props.autoSaveHistory && keyword) {
|
|
187
|
+
history.push(keyword);
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
if (props.closeOnSearch) {
|
|
191
|
+
isFocus.value = false;
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
emit('search', { keyword, imageUrl: imageUrl || undefined });
|
|
195
|
+
};
|
|
196
|
+
|
|
197
|
+
const handleClear = () => {
|
|
198
|
+
innerValue.value = '';
|
|
199
|
+
emit('clear');
|
|
200
|
+
};
|
|
201
|
+
|
|
202
|
+
const handleSuggestClick = (item: OSearchRecommendItem) => {
|
|
203
|
+
emit('recommend-click', item);
|
|
204
|
+
innerValue.value = item.key;
|
|
205
|
+
runSearch();
|
|
206
|
+
};
|
|
207
|
+
|
|
208
|
+
const handleOnestepClick = (item: OSearchRecommendItem) => {
|
|
209
|
+
emit('onestep-click', item);
|
|
210
|
+
if (item.path) {
|
|
211
|
+
const url = item.path;
|
|
212
|
+
if (typeof window !== 'undefined') window.open(url, '_blank', 'noopener,noreferrer');
|
|
213
|
+
}
|
|
214
|
+
};
|
|
215
|
+
|
|
216
|
+
const handleHistoryClick = (val: string) => {
|
|
217
|
+
emit('history-click', val);
|
|
218
|
+
innerValue.value = val;
|
|
219
|
+
runSearch();
|
|
220
|
+
};
|
|
221
|
+
|
|
222
|
+
const handleHistoryRemove = (val: string) => {
|
|
223
|
+
history.remove(val);
|
|
224
|
+
emit('delete-history-item', val);
|
|
225
|
+
};
|
|
226
|
+
|
|
227
|
+
const handleHistoryClear = () => {
|
|
228
|
+
const removed = [...history.items.value];
|
|
229
|
+
history.clearAll();
|
|
230
|
+
emit('delete-history', removed);
|
|
231
|
+
};
|
|
232
|
+
|
|
233
|
+
const handleSuggestListClick = (val: string) => {
|
|
234
|
+
// Strip HTML tags when raw HTML is allowed for display
|
|
235
|
+
const text = props.allowHtmlInSuggest ? val.replace(/<[^>]+>/g, '') : val;
|
|
236
|
+
emit('suggest-list-click', text);
|
|
237
|
+
innerValue.value = text;
|
|
238
|
+
runSearch();
|
|
239
|
+
};
|
|
240
|
+
|
|
241
|
+
const onPreviewChange = (visible: boolean) => {
|
|
242
|
+
isPreviewOpen.value = visible;
|
|
243
|
+
if (!visible) {
|
|
244
|
+
justClosedPreview.value = true;
|
|
245
|
+
setTimeout(() => {
|
|
246
|
+
justClosedPreview.value = false;
|
|
247
|
+
}, 100);
|
|
248
|
+
}
|
|
249
|
+
};
|
|
250
|
+
|
|
251
|
+
const showInlineThumbnail = computed(() =>
|
|
252
|
+
!!props.imageUrl && (props.alwaysInlineThumbnail || !isFocus.value)
|
|
253
|
+
);
|
|
254
|
+
|
|
255
|
+
const onImageUploadStart = (file: File) => {
|
|
256
|
+
hasInternalImage.value = true;
|
|
257
|
+
emit('image-upload-start', file);
|
|
258
|
+
};
|
|
259
|
+
|
|
260
|
+
const onImageUploadSuccess = (url: string, file: File) => {
|
|
261
|
+
hasInternalImage.value = false;
|
|
262
|
+
emit('image-upload-success', url, file);
|
|
263
|
+
};
|
|
264
|
+
|
|
265
|
+
const onImageClear = () => {
|
|
266
|
+
hasInternalImage.value = false;
|
|
267
|
+
emit('update:imageUrl', '');
|
|
268
|
+
};
|
|
269
|
+
|
|
270
|
+
defineExpose({
|
|
271
|
+
focus: () => inputRef.value?.focus?.(),
|
|
272
|
+
blur: () => inputRef.value?.blur?.(),
|
|
273
|
+
search: runSearch,
|
|
274
|
+
saveHistory: (val?: string) => history.push(val ?? innerValue.value),
|
|
275
|
+
});
|
|
276
|
+
</script>
|
|
277
|
+
|
|
278
|
+
<template>
|
|
279
|
+
<div ref="wrapperRef" class="o-search-input" :class="{ 'is-focus': isFocus }">
|
|
280
|
+
<div class="o-search-input-box">
|
|
281
|
+
<SearchImageInput
|
|
282
|
+
ref="inputRef"
|
|
283
|
+
v-model="innerValue"
|
|
284
|
+
:image-url="imageUrl"
|
|
285
|
+
:placeholder="placeholder"
|
|
286
|
+
:image-placeholder="imagePlaceholder"
|
|
287
|
+
:size="size"
|
|
288
|
+
:enable-image-search="enableImageSearch"
|
|
289
|
+
:upload-image="uploadImage"
|
|
290
|
+
:max-image-size="maxImageSize"
|
|
291
|
+
:image-upload-tooltip="imageUploadTooltip"
|
|
292
|
+
:expanded="isFocus && !props.alwaysInlineThumbnail"
|
|
293
|
+
:inline-thumbnail="showInlineThumbnail"
|
|
294
|
+
:clearable="clearable"
|
|
295
|
+
class="o-search-input-field"
|
|
296
|
+
@update:imageUrl="(url: string) => emit('update:imageUrl', url)"
|
|
297
|
+
@focus="handleFocus"
|
|
298
|
+
@blur="handleBlur"
|
|
299
|
+
@enter="runSearch"
|
|
300
|
+
@clear="handleClear"
|
|
301
|
+
@image-clear="onImageClear"
|
|
302
|
+
@image-upload-start="onImageUploadStart"
|
|
303
|
+
@image-upload-success="onImageUploadSuccess"
|
|
304
|
+
@image-upload-error="(error: unknown, file: File) => emit('image-upload-error', error, file)"
|
|
305
|
+
@image-validate-error="(reason: 'size' | 'type', file: File) => emit('image-validate-error', reason, file)"
|
|
306
|
+
@preview-change="onPreviewChange"
|
|
307
|
+
>
|
|
308
|
+
<template #prefix><slot name="input-prefix" /></template>
|
|
309
|
+
<template #suffix="slotProps"><slot name="input-suffix" v-bind="slotProps" /></template>
|
|
310
|
+
<template v-if="$slots['image-preview']" #preview="slotProps">
|
|
311
|
+
<slot name="image-preview" v-bind="slotProps" />
|
|
312
|
+
</template>
|
|
313
|
+
</SearchImageInput>
|
|
314
|
+
|
|
315
|
+
<Transition name="o-search-input-dropdown">
|
|
316
|
+
<div v-if="showDropdown" class="o-search-input-dropdown">
|
|
317
|
+
<slot name="dropdown" :keyword="modelValue">
|
|
318
|
+
<SearchPanel
|
|
319
|
+
:keyword="modelValue"
|
|
320
|
+
:onestep-items="onestepItems"
|
|
321
|
+
:onestep-title="onestepTitle"
|
|
322
|
+
:suggest-items="suggestItems"
|
|
323
|
+
:suggest-title="suggestTitle"
|
|
324
|
+
:history-items="enableHistory ? history.items.value : []"
|
|
325
|
+
:history-title="historyTitle"
|
|
326
|
+
:no-data-text="noDataText"
|
|
327
|
+
:highlight-keyword="highlightKeyword"
|
|
328
|
+
:hide-on-keyword="true"
|
|
329
|
+
:show-suggest-empty="showSuggestEmpty"
|
|
330
|
+
history-layout="list"
|
|
331
|
+
@onestep-click="handleOnestepClick"
|
|
332
|
+
@suggest-click="handleSuggestClick"
|
|
333
|
+
@history-click="handleHistoryClick"
|
|
334
|
+
@history-remove="handleHistoryRemove"
|
|
335
|
+
@history-clear="handleHistoryClear"
|
|
336
|
+
>
|
|
337
|
+
<template v-if="$slots['onestep-header']" #onestep-header="slotProps">
|
|
338
|
+
<slot name="onestep-header" v-bind="slotProps" />
|
|
339
|
+
</template>
|
|
340
|
+
<template v-if="$slots['onestep-content']" #onestep-content="slotProps">
|
|
341
|
+
<slot name="onestep-content" v-bind="slotProps" />
|
|
342
|
+
</template>
|
|
343
|
+
<template v-if="$slots['suggest-header']" #suggest-header="slotProps">
|
|
344
|
+
<slot name="suggest-header" v-bind="slotProps" />
|
|
345
|
+
</template>
|
|
346
|
+
<template v-if="$slots['suggest-content']" #suggest-content="slotProps">
|
|
347
|
+
<slot name="suggest-content" v-bind="slotProps" />
|
|
348
|
+
</template>
|
|
349
|
+
<template v-if="$slots['history-header']" #history-header="slotProps">
|
|
350
|
+
<slot name="history-header" v-bind="slotProps" />
|
|
351
|
+
</template>
|
|
352
|
+
<template v-if="$slots['history-content']" #history-content="slotProps">
|
|
353
|
+
<slot name="history-content" v-bind="slotProps" />
|
|
354
|
+
</template>
|
|
355
|
+
</SearchPanel>
|
|
356
|
+
</slot>
|
|
357
|
+
</div>
|
|
358
|
+
</Transition>
|
|
359
|
+
</div>
|
|
360
|
+
|
|
361
|
+
<div v-if="suggestList?.length" class="o-search-input-suggest-list-row">
|
|
362
|
+
<slot name="suggest-list" :items="suggestList">
|
|
363
|
+
<span class="o-search-input-suggest-list-label">{{ suggestListLabel ?? t('search.suggestListLabel') }}</span>
|
|
364
|
+
<ul class="o-search-input-suggest-list">
|
|
365
|
+
<li
|
|
366
|
+
v-for="(item, idx) in suggestList"
|
|
367
|
+
:key="item + idx"
|
|
368
|
+
class="o-search-input-suggest-list-item"
|
|
369
|
+
@click="handleSuggestListClick(item)"
|
|
370
|
+
>
|
|
371
|
+
<span v-if="allowHtmlInSuggest" v-html="item" />
|
|
372
|
+
<span v-else>{{ item }}</span>
|
|
373
|
+
</li>
|
|
374
|
+
</ul>
|
|
375
|
+
</slot>
|
|
376
|
+
</div>
|
|
377
|
+
</div>
|
|
378
|
+
</template>
|
|
379
|
+
|
|
380
|
+
<style lang="scss" scoped>
|
|
381
|
+
.o-search-input {
|
|
382
|
+
position: relative;
|
|
383
|
+
width: 100%;
|
|
384
|
+
background-color: var(--o-color-fill2);
|
|
385
|
+
border-radius: var(--o-radius-xs);
|
|
386
|
+
|
|
387
|
+
// Make large size 48px tall
|
|
388
|
+
:deep(.o-input.o_box-large) {
|
|
389
|
+
--_box-height: 48px;
|
|
390
|
+
}
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
.o-search-input-box {
|
|
394
|
+
position: relative;
|
|
395
|
+
width: 100%;
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
.o-search-input-field {
|
|
399
|
+
width: 100%;
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
.o-search-input-dropdown {
|
|
403
|
+
position: absolute;
|
|
404
|
+
top: calc(100% + 4px);
|
|
405
|
+
left: 0;
|
|
406
|
+
right: 0;
|
|
407
|
+
z-index: 10;
|
|
408
|
+
padding: var(--o-gap-4);
|
|
409
|
+
background-color: var(--o-color-fill2);
|
|
410
|
+
border-radius: var(--o-radius-xs);
|
|
411
|
+
box-shadow: var(--o-shadow-2);
|
|
412
|
+
}
|
|
413
|
+
|
|
414
|
+
.o-search-input-dropdown-enter-active,
|
|
415
|
+
.o-search-input-dropdown-leave-active {
|
|
416
|
+
transition: opacity var(--o-duration-m1), transform var(--o-duration-m1);
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
.o-search-input-dropdown-enter-from,
|
|
420
|
+
.o-search-input-dropdown-leave-to {
|
|
421
|
+
opacity: 0;
|
|
422
|
+
transform: translateY(-4px);
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
.o-search-input-suggest-list-row {
|
|
426
|
+
display: flex;
|
|
427
|
+
margin-top: 8px;
|
|
428
|
+
align-items: center;
|
|
429
|
+
flex-wrap: wrap;
|
|
430
|
+
@include tip1;
|
|
431
|
+
color: var(--o-color-info1);
|
|
432
|
+
}
|
|
433
|
+
|
|
434
|
+
.o-search-input-suggest-list-label {
|
|
435
|
+
color: var(--o-color-info3);
|
|
436
|
+
margin-right: 4px;
|
|
437
|
+
@include tip1;
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
.o-search-input-suggest-list {
|
|
441
|
+
display: flex;
|
|
442
|
+
flex-wrap: wrap;
|
|
443
|
+
align-items: center;
|
|
444
|
+
padding: 0;
|
|
445
|
+
margin: 0;
|
|
446
|
+
list-style: none;
|
|
447
|
+
}
|
|
448
|
+
|
|
449
|
+
.o-search-input-suggest-list-item {
|
|
450
|
+
margin-right: 8px;
|
|
451
|
+
cursor: pointer;
|
|
452
|
+
color: var(--o-color-primary1);
|
|
453
|
+
|
|
454
|
+
:deep(em) {
|
|
455
|
+
color: var(--o-color-primary1);
|
|
456
|
+
font-style: normal;
|
|
457
|
+
}
|
|
458
|
+
|
|
459
|
+
@include hover {
|
|
460
|
+
text-decoration: underline;
|
|
461
|
+
}
|
|
462
|
+
}
|
|
463
|
+
</style>
|