@dataloop-ai/components 0.19.69 → 0.19.70
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/package.json
CHANGED
|
@@ -105,7 +105,11 @@ import { DlDatePicker } from '../../../DlDateTime'
|
|
|
105
105
|
import { DlMenu, DlIcon, DlLabel } from '../../../../essential'
|
|
106
106
|
import { isEllipsisActive } from '../../../../../utils/is-ellipsis-active'
|
|
107
107
|
import { useSizeObserver } from '../../../../../hooks/use-size-observer'
|
|
108
|
-
import {
|
|
108
|
+
import {
|
|
109
|
+
getSelectionOffset,
|
|
110
|
+
setCaretAtTheEnd,
|
|
111
|
+
setSelectionOffset
|
|
112
|
+
} from '../../../../../utils'
|
|
109
113
|
import { ColorSchema, SearchStatus, SyntaxColorSchema } from '../types'
|
|
110
114
|
import { debounce, isEqual } from 'lodash'
|
|
111
115
|
import { DlTooltip } from '../../../../shared'
|
|
@@ -120,15 +124,15 @@ import {
|
|
|
120
124
|
replaceJSDatesWithStringifiedDates,
|
|
121
125
|
replaceStringifiedDatesWithJSDates,
|
|
122
126
|
setAliases,
|
|
123
|
-
revertAliases
|
|
124
|
-
clearPartlyTypedSuggestion
|
|
127
|
+
revertAliases
|
|
125
128
|
} from '../utils'
|
|
126
129
|
import { v4 } from 'uuid'
|
|
127
130
|
import {
|
|
128
131
|
Schema,
|
|
129
132
|
Alias,
|
|
130
133
|
useSuggestions,
|
|
131
|
-
removeBrackets
|
|
134
|
+
removeBrackets,
|
|
135
|
+
removeLeadingExpression
|
|
132
136
|
} from '../../../../../hooks/use-suggestions'
|
|
133
137
|
import { parseSmartQuery, stringifySmartQuery } from '../../../../../utils'
|
|
134
138
|
|
|
@@ -228,6 +232,7 @@ export default defineComponent({
|
|
|
228
232
|
//#endregion
|
|
229
233
|
|
|
230
234
|
//#region data
|
|
235
|
+
const caretAt = ref(0)
|
|
231
236
|
const searchQuery = ref<string>('')
|
|
232
237
|
const focused = ref(false)
|
|
233
238
|
const isOverflowing = ref(false)
|
|
@@ -254,9 +259,9 @@ export default defineComponent({
|
|
|
254
259
|
//#region methods
|
|
255
260
|
const setInputValue = (
|
|
256
261
|
value: string,
|
|
257
|
-
options: { noEmit?: boolean } = {}
|
|
262
|
+
options: { noEmit?: boolean; testCaret?: number } = {}
|
|
258
263
|
) => {
|
|
259
|
-
const { noEmit } = options
|
|
264
|
+
const { noEmit, testCaret } = options
|
|
260
265
|
|
|
261
266
|
showSuggestions.value = false
|
|
262
267
|
|
|
@@ -265,8 +270,9 @@ export default defineComponent({
|
|
|
265
270
|
value = value.trimEnd()
|
|
266
271
|
}
|
|
267
272
|
|
|
268
|
-
const specialSuggestions = suggestions.value.filter(
|
|
269
|
-
suggestion
|
|
273
|
+
const specialSuggestions = suggestions.value.filter(
|
|
274
|
+
(suggestion) =>
|
|
275
|
+
typeof suggestion === 'string' && suggestion.startsWith('.')
|
|
270
276
|
)
|
|
271
277
|
|
|
272
278
|
for (const suggestion of specialSuggestions) {
|
|
@@ -277,6 +283,18 @@ export default defineComponent({
|
|
|
277
283
|
|
|
278
284
|
searchQuery.value = value
|
|
279
285
|
|
|
286
|
+
// TODO
|
|
287
|
+
// here the value is finalized - this should be inner function entry point
|
|
288
|
+
|
|
289
|
+
// find value left side before current input value is altered by any code below
|
|
290
|
+
// to match previous behavior, move the caret to the end if setInputValue has been passed new value
|
|
291
|
+
caretAt.value =
|
|
292
|
+
testCaret !== undefined
|
|
293
|
+
? testCaret
|
|
294
|
+
: value === input.value.innerText
|
|
295
|
+
? getSelectionOffset(input.value)[0]
|
|
296
|
+
: value.length
|
|
297
|
+
|
|
280
298
|
if (value !== input.value.innerText) {
|
|
281
299
|
input.value.innerHTML = value
|
|
282
300
|
}
|
|
@@ -303,7 +321,7 @@ export default defineComponent({
|
|
|
303
321
|
scroll.value = input.value.offsetHeight > 40
|
|
304
322
|
|
|
305
323
|
nextTick(() => {
|
|
306
|
-
findSuggestions(value)
|
|
324
|
+
findSuggestions(value.substring(0, caretAt.value))
|
|
307
325
|
})
|
|
308
326
|
|
|
309
327
|
if (!noEmit) {
|
|
@@ -313,57 +331,54 @@ export default defineComponent({
|
|
|
313
331
|
|
|
314
332
|
const setInputFromSuggestion = (value: string) => {
|
|
315
333
|
let stringValue = ''
|
|
334
|
+
let caretPosition = 0
|
|
316
335
|
if (searchQuery.value.length) {
|
|
317
|
-
let
|
|
318
|
-
|
|
319
|
-
.
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
if (
|
|
324
|
-
if
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
336
|
+
let queryLeftSide = searchQuery.value.substring(
|
|
337
|
+
0,
|
|
338
|
+
caretAt.value
|
|
339
|
+
)
|
|
340
|
+
let queryRightSide = searchQuery.value.substring(caretAt.value)
|
|
341
|
+
|
|
342
|
+
if (['AND', 'OR'].includes(value)) {
|
|
343
|
+
// do not replace text if the value is AND or OR
|
|
344
|
+
const leftover = queryLeftSide.match(/\S+$/)?.[0] || ''
|
|
345
|
+
queryLeftSide =
|
|
346
|
+
queryLeftSide.replace(/\S+$/, '').trimEnd() + ' '
|
|
347
|
+
queryRightSide = leftover + queryRightSide
|
|
348
|
+
} else if (value.startsWith('.')) {
|
|
349
|
+
// dot notation case
|
|
350
|
+
queryLeftSide = queryLeftSide.trimEnd().replace(/\.$/, '')
|
|
351
|
+
} else if (queryLeftSide.endsWith(' ')) {
|
|
352
|
+
// caret after space: only replace multiple spaces on the left
|
|
353
|
+
queryLeftSide = queryLeftSide.trimEnd() + ' '
|
|
354
|
+
} else if (/\.\S+$/.test(queryLeftSide)) {
|
|
355
|
+
// if there are dots in left side expression, suggestions have an operator
|
|
356
|
+
// looks like a bug in findSuggestions TODO find it - for now work around it here
|
|
357
|
+
const leftover = queryRightSide.match(/^\S+/)?.[0] || ''
|
|
358
|
+
queryLeftSide += leftover + ' '
|
|
359
|
+
queryRightSide = queryRightSide
|
|
360
|
+
.substring(leftover.length)
|
|
361
|
+
.trimStart()
|
|
362
|
+
} else if (queryRightSide.startsWith(' ')) {
|
|
363
|
+
// this| situation: replace whatever is there on the left side with the value
|
|
364
|
+
queryLeftSide = queryLeftSide.replace(/\S+$/, '')
|
|
365
|
+
queryRightSide = queryRightSide.trimStart()
|
|
344
366
|
} else {
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
} else if (
|
|
350
|
-
value
|
|
351
|
-
.toLowerCase()
|
|
352
|
-
.startsWith(query[query.length - 1].toLowerCase())
|
|
353
|
-
) {
|
|
354
|
-
query = query.slice(0, query.length - 1)
|
|
355
|
-
}
|
|
356
|
-
|
|
357
|
-
stringValue = [...query, value, ''].join(' ')
|
|
367
|
+
// this|situation: replace whatever is there on both sides with the value
|
|
368
|
+
queryLeftSide = queryLeftSide.replace(/\S+$/, '')
|
|
369
|
+
queryRightSide =
|
|
370
|
+
removeLeadingExpression(queryRightSide).trimStart()
|
|
358
371
|
}
|
|
372
|
+
|
|
373
|
+
stringValue = queryLeftSide + value + ' ' + queryRightSide
|
|
374
|
+
caretPosition = stringValue.length - queryRightSide.length
|
|
359
375
|
} else {
|
|
360
376
|
stringValue = value + ' '
|
|
377
|
+
caretPosition = stringValue.length
|
|
361
378
|
}
|
|
362
379
|
|
|
363
|
-
setInputValue(
|
|
364
|
-
|
|
365
|
-
)
|
|
366
|
-
setCaretAtTheEnd(input.value)
|
|
380
|
+
setInputValue(stringValue)
|
|
381
|
+
setSelectionOffset(input.value, caretPosition, caretPosition)
|
|
367
382
|
}
|
|
368
383
|
|
|
369
384
|
const debouncedSetInputValue = debounce(setInputValue, 300)
|
|
@@ -815,19 +830,31 @@ export default defineComponent({
|
|
|
815
830
|
)
|
|
816
831
|
//#endregion
|
|
817
832
|
|
|
833
|
+
const watchMouseMove = () => {
|
|
834
|
+
isTyping.value = false
|
|
835
|
+
}
|
|
836
|
+
|
|
837
|
+
const watchKeyUp = (e: KeyboardEvent) => {
|
|
838
|
+
if (
|
|
839
|
+
focused.value &&
|
|
840
|
+
(e.key === 'ArrowLeft' || e.key === 'ArrowRight')
|
|
841
|
+
) {
|
|
842
|
+
setInputValue(searchQuery.value, { noEmit: true })
|
|
843
|
+
}
|
|
844
|
+
}
|
|
845
|
+
|
|
818
846
|
onMounted(() => {
|
|
819
847
|
if (!expanded.value) {
|
|
820
848
|
isOverflowing.value =
|
|
821
849
|
isEllipsisActive(input.value) || hasEllipsis.value
|
|
822
850
|
}
|
|
823
|
-
window.addEventListener('mousemove',
|
|
851
|
+
window.addEventListener('mousemove', watchMouseMove)
|
|
852
|
+
window.addEventListener('keyup', watchKeyUp)
|
|
824
853
|
blur(null, { force: true })
|
|
825
854
|
})
|
|
826
855
|
onBeforeUnmount(() => {
|
|
827
|
-
window.removeEventListener(
|
|
828
|
-
|
|
829
|
-
() => (isTyping.value = false)
|
|
830
|
-
)
|
|
856
|
+
window.removeEventListener('mousemove', watchMouseMove)
|
|
857
|
+
window.removeEventListener('keyup', watchKeyUp)
|
|
831
858
|
})
|
|
832
859
|
|
|
833
860
|
return {
|
|
@@ -119,28 +119,3 @@ export function setCaretAtTheEnd(target: HTMLElement) {
|
|
|
119
119
|
sel.addRange(range)
|
|
120
120
|
target.focus()
|
|
121
121
|
}
|
|
122
|
-
|
|
123
|
-
export function clearPartlyTypedSuggestion(oldValue: string, newValue: string) {
|
|
124
|
-
const oldSuggestions = oldValue.split(' ')
|
|
125
|
-
const newSuggestions = newValue.split(' ')
|
|
126
|
-
|
|
127
|
-
const oldSuggestion = oldSuggestions[oldSuggestions.length - 1]
|
|
128
|
-
const newSuggestion = newSuggestions[newSuggestions.length - 2]
|
|
129
|
-
|
|
130
|
-
if (oldSuggestion && newSuggestion?.includes(oldSuggestion)) {
|
|
131
|
-
newValue = removeOldSuggestion(newValue)
|
|
132
|
-
}
|
|
133
|
-
return newValue
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
function removeOldSuggestion(inputString: string) {
|
|
137
|
-
const words = inputString.trim().split(' ')
|
|
138
|
-
|
|
139
|
-
if (words.length >= 2) {
|
|
140
|
-
words.splice(-2, 1)
|
|
141
|
-
const resultString = words.join(' ')
|
|
142
|
-
return resultString + ' '
|
|
143
|
-
} else {
|
|
144
|
-
return inputString
|
|
145
|
-
}
|
|
146
|
-
}
|
|
@@ -610,8 +610,8 @@ export const removeBrackets = (str: string) => {
|
|
|
610
610
|
|
|
611
611
|
let result = removeAllBrackets(str.substring(0, quotesAt[0]))
|
|
612
612
|
|
|
613
|
-
let skipFrom = 0
|
|
614
|
-
|
|
613
|
+
let skipFrom = 0
|
|
614
|
+
let skipTo = 1
|
|
615
615
|
while (quotesAt[skipFrom] !== undefined) {
|
|
616
616
|
// skip as far as isValidString fails
|
|
617
617
|
while (
|
|
@@ -652,6 +652,17 @@ export const removeBrackets = (str: string) => {
|
|
|
652
652
|
return result
|
|
653
653
|
}
|
|
654
654
|
|
|
655
|
+
export const removeLeadingExpression = (str: string) => {
|
|
656
|
+
// scan for a substring that isValidString
|
|
657
|
+
for (let i = 2; i < str.length; i++) {
|
|
658
|
+
if (isValidString(str.substring(0, i))) {
|
|
659
|
+
return str.substring(i).trimStart()
|
|
660
|
+
}
|
|
661
|
+
}
|
|
662
|
+
// return everything after 1st space, or an empty string
|
|
663
|
+
return str.match(/\s+(.*)$/)?.[1] || ''
|
|
664
|
+
}
|
|
665
|
+
|
|
655
666
|
const getValueSuggestions = (dataType: string | string[], operator: string) => {
|
|
656
667
|
const types: string[] = Array.isArray(dataType) ? dataType : [dataType]
|
|
657
668
|
const suggestion: string[] = []
|