@opendesign-plus-test/components 0.0.1-rc.45 → 0.0.1-rc.47

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 (36) hide show
  1. package/dist/chunk-OElCookieNotice.cjs.js +1 -1
  2. package/dist/chunk-OElCookieNotice.es.js +46 -66
  3. package/dist/components/OHeaderSearch.vue.d.ts +534 -812
  4. package/dist/components.cjs.js +41 -41
  5. package/dist/components.css +1 -1
  6. package/dist/components.es.js +10253 -11228
  7. package/dist/index.d.ts +0 -1
  8. package/package.json +2 -2
  9. package/src/assets/svg-icons/icon-delete.svg +1 -5
  10. package/src/components/OHeaderSearch.vue +425 -407
  11. package/src/i18n/en.ts +0 -10
  12. package/src/i18n/zh.ts +0 -10
  13. package/src/index.ts +0 -1
  14. package/dist/components/search/OSearchInput.vue.d.ts +0 -1003
  15. package/dist/components/search/composables/useImageSearch.d.ts +0 -48
  16. package/dist/components/search/composables/useKeywordHighlight.d.ts +0 -2
  17. package/dist/components/search/composables/useSearchHistory.d.ts +0 -14
  18. package/dist/components/search/index.d.ts +0 -590
  19. package/dist/components/search/internal/HighlightText.vue.d.ts +0 -9
  20. package/dist/components/search/internal/SearchImageInput.vue.d.ts +0 -716
  21. package/dist/components/search/internal/SearchPanel.vue.d.ts +0 -100
  22. package/dist/components/search/types.d.ts +0 -20
  23. package/src/assets/svg-icons/icon-delete-hover.svg +0 -4
  24. package/src/assets/svg-icons/icon-image-close.svg +0 -4
  25. package/src/assets/svg-icons/icon-image-upload.svg +0 -3
  26. package/src/assets/svg-icons/icon-image-zoomin.svg +0 -3
  27. package/src/assets/svg-icons/icon-refresh.svg +0 -3
  28. package/src/components/search/OSearchInput.vue +0 -463
  29. package/src/components/search/composables/useImageSearch.ts +0 -157
  30. package/src/components/search/composables/useKeywordHighlight.ts +0 -30
  31. package/src/components/search/composables/useSearchHistory.ts +0 -75
  32. package/src/components/search/index.ts +0 -23
  33. package/src/components/search/internal/HighlightText.vue +0 -37
  34. package/src/components/search/internal/SearchImageInput.vue +0 -488
  35. package/src/components/search/internal/SearchPanel.vue +0 -430
  36. package/src/components/search/types.ts +0 -25
