@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/lib/esm/Forms/inputs.js
CHANGED
|
@@ -72,7 +72,7 @@ var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) {
|
|
|
72
72
|
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
73
73
|
import React, { forwardRef, useCallback, useEffect, useMemo, useRef, useState } from "react";
|
|
74
74
|
import axios from "axios";
|
|
75
|
-
import { Autocomplete, Box, Button, Checkbox, Chip, Collapse, Divider, FormControl, FormControlLabel, FormLabel, Grid, IconButton as MuiIconButton, InputLabel, MenuItem, Radio, RadioGroup, Select, TextField, Typography } from "@mui/material";
|
|
75
|
+
import { Autocomplete, Box, Button, Checkbox, Chip, CircularProgress, Collapse, Divider, FormControl, FormControlLabel, FormLabel, Grid, IconButton as MuiIconButton, InputLabel, MenuItem, Radio, RadioGroup, Select, TextField, Typography } from "@mui/material";
|
|
76
76
|
import { useDropzone } from "react-dropzone";
|
|
77
77
|
import { CANVAS_TITLE, EMOTII_TITLE, INSURANCE_RELATIONSHIPS, INSURANCE_RELATIONSHIPS_CANVAS, PRIMARY_HEX, RELATIONSHIP_TYPES, TELLESCOPE_GENDERS } from "@tellescope/constants";
|
|
78
78
|
import { MM_DD_YYYY_to_YYYY_MM_DD, capture_is_supported, downloadFile, emit_gtm_event, first_letter_capitalized, form_response_value_to_string, format_stripe_subscription_interval, getLocalTimezone, getPublicFileURL, mm_dd_yyyy, object_is_empty, replace_enduser_template_values, responses_satisfy_conditions, truncate_string, update_local_storage, user_display_name } from "@tellescope/utilities";
|
|
@@ -93,6 +93,15 @@ import { Elements, PaymentElement, useStripe, useElements, EmbeddedCheckout, Emb
|
|
|
93
93
|
import { loadStripe } from '@stripe/stripe-js';
|
|
94
94
|
import { CheckCircleOutline, Delete, Edit, ExpandMore } from "@mui/icons-material";
|
|
95
95
|
import { WYSIWYG } from "./wysiwyg";
|
|
96
|
+
// Debounce hook for search functionality
|
|
97
|
+
var useDebounce = function (value, delay) {
|
|
98
|
+
var _a = useState(value), debouncedValue = _a[0], setDebouncedValue = _a[1];
|
|
99
|
+
useEffect(function () {
|
|
100
|
+
var handler = setTimeout(function () { return setDebouncedValue(value); }, delay);
|
|
101
|
+
return function () { return clearTimeout(handler); };
|
|
102
|
+
}, [value, delay]);
|
|
103
|
+
return debouncedValue;
|
|
104
|
+
};
|
|
96
105
|
export var LanguageSelect = function (_a) {
|
|
97
106
|
var value = _a.value, props = __rest(_a, ["value"]);
|
|
98
107
|
return (_jsxs(Grid, __assign({ container: true, alignItems: "center", justifyContent: "center", wrap: "nowrap", spacing: 1 }, { children: [_jsx(Grid, __assign({ item: true }, { children: _jsx(LanguageIcon, { color: "primary" }) })), _jsx(Grid, __assign({ item: true, style: { width: 150 } }, { children: _jsx(StringSelector, __assign({}, props, { options: ["English", "Español"], size: "small", value: value === 'Spanish' ? 'Español' : value, label: (value === 'Español' || value === 'Spanish') ? 'Idioma'
|
|
@@ -1103,26 +1112,30 @@ export var DropdownInput = function (_a) {
|
|
|
1103
1112
|
var choicesForDatabase = {};
|
|
1104
1113
|
var preventRefetch = {};
|
|
1105
1114
|
var LOAD_CHOICES_LIMIT = 500;
|
|
1115
|
+
var MIN_SEARCH_CHARS = 3;
|
|
1116
|
+
var SEARCH_DEBOUNCE_MS = 300;
|
|
1106
1117
|
var useDatabaseChoices = function (_a) {
|
|
1107
|
-
var _b, _d
|
|
1108
|
-
var
|
|
1118
|
+
var _b, _d;
|
|
1119
|
+
var _e = _a.databaseId, databaseId = _e === void 0 ? '' : _e, field = _a.field, otherAnswers = _a.otherAnswers, _f = _a.searchQuery, searchQuery = _f === void 0 ? '' : _f;
|
|
1109
1120
|
var session = useResolvedSession();
|
|
1110
|
-
var
|
|
1111
|
-
|
|
1121
|
+
var _g = useState(false), isSearching = _g[0], setIsSearching = _g[1];
|
|
1122
|
+
var _h = useState([]), searchResults = _h[0], setSearchResults = _h[1];
|
|
1123
|
+
var _j = useState(false), initialLoadComplete = _j[0], setInitialLoadComplete = _j[1];
|
|
1124
|
+
var debouncedSearch = useDebounce(searchQuery, SEARCH_DEBOUNCE_MS);
|
|
1125
|
+
// Load initial page on mount (only once, not recursively)
|
|
1126
|
+
var initialLoadRef = useRef(false);
|
|
1112
1127
|
useEffect(function () {
|
|
1113
|
-
var _a, _b, _d
|
|
1114
|
-
if (
|
|
1128
|
+
var _a, _b, _d;
|
|
1129
|
+
if (initialLoadRef.current)
|
|
1115
1130
|
return;
|
|
1116
|
-
if (
|
|
1117
|
-
|
|
1118
|
-
var choices = (_d = (_b = choicesForDatabase[databaseId]) === null || _b === void 0 ? void 0 : _b.records) !== null && _d !== void 0 ? _d : [];
|
|
1119
|
-
var lastId = (_e = choicesForDatabase[databaseId]) === null || _e === void 0 ? void 0 : _e.lastId;
|
|
1120
|
-
if (preventRefetch[databaseId + field.id + lastId])
|
|
1131
|
+
if (((_a = choicesForDatabase[databaseId]) === null || _a === void 0 ? void 0 : _a.done) || ((_d = (_b = choicesForDatabase[databaseId]) === null || _b === void 0 ? void 0 : _b.records) === null || _d === void 0 ? void 0 : _d.length)) {
|
|
1132
|
+
setInitialLoadComplete(true);
|
|
1121
1133
|
return;
|
|
1122
|
-
|
|
1134
|
+
}
|
|
1135
|
+
initialLoadRef.current = true;
|
|
1136
|
+
preventRefetch[databaseId + field.id] = true;
|
|
1123
1137
|
session.api.form_fields.load_choices_from_database({
|
|
1124
1138
|
fieldId: field.id,
|
|
1125
|
-
lastId: lastId,
|
|
1126
1139
|
limit: LOAD_CHOICES_LIMIT,
|
|
1127
1140
|
databaseId: databaseId,
|
|
1128
1141
|
})
|
|
@@ -1131,17 +1144,67 @@ var useDatabaseChoices = function (_a) {
|
|
|
1131
1144
|
var newChoices = _a.choices;
|
|
1132
1145
|
choicesForDatabase[databaseId] = {
|
|
1133
1146
|
lastId: (_b = newChoices === null || newChoices === void 0 ? void 0 : newChoices[newChoices.length - 1]) === null || _b === void 0 ? void 0 : _b.id,
|
|
1134
|
-
records:
|
|
1147
|
+
records: newChoices.sort(function (c1, c2) { return (label_for_database_record(field, c1)
|
|
1135
1148
|
.localeCompare(label_for_database_record(field, c2))); }),
|
|
1136
|
-
done:
|
|
1149
|
+
done: true, // Don't load more pages automatically
|
|
1137
1150
|
};
|
|
1138
|
-
|
|
1151
|
+
setInitialLoadComplete(true);
|
|
1152
|
+
})
|
|
1153
|
+
.catch(function (err) {
|
|
1154
|
+
console.error(err);
|
|
1155
|
+
preventRefetch[databaseId + field.id] = false;
|
|
1156
|
+
setInitialLoadComplete(true); // Mark as complete even on error to avoid infinite loading
|
|
1157
|
+
});
|
|
1158
|
+
}, [session, field, databaseId]);
|
|
1159
|
+
// Handle debounced search
|
|
1160
|
+
var searchRef = useRef(debouncedSearch);
|
|
1161
|
+
useEffect(function () {
|
|
1162
|
+
var trimmed = debouncedSearch.trim();
|
|
1163
|
+
// If search is cleared, return to initial results
|
|
1164
|
+
if (!trimmed) {
|
|
1165
|
+
setSearchResults([]);
|
|
1166
|
+
setIsSearching(false);
|
|
1167
|
+
searchRef.current = debouncedSearch;
|
|
1168
|
+
return;
|
|
1169
|
+
}
|
|
1170
|
+
// Only search if meets minimum character requirement
|
|
1171
|
+
if (trimmed.length < MIN_SEARCH_CHARS) {
|
|
1172
|
+
setSearchResults([]);
|
|
1173
|
+
setIsSearching(false);
|
|
1174
|
+
return;
|
|
1175
|
+
}
|
|
1176
|
+
// Avoid duplicate searches
|
|
1177
|
+
if (searchRef.current === debouncedSearch)
|
|
1178
|
+
return;
|
|
1179
|
+
searchRef.current = debouncedSearch;
|
|
1180
|
+
setIsSearching(true);
|
|
1181
|
+
session.api.form_fields.load_choices_from_database({
|
|
1182
|
+
fieldId: field.id,
|
|
1183
|
+
limit: LOAD_CHOICES_LIMIT,
|
|
1184
|
+
databaseId: databaseId,
|
|
1185
|
+
search: trimmed,
|
|
1186
|
+
})
|
|
1187
|
+
.then(function (_a) {
|
|
1188
|
+
var _b, _d;
|
|
1189
|
+
var newChoices = _a.choices;
|
|
1190
|
+
// Add search results to the same cache as initial load
|
|
1191
|
+
// This ensures selected search results persist even after search is cleared
|
|
1192
|
+
var existingRecords = (_d = (_b = choicesForDatabase[databaseId]) === null || _b === void 0 ? void 0 : _b.records) !== null && _d !== void 0 ? _d : [];
|
|
1193
|
+
var existingIds = new Set(existingRecords.map(function (r) { return r.id; }));
|
|
1194
|
+
var uniqueNewChoices = newChoices.filter(function (c) { return !existingIds.has(c.id); });
|
|
1195
|
+
if (uniqueNewChoices.length > 0) {
|
|
1196
|
+
choicesForDatabase[databaseId] = __assign(__assign({}, choicesForDatabase[databaseId]), { records: __spreadArray(__spreadArray([], existingRecords, true), uniqueNewChoices, true).sort(function (c1, c2) { return (label_for_database_record(field, c1)
|
|
1197
|
+
.localeCompare(label_for_database_record(field, c2))); }), done: true });
|
|
1198
|
+
}
|
|
1199
|
+
setSearchResults(newChoices.sort(function (c1, c2) { return (label_for_database_record(field, c1)
|
|
1200
|
+
.localeCompare(label_for_database_record(field, c2))); }));
|
|
1201
|
+
setIsSearching(false);
|
|
1139
1202
|
})
|
|
1140
1203
|
.catch(function (err) {
|
|
1141
1204
|
console.error(err);
|
|
1142
|
-
|
|
1205
|
+
setIsSearching(false);
|
|
1143
1206
|
});
|
|
1144
|
-
}, [session, field, databaseId,
|
|
1207
|
+
}, [session, field, databaseId, debouncedSearch]);
|
|
1145
1208
|
var addChoice = useCallback(function (record) {
|
|
1146
1209
|
if (!choicesForDatabase[databaseId]) {
|
|
1147
1210
|
choicesForDatabase[databaseId] = {
|
|
@@ -1151,10 +1214,15 @@ var useDatabaseChoices = function (_a) {
|
|
|
1151
1214
|
}
|
|
1152
1215
|
choicesForDatabase[databaseId].records.push(record);
|
|
1153
1216
|
}, [choicesForDatabase, databaseId]);
|
|
1217
|
+
// Use search results if searching, otherwise use cached initial results
|
|
1218
|
+
var activeChoices = debouncedSearch.trim().length >= MIN_SEARCH_CHARS
|
|
1219
|
+
? searchResults
|
|
1220
|
+
: ((_d = (_b = choicesForDatabase[databaseId]) === null || _b === void 0 ? void 0 : _b.records) !== null && _d !== void 0 ? _d : []);
|
|
1154
1221
|
return {
|
|
1155
1222
|
addChoice: addChoice,
|
|
1156
|
-
doneLoading:
|
|
1157
|
-
|
|
1223
|
+
doneLoading: initialLoadComplete,
|
|
1224
|
+
isSearching: isSearching,
|
|
1225
|
+
choices: __spreadArray(__spreadArray([], activeChoices, true), (otherAnswers || []).map(function (v) {
|
|
1158
1226
|
var _a;
|
|
1159
1227
|
return ({
|
|
1160
1228
|
id: v.text,
|
|
@@ -1162,7 +1230,7 @@ var useDatabaseChoices = function (_a) {
|
|
|
1162
1230
|
values: [{ label: ((_a = field.options) === null || _a === void 0 ? void 0 : _a.databaseLabel) || '', type: 'Text', value: v.text }],
|
|
1163
1231
|
});
|
|
1164
1232
|
}), true),
|
|
1165
|
-
|
|
1233
|
+
minSearchChars: MIN_SEARCH_CHARS,
|
|
1166
1234
|
};
|
|
1167
1235
|
};
|
|
1168
1236
|
var label_for_database_record = function (field, record) {
|
|
@@ -1194,13 +1262,15 @@ var get_other_answers = function (_value, typing) {
|
|
|
1194
1262
|
};
|
|
1195
1263
|
export var DatabaseSelectInput = function (_a) {
|
|
1196
1264
|
var _b, _d, _e, _f, _g, _h, _j, _k;
|
|
1197
|
-
var AddToDatabase = _a.AddToDatabase, field = _a.field, _value = _a.value, onChange = _a.onChange, onDatabaseSelect = _a.onDatabaseSelect, responses = _a.responses, size = _a.size, disabled = _a.disabled, enduser = _a.enduser;
|
|
1265
|
+
var AddToDatabase = _a.AddToDatabase, field = _a.field, _value = _a.value, onChange = _a.onChange, onDatabaseSelect = _a.onDatabaseSelect, responses = _a.responses, size = _a.size, disabled = _a.disabled, enduser = _a.enduser, inputProps = _a.inputProps;
|
|
1198
1266
|
var _l = useState(''), typing = _l[0], setTyping = _l[1];
|
|
1199
|
-
var _m =
|
|
1267
|
+
var _m = useState(false), open = _m[0], setOpen = _m[1];
|
|
1268
|
+
var _o = useDatabaseChoices({
|
|
1200
1269
|
databaseId: (_b = field.options) === null || _b === void 0 ? void 0 : _b.databaseId,
|
|
1201
1270
|
field: field,
|
|
1202
1271
|
otherAnswers: get_other_answers(_value, ((_d = field === null || field === void 0 ? void 0 : field.options) === null || _d === void 0 ? void 0 : _d.other) ? typing : undefined),
|
|
1203
|
-
|
|
1272
|
+
searchQuery: typing,
|
|
1273
|
+
}), addChoice = _o.addChoice, choices = _o.choices, doneLoading = _o.doneLoading, isSearching = _o.isSearching, minSearchChars = _o.minSearchChars;
|
|
1204
1274
|
var value = React.useMemo(function () {
|
|
1205
1275
|
var _a, _b;
|
|
1206
1276
|
try {
|
|
@@ -1304,9 +1374,13 @@ export var DatabaseSelectInput = function (_a) {
|
|
|
1304
1374
|
}
|
|
1305
1375
|
return filtered;
|
|
1306
1376
|
}, [field, stateFilteredChoices]);
|
|
1377
|
+
// Show placeholder when typing but below minimum search characters
|
|
1378
|
+
var charsNeeded = typing.trim().length > 0 && typing.trim().length < minSearchChars
|
|
1379
|
+
? minSearchChars - typing.trim().length
|
|
1380
|
+
: 0;
|
|
1307
1381
|
if (!doneLoading)
|
|
1308
1382
|
return _jsx(LinearProgress, {});
|
|
1309
|
-
return (_jsxs(_Fragment, { children: [_jsx(Autocomplete, { id: field.id, freeSolo: false, size: size, componentsProps: { popper: { sx: { wordBreak: "break-word" } } }, options: filteredChoices, multiple: true, getOptionLabel: function (o) { return (Array.isArray(o) // edge case
|
|
1383
|
+
return (_jsxs(_Fragment, { children: [_jsx(Autocomplete, { id: field.id, freeSolo: false, size: size, componentsProps: { popper: { sx: { wordBreak: "break-word" } } }, options: filteredChoices, multiple: true, loading: isSearching, open: open, onOpen: function () { return setOpen(true); }, onClose: function () { return setOpen(false); }, getOptionLabel: function (o) { return (Array.isArray(o) // edge case
|
|
1310
1384
|
? ''
|
|
1311
1385
|
: label_for_database_record(field, o)); }, value: value, disabled: disabled, onChange: function (_, v) {
|
|
1312
1386
|
var _a, _b, _d, _e, _f;
|
|
@@ -1329,7 +1403,7 @@ export var DatabaseSelectInput = function (_a) {
|
|
|
1329
1403
|
recordId: (_f = (_e = v[v.length - 1]) === null || _e === void 0 ? void 0 : _e.id) !== null && _f !== void 0 ? _f : '',
|
|
1330
1404
|
text: label_for_database_record(field, v[v.length - 1]),
|
|
1331
1405
|
}]), field.id);
|
|
1332
|
-
}, inputValue: typing, onInputChange: function (e, v) { return e && setTyping(v); }, renderInput: function (params) { return _jsx(TextField, __assign({}, params, { InputProps: __assign(__assign({}, params.InputProps), { sx: defaultInputProps.sx }) })); },
|
|
1406
|
+
}, inputValue: typing, onInputChange: function (e, v) { return e && setTyping(v); }, renderInput: function (params) { return (_jsx(TextField, __assign({}, params, { InputProps: __assign(__assign({}, params.InputProps), { sx: (inputProps || defaultInputProps).sx, endAdornment: (_jsxs(_Fragment, { children: [isSearching ? _jsx(CircularProgress, { color: "inherit", size: 20 }) : null, params.InputProps.endAdornment] })) }), placeholder: charsNeeded > 0 ? "Type ".concat(charsNeeded, " more character").concat(charsNeeded > 1 ? 's' : '', " to search...") : undefined, helperText: charsNeeded > 0 ? "Type ".concat(charsNeeded, " more character").concat(charsNeeded > 1 ? 's' : '', " to search") : undefined }))); },
|
|
1333
1407
|
// use custom Chip to ensure very long entries break properly (whitespace: normal)
|
|
1334
1408
|
renderTags: function (value, getTagProps) {
|
|
1335
1409
|
return value.map(function (value, index) { return (_jsx(Chip, __assign({ label: _jsx(Typography, __assign({ style: { whiteSpace: 'normal' } }, { children: Array.isArray(value) ? '' : label_for_database_record(field, value) })) }, getTagProps({ index: index }), { sx: { height: "100%", py: 0.5 } }))); });
|