@opendesign-plus-test/components 0.0.1-rc.82 → 0.0.1-rc.84

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.
Files changed (210) hide show
  1. package/dist/chunk-OElCookieNotice.cjs.js +1 -1
  2. package/dist/chunk-OElCookieNotice.es.js +10 -10
  3. package/dist/components/config-provider/OPlusConfigProvider.vue.d.ts +2 -2
  4. package/dist/components/config-provider/index.d.ts +3 -3
  5. package/dist/components/meeting/composables/useMeetingConfig.d.ts +1 -1
  6. package/dist/components.cjs.js +33 -33
  7. package/dist/components.css +1 -1
  8. package/dist/components.es.js +1511 -1504
  9. package/dist/treeshaking/components/banner/OBanner.css +37 -37
  10. package/dist/treeshaking/components/banner/OBanner.vue.mjs +1 -1
  11. package/dist/treeshaking/components/banner/OBanner.vue2.mjs +2 -1
  12. package/dist/treeshaking/components/banner/OBanner2.css +10 -10
  13. package/dist/treeshaking/components/config-provider/OPlusConfigProvider.vue.d.ts +2 -2
  14. package/dist/treeshaking/components/config-provider/index.d.ts +3 -3
  15. package/dist/treeshaking/components/cookie-notice/OCookieNotice.vue.mjs +1 -1
  16. package/dist/treeshaking/components/cookie-notice/OCookieNotice.vue2.mjs +1 -1
  17. package/dist/treeshaking/components/cookie-notice/OCookieNotice2.css +62 -62
  18. package/dist/treeshaking/components/events/OEventsApply.vue.mjs +1 -1
  19. package/dist/treeshaking/components/header/OHeader.css +12 -12
  20. package/dist/treeshaking/components/header/OHeader.vue.mjs +1 -1
  21. package/dist/treeshaking/components/header/OHeader.vue2.mjs +1 -1
  22. package/dist/treeshaking/components/header/components/HeaderContent.css +235 -235
  23. package/dist/treeshaking/components/header/components/HeaderContent.vue.mjs +1 -1
  24. package/dist/treeshaking/components/header/components/HeaderContent.vue2.mjs +3 -2
  25. package/dist/treeshaking/components/header/components/HeaderNav.css +26 -26
  26. package/dist/treeshaking/components/header/components/HeaderNav.vue.mjs +1 -1
  27. package/dist/treeshaking/components/header/components/HeaderNav.vue2.mjs +1 -1
  28. package/dist/treeshaking/components/meeting/composables/useMeetingConfig.d.ts +1 -1
  29. package/dist/treeshaking/i18n/index.mjs +1 -1
  30. package/dist/treeshaking/shared/theme.mjs +13 -0
  31. package/package.json +4 -1
  32. package/docs/design.md +0 -27
  33. package/docs/design_banner.md +0 -41
  34. package/docs/design_section.md +0 -27
  35. package/plugins/css-inject-plugin.ts +0 -37
  36. package/scripts/build.js +0 -17
  37. package/scripts/generate-components-index.js +0 -62
  38. package/src/assets/events/svg-icons/icon-checked.svg +0 -3
  39. package/src/assets/events/svg-icons/icon-competition.svg +0 -7
  40. package/src/assets/events/svg-icons/icon-events.svg +0 -4
  41. package/src/assets/events/svg-icons/icon-release.svg +0 -4
  42. package/src/assets/events/svg-icons/icon-summit.svg +0 -4
  43. package/src/assets/meeting/empty.png +0 -0
  44. package/src/assets/meeting/svg-icons/icon-all.svg +0 -4
  45. package/src/assets/meeting/svg-icons/icon-backward.svg +0 -4
  46. package/src/assets/meeting/svg-icons/icon-calendar.svg +0 -3
  47. package/src/assets/meeting/svg-icons/icon-cancel.svg +0 -4
  48. package/src/assets/meeting/svg-icons/icon-captions.svg +0 -4
  49. package/src/assets/meeting/svg-icons/icon-close-captions.svg +0 -6
  50. package/src/assets/meeting/svg-icons/icon-close-fullscreen.svg +0 -6
  51. package/src/assets/meeting/svg-icons/icon-copy.svg +0 -4
  52. package/src/assets/meeting/svg-icons/icon-create.svg +0 -5
  53. package/src/assets/meeting/svg-icons/icon-delete.svg +0 -7
  54. package/src/assets/meeting/svg-icons/icon-empty.svg +0 -65
  55. package/src/assets/meeting/svg-icons/icon-event.svg +0 -4
  56. package/src/assets/meeting/svg-icons/icon-export.svg +0 -3
  57. package/src/assets/meeting/svg-icons/icon-forward.svg +0 -4
  58. package/src/assets/meeting/svg-icons/icon-fullscreen.svg +0 -6
  59. package/src/assets/meeting/svg-icons/icon-help.svg +0 -3
  60. package/src/assets/meeting/svg-icons/icon-important.svg +0 -4
  61. package/src/assets/meeting/svg-icons/icon-info.svg +0 -3
  62. package/src/assets/meeting/svg-icons/icon-meet.svg +0 -4
  63. package/src/assets/meeting/svg-icons/icon-meeting-message.svg +0 -5
  64. package/src/assets/meeting/svg-icons/icon-meeting.svg +0 -4
  65. package/src/assets/meeting/svg-icons/icon-play.svg +0 -5
  66. package/src/assets/meeting/svg-icons/icon-playing-tip.svg +0 -7
  67. package/src/assets/meeting/svg-icons/icon-playing.svg +0 -5
  68. package/src/assets/meeting/svg-icons/icon-question.svg +0 -4
  69. package/src/assets/meeting/svg-icons/icon-sound.svg +0 -5
  70. package/src/assets/meeting/svg-icons/icon-speaker.svg +0 -3
  71. package/src/assets/meeting/svg-icons/icon-summit.svg +0 -4
  72. package/src/assets/meeting/svg-icons/icon-telligent.svg +0 -3
  73. package/src/assets/meeting/svg-icons/icon-tip.svg +0 -3
  74. package/src/assets/meeting/svg-icons/icon-todo.svg +0 -4
  75. package/src/assets/meeting/transparent.png +0 -0
  76. package/src/assets/styles/element-plus.scss +0 -283
  77. package/src/assets/svg-icons/icon-arrow-left.svg +0 -3
  78. package/src/assets/svg-icons/icon-avatar-line.svg +0 -3
  79. package/src/assets/svg-icons/icon-caret-left.svg +0 -3
  80. package/src/assets/svg-icons/icon-caret-right.svg +0 -3
  81. package/src/assets/svg-icons/icon-chevron-down.svg +0 -3
  82. package/src/assets/svg-icons/icon-chevron-right.svg +0 -3
  83. package/src/assets/svg-icons/icon-chevron-up.svg +0 -3
  84. package/src/assets/svg-icons/icon-close.svg +0 -3
  85. package/src/assets/svg-icons/icon-delete-hover.svg +0 -4
  86. package/src/assets/svg-icons/icon-delete.svg +0 -7
  87. package/src/assets/svg-icons/icon-filter.svg +0 -3
  88. package/src/assets/svg-icons/icon-header-back.svg +0 -3
  89. package/src/assets/svg-icons/icon-header-delete.svg +0 -3
  90. package/src/assets/svg-icons/icon-header-menu.svg +0 -3
  91. package/src/assets/svg-icons/icon-header-person.svg +0 -3
  92. package/src/assets/svg-icons/icon-header-search.svg +0 -4
  93. package/src/assets/svg-icons/icon-image-close.svg +0 -4
  94. package/src/assets/svg-icons/icon-image-upload.svg +0 -3
  95. package/src/assets/svg-icons/icon-image-zoomin.svg +0 -3
  96. package/src/assets/svg-icons/icon-loading.svg +0 -4
  97. package/src/assets/svg-icons/icon-locale.svg +0 -3
  98. package/src/assets/svg-icons/icon-log-off.svg +0 -3
  99. package/src/assets/svg-icons/icon-message.svg +0 -3
  100. package/src/assets/svg-icons/icon-moon.svg +0 -3
  101. package/src/assets/svg-icons/icon-outlink.svg +0 -3
  102. package/src/assets/svg-icons/icon-overview.svg +0 -3
  103. package/src/assets/svg-icons/icon-refresh.svg +0 -3
  104. package/src/assets/svg-icons/icon-search.svg +0 -3
  105. package/src/assets/svg-icons/icon-setting.svg +0 -3
  106. package/src/assets/svg-icons/icon-sun.svg +0 -3
  107. package/src/assets/svg-icons/icon-tips.svg +0 -3
  108. package/src/components/activity/OActivityApproval.vue +0 -868
  109. package/src/components/activity/OActivityForm.vue +0 -548
  110. package/src/components/activity/OActivityMyCalendar.vue +0 -1540
  111. package/src/components/activity/composables/useActivityConfig.ts +0 -141
  112. package/src/components/activity/config.ts +0 -1
  113. package/src/components/activity/index.ts +0 -24
  114. package/src/components/activity/types.ts +0 -95
  115. package/src/components/banner/OBanner.vue +0 -288
  116. package/src/components/banner/OBannerContent.vue +0 -175
  117. package/src/components/banner/index.ts +0 -18
  118. package/src/components/banner/types.ts +0 -39
  119. package/src/components/common/AppAvatar.vue +0 -83
  120. package/src/components/common/ClientOnly.vue +0 -13
  121. package/src/components/common/ContentWrapper.vue +0 -82
  122. package/src/components/common/MoreText.vue +0 -124
  123. package/src/components/common/ThFilter.vue +0 -330
  124. package/src/components/config-provider/OPlusConfigProvider.vue +0 -32
  125. package/src/components/config-provider/index.ts +0 -10
  126. package/src/components/cookie-notice/OCookieNotice.vue +0 -575
  127. package/src/components/cookie-notice/index.ts +0 -10
  128. package/src/components/element-plus/OElCookieNotice.vue +0 -603
  129. package/src/components/element-plus/index.ts +0 -3
  130. package/src/components/events/OEventsApply.vue +0 -509
  131. package/src/components/events/OEventsCalendar.vue +0 -600
  132. package/src/components/events/OEventsList.vue +0 -461
  133. package/src/components/events/config.ts +0 -35
  134. package/src/components/events/index.ts +0 -24
  135. package/src/components/events/types.ts +0 -84
  136. package/src/components/events/utils.ts +0 -9
  137. package/src/components/footer/OFooter.vue +0 -577
  138. package/src/components/footer/index.ts +0 -10
  139. package/src/components/header/OHeader.vue +0 -157
  140. package/src/components/header/OHeaderMobile.vue +0 -184
  141. package/src/components/header/components/HeaderContent.vue +0 -1125
  142. package/src/components/header/components/HeaderNav.vue +0 -278
  143. package/src/components/header/components/HeaderNavMobile.vue +0 -380
  144. package/src/components/header/index.ts +0 -18
  145. package/src/components/header/types.ts +0 -96
  146. package/src/components/header-language-switcher/OHeaderLanguageSwitcher.vue +0 -249
  147. package/src/components/header-language-switcher/index.ts +0 -10
  148. package/src/components/header-search/OHeaderSearch.vue +0 -628
  149. package/src/components/header-search/index.ts +0 -10
  150. package/src/components/header-source-code/OHeaderSourceCode.vue +0 -151
  151. package/src/components/header-source-code/index.ts +0 -10
  152. package/src/components/header-theme/OHeaderTheme.vue +0 -132
  153. package/src/components/header-theme/index.ts +0 -10
  154. package/src/components/header-user/OHeaderUser.vue +0 -249
  155. package/src/components/header-user/index.ts +0 -10
  156. package/src/components/meeting/OMeetingCalendar.vue +0 -943
  157. package/src/components/meeting/OMeetingForm.vue +0 -1131
  158. package/src/components/meeting/OMeetingMyCalendar.vue +0 -1628
  159. package/src/components/meeting/OMeetingPlayback.vue +0 -469
  160. package/src/components/meeting/OMeetingSigCalendar.vue +0 -500
  161. package/src/components/meeting/components/OMeetingCalendarList.vue +0 -626
  162. package/src/components/meeting/components/OMeetingCalendarSelector.vue +0 -213
  163. package/src/components/meeting/components/OMeetingDetail.vue +0 -285
  164. package/src/components/meeting/components/OMeetingPlaybackSubtitles.vue +0 -615
  165. package/src/components/meeting/components/OMeetingPlaybackVideo.vue +0 -741
  166. package/src/components/meeting/components/OMeetingSigAside.vue +0 -205
  167. package/src/components/meeting/composables/useMeetingConfig.ts +0 -108
  168. package/src/components/meeting/config.ts +0 -48
  169. package/src/components/meeting/index.ts +0 -45
  170. package/src/components/meeting/types.ts +0 -270
  171. package/src/components/meeting/utils.ts +0 -70
  172. package/src/components/search/OSearchInput.vue +0 -526
  173. package/src/components/search/composables/useImageSearch.ts +0 -157
  174. package/src/components/search/composables/useKeywordHighlight.ts +0 -30
  175. package/src/components/search/composables/useSearchHistory.ts +0 -75
  176. package/src/components/search/index.ts +0 -23
  177. package/src/components/search/internal/HighlightText.vue +0 -37
  178. package/src/components/search/internal/SearchImageInput.vue +0 -498
  179. package/src/components/search/internal/SearchPanel.vue +0 -431
  180. package/src/components/search/types.ts +0 -25
  181. package/src/components/section/OSection.vue +0 -178
  182. package/src/components/section/index.ts +0 -10
  183. package/src/draft/Banner.vue +0 -265
  184. package/src/draft/ButtonCards.vue +0 -106
  185. package/src/draft/Feature.vue +0 -134
  186. package/src/draft/Footer.vue +0 -519
  187. package/src/draft/HorizontalAnchor.vue +0 -165
  188. package/src/draft/ItemSwiper.vue +0 -133
  189. package/src/draft/Logo.vue +0 -141
  190. package/src/draft/LogoCard.vue +0 -75
  191. package/src/draft/LogoV2.vue +0 -19
  192. package/src/draft/MainCard.vue +0 -38
  193. package/src/draft/MultiCard.vue +0 -95
  194. package/src/draft/MultiIconCard.vue +0 -74
  195. package/src/draft/OInfoCard.vue +0 -176
  196. package/src/draft/Process.vue +0 -81
  197. package/src/draft/Section.vue +0 -167
  198. package/src/draft/SingleTabCard.vue +0 -85
  199. package/src/draft/SliderCard.vue +0 -111
  200. package/src/env.d.ts +0 -16
  201. package/src/i18n/en.ts +0 -278
  202. package/src/i18n/index.ts +0 -56
  203. package/src/i18n/zh.ts +0 -268
  204. package/src/index.ts +0 -18
  205. package/src/shared/provide.ts +0 -6
  206. package/src/shims-vue-dompurify-html.d.ts +0 -17
  207. package/src/vue.d.ts +0 -10
  208. package/tsconfig.json +0 -37
  209. package/vite.config.ts +0 -123
  210. package/vite.treeshaking.config.ts +0 -127