@@ -1,488 +0,0 @@
1
- <script setup lang="ts">
2
- import { computed, nextTick, ref, watch } from 'vue';
3
- import { OFigure, OIcon, OInput, OPopover } from '@opensig/opendesign';
4
- import { useImageSearch } from '../composables/useImageSearch';
5
- import { useI18n } from '@/i18n';
6
- import type { OSearchUploadImageFn } from '../types';
7
-
8
- import IconSearch from '~icons/components/icon-header-search.svg';
9
- import IconClose from '~icons/components/icon-close.svg';
10
- import IconImageUpload from '~icons/components/icon-image-upload.svg';
11
- import IconImageClose from '~icons/components/icon-delete-hover.svg';
12
- import IconImageZoomin from '~icons/components/icon-image-zoomin.svg';
13
-
14
- export interface SearchImageInputPropsT {
15
- modelValue?: string;
16
- imageUrl?: string;
17
- placeholder?: string;
18
- imagePlaceholder?: string;
19
- size?: 'small' | 'medium' | 'large';
20
- enableImageSearch?: boolean;
21
- uploadImage?: OSearchUploadImageFn;
22
- maxImageSize?: number;
23
- imageUploadTooltip?: string;
24
- /** Show preview block below input when true and image staged */
25
- expanded?: boolean;
26
- /** Whether to render the clear icon when there is content */
27
- clearable?: boolean;
28
- /** Show the right suffix area (upload + clear). When false, suffix is empty. */
29
- showSuffix?: boolean;
30
- /** When true, render thumbnail inline inside prefix area (compact mode) */
31
- inlineThumbnail?: boolean;
32
- preview?: boolean;
33
- disabled?: boolean;
34
- allowedImageTypes?: string[];
35
- }
36
-
37
- const props = withDefaults(defineProps<SearchImageInputPropsT>(), {
38
- modelValue: '',
39
- imageUrl: '',
40
- size: 'medium',
41
- enableImageSearch: false,
42
- maxImageSize: 10 * 1024 * 1024,
43
- expanded: true,
44
- clearable: true,
45
- showSuffix: true,
46
- inlineThumbnail: false,
47
- preview: true,
48
- disabled: false,
49
- allowedImageTypes: () => ['image/jpeg', 'image/png', 'image/gif', 'image/webp'],
50
- });
51
-
52
- const emit = defineEmits<{
53
- (e: 'update:modelValue', val: string): void;
54
- (e: 'update:imageUrl', url: string): void;
55
- (e: 'focus', ev: FocusEvent): void;
56
- (e: 'blur', ev: FocusEvent): void;
57
- (e: 'enter'): void;
58
- (e: 'clear'): void;
59
- (e: 'image-clear'): void;
60
- (e: 'image-upload-start', file: File): void;
61
- (e: 'image-upload-success', url: string, file: File): void;
62
- (e: 'image-upload-error', error: unknown, file: File): void;
63
- (e: 'image-validate-error', reason: 'size' | 'type', file: File): void;
64
- (e: 'preview-change', visible: boolean): void;
65
- }>();
66
-
67
- const { t } = useI18n();
68
-
69
- const uploadImageRef = computed(() => props.uploadImage);
70
- const maxImageSizeRef = computed(() => props.maxImageSize);
71
- const allowedImageTypesRef = computed(() => props.allowedImageTypes);
72
- const acceptAttr = computed(() => (props.allowedImageTypes ?? []).join(','));
73
-
74
- const image = useImageSearch({
75
- uploadImage: uploadImageRef,
76
- maxImageSize: maxImageSizeRef,
77
- allowedImageTypes: allowedImageTypesRef,
78
- onUploadStart: (file) => emit('image-upload-start', file),
79
- onUploadSuccess: (url, file) => {
80
- emit('update:imageUrl', url);
81
- emit('image-upload-success', url, file);
82
- },
83
- onUploadError: (error, file) => emit('image-upload-error', error, file),
84
- onValidationError: (reason, file) => emit('image-validate-error', reason, file),
85
- });
86
-
87
- const fileInputRef = ref<HTMLInputElement>();
88
- const inputRef = ref<InstanceType<typeof OInput>>();
89
- const uploadBtnRef = ref<HTMLElement | null>(null);
90
-
91
- const innerValue = computed({
92
- get: () => props.modelValue,
93
- set: (val: string) => emit('update:modelValue', val),
94
- });
95
-
96
- watch(
97
- () => props.imageUrl,
98
- (val) => {
99
- image.setExternalUrl(val);
100
- },
101
- { immediate: true }
102
- );
103
-
104
- const showThumbnail = computed(() => !!image.previewUrl.value);
105
-
106
- const placeholder = computed(() => {
107
- if (showThumbnail.value) {
108
- return props.imagePlaceholder ?? t('search.extendedPlaceholder');
109
- }
110
- return props.placeholder ?? t('search.placeholder');
111
- });
112
-
113
- const handleClear = () => {
114
- innerValue.value = '';
115
- if (showThumbnail.value) {
116
- handleImageClear();
117
- }
118
- emit('clear');
119
- };
120
-
121
- const handleImageClear = () => {
122
- image.reset();
123
- emit('update:imageUrl', '');
124
- emit('image-clear');
125
- };
126
-
127
- const handleUploadClick = () => {
128
- image.pickFile(fileInputRef.value);
129
- nextTick(() => inputRef.value?.focus?.());
130
- };
131
-
132
- const handleFileSelect = (event: Event) => {
133
- image.onFileChange(event);
134
- nextTick(() => inputRef.value?.focus?.());
135
- };
136
-
137
- const handlePaste = (event: ClipboardEvent) => {
138
- if (!props.enableImageSearch) return;
139
- image.onPaste(event);
140
- };
141
-
142
- const handleDragOver = (event: DragEvent) => {
143
- if (!props.enableImageSearch) return;
144
- image.onDragOver(event);
145
- };
146
-
147
- const handleDrop = (event: DragEvent) => {
148
- if (!props.enableImageSearch) return;
149
- image.onDrop(event);
150
- };
151
-
152
- const onPreviewChange = (visible: boolean) => {
153
- emit('preview-change', visible);
154
- };
155
-
156
- const hasValue = computed(() => !!innerValue.value || showThumbnail.value);
157
-
158
- const awaitUpload = () => image.awaitUpload();
159
-
160
- defineExpose({
161
- focus: () => inputRef.value?.focus?.(),
162
- blur: () => inputRef.value?.blur?.(),
163
- awaitUpload,
164
- getUploadedUrl: () => image.uploadedUrl.value,
165
- getIsUploading: () => image.isUploading.value,
166
- resetImage: () => {
167
- image.reset();
168
- emit('update:imageUrl', '');
169
- },
170
- });
171
- </script>
172
-
173
- <template>
174
- <div
175
- class="o-search-image-input"
176
- :class="{ 'has-image': showThumbnail, 'is-expanded': expanded && showThumbnail }"
177
- @dragover="handleDragOver"
178
- @drop="handleDrop"
179
- >
180
- <div class="o-search-image-input-row">
181
- <OInput
182
- ref="inputRef"
183
- v-model="innerValue"
184
- :placeholder="placeholder"
185
- :size="size"
186
- :disabled="disabled"
187
- class="o-search-image-input-input"
188
- @pressEnter="emit('enter')"
189
- @focus="(e: FocusEvent) => emit('focus', e)"
190
- @blur="(e: FocusEvent) => emit('blur', e)"
191
- @paste="handlePaste"
192
- >
193
- <template #prefix>
194
- <slot name="prefix">
195
- <OIcon class="o-search-image-input-icon">
196
- <IconSearch />
197
- </OIcon>
198
- </slot>
199
- <div v-if="inlineThumbnail && showThumbnail" class="o-search-image-input-thumb">
200
- <OFigure :src="image.previewUrl.value" alt="" class="o-search-image-input-thumb-figure" />
201
- <div class="o-search-image-input-thumb-zoom" @mousedown.prevent>
202
- <OIcon class="o-search-image-input-thumb-zoom-icon"><IconImageZoomin /></OIcon>
203
- </div>
204
- <OIcon class="o-search-image-input-thumb-remove" @mousedown.prevent @click.stop="handleImageClear">
205
- <IconImageClose />
206
- </OIcon>
207
- </div>
208
- </template>
209
-
210
- <template v-if="showSuffix" #suffix>
211
- <slot name="suffix" :has-value="hasValue">
212
- <span v-if="enableImageSearch" ref="uploadBtnRef" class="o-search-image-input-upload-btn">
213
- <OIcon class="o-search-image-input-icon upload" @click.stop="handleUploadClick">
214
- <IconImageUpload />
215
- </OIcon>
216
- </span>
217
- <OPopover
218
- v-if="enableImageSearch && uploadBtnRef"
219
- trigger="hover"
220
- position="bottom"
221
- :target="uploadBtnRef"
222
- body-class="o-search-image-input-tooltip"
223
- >
224
- {{ imageUploadTooltip ?? t('search.imageUploadTooltip') }}
225
- </OPopover>
226
- <OIcon
227
- v-if="clearable && hasValue"
228
- class="o-search-image-input-icon close"
229
- @mousedown.prevent
230
- @click.stop="handleClear"
231
- >
232
- <IconClose />
233
- </OIcon>
234
- </slot>
235
- </template>
236
- </OInput>
237
- </div>
238
-
239
- <div v-if="expanded && showThumbnail" class="o-search-image-input-preview">
240
- <slot name="preview" :preview-url="image.previewUrl.value" :remove="handleImageClear">
241
- <div class="o-search-image-input-preview-wrapper">
242
- <OFigure
243
- :src="image.previewUrl.value"
244
- :preview="preview"
245
- alt=""
246
- class="o-search-image-input-preview-figure"
247
- @preview="onPreviewChange"
248
- />
249
- <div class="o-search-image-input-preview-zoom">
250
- <OIcon class="o-search-image-input-preview-zoom-icon"><IconImageZoomin /></OIcon>
251
- </div>
252
- <OIcon class="o-search-image-input-preview-remove" @click.stop="handleImageClear">
253
- <IconImageClose />
254
- </OIcon>
255
- </div>
256
- </slot>
257
- </div>
258
-
259
- <input
260
- v-if="enableImageSearch"
261
- ref="fileInputRef"
262
- type="file"
263
- :accept="acceptAttr"
264
- class="o-search-image-input-file"
265
- @change="handleFileSelect"
266
- />
267
- </div>
268
- </template>
269
-
270
- <style lang="scss" scoped>
271
- .o-search-image-input {
272
- display: flex;
273
- flex-direction: column;
274
- border: 1px solid transparent;
275
- border-radius: var(--o-radius-xs);
276
- background-color: var(--o-color-fill2);
277
- transition: border-color var(--o-duration-m1);
278
-
279
- &.is-expanded {
280
- border-color: var(--o-color-primary1);
281
-
282
- :deep(.o-input.el-input .el-input__wrapper),
283
- :deep(.o_box-main) {
284
- border: none !important;
285
- border-radius: var(--o-radius-xs) var(--o-radius-xs) 0 0;
286
- box-shadow: none !important;
287
- }
288
- }
289
- }
290
-
291
- .o-search-image-input-row {
292
- display: flex;
293
- align-items: center;
294
- }
295
-
296
- .o-search-image-input-input {
297
- width: 100%;
298
- }
299
-
300
- .o-search-image-input-icon {
301
- cursor: pointer;
302
- color: var(--o-color-info1);
303
- font-size: 16px;
304
-
305
- &.close {
306
- font-size: 16px;
307
- @include x-svg-hover;
308
- }
309
-
310
- &.upload {
311
- fill: var(--o-color-info1);
312
- }
313
- }
314
-
315
- .o-search-image-input-upload-btn {
316
- display: inline-flex;
317
- align-items: center;
318
- justify-content: center;
319
- width: 16px;
320
- height: 16px;
321
- border-radius: 4px;
322
- margin-right: 8px;
323
- cursor: pointer;
324
- flex-shrink: 0;
325
-
326
- @include hover {
327
- background-color: var(--o-color-control2-light);
328
-
329
- .o-search-image-input-icon.upload {
330
- color: var(--o-color-primary2);
331
- }
332
- }
333
- }
334
-
335
- .o-search-image-input-file {
336
- display: none;
337
- }
338
-
339
- .o-search-image-input-thumb {
340
- display: inline-flex;
341
- align-items: center;
342
- margin-left: 8px;
343
- position: relative;
344
- overflow: visible;
345
- flex-shrink: 0;
346
-
347
- @include hover {
348
- .o-search-image-input-thumb-remove,
349
- .o-search-image-input-thumb-zoom {
350
- opacity: 1;
351
- }
352
- }
353
- }
354
-
355
- .o-search-image-input-thumb-figure {
356
- height: 40px;
357
- width: 40px;
358
- border-radius: 4px;
359
- overflow: hidden;
360
-
361
- :deep(img) {
362
- height: 40px;
363
- width: 40px;
364
- object-fit: cover;
365
- object-position: center;
366
- border-radius: 4px;
367
- }
368
- }
369
-
370
- .o-search-image-input-thumb-zoom {
371
- position: absolute;
372
- inset: 0;
373
- display: flex;
374
- align-items: center;
375
- justify-content: center;
376
- background-color: rgba(0, 0, 0, 0.3);
377
- border-radius: 4px;
378
- pointer-events: auto;
379
- cursor: pointer;
380
- opacity: 0;
381
- transition: opacity var(--o-duration-m1);
382
-
383
- .o-search-image-input-thumb-zoom-icon {
384
- color: #fff;
385
- font-size: 16px;
386
- }
387
- }
388
-
389
- .o-search-image-input-thumb-remove {
390
- position: absolute;
391
- top: -8px;
392
- right: -8px;
393
- width: 16px;
394
- height: 16px;
395
- display: flex !important;
396
- align-items: center;
397
- justify-content: center;
398
- cursor: pointer;
399
- opacity: 0;
400
- z-index: 1;
401
- transition: opacity var(--o-duration-m1);
402
-
403
- :deep(svg) {
404
- width: 16px;
405
- height: 16px;
406
- fill: rgb(var(--o-mixedgray-9));
407
- }
408
- }
409
-
410
- .o-search-image-input-preview {
411
- padding: 0 12px 8px;
412
-
413
- .o-search-image-input-preview-wrapper {
414
- position: relative;
415
- display: inline-flex;
416
- overflow: visible;
417
- margin-top: 8px;
418
-
419
- @include hover {
420
- .o-search-image-input-preview-remove,
421
- .o-search-image-input-preview-zoom {
422
- opacity: 1;
423
- }
424
- }
425
- }
426
-
427
- .o-search-image-input-preview-zoom {
428
- position: absolute;
429
- inset: 0;
430
- display: flex;
431
- align-items: center;
432
- justify-content: center;
433
- background-color: rgba(0, 0, 0, 0.3);
434
- border-radius: 4px;
435
- pointer-events: none;
436
- opacity: 0;
437
- transition: opacity var(--o-duration-m1);
438
-
439
- .o-search-image-input-preview-zoom-icon {
440
- color: #fff;
441
- font-size: 24px;
442
- }
443
- }
444
-
445
- .o-search-image-input-preview-figure {
446
- height: 72px;
447
- width: 72px;
448
- border-radius: 4px;
449
- overflow: hidden;
450
-
451
- :deep(img) {
452
- height: 72px;
453
- width: 72px;
454
- object-fit: cover;
455
- object-position: center;
456
- border-radius: 4px;
457
- }
458
- }
459
-
460
- .o-search-image-input-preview-remove {
461
- position: absolute;
462
- top: -8px;
463
- right: -8px;
464
- width: 16px;
465
- height: 16px;
466
- display: flex !important;
467
- align-items: center;
468
- justify-content: center;
469
- cursor: pointer;
470
- opacity: 0;
471
- z-index: 1;
472
- transition: opacity var(--o-duration-m1);
473
-
474
- :deep(svg) {
475
- width: 16px;
476
- height: 16px;
477
- }
478
- }
479
- }
480
- </style>
481
-
482
- <style lang="scss">
483
- .o-search-image-input-tooltip {
484
- padding: var(--o-gap-3) var(--o-gap-4);
485
- max-width: 240px;
486
- @include tip2;
487
- }
488
- </style>