@tellescope/react-components 1.232.0 → 1.232.1
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/lib/cjs/Forms/forms.v2.d.ts +1 -1
- package/lib/cjs/Forms/hooks.d.ts.map +1 -1
- package/lib/cjs/Forms/hooks.js +24 -0
- package/lib/cjs/Forms/hooks.js.map +1 -1
- package/lib/cjs/Forms/inputs.d.ts +4 -1
- package/lib/cjs/Forms/inputs.d.ts.map +1 -1
- package/lib/cjs/Forms/inputs.js +100 -26
- package/lib/cjs/Forms/inputs.js.map +1 -1
- package/lib/cjs/Forms/inputs.v2.d.ts +5 -7
- package/lib/cjs/Forms/inputs.v2.d.ts.map +1 -1
- package/lib/cjs/Forms/inputs.v2.js +7 -234
- package/lib/cjs/Forms/inputs.v2.js.map +1 -1
- package/lib/esm/CMS/components.d.ts +0 -1
- package/lib/esm/CMS/components.d.ts.map +1 -1
- package/lib/esm/Forms/form_responses.d.ts +0 -1
- package/lib/esm/Forms/form_responses.d.ts.map +1 -1
- package/lib/esm/Forms/forms.d.ts +3 -3
- package/lib/esm/Forms/forms.v2.d.ts +4 -4
- package/lib/esm/Forms/hooks.d.ts +0 -1
- package/lib/esm/Forms/hooks.d.ts.map +1 -1
- package/lib/esm/Forms/hooks.js +24 -0
- package/lib/esm/Forms/hooks.js.map +1 -1
- package/lib/esm/Forms/inputs.d.ts +5 -2
- package/lib/esm/Forms/inputs.d.ts.map +1 -1
- package/lib/esm/Forms/inputs.js +101 -27
- package/lib/esm/Forms/inputs.js.map +1 -1
- package/lib/esm/Forms/inputs.v2.d.ts +6 -8
- package/lib/esm/Forms/inputs.v2.d.ts.map +1 -1
- package/lib/esm/Forms/inputs.v2.js +7 -234
- package/lib/esm/Forms/inputs.v2.js.map +1 -1
- package/lib/esm/controls.d.ts +2 -2
- package/lib/esm/inputs.d.ts +1 -1
- package/lib/esm/inputs.native.d.ts +0 -1
- package/lib/esm/inputs.native.d.ts.map +1 -1
- package/lib/esm/state.d.ts +315 -315
- package/lib/tsconfig.tsbuildinfo +1 -1
- package/package.json +9 -9
- package/src/Forms/hooks.tsx +33 -5
- package/src/Forms/inputs.tsx +151 -29
- package/src/Forms/inputs.v2.tsx +9 -299
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tellescope/react-components",
|
|
3
|
-
"version": "1.232.
|
|
3
|
+
"version": "1.232.1",
|
|
4
4
|
"description": "",
|
|
5
5
|
"main": "./lib/cjs/index.js",
|
|
6
6
|
"module": "./lib/esm/index.js",
|
|
@@ -47,13 +47,13 @@
|
|
|
47
47
|
"@reduxjs/toolkit": "^1.6.2",
|
|
48
48
|
"@stripe/react-stripe-js": "^2.9.0",
|
|
49
49
|
"@stripe/stripe-js": "^1.52.1",
|
|
50
|
-
"@tellescope/constants": "1.232.
|
|
51
|
-
"@tellescope/sdk": "1.232.
|
|
52
|
-
"@tellescope/types-client": "1.232.
|
|
53
|
-
"@tellescope/types-models": "1.232.
|
|
54
|
-
"@tellescope/types-utilities": "1.232.
|
|
55
|
-
"@tellescope/utilities": "1.232.
|
|
56
|
-
"@tellescope/validation": "1.232.
|
|
50
|
+
"@tellescope/constants": "1.232.1",
|
|
51
|
+
"@tellescope/sdk": "1.232.1",
|
|
52
|
+
"@tellescope/types-client": "1.232.1",
|
|
53
|
+
"@tellescope/types-models": "1.232.1",
|
|
54
|
+
"@tellescope/types-utilities": "1.232.1",
|
|
55
|
+
"@tellescope/utilities": "1.232.1",
|
|
56
|
+
"@tellescope/validation": "1.232.1",
|
|
57
57
|
"@typescript-eslint/eslint-plugin": "^4.33.0",
|
|
58
58
|
"@typescript-eslint/parser": "^4.33.0",
|
|
59
59
|
"css-to-react-native": "^3.0.0",
|
|
@@ -83,7 +83,7 @@
|
|
|
83
83
|
"react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0",
|
|
84
84
|
"react-native": "^0.65.0 || ^0.66.0 || ^0.67.0 || ^0.68.0 || ^0.71.0"
|
|
85
85
|
},
|
|
86
|
-
"gitHead": "
|
|
86
|
+
"gitHead": "1cbb2f579785066cd64d72b4bfdd2c788e192391",
|
|
87
87
|
"publishConfig": {
|
|
88
88
|
"access": "public"
|
|
89
89
|
}
|
package/src/Forms/hooks.tsx
CHANGED
|
@@ -549,6 +549,7 @@ export const useTellescopeForm = ({ dontAutoadvance, isPublicForm, form, urlLogi
|
|
|
549
549
|
|
|
550
550
|
const gaEventRef = useRef({} as Record<string, boolean>)
|
|
551
551
|
const gtmEventRef = useRef({} as Record<string, boolean>)
|
|
552
|
+
const fieldViewCacheRef = useRef({} as Record<string, number>) // fieldId -> timestamp
|
|
552
553
|
|
|
553
554
|
let goBackURL = ''
|
|
554
555
|
try {
|
|
@@ -606,16 +607,43 @@ export const useTellescopeForm = ({ dontAutoadvance, isPublicForm, form, urlLogi
|
|
|
606
607
|
if (gtmEventRef.current[activeField.value.id]) return
|
|
607
608
|
gtmEventRef.current[activeField.value.id] = true
|
|
608
609
|
|
|
609
|
-
emit_gtm_event({
|
|
610
|
-
event: 'form_progress',
|
|
611
|
-
formId: activeField.value.formId,
|
|
612
|
-
fieldId: activeField.value.id,
|
|
610
|
+
emit_gtm_event({
|
|
611
|
+
event: 'form_progress',
|
|
612
|
+
formId: activeField.value.formId,
|
|
613
|
+
fieldId: activeField.value.id,
|
|
613
614
|
title: activeField.value.title,
|
|
614
615
|
previousTitle: prevFieldStackRef.current[prevFieldStackRef.current.length - 1]?.value?.title || '',
|
|
615
|
-
status: ''
|
|
616
|
+
status: ''
|
|
616
617
|
})
|
|
617
618
|
}, [activeField])
|
|
618
619
|
|
|
620
|
+
// Track field views for analytics
|
|
621
|
+
useEffect(() => {
|
|
622
|
+
if (!accessCode && !formResponseId) return // Need either accessCode or formResponseId
|
|
623
|
+
|
|
624
|
+
const fieldId = activeField.value.id
|
|
625
|
+
const now = Date.now()
|
|
626
|
+
const lastLogged = fieldViewCacheRef.current[fieldId]
|
|
627
|
+
|
|
628
|
+
// Only log if field hasn't been logged before, or more than 60 seconds have passed
|
|
629
|
+
const shouldLog = !lastLogged || (now - lastLogged > 60000) // 60 seconds
|
|
630
|
+
|
|
631
|
+
if (shouldLog) {
|
|
632
|
+
fieldViewCacheRef.current[fieldId] = now
|
|
633
|
+
|
|
634
|
+
// Call API to log the view (fire and forget, don't block UI)
|
|
635
|
+
session.api.form_responses.save_field_response({
|
|
636
|
+
accessCode,
|
|
637
|
+
formResponseId,
|
|
638
|
+
viewOnly: true,
|
|
639
|
+
fieldId,
|
|
640
|
+
}).catch(err => {
|
|
641
|
+
// Silent fail - view tracking is non-critical
|
|
642
|
+
console.debug('Failed to log field view:', err)
|
|
643
|
+
})
|
|
644
|
+
}
|
|
645
|
+
}, [activeField, accessCode, formResponseId, session])
|
|
646
|
+
|
|
619
647
|
// placeholders for initial fields, reset when fields prop changes, since questions are now different (e.g. different form selected)
|
|
620
648
|
const fieldInitRef = useRef('')
|
|
621
649
|
const initializeFields = useCallback(() => (
|
package/src/Forms/inputs.tsx
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import React, { forwardRef, useCallback, useEffect, useMemo, useRef, useState } from "react"
|
|
2
2
|
import axios from "axios"
|
|
3
|
-
import { Autocomplete, Box, Button, Checkbox, Chip, Collapse, Divider, FormControl, FormControlLabel, FormLabel, Grid, IconButton as MuiIconButton, InputLabel, MenuItem, Radio, RadioGroup, Select, SxProps, TextField, TextFieldProps, Typography } from "@mui/material"
|
|
3
|
+
import { Autocomplete, Box, Button, Checkbox, Chip, CircularProgress, Collapse, Divider, FormControl, FormControlLabel, FormLabel, Grid, IconButton as MuiIconButton, InputLabel, MenuItem, Radio, RadioGroup, Select, SxProps, TextField, TextFieldProps, Typography } from "@mui/material"
|
|
4
4
|
import { FormInputProps } from "./types"
|
|
5
5
|
import { useDropzone } from "react-dropzone"
|
|
6
6
|
import { CANVAS_TITLE, EMOTII_TITLE, INSURANCE_RELATIONSHIPS, INSURANCE_RELATIONSHIPS_CANVAS, PRIMARY_HEX, RELATIONSHIP_TYPES, TELLESCOPE_GENDERS } from "@tellescope/constants"
|
|
@@ -26,6 +26,16 @@ import { loadStripe } from '@stripe/stripe-js';
|
|
|
26
26
|
import { CheckCircleOutline, Delete, Edit, ExpandMore } from "@mui/icons-material"
|
|
27
27
|
import { WYSIWYG } from "./wysiwyg"
|
|
28
28
|
|
|
29
|
+
// Debounce hook for search functionality
|
|
30
|
+
const useDebounce = <T,>(value: T, delay: number): T => {
|
|
31
|
+
const [debouncedValue, setDebouncedValue] = useState<T>(value)
|
|
32
|
+
useEffect(() => {
|
|
33
|
+
const handler = setTimeout(() => setDebouncedValue(value), delay)
|
|
34
|
+
return () => clearTimeout(handler)
|
|
35
|
+
}, [value, delay])
|
|
36
|
+
return debouncedValue
|
|
37
|
+
}
|
|
38
|
+
|
|
29
39
|
export const LanguageSelect = ({ value, ...props }: { value: string, onChange: (s: string) => void}) => (
|
|
30
40
|
<Grid container alignItems="center" justifyContent={"center"} wrap="nowrap" spacing={1}>
|
|
31
41
|
<Grid item>
|
|
@@ -2191,48 +2201,126 @@ const choicesForDatabase: {
|
|
|
2191
2201
|
const preventRefetch: Record<string, boolean> = {}
|
|
2192
2202
|
|
|
2193
2203
|
const LOAD_CHOICES_LIMIT = 500
|
|
2194
|
-
const
|
|
2204
|
+
const MIN_SEARCH_CHARS = 3
|
|
2205
|
+
const SEARCH_DEBOUNCE_MS = 300
|
|
2206
|
+
|
|
2207
|
+
const useDatabaseChoices = ({
|
|
2208
|
+
databaseId='',
|
|
2209
|
+
field,
|
|
2210
|
+
otherAnswers,
|
|
2211
|
+
searchQuery = ''
|
|
2212
|
+
} : {
|
|
2213
|
+
databaseId?: string,
|
|
2214
|
+
field: FormField,
|
|
2215
|
+
otherAnswers?: DatabaseSelectResponse[],
|
|
2216
|
+
searchQuery?: string
|
|
2217
|
+
}) => {
|
|
2195
2218
|
const session = useResolvedSession()
|
|
2196
|
-
const [
|
|
2219
|
+
const [isSearching, setIsSearching] = useState(false)
|
|
2220
|
+
const [searchResults, setSearchResults] = useState<DatabaseRecord[]>([])
|
|
2221
|
+
const [initialLoadComplete, setInitialLoadComplete] = useState(false)
|
|
2222
|
+
const debouncedSearch = useDebounce(searchQuery, SEARCH_DEBOUNCE_MS)
|
|
2197
2223
|
|
|
2198
|
-
//
|
|
2224
|
+
// Load initial page on mount (only once, not recursively)
|
|
2225
|
+
const initialLoadRef = useRef(false)
|
|
2199
2226
|
useEffect(() => {
|
|
2200
|
-
if (
|
|
2201
|
-
if (
|
|
2202
|
-
|
|
2203
|
-
|
|
2227
|
+
if (initialLoadRef.current) return
|
|
2228
|
+
if (choicesForDatabase[databaseId]?.done || choicesForDatabase[databaseId]?.records?.length) {
|
|
2229
|
+
setInitialLoadComplete(true)
|
|
2230
|
+
return
|
|
2231
|
+
}
|
|
2204
2232
|
|
|
2205
|
-
|
|
2206
|
-
preventRefetch[databaseId + field.id
|
|
2233
|
+
initialLoadRef.current = true
|
|
2234
|
+
preventRefetch[databaseId + field.id] = true
|
|
2207
2235
|
|
|
2208
2236
|
session.api.form_fields.load_choices_from_database({
|
|
2209
2237
|
fieldId: field.id,
|
|
2210
|
-
lastId,
|
|
2211
2238
|
limit: LOAD_CHOICES_LIMIT,
|
|
2212
2239
|
databaseId, // overrides fieldId, supports using Database question in Table Input
|
|
2213
2240
|
})
|
|
2214
2241
|
.then(({ choices: newChoices }) => {
|
|
2215
2242
|
choicesForDatabase[databaseId] = {
|
|
2216
2243
|
lastId: newChoices?.[newChoices.length - 1]?.id,
|
|
2217
|
-
records:
|
|
2218
|
-
|
|
2244
|
+
records: newChoices.sort((c1, c2) => (
|
|
2245
|
+
label_for_database_record(field, c1)
|
|
2246
|
+
.localeCompare(label_for_database_record(field, c2))
|
|
2247
|
+
)),
|
|
2248
|
+
done: true, // Don't load more pages automatically
|
|
2249
|
+
}
|
|
2250
|
+
setInitialLoadComplete(true)
|
|
2251
|
+
})
|
|
2252
|
+
.catch(err => {
|
|
2253
|
+
console.error(err)
|
|
2254
|
+
preventRefetch[databaseId + field.id] = false
|
|
2255
|
+
setInitialLoadComplete(true) // Mark as complete even on error to avoid infinite loading
|
|
2256
|
+
})
|
|
2257
|
+
}, [session, field, databaseId])
|
|
2258
|
+
|
|
2259
|
+
// Handle debounced search
|
|
2260
|
+
const searchRef = useRef(debouncedSearch)
|
|
2261
|
+
useEffect(() => {
|
|
2262
|
+
const trimmed = debouncedSearch.trim()
|
|
2263
|
+
|
|
2264
|
+
// If search is cleared, return to initial results
|
|
2265
|
+
if (!trimmed) {
|
|
2266
|
+
setSearchResults([])
|
|
2267
|
+
setIsSearching(false)
|
|
2268
|
+
searchRef.current = debouncedSearch
|
|
2269
|
+
return
|
|
2270
|
+
}
|
|
2271
|
+
|
|
2272
|
+
// Only search if meets minimum character requirement
|
|
2273
|
+
if (trimmed.length < MIN_SEARCH_CHARS) {
|
|
2274
|
+
setSearchResults([])
|
|
2275
|
+
setIsSearching(false)
|
|
2276
|
+
return
|
|
2277
|
+
}
|
|
2278
|
+
|
|
2279
|
+
// Avoid duplicate searches
|
|
2280
|
+
if (searchRef.current === debouncedSearch) return
|
|
2281
|
+
searchRef.current = debouncedSearch
|
|
2282
|
+
|
|
2283
|
+
setIsSearching(true)
|
|
2284
|
+
session.api.form_fields.load_choices_from_database({
|
|
2285
|
+
fieldId: field.id,
|
|
2286
|
+
limit: LOAD_CHOICES_LIMIT,
|
|
2287
|
+
databaseId,
|
|
2288
|
+
search: trimmed,
|
|
2289
|
+
})
|
|
2290
|
+
.then(({ choices: newChoices }) => {
|
|
2291
|
+
// Add search results to the same cache as initial load
|
|
2292
|
+
// This ensures selected search results persist even after search is cleared
|
|
2293
|
+
const existingRecords = choicesForDatabase[databaseId]?.records ?? []
|
|
2294
|
+
const existingIds = new Set(existingRecords.map(r => r.id))
|
|
2295
|
+
|
|
2296
|
+
const uniqueNewChoices = newChoices.filter(c => !existingIds.has(c.id))
|
|
2297
|
+
|
|
2298
|
+
if (uniqueNewChoices.length > 0) {
|
|
2299
|
+
choicesForDatabase[databaseId] = {
|
|
2300
|
+
...choicesForDatabase[databaseId],
|
|
2301
|
+
records: [...existingRecords, ...uniqueNewChoices].sort((c1, c2) => (
|
|
2219
2302
|
label_for_database_record(field, c1)
|
|
2220
2303
|
.localeCompare(label_for_database_record(field, c2))
|
|
2221
|
-
)
|
|
2222
|
-
|
|
2223
|
-
|
|
2224
|
-
}
|
|
2225
|
-
|
|
2304
|
+
)),
|
|
2305
|
+
done: true, // Mark as done since we're not paginating search results
|
|
2306
|
+
}
|
|
2307
|
+
}
|
|
2308
|
+
|
|
2309
|
+
setSearchResults(newChoices.sort((c1, c2) => (
|
|
2310
|
+
label_for_database_record(field, c1)
|
|
2311
|
+
.localeCompare(label_for_database_record(field, c2))
|
|
2312
|
+
)))
|
|
2313
|
+
setIsSearching(false)
|
|
2226
2314
|
})
|
|
2227
2315
|
.catch(err => {
|
|
2228
2316
|
console.error(err)
|
|
2229
|
-
|
|
2317
|
+
setIsSearching(false)
|
|
2230
2318
|
})
|
|
2231
|
-
}, [session, field, databaseId,
|
|
2319
|
+
}, [session, field, databaseId, debouncedSearch])
|
|
2232
2320
|
|
|
2233
2321
|
const addChoice = useCallback((record: DatabaseRecord) => {
|
|
2234
2322
|
if (!choicesForDatabase[databaseId]) {
|
|
2235
|
-
choicesForDatabase[databaseId] = {
|
|
2323
|
+
choicesForDatabase[databaseId] = {
|
|
2236
2324
|
done: false,
|
|
2237
2325
|
records: [],
|
|
2238
2326
|
}
|
|
@@ -2240,18 +2328,24 @@ const useDatabaseChoices = ({ databaseId='', field, otherAnswers } : { databaseI
|
|
|
2240
2328
|
choicesForDatabase[databaseId].records!.push(record)
|
|
2241
2329
|
}, [choicesForDatabase, databaseId])
|
|
2242
2330
|
|
|
2331
|
+
// Use search results if searching, otherwise use cached initial results
|
|
2332
|
+
const activeChoices = debouncedSearch.trim().length >= MIN_SEARCH_CHARS
|
|
2333
|
+
? searchResults
|
|
2334
|
+
: (choicesForDatabase[databaseId]?.records ?? [])
|
|
2335
|
+
|
|
2243
2336
|
return {
|
|
2244
2337
|
addChoice,
|
|
2245
|
-
doneLoading:
|
|
2338
|
+
doneLoading: initialLoadComplete,
|
|
2339
|
+
isSearching,
|
|
2246
2340
|
choices: [
|
|
2247
|
-
...
|
|
2341
|
+
...activeChoices,
|
|
2248
2342
|
...(otherAnswers || []).map(v => ({
|
|
2249
2343
|
id: v.text,
|
|
2250
2344
|
databaseId,
|
|
2251
2345
|
values: [{ label: field.options?.databaseLabel || '', type: 'Text', value: v.text }],
|
|
2252
2346
|
}) as Pick<DatabaseRecord, 'id' | 'values' | 'databaseId'>)
|
|
2253
2347
|
],
|
|
2254
|
-
|
|
2348
|
+
minSearchChars: MIN_SEARCH_CHARS,
|
|
2255
2349
|
}
|
|
2256
2350
|
}
|
|
2257
2351
|
|
|
@@ -2297,15 +2391,18 @@ export interface AddToDatabaseProps {
|
|
|
2297
2391
|
onAdd: (record: DatabaseRecord) => void
|
|
2298
2392
|
}
|
|
2299
2393
|
|
|
2300
|
-
export const DatabaseSelectInput = ({ AddToDatabase, field, value: _value, onChange, onDatabaseSelect, responses, size, disabled, enduser }: FormInputProps<'Database Select'> & {
|
|
2394
|
+
export const DatabaseSelectInput = ({ AddToDatabase, field, value: _value, onChange, onDatabaseSelect, responses, size, disabled, enduser, inputProps }: FormInputProps<'Database Select'> & {
|
|
2301
2395
|
responses: FormResponseValue[],
|
|
2302
2396
|
AddToDatabase?: React.JSXElementConstructor<AddToDatabaseProps>,
|
|
2397
|
+
inputProps?: { sx: SxProps },
|
|
2303
2398
|
}) => {
|
|
2304
2399
|
const [typing, setTyping] = useState('')
|
|
2305
|
-
const
|
|
2400
|
+
const [open, setOpen] = useState(false)
|
|
2401
|
+
const { addChoice, choices, doneLoading, isSearching, minSearchChars } = useDatabaseChoices({
|
|
2306
2402
|
databaseId: field.options?.databaseId,
|
|
2307
2403
|
field,
|
|
2308
2404
|
otherAnswers: get_other_answers(_value, field?.options?.other ? typing : undefined),
|
|
2405
|
+
searchQuery: typing,
|
|
2309
2406
|
})
|
|
2310
2407
|
|
|
2311
2408
|
const value = React.useMemo(() => {
|
|
@@ -2313,8 +2410,8 @@ export const DatabaseSelectInput = ({ AddToDatabase, field, value: _value, onCha
|
|
|
2313
2410
|
// if the value is a string (some single answer that was save), make sure we coerce to array
|
|
2314
2411
|
const __value = typeof _value === 'string' ? [_value] : _value
|
|
2315
2412
|
return (
|
|
2316
|
-
(__value?.map(v =>
|
|
2317
|
-
choices.find(c =>
|
|
2413
|
+
(__value?.map(v =>
|
|
2414
|
+
choices.find(c =>
|
|
2318
2415
|
c.id === v.recordId || (typeof v === 'string' && label_for_database_record(field, c) === v)
|
|
2319
2416
|
)
|
|
2320
2417
|
)?.filter(v => v!) ?? []) as DatabaseRecord[]
|
|
@@ -2423,12 +2520,21 @@ export const DatabaseSelectInput = ({ AddToDatabase, field, value: _value, onCha
|
|
|
2423
2520
|
return filtered
|
|
2424
2521
|
}, [field, stateFilteredChoices])
|
|
2425
2522
|
|
|
2523
|
+
// Show placeholder when typing but below minimum search characters
|
|
2524
|
+
const charsNeeded = typing.trim().length > 0 && typing.trim().length < minSearchChars
|
|
2525
|
+
? minSearchChars - typing.trim().length
|
|
2526
|
+
: 0
|
|
2527
|
+
|
|
2426
2528
|
if (!doneLoading) return <LinearProgress />
|
|
2427
2529
|
return (
|
|
2428
2530
|
<>
|
|
2429
2531
|
<Autocomplete id={field.id} freeSolo={false} size={size}
|
|
2430
2532
|
componentsProps={{ popper: { sx: { wordBreak: "break-word" } } } }
|
|
2431
2533
|
options={filteredChoices} multiple={true}
|
|
2534
|
+
loading={isSearching}
|
|
2535
|
+
open={open}
|
|
2536
|
+
onOpen={() => setOpen(true)}
|
|
2537
|
+
onClose={() => setOpen(false)}
|
|
2432
2538
|
getOptionLabel={o => (
|
|
2433
2539
|
Array.isArray(o) // edge case
|
|
2434
2540
|
? ''
|
|
@@ -2463,7 +2569,23 @@ export const DatabaseSelectInput = ({ AddToDatabase, field, value: _value, onCha
|
|
|
2463
2569
|
}}
|
|
2464
2570
|
inputValue={typing}
|
|
2465
2571
|
onInputChange={(e, v) => e && setTyping(v)}
|
|
2466
|
-
renderInput={params =>
|
|
2572
|
+
renderInput={params => (
|
|
2573
|
+
<TextField
|
|
2574
|
+
{...params}
|
|
2575
|
+
InputProps={{
|
|
2576
|
+
...params.InputProps,
|
|
2577
|
+
sx: (inputProps || defaultInputProps).sx,
|
|
2578
|
+
endAdornment: (
|
|
2579
|
+
<>
|
|
2580
|
+
{isSearching ? <CircularProgress color="inherit" size={20} /> : null}
|
|
2581
|
+
{params.InputProps.endAdornment}
|
|
2582
|
+
</>
|
|
2583
|
+
),
|
|
2584
|
+
}}
|
|
2585
|
+
placeholder={charsNeeded > 0 ? `Type ${charsNeeded} more character${charsNeeded > 1 ? 's' : ''} to search...` : undefined}
|
|
2586
|
+
helperText={charsNeeded > 0 ? `Type ${charsNeeded} more character${charsNeeded > 1 ? 's' : ''} to search` : undefined}
|
|
2587
|
+
/>
|
|
2588
|
+
)}
|
|
2467
2589
|
// use custom Chip to ensure very long entries break properly (whitespace: normal)
|
|
2468
2590
|
renderTags={(value, getTagProps) =>
|
|
2469
2591
|
value.map((value, index) => (
|