@@ -1,70 +0,0 @@
1
- import dayjs, { Dayjs } from 'dayjs';
2
- import { OptionItemT } from './types';
3
-
4
- export const formatDate = (date: undefined | string | Date | Dayjs = new Date(), format: string = 'YYYY/MM/DD'): string => {
5
- let dateStr: any = date;
6
- if (!dateStr) {
7
- dateStr = undefined;
8
- }
9
- if (!dayjs(new Date(dateStr)).isValid()) {
10
- return dateStr as string;
11
- }
12
- return dayjs(new Date(dateStr)).format(format);
13
- };
14
-
15
- export const findLabelFromOptions = (value: string | number, options: OptionItemT[], labelKey: keyof OptionItemT = 'label', valueKey: keyof OptionItemT = 'value') => {
16
- const find = options.find((o) => o[valueKey] === value);
17
- return find?.[labelKey] || value;
18
- };
19
-
20
- export const speakerNum = (val: string) => {
21
- const regex = /\d+/g;
22
- const match = val.match(regex) || '';
23
-
24
- return parseInt(match[0]);
25
- };
26
-
27
- export const getDateNumber = (date: string) => {
28
- const arr: string[] = date.split(':');
29
- if (arr.length > 3 || !arr.length) {
30
- return 0;
31
- }
32
- let res = 0;
33
- let base = 1;
34
- while (arr.length > 0) {
35
- const current = arr.pop();
36
- res += parseInt(current!) * base;
37
- base *= 60;
38
- }
39
- return res;
40
- };
41
-
42
- const formatNumber = (num: number) => {
43
- if (num < 0) return 'Invalid number';
44
- if (num >= 10) return `${ num }`;
45
- return `0${ num }`;
46
- };
47
-
48
- export const formatDateNumber = (num: number) => {
49
- if (num > 24 * 60 * 60) return 'Invalid date';
50
- const h = Math.floor(num / 60 / 60);
51
- const m = Math.floor((num - h * 60 * 60) / 60);
52
- const s = num % 60;
53
- return `${ formatNumber(h) }:${ formatNumber(m) }:${ formatNumber(s) }`;
54
- };
55
-
56
- export const transformTime = (time: string) => {
57
- const arr = time.split(':');
58
- const hh = arr[arr.length - 3] ? parseInt(arr[arr.length - 3]) : 0;
59
- const mm = parseInt(arr[arr.length - 2]);
60
- const ss = parseFloat(arr[arr.length - 1]);
61
-
62
- return hh * 60 * 60 + mm * 60 + ss;
63
- };
64
-
65
- export const transformSeconds = (seconds: number) => {
66
- const hh = Math.floor(seconds / 3600);
67
- const mm = Math.floor((seconds - hh * 3600) / 60);
68
- const ss = Math.floor(seconds - hh * 3600 - mm * 60);
69
- return `${ hh ? `${ hh.toString().padStart(2, '0') }:` : '' }${ mm.toString().padStart(2, '0') }:${ ss.toString().padStart(2, '0') }`;
70
- };
@@ -1,526 +0,0 @@
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
- allowedImageTypes?: string[];
28
-
29
- /** ---- Recommendation lists (controlled by parent) ---- */
30
- suggestItems?: OSearchRecommendItem[];
31
- onestepItems?: OSearchRecommendItem[];
32
- suggestTitle?: string;
33
- onestepTitle?: string;
34
- noDataText?: string;
35
- /** When true, show "no data" placeholder for empty suggest while typing */
36
- showSuggestEmpty?: boolean;
37
- highlightKeyword?: boolean;
38
- debounce?: number;
39
-
40
- /** ---- History ---- */
41
- enableHistory?: boolean;
42
- historyItems?: string[];
43
- maxHistoryCount?: number;
44
- storeHistory?: boolean;
45
- storageKey?: string;
46
- historyTitle?: string;
47
- /** Auto-record history on search; default true */
48
- autoSaveHistory?: boolean;
49
-
50
- /** ---- Hot searches (shown alongside history when no keyword) ---- */
51
- hotItems?: string[];
52
- hotTitle?: string;
53
-
54
- /** ---- "Did you mean" list (below input) ---- */
55
- suggestList?: string[];
56
- suggestListLabel?: string;
57
-
58
- /** ---- Misc ---- */
59
- clearable?: boolean;
60
- closeOnSearch?: boolean;
61
- closeOnClickOutside?: boolean;
62
- /** Show dropdown on focus even when empty (history) */
63
- openOnFocus?: boolean;
64
- /** Always show image as inline thumbnail inside the input; never expand preview below */
65
- alwaysInlineThumbnail?: boolean;
66
- }
67
-
68
- const props = withDefaults(defineProps<OSearchInputPropsT>(), {
69
- modelValue: '',
70
- imageUrl: '',
71
- size: 'large',
72
- enableImageSearch: false,
73
- maxImageSize: 10 * 1024 * 1024,
74
- suggestItems: () => [],
75
- onestepItems: () => [],
76
- showSuggestEmpty: true,
77
- highlightKeyword: true,
78
- debounce: 300,
79
- enableHistory: true,
80
- historyItems: () => [],
81
- maxHistoryCount: 6,
82
- storeHistory: false,
83
- storageKey: 'search-history',
84
- autoSaveHistory: true,
85
- hotItems: () => [],
86
- suggestList: () => [],
87
- clearable: true,
88
- closeOnSearch: true,
89
- closeOnClickOutside: true,
90
- openOnFocus: true,
91
- });
92
-
93
- const emit = defineEmits<{
94
- (e: 'update:modelValue', val: string): void;
95
- (e: 'update:imageUrl', url: string): void;
96
- (e: 'update:historyItems', items: string[]): void;
97
- (e: 'focus'): void;
98
- (e: 'blur'): void;
99
- (e: 'input', val: string): void;
100
- (e: 'clear'): void;
101
- (e: 'search', payload: OSearchPayload): void;
102
- (e: 'recommend-click', item: OSearchRecommendItem): void;
103
- (e: 'onestep-click', item: OSearchRecommendItem): void;
104
- (e: 'history-click', val: string): void;
105
- (e: 'hot-click', val: string): void;
106
- (e: 'suggest-list-click', val: string): void;
107
- (e: 'delete-history', items: string[]): void;
108
- (e: 'delete-history-item', val: string): void;
109
- (e: 'image-upload-start', file: File): void;
110
- (e: 'image-upload-success', url: string, file: File): void;
111
- (e: 'image-upload-error', error: unknown, file: File): void;
112
- (e: 'image-validate-error', reason: 'size' | 'type', file: File): void;
113
- }>();
114
-
115
- const { t } = useI18n();
116
-
117
- type SuggestSegment = { text: string; em: boolean };
118
- function parseSuggest(raw: string): SuggestSegment[] {
119
- const segments: SuggestSegment[] = [];
120
- const re = /<em>(.*?)<\/em>/g;
121
- let last = 0;
122
- let m: RegExpExecArray | null;
123
- while ((m = re.exec(raw)) !== null) {
124
- if (m.index > last) segments.push({ text: raw.slice(last, m.index), em: false });
125
- segments.push({ text: m[1], em: true });
126
- last = m.index + m[0].length;
127
- }
128
- if (last < raw.length) segments.push({ text: raw.slice(last), em: false });
129
- return segments;
130
- }
131
-
132
- const inputRef = ref<InstanceType<typeof SearchImageInput>>();
133
- const wrapperRef = ref<HTMLElement | null>(null);
134
-
135
- const innerValue = computed({
136
- get: () => props.modelValue,
137
- set: (val: string) => emit('update:modelValue', val),
138
- });
139
-
140
- const isFocus = ref(false);
141
- const isPreviewOpen = ref(false);
142
- const justClosedPreview = ref(false);
143
- const hasInternalImage = ref(false);
144
-
145
- const showDropdown = computed(() => {
146
- if (!isFocus.value) return false;
147
- if (props.imageUrl || hasInternalImage.value) return false;
148
- const hasSuggest =
149
- !!innerValue.value &&
150
- (props.suggestItems.length > 0 || props.onestepItems.length > 0 || props.showSuggestEmpty);
151
- const hasHistory = props.enableHistory && history.items.value.length > 0 && !innerValue.value;
152
- const hasHot = props.hotItems.length > 0 && !innerValue.value;
153
- if (hasSuggest) return true;
154
- if (props.openOnFocus && (hasHistory || hasHot)) return true;
155
- return false;
156
- });
157
-
158
- // history
159
- const historyItemsRef = toRef(props, 'historyItems');
160
- const storageKeyRef = toRef(props, 'storageKey');
161
- const storeHistoryRef = toRef(props, 'storeHistory');
162
- const maxHistoryRef = toRef(props, 'maxHistoryCount');
163
-
164
- const history = useSearchHistory({
165
- initial: historyItemsRef,
166
- storageKey: storageKeyRef,
167
- storeHistory: storeHistoryRef,
168
- maxHistoryCount: maxHistoryRef,
169
- onChange: (items) => emit('update:historyItems', items),
170
- });
171
-
172
- // debounced input event
173
- // suppressNextInput: set to true before programmatic value assignments (history/suggest
174
- // clicks) so the watcher-triggered debounce doesn't fire the input event.
175
- let suppressNextInput = false;
176
- const emitInputDebounced = useDebounceFn((val: string) => {
177
- if (suppressNextInput) {
178
- suppressNextInput = false;
179
- return;
180
- }
181
- emit('input', val);
182
- }, () => props.debounce);
183
-
184
- watch(innerValue, (val) => {
185
- emitInputDebounced(val);
186
- });
187
-
188
- // click outside
189
- onClickOutside(wrapperRef, () => {
190
- if (!props.closeOnClickOutside) return;
191
- if (isPreviewOpen.value || justClosedPreview.value) return;
192
- isFocus.value = false;
193
- });
194
-
195
- const handleFocus = () => {
196
- isFocus.value = true;
197
- emit('focus');
198
- };
199
-
200
- const handleBlur = () => {
201
- emit('blur');
202
- };
203
-
204
- const runSearch = async (overrideKeyword?: string) => {
205
- if (inputRef.value?.getIsUploading?.()) {
206
- await inputRef.value.awaitUpload?.();
207
- }
208
- const keyword = overrideKeyword !== undefined ? overrideKeyword.trim() : innerValue.value.trim();
209
- const imageUrl = inputRef.value?.getUploadedUrl?.() || props.imageUrl;
210
-
211
- if (!keyword && !imageUrl) return;
212
-
213
- if (props.autoSaveHistory && keyword) {
214
- history.push(keyword);
215
- }
216
-
217
- if (props.closeOnSearch) {
218
- isFocus.value = false;
219
- }
220
-
221
- emit('search', { keyword, imageUrl: imageUrl || undefined });
222
- };
223
-
224
- const handleClear = () => {
225
- innerValue.value = '';
226
- emit('clear');
227
- };
228
-
229
- const handleSuggestClick = (item: OSearchRecommendItem) => {
230
- emit('recommend-click', item);
231
- suppressNextInput = true;
232
- innerValue.value = item.key;
233
- runSearch(item.key ?? '');
234
- };
235
-
236
- const handleOnestepClick = (item: OSearchRecommendItem) => {
237
- emit('onestep-click', item);
238
- if (item.path) {
239
- const url = item.path;
240
- if (typeof window !== 'undefined') window.open(url, '_blank', 'noopener,noreferrer');
241
- }
242
- };
243
-
244
- const handleHistoryClick = (val: string) => {
245
- emit('history-click', val);
246
- runSearch(val);
247
- };
248
-
249
- const handleHotClick = (val: string) => {
250
- emit('hot-click', val);
251
- runSearch(val);
252
- };
253
-
254
- const handleHistoryRemove = (val: string) => {
255
- history.remove(val);
256
- emit('delete-history-item', val);
257
- };
258
-
259
- const handleHistoryClear = () => {
260
- const removed = [...history.items.value];
261
- history.clearAll();
262
- emit('delete-history', removed);
263
- };
264
-
265
- const handleSuggestListClick = (val: string) => {
266
- const text = val.replace(/<[^>]+>/g, '');
267
- emit('suggest-list-click', text);
268
- suppressNextInput = true;
269
- innerValue.value = text;
270
- runSearch(text);
271
- };
272
-
273
- const onPreviewChange = (visible: boolean) => {
274
- isPreviewOpen.value = visible;
275
- if (!visible) {
276
- justClosedPreview.value = true;
277
- setTimeout(() => {
278
- justClosedPreview.value = false;
279
- }, 100);
280
- }
281
- };
282
-
283
- const showInlineThumbnail = computed(() =>
284
- !!props.imageUrl && (props.alwaysInlineThumbnail || !isFocus.value)
285
- );
286
-
287
- const onImageUploadStart = (file: File) => {
288
- hasInternalImage.value = true;
289
- emit('image-upload-start', file);
290
- };
291
-
292
- const onImageUploadSuccess = (url: string, file: File) => {
293
- hasInternalImage.value = false;
294
- emit('image-upload-success', url, file);
295
- };
296
-
297
- const onImageClear = () => {
298
- hasInternalImage.value = false;
299
- emit('update:imageUrl', '');
300
- };
301
-
302
- defineExpose({
303
- focus: () => inputRef.value?.focus?.(),
304
- blur: () => inputRef.value?.blur?.(),
305
- search: runSearch,
306
- saveHistory: (val?: string) => history.push(val ?? innerValue.value),
307
- });
308
- </script>
309
-
310
- <template>
311
- <div ref="wrapperRef" class="o-search-input" :class="{ 'is-focus': isFocus }">
312
- <div class="o-search-input-box">
313
- <SearchImageInput
314
- ref="inputRef"
315
- v-model="innerValue"
316
- :image-url="imageUrl"
317
- :placeholder="placeholder"
318
- :image-placeholder="imagePlaceholder"
319
- :size="size"
320
- :enable-image-search="enableImageSearch"
321
- :upload-image="uploadImage"
322
- :max-image-size="maxImageSize"
323
- :image-upload-tooltip="imageUploadTooltip"
324
- :allowed-image-types="allowedImageTypes"
325
- :expanded="isFocus && !props.alwaysInlineThumbnail"
326
- :inline-thumbnail="showInlineThumbnail"
327
- :clearable="clearable"
328
- class="o-search-input-field"
329
- @update:imageUrl="(url: string) => emit('update:imageUrl', url)"
330
- @focus="handleFocus"
331
- @blur="handleBlur"
332
- @enter="runSearch"
333
- @clear="handleClear"
334
- @image-clear="onImageClear"
335
- @image-upload-start="onImageUploadStart"
336
- @image-upload-success="onImageUploadSuccess"
337
- @image-upload-error="(error: unknown, file: File) => emit('image-upload-error', error, file)"
338
- @image-validate-error="(reason: 'size' | 'type', file: File) => emit('image-validate-error', reason, file)"
339
- @preview-change="onPreviewChange"
340
- >
341
- <template #prefix><slot name="input-prefix" /></template>
342
- <template #suffix="slotProps"><slot name="input-suffix" v-bind="slotProps" /></template>
343
- <template v-if="$slots['image-preview']" #preview="slotProps">
344
- <slot name="image-preview" v-bind="slotProps" />
345
- </template>
346
- </SearchImageInput>
347
-
348
- <Transition name="o-search-input-dropdown">
349
- <div v-if="showDropdown" class="o-search-input-dropdown">
350
- <slot name="dropdown" :keyword="modelValue">
351
- <SearchPanel
352
- :keyword="modelValue"
353
- :onestep-items="onestepItems"
354
- :onestep-title="onestepTitle"
355
- :suggest-items="suggestItems"
356
- :suggest-title="suggestTitle"
357
- :history-items="enableHistory ? history.items.value : []"
358
- :history-title="historyTitle"
359
- :hot-items="hotItems"
360
- :hot-title="hotTitle"
361
- :no-data-text="noDataText"
362
- :highlight-keyword="highlightKeyword"
363
- :hide-on-keyword="true"
364
- :show-suggest-empty="showSuggestEmpty"
365
- history-layout="list"
366
- @onestep-click="handleOnestepClick"
367
- @suggest-click="handleSuggestClick"
368
- @history-click="handleHistoryClick"
369
- @history-remove="handleHistoryRemove"
370
- @history-clear="handleHistoryClear"
371
- @hot-click="handleHotClick"
372
- >
373
- <template v-if="$slots['onestep-header']" #onestep-header="slotProps">
374
- <slot name="onestep-header" v-bind="slotProps" />
375
- </template>
376
- <template v-if="$slots['onestep-content']" #onestep-content="slotProps">
377
- <slot name="onestep-content" v-bind="slotProps" />
378
- </template>
379
- <template v-if="$slots['suggest-header']" #suggest-header="slotProps">
380
- <slot name="suggest-header" v-bind="slotProps" />
381
- </template>
382
- <template v-if="$slots['suggest-content']" #suggest-content="slotProps">
383
- <slot name="suggest-content" v-bind="slotProps" />
384
- </template>
385
- <template v-if="$slots['history-header']" #history-header="slotProps">
386
- <slot name="history-header" v-bind="slotProps" />
387
- </template>
388
- <template v-if="$slots['history-content']" #history-content="slotProps">
389
- <slot name="history-content" v-bind="slotProps" />
390
- </template>
391
- </SearchPanel>
392
- </slot>
393
- </div>
394
- </Transition>
395
- </div>
396
-
397
- <div v-if="suggestList?.length" class="o-search-input-suggest-list-row">
398
- <slot name="suggest-list" :items="suggestList">
399
- <span class="o-search-input-suggest-list-label">{{ suggestListLabel ?? t('search.suggestListLabel') }}</span>
400
- <ul class="o-search-input-suggest-list">
401
- <li
402
- v-for="(item, idx) in suggestList"
403
- :key="item + idx"
404
- class="o-search-input-suggest-list-item"
405
- @click="handleSuggestListClick(item)"
406
- >
407
- <template v-for="seg in parseSuggest(item)" :key="seg.text + String(seg.em)">
408
- <em v-if="seg.em">{{ seg.text }}</em>
409
- <template v-else>{{ seg.text }}</template>
410
- </template>
411
- </li>
412
- </ul>
413
- </slot>
414
- </div>
415
- </div>
416
- </template>
417
-
418
- <style lang="scss" scoped>
419
- .o-search-input {
420
- position: relative;
421
- width: 100%;
422
- background-color: var(--o-color-fill2);
423
- border-radius: var(--o-radius-xs);
424
-
425
- :deep(.o-input.o_box-large) {
426
- --_box-height: 48px;
427
- }
428
- :deep(.o-search-image-input-icon) {
429
- font-size: 24px;
430
- }
431
- :deep(.o-search-image-input-upload-btn) {
432
- width: 24px;
433
- height: 24px;
434
- }
435
-
436
- @include respond-to('pad_v-pc_s') {
437
- :deep(.o-input.o_box-large) {
438
- --_box-height: 40px;
439
- }
440
- }
441
-
442
- @include respond-to('<=pad_v') {
443
- :deep(.o-input.o_box-large) {
444
- --_box-height: 32px;
445
- }
446
- :deep(.o-search-image-input-icon) {
447
- font-size: 16px;
448
- }
449
- :deep(.o-search-image-input-upload-btn) {
450
- width: 16px;
451
- height: 16px;
452
- }
453
- }
454
- }
455
-
456
- .o-search-input-box {
457
- position: relative;
458
- width: 100%;
459
- }
460
-
461
- .o-search-input-field {
462
- width: 100%;
463
- }
464
-
465
- .o-search-input-dropdown {
466
- position: absolute;
467
- top: calc(100% + 4px);
468
- left: 0;
469
- right: 0;
470
- z-index: 10;
471
- padding: var(--o-gap-4);
472
- background-color: var(--o-color-fill2);
473
- border-radius: var(--o-radius-xs);
474
- box-shadow: var(--o-shadow-2);
475
- }
476
-
477
- .o-search-input-dropdown-enter-active,
478
- .o-search-input-dropdown-leave-active {
479
- transition: opacity var(--o-duration-m1), transform var(--o-duration-m1);
480
- }
481
-
482
- .o-search-input-dropdown-enter-from,
483
- .o-search-input-dropdown-leave-to {
484
- opacity: 0;
485
- transform: translateY(-4px);
486
- }
487
-
488
- .o-search-input-suggest-list-row {
489
- display: flex;
490
- margin-top: 8px;
491
- align-items: center;
492
- flex-wrap: wrap;
493
- @include tip1;
494
- color: var(--o-color-info1);
495
- }
496
-
497
- .o-search-input-suggest-list-label {
498
- color: var(--o-color-info3);
499
- margin-right: 4px;
500
- @include tip1;
501
- }
502
-
503
- .o-search-input-suggest-list {
504
- display: flex;
505
- flex-wrap: wrap;
506
- align-items: center;
507
- padding: 0;
508
- margin: 0;
509
- list-style: none;
510
- }
511
-
512
- .o-search-input-suggest-list-item {
513
- margin-right: 8px;
514
- cursor: pointer;
515
- color: var(--o-color-primary1);
516
-
517
- :deep(em) {
518
- color: var(--o-color-primary1);
519
- font-style: normal;
520
- }
521
-
522
- @include hover {
523
- text-decoration: underline;
524
- }
525
- }
526
- </style>