@getlupa/vue 0.18.3 → 0.18.4
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/lupaContainerStyle.css +1 -1
- package/dist/lupaSearch.js +490 -41
- package/dist/lupaSearch.mjs +491 -42
- package/dist/src/components/search-box/voice-search/VoiceSearchDialog.vue.d.ts +26 -0
- package/dist/src/components/search-box/voice-search/VoiceSearchProgressCircle.vue.d.ts +29 -0
- package/dist/src/composables/useVoiceRecorder.d.ts +12 -0
- package/dist/src/constants/searchBox.const.d.ts +4 -0
- package/dist/src/types/search-box/SearchBoxOptions.d.ts +16 -0
- package/dist/src/types/search-results/Filters.d.ts +1 -1
- package/dist/src/types/search-results/SearchResultsOptions.d.ts +1 -0
- package/dist/src/utils/api.utils.d.ts +1 -0
- package/dist/src/utils/stream.utils.d.ts +1 -0
- package/dist/src/utils/string.utils.d.ts +1 -0
- package/dist/style.css +1 -1
- package/package.json +1 -1
package/dist/lupaSearch.mjs
CHANGED
|
@@ -49,7 +49,7 @@ var __async = (__this, __arguments, generator) => {
|
|
|
49
49
|
step((generator = generator.apply(__this, __arguments)).next());
|
|
50
50
|
});
|
|
51
51
|
};
|
|
52
|
-
import { toRaw, isRef, isReactive, toRef, effectScope, ref, markRaw, hasInjectionContext, inject, getCurrentInstance, watch, reactive, nextTick, computed, unref, getCurrentScope, onScopeDispose, toRefs, defineComponent, openBlock, createElementBlock, createElementVNode, normalizeClass,
|
|
52
|
+
import { toRaw, isRef, isReactive, toRef, effectScope, ref, markRaw, hasInjectionContext, inject, getCurrentInstance, watch, reactive, nextTick, computed, unref, getCurrentScope, onScopeDispose, toRefs, defineComponent, openBlock, createElementBlock, onBeforeUnmount, onMounted, createElementVNode, toDisplayString, normalizeClass, createVNode, createCommentVNode, withDirectives, mergeProps, vModelText, createBlock, onBeforeMount, Fragment, renderList, normalizeStyle, Transition, withCtx, toHandlers, withModifiers, resolveDynamicComponent, renderSlot, createSlots, createTextVNode, normalizeProps, guardReactiveProps, onUnmounted, resolveComponent, vModelSelect, vShow, h as h$1, provide, cloneVNode } from "vue";
|
|
53
53
|
var isVue2 = false;
|
|
54
54
|
function set(target, key, val) {
|
|
55
55
|
if (Array.isArray(target)) {
|
|
@@ -7323,6 +7323,11 @@ const getRandomString = (length) => {
|
|
|
7323
7323
|
}
|
|
7324
7324
|
return result2;
|
|
7325
7325
|
};
|
|
7326
|
+
const getSocketClientId = () => {
|
|
7327
|
+
const timestamp = Date.now().toString(36);
|
|
7328
|
+
const randomString = getRandomString(8);
|
|
7329
|
+
return `${timestamp}-${randomString}`;
|
|
7330
|
+
};
|
|
7326
7331
|
const toFixedIfNecessary = (value, precision = 2) => {
|
|
7327
7332
|
return (+parseFloat(value).toFixed(precision)).toString();
|
|
7328
7333
|
};
|
|
@@ -7437,6 +7442,10 @@ const DEFAULT_SEARCH_BOX_OPTIONS = {
|
|
|
7437
7442
|
links: {
|
|
7438
7443
|
searchResults: "/search"
|
|
7439
7444
|
},
|
|
7445
|
+
voiceSearch: {
|
|
7446
|
+
enabled: false,
|
|
7447
|
+
queryKey: ""
|
|
7448
|
+
},
|
|
7440
7449
|
panels: [
|
|
7441
7450
|
{
|
|
7442
7451
|
type: "suggestion",
|
|
@@ -9018,6 +9027,350 @@ const useSearchBoxStore = defineStore("searchBox", () => {
|
|
|
9018
9027
|
resetHighlightIndex
|
|
9019
9028
|
};
|
|
9020
9029
|
});
|
|
9030
|
+
const Env = {
|
|
9031
|
+
production: "https://api.lupasearch.com/v1/",
|
|
9032
|
+
staging: "https://api.staging.lupasearch.com/v1/"
|
|
9033
|
+
};
|
|
9034
|
+
const VoiceServiceEnv = {
|
|
9035
|
+
production: "ws://voice.lupasearch.com:3001",
|
|
9036
|
+
staging: "ws://voice.lupasearch.dev:3001"
|
|
9037
|
+
};
|
|
9038
|
+
const DEFAULT_REQUEST_CONFIG = {
|
|
9039
|
+
method: "POST",
|
|
9040
|
+
headers: { "Content-Type": "application/json" }
|
|
9041
|
+
};
|
|
9042
|
+
const DEFAULT_HEADERS = DEFAULT_REQUEST_CONFIG.headers;
|
|
9043
|
+
const getVoiceServiceApiUrl = (environment, customVoiceServiceUrl) => {
|
|
9044
|
+
if (customVoiceServiceUrl) {
|
|
9045
|
+
return customVoiceServiceUrl;
|
|
9046
|
+
}
|
|
9047
|
+
return VoiceServiceEnv[environment] || VoiceServiceEnv["production"];
|
|
9048
|
+
};
|
|
9049
|
+
const getApiUrl = (environment, customBaseUrl) => {
|
|
9050
|
+
if (customBaseUrl) {
|
|
9051
|
+
return customBaseUrl;
|
|
9052
|
+
}
|
|
9053
|
+
return Env[environment] || Env["production"];
|
|
9054
|
+
};
|
|
9055
|
+
const _sfc_main$1z = /* @__PURE__ */ defineComponent({
|
|
9056
|
+
__name: "VoiceSearchProgressCircle",
|
|
9057
|
+
props: {
|
|
9058
|
+
isRecording: { type: Boolean },
|
|
9059
|
+
timesliceLimit: {},
|
|
9060
|
+
timeSliceLength: {}
|
|
9061
|
+
},
|
|
9062
|
+
setup(__props, { expose: __expose }) {
|
|
9063
|
+
const props = __props;
|
|
9064
|
+
const progressBar = ref(null);
|
|
9065
|
+
const getProgressBarColor = (progressBarStyle) => {
|
|
9066
|
+
if (!progressBarStyle.backgroundImage.startsWith("conic-gradient")) {
|
|
9067
|
+
return progressBarStyle.backgroundColor;
|
|
9068
|
+
}
|
|
9069
|
+
const colorStops = progressBarStyle.backgroundImage.replace(/conic-gradient\(|\)$/g, "").split(")");
|
|
9070
|
+
if (colorStops.length > 1) {
|
|
9071
|
+
return `${colorStops[0]})`;
|
|
9072
|
+
} else {
|
|
9073
|
+
return progressBarStyle.backgroundColor;
|
|
9074
|
+
}
|
|
9075
|
+
};
|
|
9076
|
+
const startProgressBar = () => {
|
|
9077
|
+
if (!progressBar.value || !props.isRecording) {
|
|
9078
|
+
return;
|
|
9079
|
+
}
|
|
9080
|
+
const duration = props.timesliceLimit * props.timeSliceLength;
|
|
9081
|
+
const progressBarStyle = window.getComputedStyle(progressBar.value);
|
|
9082
|
+
const progressBarColor = getProgressBarColor(progressBarStyle);
|
|
9083
|
+
progressBar.value.style.background = `conic-gradient(${progressBarColor} 0%, transparent 0%)`;
|
|
9084
|
+
let startTime = null;
|
|
9085
|
+
function updateProgress(timestamp) {
|
|
9086
|
+
if (!progressBar.value || !props.isRecording) {
|
|
9087
|
+
return;
|
|
9088
|
+
}
|
|
9089
|
+
if (!startTime)
|
|
9090
|
+
startTime = timestamp;
|
|
9091
|
+
const elapsed = timestamp - startTime;
|
|
9092
|
+
const progress = Math.min(elapsed / duration, 1) * 100;
|
|
9093
|
+
progressBar.value.style.background = `conic-gradient(${progressBarColor} ${progress}%, transparent ${progress}%)`;
|
|
9094
|
+
if (elapsed < duration) {
|
|
9095
|
+
requestAnimationFrame(updateProgress);
|
|
9096
|
+
}
|
|
9097
|
+
}
|
|
9098
|
+
requestAnimationFrame(updateProgress);
|
|
9099
|
+
};
|
|
9100
|
+
const stopProgressBar = () => {
|
|
9101
|
+
if (!progressBar.value) {
|
|
9102
|
+
return;
|
|
9103
|
+
}
|
|
9104
|
+
progressBar.value.style.background = "";
|
|
9105
|
+
};
|
|
9106
|
+
__expose({
|
|
9107
|
+
startProgressBar,
|
|
9108
|
+
stopProgressBar
|
|
9109
|
+
});
|
|
9110
|
+
return (_ctx, _cache) => {
|
|
9111
|
+
return openBlock(), createElementBlock("div", {
|
|
9112
|
+
ref_key: "progressBar",
|
|
9113
|
+
ref: progressBar,
|
|
9114
|
+
class: "lupa-progress-circle"
|
|
9115
|
+
}, null, 512);
|
|
9116
|
+
};
|
|
9117
|
+
}
|
|
9118
|
+
});
|
|
9119
|
+
const buildSocketMessageFrameHeader = (event, payloadLength) => {
|
|
9120
|
+
const headerObj = { event, length: payloadLength };
|
|
9121
|
+
const headerJson = JSON.stringify(headerObj);
|
|
9122
|
+
const headerBytes = new TextEncoder().encode(headerJson);
|
|
9123
|
+
const headerLength = new Uint32Array([headerBytes.length]);
|
|
9124
|
+
const headerLengthBytes = new Uint8Array(headerLength.buffer);
|
|
9125
|
+
const result2 = new Uint8Array(4 + headerBytes.length);
|
|
9126
|
+
result2.set(headerLengthBytes, 0);
|
|
9127
|
+
result2.set(headerBytes, 4);
|
|
9128
|
+
return result2;
|
|
9129
|
+
};
|
|
9130
|
+
function useVoiceRecorder(options) {
|
|
9131
|
+
const socket = ref(null);
|
|
9132
|
+
const mediaStream = ref(null);
|
|
9133
|
+
const mediaRecorder = ref(null);
|
|
9134
|
+
const isRecording = ref(false);
|
|
9135
|
+
const errorRef = ref(null);
|
|
9136
|
+
const transcription = ref("");
|
|
9137
|
+
const timeSliceLength = computed(() => {
|
|
9138
|
+
var _a;
|
|
9139
|
+
return (_a = options.timesliceLength) != null ? _a : 1e3;
|
|
9140
|
+
});
|
|
9141
|
+
onBeforeUnmount(() => {
|
|
9142
|
+
closeSocket();
|
|
9143
|
+
stopRecording();
|
|
9144
|
+
});
|
|
9145
|
+
const initSocket = (url, onMessage) => {
|
|
9146
|
+
socket.value = new WebSocket(url);
|
|
9147
|
+
socket.value.onopen = () => __async(this, null, function* () {
|
|
9148
|
+
var _a;
|
|
9149
|
+
if (((_a = mediaRecorder.value) == null ? void 0 : _a.state) !== "recording") {
|
|
9150
|
+
yield startRecording();
|
|
9151
|
+
}
|
|
9152
|
+
});
|
|
9153
|
+
socket.value.onmessage = (event) => {
|
|
9154
|
+
const msg = JSON.parse(event.data);
|
|
9155
|
+
if (msg.event === "transcription") {
|
|
9156
|
+
transcription.value = msg.transcription;
|
|
9157
|
+
onMessage == null ? void 0 : onMessage(msg.transcription);
|
|
9158
|
+
stopSocketConnection();
|
|
9159
|
+
} else if (msg.event === "error") {
|
|
9160
|
+
errorRef.value = "Server error during transcription";
|
|
9161
|
+
stopRecording();
|
|
9162
|
+
}
|
|
9163
|
+
};
|
|
9164
|
+
socket.value.onclose = () => {
|
|
9165
|
+
stopRecording();
|
|
9166
|
+
};
|
|
9167
|
+
socket.value.onerror = () => {
|
|
9168
|
+
stopRecording();
|
|
9169
|
+
errorRef.value = "Service connection error";
|
|
9170
|
+
};
|
|
9171
|
+
};
|
|
9172
|
+
const onMediaRecorderDataAvailable = (event) => __async(this, null, function* () {
|
|
9173
|
+
var _a, _b;
|
|
9174
|
+
if (((_a = mediaRecorder.value) == null ? void 0 : _a.state) !== "recording")
|
|
9175
|
+
return;
|
|
9176
|
+
const audioBuffer = yield event.data.arrayBuffer();
|
|
9177
|
+
const header = buildSocketMessageFrameHeader("audio-chunk", audioBuffer.byteLength);
|
|
9178
|
+
const buffer = new Uint8Array(header.length + audioBuffer.byteLength);
|
|
9179
|
+
buffer.set(header, 0);
|
|
9180
|
+
buffer.set(new Uint8Array(audioBuffer), header.length);
|
|
9181
|
+
(_b = socket.value) == null ? void 0 : _b.send(buffer);
|
|
9182
|
+
});
|
|
9183
|
+
const startRecording = () => __async(this, null, function* () {
|
|
9184
|
+
mediaStream.value = yield navigator.mediaDevices.getUserMedia({
|
|
9185
|
+
video: false,
|
|
9186
|
+
audio: {
|
|
9187
|
+
channelCount: 1,
|
|
9188
|
+
echoCancellation: true,
|
|
9189
|
+
sampleRate: 16e3
|
|
9190
|
+
}
|
|
9191
|
+
});
|
|
9192
|
+
mediaRecorder.value = new MediaRecorder(mediaStream.value, {
|
|
9193
|
+
mimeType: "audio/webm; codecs=opus"
|
|
9194
|
+
});
|
|
9195
|
+
mediaRecorder.value.ondataavailable = onMediaRecorderDataAvailable;
|
|
9196
|
+
mediaRecorder.value.start(timeSliceLength.value);
|
|
9197
|
+
isRecording.value = true;
|
|
9198
|
+
});
|
|
9199
|
+
const stopRecording = () => {
|
|
9200
|
+
var _a, _b;
|
|
9201
|
+
(_a = mediaRecorder.value) == null ? void 0 : _a.stop();
|
|
9202
|
+
(_b = mediaStream.value) == null ? void 0 : _b.getTracks().forEach((track2) => {
|
|
9203
|
+
track2.stop();
|
|
9204
|
+
});
|
|
9205
|
+
isRecording.value = false;
|
|
9206
|
+
};
|
|
9207
|
+
const stopSocketConnection = () => {
|
|
9208
|
+
if (socket.value && socket.value.readyState === WebSocket.OPEN) {
|
|
9209
|
+
const endHeader = buildSocketMessageFrameHeader("audio-chunk-end", 0);
|
|
9210
|
+
socket.value.send(endHeader);
|
|
9211
|
+
setTimeout(() => {
|
|
9212
|
+
closeSocket();
|
|
9213
|
+
}, 1e3);
|
|
9214
|
+
}
|
|
9215
|
+
};
|
|
9216
|
+
const closeSocket = () => {
|
|
9217
|
+
var _a;
|
|
9218
|
+
(_a = socket.value) == null ? void 0 : _a.close();
|
|
9219
|
+
socket.value = null;
|
|
9220
|
+
};
|
|
9221
|
+
const reset = () => {
|
|
9222
|
+
stopRecording();
|
|
9223
|
+
closeSocket();
|
|
9224
|
+
transcription.value = "";
|
|
9225
|
+
errorRef.value = null;
|
|
9226
|
+
isRecording.value = false;
|
|
9227
|
+
};
|
|
9228
|
+
return {
|
|
9229
|
+
isRecording,
|
|
9230
|
+
transcription,
|
|
9231
|
+
errorRef,
|
|
9232
|
+
initSocket,
|
|
9233
|
+
startRecording,
|
|
9234
|
+
stopRecording,
|
|
9235
|
+
stopSocketConnection,
|
|
9236
|
+
reset,
|
|
9237
|
+
closeSocket
|
|
9238
|
+
};
|
|
9239
|
+
}
|
|
9240
|
+
const _hoisted_1$1l = {
|
|
9241
|
+
key: 0,
|
|
9242
|
+
class: "lupa-dialog-overlay"
|
|
9243
|
+
};
|
|
9244
|
+
const _hoisted_2$W = { class: "lupa-dialog-content" };
|
|
9245
|
+
const _hoisted_3$F = { class: "lupa-listening-text" };
|
|
9246
|
+
const _hoisted_4$v = { class: "lupa-mic-button-wrapper" };
|
|
9247
|
+
const _sfc_main$1y = /* @__PURE__ */ defineComponent({
|
|
9248
|
+
__name: "VoiceSearchDialog",
|
|
9249
|
+
props: {
|
|
9250
|
+
isOpen: { type: Boolean },
|
|
9251
|
+
options: {}
|
|
9252
|
+
},
|
|
9253
|
+
emits: [
|
|
9254
|
+
"close",
|
|
9255
|
+
"transcript-update",
|
|
9256
|
+
"stop-recognize"
|
|
9257
|
+
],
|
|
9258
|
+
setup(__props, { expose: __expose, emit }) {
|
|
9259
|
+
const props = __props;
|
|
9260
|
+
const optionsStore = useOptionsStore();
|
|
9261
|
+
const {
|
|
9262
|
+
isRecording,
|
|
9263
|
+
transcription,
|
|
9264
|
+
errorRef,
|
|
9265
|
+
initSocket,
|
|
9266
|
+
stopSocketConnection,
|
|
9267
|
+
reset
|
|
9268
|
+
} = useVoiceRecorder(props.options);
|
|
9269
|
+
const clientId = ref(null);
|
|
9270
|
+
const voiceSearchProgressBar = ref(null);
|
|
9271
|
+
const timesliceLimit = computed(() => {
|
|
9272
|
+
var _a;
|
|
9273
|
+
return (_a = props.options.timesliceLimit) != null ? _a : 4;
|
|
9274
|
+
});
|
|
9275
|
+
const timeSliceLength = computed(() => {
|
|
9276
|
+
var _a;
|
|
9277
|
+
return (_a = props.options.timesliceLength) != null ? _a : 1e3;
|
|
9278
|
+
});
|
|
9279
|
+
const stopDelay = computed(() => {
|
|
9280
|
+
var _a;
|
|
9281
|
+
return (_a = props.options.stopDelay) != null ? _a : 700;
|
|
9282
|
+
});
|
|
9283
|
+
const labels = computed(() => {
|
|
9284
|
+
var _a;
|
|
9285
|
+
return (_a = props.options.labels) != null ? _a : {};
|
|
9286
|
+
});
|
|
9287
|
+
const description = computed(() => {
|
|
9288
|
+
var _a, _b, _c;
|
|
9289
|
+
if (errorRef.value) {
|
|
9290
|
+
return (_a = labels.value.serviceError) != null ? _a : errorRef.value;
|
|
9291
|
+
}
|
|
9292
|
+
if (!isRecording.value) {
|
|
9293
|
+
return (_b = labels.value.microphoneOff) != null ? _b : "Microphone is off. Try again.";
|
|
9294
|
+
}
|
|
9295
|
+
return (_c = labels.value.listening) != null ? _c : "Listening...";
|
|
9296
|
+
});
|
|
9297
|
+
watch(transcription, (newValue) => {
|
|
9298
|
+
emit("transcript-update", newValue);
|
|
9299
|
+
});
|
|
9300
|
+
const handleRecordingButtonClick = () => {
|
|
9301
|
+
var _a, _b;
|
|
9302
|
+
if (isRecording.value) {
|
|
9303
|
+
setTimeout(() => {
|
|
9304
|
+
stopSocketConnection();
|
|
9305
|
+
handleOnStopEvent();
|
|
9306
|
+
}, stopDelay.value);
|
|
9307
|
+
return;
|
|
9308
|
+
}
|
|
9309
|
+
const voiceServiceUrl = getVoiceServiceApiUrl(
|
|
9310
|
+
optionsStore.envOptions.environment,
|
|
9311
|
+
props.options.customVoiceServiceUrl
|
|
9312
|
+
);
|
|
9313
|
+
const socketUrl = `${voiceServiceUrl}?clientId=${clientId.value}&queryKey=${props.options.queryKey}&languageCode=${(_a = props.options.language) != null ? _a : "en-US"}&connectionType=write-first`;
|
|
9314
|
+
initSocket(socketUrl);
|
|
9315
|
+
(_b = voiceSearchProgressBar.value) == null ? void 0 : _b.startProgressBar();
|
|
9316
|
+
setTimeout(() => {
|
|
9317
|
+
stopSocketConnection();
|
|
9318
|
+
handleOnStopEvent();
|
|
9319
|
+
}, timesliceLimit.value * timeSliceLength.value);
|
|
9320
|
+
};
|
|
9321
|
+
const handleOnStopEvent = () => {
|
|
9322
|
+
var _a;
|
|
9323
|
+
setTimeout(() => {
|
|
9324
|
+
if (errorRef.value)
|
|
9325
|
+
return;
|
|
9326
|
+
emit("stop-recognize", transcription.value);
|
|
9327
|
+
}, 1500);
|
|
9328
|
+
(_a = voiceSearchProgressBar.value) == null ? void 0 : _a.stopProgressBar();
|
|
9329
|
+
};
|
|
9330
|
+
onMounted(() => {
|
|
9331
|
+
clientId.value = getSocketClientId();
|
|
9332
|
+
});
|
|
9333
|
+
onBeforeUnmount(() => {
|
|
9334
|
+
clientId.value = null;
|
|
9335
|
+
});
|
|
9336
|
+
const dialogReset = () => {
|
|
9337
|
+
var _a;
|
|
9338
|
+
reset();
|
|
9339
|
+
(_a = voiceSearchProgressBar.value) == null ? void 0 : _a.stopProgressBar();
|
|
9340
|
+
};
|
|
9341
|
+
__expose({
|
|
9342
|
+
handleRecordingButtonClick,
|
|
9343
|
+
reset: dialogReset
|
|
9344
|
+
});
|
|
9345
|
+
return (_ctx, _cache) => {
|
|
9346
|
+
return openBlock(), createElementBlock("div", null, [
|
|
9347
|
+
props.isOpen ? (openBlock(), createElementBlock("div", _hoisted_1$1l, [
|
|
9348
|
+
createElementVNode("button", {
|
|
9349
|
+
class: "lupa-dialog-box-close-button",
|
|
9350
|
+
onClick: _cache[0] || (_cache[0] = () => emit("close"))
|
|
9351
|
+
}),
|
|
9352
|
+
createElementVNode("div", _hoisted_2$W, [
|
|
9353
|
+
createElementVNode("p", _hoisted_3$F, toDisplayString(description.value), 1),
|
|
9354
|
+
createElementVNode("div", _hoisted_4$v, [
|
|
9355
|
+
createElementVNode("button", {
|
|
9356
|
+
class: normalizeClass(["lupa-mic-button", { recording: unref(isRecording) }]),
|
|
9357
|
+
onClick: handleRecordingButtonClick
|
|
9358
|
+
}, null, 2),
|
|
9359
|
+
createVNode(_sfc_main$1z, {
|
|
9360
|
+
ref_key: "voiceSearchProgressBar",
|
|
9361
|
+
ref: voiceSearchProgressBar,
|
|
9362
|
+
class: "lupa-progress-circle",
|
|
9363
|
+
isRecording: unref(isRecording),
|
|
9364
|
+
timesliceLimit: timesliceLimit.value,
|
|
9365
|
+
timeSliceLength: timeSliceLength.value
|
|
9366
|
+
}, null, 8, ["isRecording", "timesliceLimit", "timeSliceLength"])
|
|
9367
|
+
])
|
|
9368
|
+
])
|
|
9369
|
+
])) : createCommentVNode("", true)
|
|
9370
|
+
]);
|
|
9371
|
+
};
|
|
9372
|
+
}
|
|
9373
|
+
});
|
|
9021
9374
|
const _hoisted_1$1k = { id: "lupa-search-box-input-container" };
|
|
9022
9375
|
const _hoisted_2$V = { class: "lupa-input-clear" };
|
|
9023
9376
|
const _hoisted_3$E = { id: "lupa-search-box-input" };
|
|
@@ -9031,6 +9384,7 @@ const _hoisted_8$3 = {
|
|
|
9031
9384
|
key: 0,
|
|
9032
9385
|
class: "lupa-close-label"
|
|
9033
9386
|
};
|
|
9387
|
+
const _hoisted_9$3 = { key: 1 };
|
|
9034
9388
|
const _sfc_main$1x = /* @__PURE__ */ defineComponent({
|
|
9035
9389
|
__name: "SearchBoxInput",
|
|
9036
9390
|
props: {
|
|
@@ -9046,6 +9400,8 @@ const _sfc_main$1x = /* @__PURE__ */ defineComponent({
|
|
|
9046
9400
|
const searchBoxStore = useSearchBoxStore();
|
|
9047
9401
|
const { query } = storeToRefs(paramStore);
|
|
9048
9402
|
const mainInput = ref(null);
|
|
9403
|
+
const voiceDialogOverlay = ref(null);
|
|
9404
|
+
const isVoiceDialogOpen = ref(false);
|
|
9049
9405
|
const emitInputOnFocus = computed(() => {
|
|
9050
9406
|
var _a;
|
|
9051
9407
|
return (_a = props.emitInputOnFocus) != null ? _a : true;
|
|
@@ -9056,6 +9412,10 @@ const _sfc_main$1x = /* @__PURE__ */ defineComponent({
|
|
|
9056
9412
|
return (_a = props.suggestedValue) != null ? _a : { value: "", override: false, item: { suggestion: "" } };
|
|
9057
9413
|
}
|
|
9058
9414
|
);
|
|
9415
|
+
const isVoiceSearchEnabled = computed(() => {
|
|
9416
|
+
var _a, _b;
|
|
9417
|
+
return (_b = (_a = props.options.voiceSearch) == null ? void 0 : _a.enabled) != null ? _b : false;
|
|
9418
|
+
});
|
|
9059
9419
|
const labels = computed(() => props.options.labels);
|
|
9060
9420
|
const input2 = ref("");
|
|
9061
9421
|
const inputValue = computed({
|
|
@@ -9079,6 +9439,12 @@ const _sfc_main$1x = /* @__PURE__ */ defineComponent({
|
|
|
9079
9439
|
var _a;
|
|
9080
9440
|
return (_a = labels.value.searchInputAriaLabel) != null ? _a : "Search input";
|
|
9081
9441
|
});
|
|
9442
|
+
onMounted(() => {
|
|
9443
|
+
document.addEventListener("click", handleClickOutsideVoiceDialogOverlay);
|
|
9444
|
+
});
|
|
9445
|
+
onBeforeUnmount(() => {
|
|
9446
|
+
document.removeEventListener("click", handleClickOutsideVoiceDialogOverlay);
|
|
9447
|
+
});
|
|
9082
9448
|
watch(suggestedValue, () => {
|
|
9083
9449
|
if (suggestedValue.value.override) {
|
|
9084
9450
|
input2.value = suggestedValue.value.item.suggestion;
|
|
@@ -9113,6 +9479,37 @@ const _sfc_main$1x = /* @__PURE__ */ defineComponent({
|
|
|
9113
9479
|
}
|
|
9114
9480
|
(_a = mainInput == null ? void 0 : mainInput.value) == null ? void 0 : _a.focus();
|
|
9115
9481
|
};
|
|
9482
|
+
const openVoiceSearchDialog = () => {
|
|
9483
|
+
var _a;
|
|
9484
|
+
isVoiceDialogOpen.value = true;
|
|
9485
|
+
(_a = voiceDialogOverlay.value) == null ? void 0 : _a.handleRecordingButtonClick();
|
|
9486
|
+
};
|
|
9487
|
+
const closeDialog = () => {
|
|
9488
|
+
var _a;
|
|
9489
|
+
isVoiceDialogOpen.value = false;
|
|
9490
|
+
(_a = voiceDialogOverlay.value) == null ? void 0 : _a.reset();
|
|
9491
|
+
};
|
|
9492
|
+
const handleVoiceSearchOutput = (transcription) => {
|
|
9493
|
+
inputValue.value = transcription;
|
|
9494
|
+
handleSubmit();
|
|
9495
|
+
};
|
|
9496
|
+
const stopRecognition = (trascription) => {
|
|
9497
|
+
setTimeout(() => {
|
|
9498
|
+
isVoiceDialogOpen.value = false;
|
|
9499
|
+
handleVoiceSearchOutput(trascription);
|
|
9500
|
+
}, 500);
|
|
9501
|
+
};
|
|
9502
|
+
const handleClickOutsideVoiceDialogOverlay = (event) => {
|
|
9503
|
+
if (event.target.classList.contains("lupa-voice-search-button")) {
|
|
9504
|
+
return;
|
|
9505
|
+
}
|
|
9506
|
+
if (voiceDialogOverlay.value && voiceDialogOverlay.value.$el.contains(event.target)) {
|
|
9507
|
+
return;
|
|
9508
|
+
}
|
|
9509
|
+
if (isVoiceDialogOpen.value) {
|
|
9510
|
+
closeDialog();
|
|
9511
|
+
}
|
|
9512
|
+
};
|
|
9116
9513
|
__expose({ focus });
|
|
9117
9514
|
return (_ctx, _cache) => {
|
|
9118
9515
|
return openBlock(), createElementBlock("div", _hoisted_1$1k, [
|
|
@@ -9156,7 +9553,23 @@ const _sfc_main$1x = /* @__PURE__ */ defineComponent({
|
|
|
9156
9553
|
onClick: _cache[1] || (_cache[1] = ($event) => _ctx.$emit("close"))
|
|
9157
9554
|
}, [
|
|
9158
9555
|
labels.value.close ? (openBlock(), createElementBlock("span", _hoisted_8$3, toDisplayString(labels.value.close), 1)) : createCommentVNode("", true)
|
|
9159
|
-
])) : createCommentVNode("", true)
|
|
9556
|
+
])) : createCommentVNode("", true),
|
|
9557
|
+
isVoiceSearchEnabled.value ? (openBlock(), createElementBlock("div", _hoisted_9$3, [
|
|
9558
|
+
createElementVNode("button", {
|
|
9559
|
+
onClick: openVoiceSearchDialog,
|
|
9560
|
+
class: "lupa-voice-search-button"
|
|
9561
|
+
})
|
|
9562
|
+
])) : createCommentVNode("", true),
|
|
9563
|
+
isVoiceSearchEnabled.value ? (openBlock(), createBlock(_sfc_main$1y, {
|
|
9564
|
+
key: 2,
|
|
9565
|
+
ref_key: "voiceDialogOverlay",
|
|
9566
|
+
ref: voiceDialogOverlay,
|
|
9567
|
+
isOpen: isVoiceDialogOpen.value,
|
|
9568
|
+
options: props.options.voiceSearch,
|
|
9569
|
+
onClose: closeDialog,
|
|
9570
|
+
onTranscriptUpdate: handleVoiceSearchOutput,
|
|
9571
|
+
onStopRecognize: stopRecognition
|
|
9572
|
+
}, null, 8, ["isOpen", "options"])) : createCommentVNode("", true)
|
|
9160
9573
|
]);
|
|
9161
9574
|
};
|
|
9162
9575
|
}
|
|
@@ -20745,7 +21158,8 @@ const _sfc_main$12 = /* @__PURE__ */ defineComponent({
|
|
|
20745
21158
|
"labels",
|
|
20746
21159
|
"links",
|
|
20747
21160
|
"inputAttributes",
|
|
20748
|
-
"showSubmitButton"
|
|
21161
|
+
"showSubmitButton",
|
|
21162
|
+
"voiceSearch"
|
|
20749
21163
|
])
|
|
20750
21164
|
);
|
|
20751
21165
|
const panelOptions = computed(
|
|
@@ -21345,22 +21759,42 @@ const _sfc_main$_ = /* @__PURE__ */ defineComponent({
|
|
|
21345
21759
|
emits: ["remove"],
|
|
21346
21760
|
setup(__props, { emit }) {
|
|
21347
21761
|
const props = __props;
|
|
21348
|
-
const facetKeyClass = computed(() => {
|
|
21349
|
-
|
|
21762
|
+
const facetKeyClass = computed(() => `lupa-facet-active-filter-${props.filter.key}`);
|
|
21763
|
+
const { searchResultOptions } = storeToRefs(useOptionsStore());
|
|
21764
|
+
const units = computed(() => {
|
|
21765
|
+
var _a;
|
|
21766
|
+
return (_a = searchResultOptions.value.filters.facets.stats.units) != null ? _a : {};
|
|
21350
21767
|
});
|
|
21351
|
-
|
|
21768
|
+
function handleClick() {
|
|
21352
21769
|
emit("remove", { filter: props.filter });
|
|
21353
|
-
}
|
|
21770
|
+
}
|
|
21771
|
+
function formatFilterValue(filter2) {
|
|
21772
|
+
const unit = units.value[filter2.key] || "";
|
|
21773
|
+
let min, max;
|
|
21774
|
+
if (Array.isArray(filter2.value)) {
|
|
21775
|
+
[min, max] = filter2.value.map(String);
|
|
21776
|
+
} else if (typeof filter2.value === "string" && filter2.value.includes("-")) {
|
|
21777
|
+
const parts = filter2.value.split("-").map((s) => s.trim());
|
|
21778
|
+
if (parts.length === 2)
|
|
21779
|
+
[min, max] = parts;
|
|
21780
|
+
}
|
|
21781
|
+
if (min != null && max != null) {
|
|
21782
|
+
return `${min} ${unit} – ${max} ${unit}`;
|
|
21783
|
+
}
|
|
21784
|
+
return `${filter2.value} ${unit}`.trim();
|
|
21785
|
+
}
|
|
21354
21786
|
return (_ctx, _cache) => {
|
|
21355
21787
|
return openBlock(), createElementBlock("div", {
|
|
21356
|
-
class: normalizeClass(["lupa-search-result-filter-value",
|
|
21788
|
+
class: normalizeClass(["lupa-search-result-filter-value", [facetKeyClass.value]]),
|
|
21789
|
+
"data-cy": "lupa-current-filter-item"
|
|
21357
21790
|
}, [
|
|
21358
21791
|
createElementVNode("div", {
|
|
21359
21792
|
class: "lupa-current-filter-action",
|
|
21360
|
-
onClick: handleClick
|
|
21361
|
-
|
|
21793
|
+
onClick: handleClick,
|
|
21794
|
+
"aria-label": "Remove filter"
|
|
21795
|
+
}, " ⨉ "),
|
|
21362
21796
|
createElementVNode("div", _hoisted_1$U, toDisplayString(_ctx.filter.label) + ": ", 1),
|
|
21363
|
-
createElementVNode("div", _hoisted_2$F, toDisplayString(
|
|
21797
|
+
createElementVNode("div", _hoisted_2$F, toDisplayString(formatFilterValue(props.filter)), 1)
|
|
21364
21798
|
], 2);
|
|
21365
21799
|
};
|
|
21366
21800
|
}
|
|
@@ -21382,6 +21816,14 @@ const _sfc_main$Z = /* @__PURE__ */ defineComponent({
|
|
|
21382
21816
|
expandable: { type: Boolean }
|
|
21383
21817
|
},
|
|
21384
21818
|
setup(__props) {
|
|
21819
|
+
const optionsStore = useOptionsStore();
|
|
21820
|
+
const { searchResultOptions } = storeToRefs(optionsStore);
|
|
21821
|
+
const units = computed(
|
|
21822
|
+
() => {
|
|
21823
|
+
var _a, _b, _c, _d, _e;
|
|
21824
|
+
return (_e = (_d = (_c = (_b = (_a = searchResultOptions == null ? void 0 : searchResultOptions.value) == null ? void 0 : _a.filters) == null ? void 0 : _b.facets) == null ? void 0 : _c.stats) == null ? void 0 : _d.units) != null ? _e : {};
|
|
21825
|
+
}
|
|
21826
|
+
);
|
|
21385
21827
|
const isOpen = ref(false);
|
|
21386
21828
|
const paramsStore = useParamsStore();
|
|
21387
21829
|
const optionStore = useOptionsStore();
|
|
@@ -21463,8 +21905,9 @@ const _sfc_main$Z = /* @__PURE__ */ defineComponent({
|
|
|
21463
21905
|
return openBlock(), createBlock(_sfc_main$_, {
|
|
21464
21906
|
key: filter2.key + "_" + filter2.value,
|
|
21465
21907
|
filter: filter2,
|
|
21908
|
+
units: units.value,
|
|
21466
21909
|
onRemove: handleRemove
|
|
21467
|
-
}, null, 8, ["filter"]);
|
|
21910
|
+
}, null, 8, ["filter", "units"]);
|
|
21468
21911
|
}), 128))
|
|
21469
21912
|
]),
|
|
21470
21913
|
createElementVNode("div", {
|
|
@@ -22788,15 +23231,17 @@ const _hoisted_4$j = {
|
|
|
22788
23231
|
const _hoisted_5$d = { class: "lupa-stats-from" };
|
|
22789
23232
|
const _hoisted_6$7 = ["max", "min", "pattern", "aria-label"];
|
|
22790
23233
|
const _hoisted_7$5 = { key: 0 };
|
|
22791
|
-
const _hoisted_8$1 =
|
|
22792
|
-
const _hoisted_9$1 = {
|
|
23234
|
+
const _hoisted_8$1 = { key: 1 };
|
|
23235
|
+
const _hoisted_9$1 = /* @__PURE__ */ createElementVNode("div", { class: "lupa-stats-separator" }, null, -1);
|
|
23236
|
+
const _hoisted_10 = {
|
|
22793
23237
|
key: 0,
|
|
22794
23238
|
class: "lupa-stats-range-label"
|
|
22795
23239
|
};
|
|
22796
|
-
const
|
|
22797
|
-
const
|
|
22798
|
-
const
|
|
22799
|
-
const
|
|
23240
|
+
const _hoisted_11 = { class: "lupa-stats-to" };
|
|
23241
|
+
const _hoisted_12 = ["max", "min", "pattern", "aria-label"];
|
|
23242
|
+
const _hoisted_13 = { key: 0 };
|
|
23243
|
+
const _hoisted_14 = { key: 1 };
|
|
23244
|
+
const _hoisted_15 = {
|
|
22800
23245
|
key: 2,
|
|
22801
23246
|
class: "lupa-stats-slider-wrapper"
|
|
22802
23247
|
};
|
|
@@ -22863,7 +23308,7 @@ const _sfc_main$V = /* @__PURE__ */ defineComponent({
|
|
|
22863
23308
|
if (!value || value > facetMax.value) {
|
|
22864
23309
|
return;
|
|
22865
23310
|
}
|
|
22866
|
-
innerSliderRange.value = [
|
|
23311
|
+
innerSliderRange.value = [sliderRange.value[1], value];
|
|
22867
23312
|
handleInputChange();
|
|
22868
23313
|
}
|
|
22869
23314
|
});
|
|
@@ -22919,7 +23364,18 @@ const _sfc_main$V = /* @__PURE__ */ defineComponent({
|
|
|
22919
23364
|
});
|
|
22920
23365
|
const statsSummary = computed(() => {
|
|
22921
23366
|
const [min, max] = sliderRange.value;
|
|
22922
|
-
|
|
23367
|
+
if (isPrice.value) {
|
|
23368
|
+
return formatPriceSummary(
|
|
23369
|
+
[min, max],
|
|
23370
|
+
currency.value,
|
|
23371
|
+
separator.value,
|
|
23372
|
+
currencyTemplate.value
|
|
23373
|
+
);
|
|
23374
|
+
}
|
|
23375
|
+
if (unit.value) {
|
|
23376
|
+
return `${min} ${unit.value} - ${max} ${unit.value}`;
|
|
23377
|
+
}
|
|
23378
|
+
return formatRange({ gte: min, lte: max });
|
|
22923
23379
|
});
|
|
22924
23380
|
const separator = computed(() => {
|
|
22925
23381
|
var _a, _b, _c;
|
|
@@ -22980,6 +23436,12 @@ const _sfc_main$V = /* @__PURE__ */ defineComponent({
|
|
|
22980
23436
|
const handleDragging = (value) => {
|
|
22981
23437
|
innerSliderRange.value = value;
|
|
22982
23438
|
};
|
|
23439
|
+
const unit = computed(
|
|
23440
|
+
() => {
|
|
23441
|
+
var _a, _b, _c, _d, _e;
|
|
23442
|
+
return (_e = (_d = (_a = props.options.stats) == null ? void 0 : _a.units) == null ? void 0 : _d[(_c = (_b = props.facet) == null ? void 0 : _b.key) != null ? _c : ""]) != null ? _e : "";
|
|
23443
|
+
}
|
|
23444
|
+
);
|
|
22983
23445
|
return (_ctx, _cache) => {
|
|
22984
23446
|
return openBlock(), createElementBlock("div", _hoisted_1$P, [
|
|
22985
23447
|
!isInputVisible.value ? (openBlock(), createElementBlock("div", _hoisted_2$B, toDisplayString(statsSummary.value), 1)) : (openBlock(), createElementBlock("div", _hoisted_3$s, [
|
|
@@ -23002,13 +23464,14 @@ const _sfc_main$V = /* @__PURE__ */ defineComponent({
|
|
|
23002
23464
|
{ lazy: true }
|
|
23003
23465
|
]
|
|
23004
23466
|
]),
|
|
23005
|
-
isPrice.value ? (openBlock(), createElementBlock("span", _hoisted_7$5, toDisplayString(currency.value), 1)) : createCommentVNode("", true)
|
|
23467
|
+
isPrice.value ? (openBlock(), createElementBlock("span", _hoisted_7$5, toDisplayString(currency.value), 1)) : createCommentVNode("", true),
|
|
23468
|
+
unit.value ? (openBlock(), createElementBlock("span", _hoisted_8$1, toDisplayString(unit.value), 1)) : createCommentVNode("", true)
|
|
23006
23469
|
])
|
|
23007
23470
|
]),
|
|
23008
|
-
|
|
23471
|
+
_hoisted_9$1,
|
|
23009
23472
|
createElementVNode("div", null, [
|
|
23010
|
-
rangeLabelTo.value ? (openBlock(), createElementBlock("div",
|
|
23011
|
-
createElementVNode("div",
|
|
23473
|
+
rangeLabelTo.value ? (openBlock(), createElementBlock("div", _hoisted_10, toDisplayString(rangeLabelTo.value), 1)) : createCommentVNode("", true),
|
|
23474
|
+
createElementVNode("div", _hoisted_11, [
|
|
23012
23475
|
withDirectives(createElementVNode("input", {
|
|
23013
23476
|
"onUpdate:modelValue": _cache[1] || (_cache[1] = ($event) => toValue.value = $event),
|
|
23014
23477
|
type: "text",
|
|
@@ -23017,7 +23480,7 @@ const _sfc_main$V = /* @__PURE__ */ defineComponent({
|
|
|
23017
23480
|
min: facetMin.value,
|
|
23018
23481
|
pattern: sliderInputFormat.value,
|
|
23019
23482
|
"aria-label": ariaLabelTo.value
|
|
23020
|
-
}, null, 8,
|
|
23483
|
+
}, null, 8, _hoisted_12), [
|
|
23021
23484
|
[
|
|
23022
23485
|
vModelText,
|
|
23023
23486
|
toValue.value,
|
|
@@ -23025,11 +23488,12 @@ const _sfc_main$V = /* @__PURE__ */ defineComponent({
|
|
|
23025
23488
|
{ lazy: true }
|
|
23026
23489
|
]
|
|
23027
23490
|
]),
|
|
23028
|
-
isPrice.value ? (openBlock(), createElementBlock("span",
|
|
23491
|
+
isPrice.value ? (openBlock(), createElementBlock("span", _hoisted_13, toDisplayString(currency.value), 1)) : createCommentVNode("", true),
|
|
23492
|
+
unit.value ? (openBlock(), createElementBlock("span", _hoisted_14, toDisplayString(unit.value), 1)) : createCommentVNode("", true)
|
|
23029
23493
|
])
|
|
23030
23494
|
])
|
|
23031
23495
|
])),
|
|
23032
|
-
isSliderVisible.value ? (openBlock(), createElementBlock("div",
|
|
23496
|
+
isSliderVisible.value ? (openBlock(), createElementBlock("div", _hoisted_15, [
|
|
23033
23497
|
createVNode(unref(m), {
|
|
23034
23498
|
class: "slider",
|
|
23035
23499
|
tooltips: false,
|
|
@@ -27932,21 +28396,6 @@ const _sfc_main$8 = /* @__PURE__ */ defineComponent({
|
|
|
27932
28396
|
};
|
|
27933
28397
|
}
|
|
27934
28398
|
});
|
|
27935
|
-
const Env = {
|
|
27936
|
-
production: "https://api.lupasearch.com/v1/",
|
|
27937
|
-
staging: "https://api.staging.lupasearch.com/v1/"
|
|
27938
|
-
};
|
|
27939
|
-
const DEFAULT_REQUEST_CONFIG = {
|
|
27940
|
-
method: "POST",
|
|
27941
|
-
headers: { "Content-Type": "application/json" }
|
|
27942
|
-
};
|
|
27943
|
-
const DEFAULT_HEADERS = DEFAULT_REQUEST_CONFIG.headers;
|
|
27944
|
-
const getApiUrl = (environment, customBaseUrl) => {
|
|
27945
|
-
if (customBaseUrl) {
|
|
27946
|
-
return customBaseUrl;
|
|
27947
|
-
}
|
|
27948
|
-
return Env[environment] || Env["production"];
|
|
27949
|
-
};
|
|
27950
28399
|
const suggestSearchChatPhrases = (options, request, chatSettings) => __async(void 0, null, function* () {
|
|
27951
28400
|
var _a, _b, _c;
|
|
27952
28401
|
const { environment, customBaseUrl } = options;
|