@tellescope/react-components 1.167.1 → 1.169.0
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/form_responses.js +1 -1
- package/lib/cjs/Forms/form_responses.js.map +1 -1
- package/lib/cjs/Forms/forms.d.ts +9 -2
- package/lib/cjs/Forms/forms.d.ts.map +1 -1
- package/lib/cjs/Forms/forms.js +50 -42
- package/lib/cjs/Forms/forms.js.map +1 -1
- package/lib/cjs/Forms/hooks.d.ts +7 -0
- package/lib/cjs/Forms/hooks.d.ts.map +1 -1
- package/lib/cjs/Forms/hooks.js +96 -68
- package/lib/cjs/Forms/hooks.js.map +1 -1
- package/lib/cjs/Forms/inputs.d.ts +3 -2
- package/lib/cjs/Forms/inputs.d.ts.map +1 -1
- package/lib/cjs/Forms/inputs.js +70 -24
- package/lib/cjs/Forms/inputs.js.map +1 -1
- package/lib/cjs/Forms/types.d.ts +7 -0
- package/lib/cjs/Forms/types.d.ts.map +1 -1
- package/lib/cjs/Forms/wysiwyg.d.ts +12 -0
- package/lib/cjs/Forms/wysiwyg.d.ts.map +1 -0
- package/lib/cjs/Forms/wysiwyg.js +225 -0
- package/lib/cjs/Forms/wysiwyg.js.map +1 -0
- package/lib/cjs/inputs.d.ts +1 -1
- package/lib/cjs/inputs.d.ts.map +1 -1
- package/lib/cjs/state.d.ts.map +1 -1
- package/lib/cjs/state.js +4 -0
- package/lib/cjs/state.js.map +1 -1
- package/lib/cjs/table.js +1 -1
- package/lib/cjs/table.js.map +1 -1
- package/lib/esm/Forms/form_responses.js +1 -1
- package/lib/esm/Forms/form_responses.js.map +1 -1
- package/lib/esm/Forms/forms.d.ts +10 -3
- package/lib/esm/Forms/forms.d.ts.map +1 -1
- package/lib/esm/Forms/forms.js +51 -43
- package/lib/esm/Forms/forms.js.map +1 -1
- package/lib/esm/Forms/hooks.d.ts +7 -0
- package/lib/esm/Forms/hooks.d.ts.map +1 -1
- package/lib/esm/Forms/hooks.js +96 -68
- package/lib/esm/Forms/hooks.js.map +1 -1
- package/lib/esm/Forms/inputs.d.ts +4 -3
- package/lib/esm/Forms/inputs.d.ts.map +1 -1
- package/lib/esm/Forms/inputs.js +68 -23
- package/lib/esm/Forms/inputs.js.map +1 -1
- package/lib/esm/Forms/inputs.native.d.ts +0 -1
- package/lib/esm/Forms/inputs.native.d.ts.map +1 -1
- package/lib/esm/Forms/types.d.ts +7 -0
- package/lib/esm/Forms/types.d.ts.map +1 -1
- package/lib/esm/Forms/wysiwyg.d.ts +12 -0
- package/lib/esm/Forms/wysiwyg.d.ts.map +1 -0
- package/lib/esm/Forms/wysiwyg.js +218 -0
- package/lib/esm/Forms/wysiwyg.js.map +1 -0
- package/lib/esm/controls.d.ts +2 -2
- package/lib/esm/inputs.d.ts +1 -1
- package/lib/esm/inputs.d.ts.map +1 -1
- package/lib/esm/state.d.ts.map +1 -1
- package/lib/esm/state.js +4 -0
- package/lib/esm/state.js.map +1 -1
- package/lib/esm/table.js +1 -1
- package/lib/esm/table.js.map +1 -1
- package/lib/esm/theme.native.d.ts +0 -1
- package/lib/esm/theme.native.d.ts.map +1 -1
- package/lib/tsconfig.tsbuildinfo +1 -1
- package/package.json +13 -9
- package/src/Forms/form_responses.tsx +1 -1
- package/src/Forms/forms.tsx +20 -2
- package/src/Forms/hooks.tsx +43 -26
- package/src/Forms/inputs.tsx +32 -7
- package/src/Forms/types.ts +4 -0
- package/src/Forms/wysiwyg.tsx +234 -0
- package/src/inputs.tsx +1 -1
- package/src/state.tsx +1 -0
- package/src/table.tsx +1 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tellescope/react-components",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.169.0",
|
|
4
4
|
"description": "",
|
|
5
5
|
"main": "./lib/cjs/index.js",
|
|
6
6
|
"module": "./lib/esm/index.js",
|
|
@@ -47,23 +47,27 @@
|
|
|
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.
|
|
51
|
-
"@tellescope/sdk": "^1.
|
|
52
|
-
"@tellescope/types-client": "^1.
|
|
53
|
-
"@tellescope/types-models": "^1.
|
|
54
|
-
"@tellescope/types-utilities": "^1.
|
|
55
|
-
"@tellescope/utilities": "^1.
|
|
56
|
-
"@tellescope/validation": "^1.
|
|
50
|
+
"@tellescope/constants": "^1.169.0",
|
|
51
|
+
"@tellescope/sdk": "^1.169.0",
|
|
52
|
+
"@tellescope/types-client": "^1.169.0",
|
|
53
|
+
"@tellescope/types-models": "^1.169.0",
|
|
54
|
+
"@tellescope/types-utilities": "^1.169.0",
|
|
55
|
+
"@tellescope/utilities": "^1.169.0",
|
|
56
|
+
"@tellescope/validation": "^1.169.0",
|
|
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",
|
|
60
|
+
"draft-js": "^0.11.7",
|
|
61
|
+
"draftjs-to-html": "^0.9.1",
|
|
60
62
|
"eslint": "^7.32.0",
|
|
61
63
|
"eslint-plugin-react": "^7.26.1",
|
|
62
64
|
"formik": "^2.2.9",
|
|
63
65
|
"heic2any": "^0.0.4",
|
|
66
|
+
"html-to-draftjs": "^1.5.0",
|
|
64
67
|
"nodemon": "^2.0.13",
|
|
65
68
|
"react-beautiful-dnd": "^13.1.1",
|
|
66
69
|
"react-datepicker": "^3.4.1",
|
|
70
|
+
"react-draft-wysiwyg": "^1.15.0",
|
|
67
71
|
"react-draggable": "^4.4.6",
|
|
68
72
|
"react-dropzone": "^11.4.2",
|
|
69
73
|
"react-ga4": "^1.4.1",
|
|
@@ -80,7 +84,7 @@
|
|
|
80
84
|
"react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0",
|
|
81
85
|
"react-native": "^0.65.0 || ^0.66.0 || ^0.67.0 || ^0.68.0 || ^0.71.0"
|
|
82
86
|
},
|
|
83
|
-
"gitHead": "
|
|
87
|
+
"gitHead": "038ccd6e24a110a290ce7b0b6333ec2593817204",
|
|
84
88
|
"publishConfig": {
|
|
85
89
|
"access": "public"
|
|
86
90
|
}
|
|
@@ -31,7 +31,7 @@ export const ResponseAnswer = ({ formResponse, fieldId, isHTML, answer: a, print
|
|
|
31
31
|
onImageClick?: (args: { src: string }) => void,
|
|
32
32
|
isHTML?: boolean,
|
|
33
33
|
}) => (
|
|
34
|
-
(isHTML && typeof a.value === 'string')
|
|
34
|
+
((isHTML || a.type === 'Rich Text') && typeof a.value === 'string')
|
|
35
35
|
? <div dangerouslySetInnerHTML={{ __html: remove_script_tags(a.value) }} />
|
|
36
36
|
: a.value
|
|
37
37
|
? (
|
package/src/Forms/forms.tsx
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import React, { useCallback, useEffect, useMemo, useRef, useState } from "react"
|
|
2
|
-
import { Button, CircularProgress, Flex, LinearProgress, LoadingButton, Modal, Paper, Styled, Typography, form_display_text_for_language, useFileUpload, useFormResponses, useSession } from "../index"
|
|
2
|
+
import { Button, CircularProgress, FileBlob, FileUploadHandler, Flex, LinearProgress, LoadingButton, Modal, Paper, Styled, Typography, form_display_text_for_language, useFileUpload, useFormResponses, useSession } from "../index"
|
|
3
3
|
import { useListForFormFields, useOrganizationTheme, useTellescopeForm, WithOrganizationTheme, Response, FileResponse, NextFieldLogicOptions } from "./hooks"
|
|
4
4
|
import { ChangeHandler, FormInputs } from "./types"
|
|
5
|
-
import { AddressInput, AllergiesInput, AppointmentBookingInput, ConditionsInput, DatabaseSelectInput, DateInput, DateStringInput, DropdownInput, EmailInput, EmotiiInput, FileInput, FilesInput, HeightInput, HiddenValueInput, InsuranceInput, LanguageSelect, MedicationsInput, MultipleChoiceInput, NumberInput, PhoneInput, Progress, RankingInput, RatingInput, RedirectInput, RelatedContactsInput, SignatureInput, StringInput, StringLongInput, StripeInput, TableInput, TimeInput, defaultButtonStyles } from "./inputs"
|
|
5
|
+
import { AddressInput, AllergiesInput, AppointmentBookingInput, ConditionsInput, DatabaseSelectInput, DateInput, DateStringInput, DropdownInput, EmailInput, EmotiiInput, FileInput, FilesInput, HeightInput, HiddenValueInput, InsuranceInput, LanguageSelect, MedicationsInput, MultipleChoiceInput, NumberInput, PhoneInput, Progress, RankingInput, RatingInput, RedirectInput, RelatedContactsInput, RichTextInput, SignatureInput, StringInput, StringLongInput, StripeInput, TableInput, TimeInput, defaultButtonStyles } from "./inputs"
|
|
6
6
|
import { PRIMARY_HEX } from "@tellescope/constants"
|
|
7
7
|
import { FormResponse, FormField, Form, Enduser } from "@tellescope/types-client"
|
|
8
8
|
import { FormResponseAnswerFileValue, OrganizationTheme } from "@tellescope/types-models"
|
|
@@ -135,6 +135,7 @@ export const QuestionForField = ({
|
|
|
135
135
|
rootResponseId,
|
|
136
136
|
isInQuestionGroup,
|
|
137
137
|
logicOptions,
|
|
138
|
+
uploadingFiles, setUploadingFiles, handleFileUpload,
|
|
138
139
|
} : {
|
|
139
140
|
spacing?: number,
|
|
140
141
|
form?: Form,
|
|
@@ -147,6 +148,9 @@ export const QuestionForField = ({
|
|
|
147
148
|
isSinglePage?: boolean,
|
|
148
149
|
isInQuestionGroup?: boolean,
|
|
149
150
|
logicOptions?: NextFieldLogicOptions,
|
|
151
|
+
handleFileUpload: (blob: FileBlob, fieldId: string) => Promise<any>,
|
|
152
|
+
uploadingFiles: { fieldId: string }[]
|
|
153
|
+
setUploadingFiles: React.Dispatch<React.SetStateAction<{ fieldId: string }[]>>,
|
|
150
154
|
} & Pick<TellescopeFormProps, "rootResponseId" | "goToNextField" | "groupId" | "groupInstance" | "submit" | "formResponseId" | 'enduserId' | 'isPreviousDisabled' | 'goToPreviousField' | 'enduser' | 'handleDatabaseSelect' | 'onAddFile' | 'onFieldChange' | 'fields' | 'customInputs' | 'responses' | 'selectedFiles' | 'validateField'>) => {
|
|
151
155
|
const String = customInputs?.['string'] ?? StringInput
|
|
152
156
|
const StringLong = customInputs?.['stringLong'] ?? StringLongInput
|
|
@@ -175,6 +179,7 @@ export const QuestionForField = ({
|
|
|
175
179
|
const Emotii = customInputs?.['Emotii'] ?? EmotiiInput
|
|
176
180
|
const Allergies = customInputs?.['Allergies'] ?? AllergiesInput
|
|
177
181
|
const Conditions = customInputs?.['Conditions'] ?? ConditionsInput
|
|
182
|
+
const RichText = customInputs?.['Rich Text'] ?? RichTextInput
|
|
178
183
|
|
|
179
184
|
const validationMessage = validateField(field)
|
|
180
185
|
|
|
@@ -233,6 +238,7 @@ export const QuestionForField = ({
|
|
|
233
238
|
? value.answer.value?.name
|
|
234
239
|
: ''
|
|
235
240
|
}
|
|
241
|
+
handleFileUpload={handleFileUpload} uploadingFiles={uploadingFiles} setUploadingFiles={setUploadingFiles}
|
|
236
242
|
/>
|
|
237
243
|
)
|
|
238
244
|
: field.type === 'files' ? (
|
|
@@ -242,6 +248,7 @@ export const QuestionForField = ({
|
|
|
242
248
|
// ? value.answer.value?.name
|
|
243
249
|
// : ''
|
|
244
250
|
// }
|
|
251
|
+
handleFileUpload={handleFileUpload} uploadingFiles={uploadingFiles} setUploadingFiles={setUploadingFiles}
|
|
245
252
|
/>
|
|
246
253
|
)
|
|
247
254
|
: field.type === 'dateString' ? (
|
|
@@ -283,6 +290,9 @@ export const QuestionForField = ({
|
|
|
283
290
|
: field.type === 'stringLong' ? (
|
|
284
291
|
<StringLong field={field} disabled={value.disabled} value={value.answer.value as string} onChange={onFieldChange as ChangeHandler<'string' | 'stringLong'>} form={form} />
|
|
285
292
|
)
|
|
293
|
+
: field.type === 'Rich Text' ? (
|
|
294
|
+
<RichText field={field} disabled={value.disabled} value={value.answer.value as string} onChange={onFieldChange as ChangeHandler<'Rich Text'>} form={form} />
|
|
295
|
+
)
|
|
286
296
|
: field.type === 'email' ? (
|
|
287
297
|
<Email field={field} disabled={value.disabled} value={value.answer.value as string} onChange={onFieldChange as ChangeHandler<'email'>} form={form} />
|
|
288
298
|
)
|
|
@@ -358,6 +368,8 @@ export const QuestionForField = ({
|
|
|
358
368
|
spacing={field.options?.groupPadding}
|
|
359
369
|
logicOptions={logicOptions}
|
|
360
370
|
isInQuestionGroup
|
|
371
|
+
uploadingFiles={uploadingFiles} setUploadingFiles={setUploadingFiles}
|
|
372
|
+
handleFileUpload={handleFileUpload}
|
|
361
373
|
/>
|
|
362
374
|
</Flex>
|
|
363
375
|
)
|
|
@@ -443,6 +455,7 @@ export const TellescopeSingleQuestionFlow: typeof TellescopeForm = ({
|
|
|
443
455
|
groupId,
|
|
444
456
|
groupInstance,
|
|
445
457
|
logicOptions,
|
|
458
|
+
uploadingFiles, setUploadingFiles, handleFileUpload,
|
|
446
459
|
}) => {
|
|
447
460
|
const beforeunloadHandler = React.useCallback((e: BeforeUnloadEvent) => {
|
|
448
461
|
try {
|
|
@@ -541,6 +554,8 @@ export const TellescopeSingleQuestionFlow: typeof TellescopeForm = ({
|
|
|
541
554
|
validateField={validateField}
|
|
542
555
|
groupId={groupId} groupInstance={groupInstance}
|
|
543
556
|
logicOptions={logicOptions}
|
|
557
|
+
uploadingFiles={uploadingFiles} setUploadingFiles={setUploadingFiles}
|
|
558
|
+
handleFileUpload={handleFileUpload}
|
|
544
559
|
/>
|
|
545
560
|
</Flex>
|
|
546
561
|
</Flex>
|
|
@@ -942,6 +957,7 @@ export const TellescopeSinglePageForm: React.JSXElementConstructor<TellescopeFor
|
|
|
942
957
|
enduser,
|
|
943
958
|
groupId,
|
|
944
959
|
groupInstance,
|
|
960
|
+
uploadingFiles, setUploadingFiles, handleFileUpload,
|
|
945
961
|
...props
|
|
946
962
|
}) => {
|
|
947
963
|
const list = useListForFormFields(fields, responses, { form: props.form, gender: enduser?.gender })
|
|
@@ -1019,6 +1035,8 @@ export const TellescopeSinglePageForm: React.JSXElementConstructor<TellescopeFor
|
|
|
1019
1035
|
responses={responses} selectedFiles={selectedFiles}
|
|
1020
1036
|
validateField={validateField}
|
|
1021
1037
|
groupId={groupId} groupInstance={groupInstance}
|
|
1038
|
+
uploadingFiles={uploadingFiles} setUploadingFiles={setUploadingFiles}
|
|
1039
|
+
handleFileUpload={handleFileUpload}
|
|
1022
1040
|
/>
|
|
1023
1041
|
</Flex>
|
|
1024
1042
|
</Flex>
|
package/src/Forms/hooks.tsx
CHANGED
|
@@ -531,6 +531,7 @@ export const useTellescopeForm = ({ isPublicForm, form, urlLogicValue, customiza
|
|
|
531
531
|
const [submittingStatus, setSubmittingStatus] = useState<SubmitStatus>(undefined)
|
|
532
532
|
const [submitErrorMessage, setSubmitErrorMessage] = useState('')
|
|
533
533
|
const [currentPageIndex, setCurrentPageIndex] = useState(0)
|
|
534
|
+
const [uploadingFiles, setUploadingFiles] = useState<{ fieldId: string }[]>([])
|
|
534
535
|
const prevFieldStackRef = useRef<typeof root[]>([])
|
|
535
536
|
|
|
536
537
|
const [repeats, setRepeats] = useState({} as Record<string, string | number>)
|
|
@@ -815,6 +816,10 @@ export const useTellescopeForm = ({ isPublicForm, form, urlLogicValue, customiza
|
|
|
815
816
|
return null
|
|
816
817
|
}
|
|
817
818
|
|
|
819
|
+
if (value.answer?.type === 'Rich Text' && value.answer?.value?.trim() === '<p></p>' && !field.isOptional) {
|
|
820
|
+
return "Answer is required"
|
|
821
|
+
}
|
|
822
|
+
|
|
818
823
|
if (value.answer.type === 'Insurance') {
|
|
819
824
|
if (value.answer.value?.relationshipDetails?.dateOfBirth && !isDateString(value.answer.value.relationshipDetails.dateOfBirth)) {
|
|
820
825
|
return "Enter date of birth in MM-DD-YYYY format"
|
|
@@ -1102,6 +1107,31 @@ export const useTellescopeForm = ({ isPublicForm, form, urlLogicValue, customiza
|
|
|
1102
1107
|
return responsesToSubmit
|
|
1103
1108
|
}, [responses])
|
|
1104
1109
|
|
|
1110
|
+
const handleFileUpload = useCallback(async (blob: FileBlob, fieldId: string) => {
|
|
1111
|
+
const responseIndex = responses.findIndex(f => f.fieldId === fieldId)
|
|
1112
|
+
const result: FormResponseAnswerFileValue = { name: blob.name, secureName: '' }
|
|
1113
|
+
const { secureName } = await handleUpload(
|
|
1114
|
+
{
|
|
1115
|
+
name: blob.name,
|
|
1116
|
+
size: blob.size,
|
|
1117
|
+
type: blob.type,
|
|
1118
|
+
enduserId,
|
|
1119
|
+
},
|
|
1120
|
+
blob
|
|
1121
|
+
)
|
|
1122
|
+
|
|
1123
|
+
if (responses[responseIndex].answer.type === 'files') {
|
|
1124
|
+
if (!responses[responseIndex].answer.value) {
|
|
1125
|
+
responses[responseIndex].answer.value = []
|
|
1126
|
+
}
|
|
1127
|
+
(responses[responseIndex].answer.value as any[]).push({
|
|
1128
|
+
...result, type: blob.type, secureName, name: result.name ?? ''
|
|
1129
|
+
})
|
|
1130
|
+
} else {
|
|
1131
|
+
responses[responseIndex].answer.value = { ...result, type: blob.type, secureName, name: result.name ?? '' }
|
|
1132
|
+
}
|
|
1133
|
+
}, [responses, handleUpload])
|
|
1134
|
+
|
|
1105
1135
|
const submit = useCallback(async (options?: { onPreRedirect?: () => void, onFileUploadsDone?: () => void, onSuccess?: (r: FormResponse) => void, includedFieldIds?: string[], otherEnduserIds?: string[], onBulkErrors?: (errors: { enduserId: string, message: string }[]) => void }) => {
|
|
1106
1136
|
setSubmitErrorMessage('')
|
|
1107
1137
|
const hasFile = selectedFiles.find(f => !!f.blobs?.length) !== undefined
|
|
@@ -1113,31 +1143,14 @@ export const useTellescopeForm = ({ isPublicForm, form, urlLogicValue, customiza
|
|
|
1113
1143
|
for (const blobInfo of selectedFiles) {
|
|
1114
1144
|
const { blobs, fieldId } = blobInfo
|
|
1115
1145
|
if (!blobs) continue
|
|
1116
|
-
|
|
1146
|
+
|
|
1147
|
+
const responseIndex = responses.findIndex(f => f.fieldId === fieldId)
|
|
1148
|
+
|
|
1149
|
+
const response = responses[responseIndex]
|
|
1150
|
+
if (response.field?.options?.autoUploadFiles) { continue } // must have uploaded prior to submission
|
|
1151
|
+
|
|
1117
1152
|
for (const blob of blobs) {
|
|
1118
|
-
|
|
1119
|
-
const { secureName } = await handleUpload(
|
|
1120
|
-
{
|
|
1121
|
-
name: blob.name,
|
|
1122
|
-
size: blob.size,
|
|
1123
|
-
type: blob.type,
|
|
1124
|
-
enduserId,
|
|
1125
|
-
},
|
|
1126
|
-
blob
|
|
1127
|
-
)
|
|
1128
|
-
|
|
1129
|
-
const responseIndex = responses.findIndex(f => f.fieldId === fieldId)
|
|
1130
|
-
|
|
1131
|
-
if (responses[responseIndex].answer.type === 'files') {
|
|
1132
|
-
if (!responses[responseIndex].answer.value) {
|
|
1133
|
-
responses[responseIndex].answer.value = []
|
|
1134
|
-
}
|
|
1135
|
-
(responses[responseIndex].answer.value as any[]).push({
|
|
1136
|
-
...result, type: blob.type, secureName, name: result.name ?? ''
|
|
1137
|
-
})
|
|
1138
|
-
} else {
|
|
1139
|
-
responses[responseIndex].answer.value = { ...result, type: blob.type, secureName, name: result.name ?? '' }
|
|
1140
|
-
}
|
|
1153
|
+
await handleFileUpload(blob, fieldId)
|
|
1141
1154
|
}
|
|
1142
1155
|
}
|
|
1143
1156
|
|
|
@@ -1260,9 +1273,11 @@ export const useTellescopeForm = ({ isPublicForm, form, urlLogicValue, customiza
|
|
|
1260
1273
|
} finally {
|
|
1261
1274
|
setSubmittingStatus(undefined)
|
|
1262
1275
|
}
|
|
1263
|
-
}, [accessCode, automationStepId, enduserId, responses, selectedFiles, session, handleUpload, existingResponses, ga4measurementId, rootResponseId, parentResponseId, calendarEventId, goBackURL, logicOptions])
|
|
1276
|
+
}, [accessCode, automationStepId, enduserId, responses, selectedFiles, session, handleUpload, existingResponses, ga4measurementId, rootResponseId, parentResponseId, calendarEventId, goBackURL, logicOptions, handleFileUpload])
|
|
1264
1277
|
|
|
1265
1278
|
const isNextDisabled = useCallback(() => {
|
|
1279
|
+
if (uploadingFiles.length) { return true }
|
|
1280
|
+
|
|
1266
1281
|
if (activeField.children.length === 0) {
|
|
1267
1282
|
return true
|
|
1268
1283
|
}
|
|
@@ -1272,7 +1287,7 @@ export const useTellescopeForm = ({ isPublicForm, form, urlLogicValue, customiza
|
|
|
1272
1287
|
}
|
|
1273
1288
|
|
|
1274
1289
|
return false
|
|
1275
|
-
}, [activeField, validateField])
|
|
1290
|
+
}, [activeField, validateField, uploadingFiles])
|
|
1276
1291
|
|
|
1277
1292
|
const autoAdvanceRef = useRef(false)
|
|
1278
1293
|
const goToNextField = useCallback(() => {
|
|
@@ -1445,5 +1460,7 @@ export const useTellescopeForm = ({ isPublicForm, form, urlLogicValue, customiza
|
|
|
1445
1460
|
customization,
|
|
1446
1461
|
handleDatabaseSelect,
|
|
1447
1462
|
logicOptions,
|
|
1463
|
+
uploadingFiles, setUploadingFiles,
|
|
1464
|
+
handleFileUpload,
|
|
1448
1465
|
}
|
|
1449
1466
|
}
|
package/src/Forms/inputs.tsx
CHANGED
|
@@ -24,6 +24,7 @@ import LanguageIcon from '@mui/icons-material/Language';
|
|
|
24
24
|
import { Elements, PaymentElement, useStripe, useElements, EmbeddedCheckout, EmbeddedCheckoutProvider } from '@stripe/react-stripe-js';
|
|
25
25
|
import { loadStripe } from '@stripe/stripe-js';
|
|
26
26
|
import { CheckCircleOutline, Delete, Edit } from "@mui/icons-material"
|
|
27
|
+
import { WYSIWYG } from "./wysiwyg"
|
|
27
28
|
|
|
28
29
|
export const LanguageSelect = ({ value, ...props }: { value: string, onChange: (s: string) => void}) => (
|
|
29
30
|
<Grid container alignItems="center" justifyContent={"center"} wrap="nowrap" spacing={1}>
|
|
@@ -1185,7 +1186,7 @@ export async function convertHEIC (file: FileBlob | string){
|
|
|
1185
1186
|
};
|
|
1186
1187
|
|
|
1187
1188
|
const value_is_image = (f?: { type?: string })=> f?.type?.includes('image')
|
|
1188
|
-
export const FileInput = ({ value, onChange, field, existingFileName }: FormInputProps<'file'> & { existingFileName?: string }) => {
|
|
1189
|
+
export const FileInput = ({ value, onChange, field, existingFileName, uploadingFiles, handleFileUpload, setUploadingFiles }: FormInputProps<'file'> & { existingFileName?: string }) => {
|
|
1189
1190
|
const [error, setError] = useState('')
|
|
1190
1191
|
const { getRootProps, getInputProps, isDragActive } = useDropzone({
|
|
1191
1192
|
onDrop: useCallback(
|
|
@@ -1202,7 +1203,16 @@ export const FileInput = ({ value, onChange, field, existingFileName }: FormInpu
|
|
|
1202
1203
|
|
|
1203
1204
|
setError('')
|
|
1204
1205
|
onChange(file, field.id)
|
|
1205
|
-
|
|
1206
|
+
|
|
1207
|
+
if (field.options?.autoUploadFiles && handleFileUpload) {
|
|
1208
|
+
setUploadingFiles?.(fs => [...fs, { fieldId: field.id }])
|
|
1209
|
+
|
|
1210
|
+
handleFileUpload(file, field.id)
|
|
1211
|
+
.finally(
|
|
1212
|
+
() => setUploadingFiles?.(fs => fs.filter(f => f.fieldId !== field.id))
|
|
1213
|
+
)
|
|
1214
|
+
}
|
|
1215
|
+
}, [onChange, field.options?.validFileTypes, handleFileUpload, setUploadingFiles]
|
|
1206
1216
|
),
|
|
1207
1217
|
})
|
|
1208
1218
|
|
|
@@ -1221,7 +1231,9 @@ export const FileInput = ({ value, onChange, field, existingFileName }: FormInpu
|
|
|
1221
1231
|
}
|
|
1222
1232
|
}, [value])
|
|
1223
1233
|
|
|
1224
|
-
|
|
1234
|
+
if (uploadingFiles?.find(f => f.fieldId === field.id)) {
|
|
1235
|
+
return <LinearProgress />
|
|
1236
|
+
}
|
|
1225
1237
|
return (
|
|
1226
1238
|
<Grid container direction="column">
|
|
1227
1239
|
<Grid container {...getRootProps()} sx={{
|
|
@@ -1287,11 +1299,12 @@ export const safe_create_url = (file: any) => {
|
|
|
1287
1299
|
}
|
|
1288
1300
|
}
|
|
1289
1301
|
|
|
1290
|
-
export const FilesInput = ({ value, onChange, field, existingFileName }: FormInputProps<'files'> & { existingFileName?: string }) => {
|
|
1302
|
+
export const FilesInput = ({ value, onChange, field, existingFileName, uploadingFiles, handleFileUpload, setUploadingFiles }: FormInputProps<'files'> & { existingFileName?: string }) => {
|
|
1291
1303
|
const [error, setError] = useState('')
|
|
1292
1304
|
const { getRootProps, getInputProps, isDragActive } = useDropzone({
|
|
1293
1305
|
onDrop: useCallback(
|
|
1294
|
-
acceptedFiles => {
|
|
1306
|
+
async acceptedFiles => {
|
|
1307
|
+
setUploadingFiles?.(fs => [...fs, { fieldId: field.id }])
|
|
1295
1308
|
for (const file of acceptedFiles) {
|
|
1296
1309
|
if (field.options?.validFileTypes?.length) {
|
|
1297
1310
|
const match = field.options.validFileTypes.find(t => file.type.includes(t.toLowerCase()))
|
|
@@ -1299,11 +1312,16 @@ export const FilesInput = ({ value, onChange, field, existingFileName }: FormInp
|
|
|
1299
1312
|
return setError(`File must have type: ${field.options.validFileTypes.join(', ')}`)
|
|
1300
1313
|
}
|
|
1301
1314
|
}
|
|
1315
|
+
|
|
1316
|
+
if (field.options?.autoUploadFiles && handleFileUpload) {
|
|
1317
|
+
await handleFileUpload(file, field.id).catch(console.error)
|
|
1318
|
+
}
|
|
1302
1319
|
}
|
|
1320
|
+
setUploadingFiles?.(fs => fs.filter(f => f.fieldId !== field.id))
|
|
1303
1321
|
|
|
1304
1322
|
setError('')
|
|
1305
1323
|
onChange([...(value ?? []), ...acceptedFiles], field.id)
|
|
1306
|
-
}, [onChange, value, field.options?.validFileTypes]
|
|
1324
|
+
}, [onChange, value, field.options?.validFileTypes, handleFileUpload, setUploadingFiles]
|
|
1307
1325
|
),
|
|
1308
1326
|
})
|
|
1309
1327
|
|
|
@@ -1313,6 +1331,9 @@ export const FilesInput = ({ value, onChange, field, existingFileName }: FormInp
|
|
|
1313
1331
|
})
|
|
1314
1332
|
), [value])
|
|
1315
1333
|
|
|
1334
|
+
if (uploadingFiles?.find(f => f.fieldId === field.id)) {
|
|
1335
|
+
return <LinearProgress />
|
|
1336
|
+
}
|
|
1316
1337
|
return (
|
|
1317
1338
|
<Grid container direction="column">
|
|
1318
1339
|
<Grid container {...getRootProps()} sx={{
|
|
@@ -3277,4 +3298,8 @@ export const ConditionsInput = ({ goToNextField, goToPreviousField, field, value
|
|
|
3277
3298
|
}
|
|
3278
3299
|
/>
|
|
3279
3300
|
)
|
|
3280
|
-
}
|
|
3301
|
+
}
|
|
3302
|
+
|
|
3303
|
+
export const RichTextInput = ({ field, value, onChange }: FormInputProps<'Rich Text'>) => (
|
|
3304
|
+
<WYSIWYG initialHTML={value} onChange={v => onChange(v, field.id)} style={{ width: '100%' }} editorStyle={{ width: '100%' }} />
|
|
3305
|
+
)
|
package/src/Forms/types.ts
CHANGED
|
@@ -3,6 +3,7 @@ import { DatabaseRecord, Enduser, Form, FormField } from "@tellescope/types-clie
|
|
|
3
3
|
import { FileBlob, TreeNode } from "@tellescope/types-utilities";
|
|
4
4
|
import { JSXElementConstructor } from "react";
|
|
5
5
|
import { Response } from "./hooks";
|
|
6
|
+
import { FileUploadHandler } from "../inputs";
|
|
6
7
|
|
|
7
8
|
export type FormFieldNode = TreeNode<FormField>
|
|
8
9
|
|
|
@@ -32,6 +33,9 @@ export interface FormInputProps<K extends keyof AnswerForType> {
|
|
|
32
33
|
groupInsance?: string,
|
|
33
34
|
disabled?: boolean,
|
|
34
35
|
isSinglePage?: boolean,
|
|
36
|
+
handleFileUpload?: (blob: FileBlob, fieldId: string) => Promise<any>,
|
|
37
|
+
uploadingFiles?: { fieldId: string }[]
|
|
38
|
+
setUploadingFiles?: React.Dispatch<React.SetStateAction<{ fieldId: string }[]>>,
|
|
35
39
|
}
|
|
36
40
|
|
|
37
41
|
export type FormInputs = {
|
|
@@ -0,0 +1,234 @@
|
|
|
1
|
+
import React, { useEffect, useMemo, useRef, useState } from 'react';
|
|
2
|
+
import { Editor } from 'react-draft-wysiwyg';
|
|
3
|
+
import draftToHtml from 'draftjs-to-html';
|
|
4
|
+
import htmlToDraft from 'html-to-draftjs';
|
|
5
|
+
import { EditorState, ContentState, convertToRaw } from 'draft-js';
|
|
6
|
+
import { Paper } from '@mui/material';
|
|
7
|
+
import { Styled } from '../mui';
|
|
8
|
+
import "react-draft-wysiwyg/dist/react-draft-wysiwyg.css";
|
|
9
|
+
|
|
10
|
+
const getToolbar = ({ hideEmoji } : { hideEmoji?: boolean }) => ({
|
|
11
|
+
// hide image and embedded in favor of custom sections
|
|
12
|
+
options: [
|
|
13
|
+
// 'inline',
|
|
14
|
+
// 'blockType',
|
|
15
|
+
'fontSize',
|
|
16
|
+
// 'fontFamily',
|
|
17
|
+
'list',
|
|
18
|
+
'textAlign',
|
|
19
|
+
// 'colorPicker',
|
|
20
|
+
'link',
|
|
21
|
+
...(hideEmoji ? [] : ['emoji']),
|
|
22
|
+
// 'remove',
|
|
23
|
+
// 'history',
|
|
24
|
+
// 'image',
|
|
25
|
+
// 'embedded',
|
|
26
|
+
],
|
|
27
|
+
inline: {
|
|
28
|
+
inDropdown: false,
|
|
29
|
+
className: undefined,
|
|
30
|
+
component: undefined,
|
|
31
|
+
dropdownClassName: undefined,
|
|
32
|
+
options: ['bold', 'italic', 'underline', 'strikethrough', 'monospace', 'superscript', 'subscript'],
|
|
33
|
+
// bold: { icon: bold, className: undefined },
|
|
34
|
+
// italic: { icon: italic, className: undefined },
|
|
35
|
+
// underline: { icon: underline, className: undefined },
|
|
36
|
+
// strikethrough: { icon: strikethrough, className: undefined },
|
|
37
|
+
// monospace: { icon: monospace, className: undefined },
|
|
38
|
+
// superscript: { icon: superscript, className: undefined },
|
|
39
|
+
// subscript: { icon: subscript, className: undefined },
|
|
40
|
+
},
|
|
41
|
+
blockType: {
|
|
42
|
+
inDropdown: true,
|
|
43
|
+
options: ['Normal', 'H1', 'H2', 'H3', 'H4', 'H5', 'H6', 'Blockquote', 'Code'],
|
|
44
|
+
className: undefined,
|
|
45
|
+
component: undefined,
|
|
46
|
+
dropdownClassName: undefined,
|
|
47
|
+
},
|
|
48
|
+
fontSize: {
|
|
49
|
+
// icon: fontSize,
|
|
50
|
+
options: [8, 9, 10, 11, 12, 14, 16, 18, 24, 30, 36, 48, 60, 72, 96],
|
|
51
|
+
className: undefined,
|
|
52
|
+
component: undefined,
|
|
53
|
+
dropdownClassName: undefined,
|
|
54
|
+
},
|
|
55
|
+
fontFamily: {
|
|
56
|
+
options: ['Arial', 'Georgia', 'Impact', 'Tahoma', 'Times New Roman', 'Verdana'],
|
|
57
|
+
className: undefined,
|
|
58
|
+
component: undefined,
|
|
59
|
+
dropdownClassName: undefined,
|
|
60
|
+
},
|
|
61
|
+
list: {
|
|
62
|
+
inDropdown: false,
|
|
63
|
+
className: undefined,
|
|
64
|
+
component: undefined,
|
|
65
|
+
dropdownClassName: undefined,
|
|
66
|
+
options: ['unordered', 'ordered', 'indent', 'outdent'],
|
|
67
|
+
// unordered: { icon: unordered, className: undefined },
|
|
68
|
+
// ordered: { icon: ordered, className: undefined },
|
|
69
|
+
// indent: { icon: indent, className: undefined },
|
|
70
|
+
// outdent: { icon: outdent, className: undefined },
|
|
71
|
+
},
|
|
72
|
+
textAlign: {
|
|
73
|
+
inDropdown: false,
|
|
74
|
+
className: undefined,
|
|
75
|
+
component: undefined,
|
|
76
|
+
dropdownClassName: undefined,
|
|
77
|
+
options: ['left', 'center', 'right', 'justify'],
|
|
78
|
+
// left: { icon: left, className: undefined },
|
|
79
|
+
// center: { icon: center, className: undefined },
|
|
80
|
+
// right: { icon: right, className: undefined },
|
|
81
|
+
// justify: { icon: justify, className: undefined },
|
|
82
|
+
},
|
|
83
|
+
colorPicker: {
|
|
84
|
+
// icon: color,
|
|
85
|
+
className: undefined,
|
|
86
|
+
component: undefined,
|
|
87
|
+
popupClassName: undefined,
|
|
88
|
+
colors: ['rgb(97,189,109)', 'rgb(26,188,156)', 'rgb(84,172,210)', 'rgb(44,130,201)',
|
|
89
|
+
'rgb(147,101,184)', 'rgb(71,85,119)', 'rgb(204,204,204)', 'rgb(65,168,95)', 'rgb(0,168,133)',
|
|
90
|
+
'rgb(61,142,185)', 'rgb(41,105,176)', 'rgb(85,57,130)', 'rgb(40,50,78)', 'rgb(0,0,0)',
|
|
91
|
+
'rgb(247,218,100)', 'rgb(251,160,38)', 'rgb(235,107,86)', 'rgb(226,80,65)', 'rgb(163,143,132)',
|
|
92
|
+
'rgb(239,239,239)', 'rgb(255,255,255)', 'rgb(250,197,28)', 'rgb(243,121,52)', 'rgb(209,72,65)',
|
|
93
|
+
'rgb(184,49,47)', 'rgb(124,112,107)', 'rgb(209,213,216)'],
|
|
94
|
+
},
|
|
95
|
+
link: {
|
|
96
|
+
inDropdown: false,
|
|
97
|
+
className: undefined,
|
|
98
|
+
component: undefined,
|
|
99
|
+
popupClassName: undefined,
|
|
100
|
+
dropdownClassName: undefined,
|
|
101
|
+
showOpenOptionOnHover: true,
|
|
102
|
+
defaultTargetOption: '_blank',
|
|
103
|
+
options: ['link', 'unlink'],
|
|
104
|
+
// link: { icon: link, className: undefined },
|
|
105
|
+
// unlink: { icon: unlink, className: undefined },
|
|
106
|
+
linkCallback: undefined
|
|
107
|
+
},
|
|
108
|
+
emoji: {
|
|
109
|
+
// icon: emoji,
|
|
110
|
+
className: undefined,
|
|
111
|
+
component: undefined,
|
|
112
|
+
popupClassName: undefined,
|
|
113
|
+
emojis: [
|
|
114
|
+
'😀', '😁', '😂', '😃', '😉', '😋', '😎', '😍', '😗', '🤗', '🤔', '😣', '😫', '😴', '😌', '🤓',
|
|
115
|
+
'😛', '😜', '😠', '😇', '😷', '😈', '👻', '😺', '😸', '😹', '😻', '😼', '😽', '🙀', '🙈',
|
|
116
|
+
'🙉', '🙊', '👼', '👮', '🕵', '💂', '👳', '🎅', '👸', '👰', '👲', '🙍', '🙇', '🚶', '🏃', '💃',
|
|
117
|
+
'⛷', '🏂', '🏌', '🏄', '🚣', '🏊', '⛹', '🏋', '🚴', '👫', '💪', '👈', '👉', '👉', '👆', '🖕',
|
|
118
|
+
'👇', '🖖', '🤘', '🖐', '👌', '👍', '👎', '✊', '👊', '👏', '🙌', '🙏', '🐵', '🐶', '🐇', '🐥',
|
|
119
|
+
'🐸', '🐌', '🐛', '🐜', '🐝', '🍉', '🍄', '🍔', '🍤', '🍨', '🍪', '🎂', '🍰', '🍾', '🍷', '🍸',
|
|
120
|
+
'🍺', '🌍', '🚑', '⏰', '🌙', '🌝', '🌞', '⭐', '🌟', '🌠', '🌨', '🌩', '⛄', '🔥', '🎄', '🎈',
|
|
121
|
+
'🎉', '🎊', '🎁', '🎗', '🏀', '🏈', '🎲', '🔇', '🔈', '📣', '🔔', '🎵', '🎷', '💰', '🖊', '📅',
|
|
122
|
+
'✅', '❎', '💯',
|
|
123
|
+
],
|
|
124
|
+
},
|
|
125
|
+
embedded: {
|
|
126
|
+
// icon: embedded,
|
|
127
|
+
className: undefined,
|
|
128
|
+
component: undefined,
|
|
129
|
+
popupClassName: undefined,
|
|
130
|
+
embedCallback: undefined,
|
|
131
|
+
defaultSize: {
|
|
132
|
+
height: 'auto',
|
|
133
|
+
width: 'auto',
|
|
134
|
+
},
|
|
135
|
+
},
|
|
136
|
+
image: {
|
|
137
|
+
// icon: image,
|
|
138
|
+
className: undefined,
|
|
139
|
+
component: undefined,
|
|
140
|
+
popupClassName: undefined,
|
|
141
|
+
urlEnabled: true,
|
|
142
|
+
uploadEnabled: true,
|
|
143
|
+
alignmentEnabled: true,
|
|
144
|
+
// uploadCallback,
|
|
145
|
+
previewImage: true,
|
|
146
|
+
inputAccept: 'image/gif,image/jpeg,image/jpg,image/png,image/svg',
|
|
147
|
+
alt: { present: false, mandatory: false },
|
|
148
|
+
defaultSize: {
|
|
149
|
+
height: 'auto',
|
|
150
|
+
width: 'auto',
|
|
151
|
+
},
|
|
152
|
+
},
|
|
153
|
+
remove: {
|
|
154
|
+
// icon: eraser,
|
|
155
|
+
className: undefined, component: undefined
|
|
156
|
+
},
|
|
157
|
+
history: {
|
|
158
|
+
inDropdown: false,
|
|
159
|
+
className: undefined,
|
|
160
|
+
component: undefined,
|
|
161
|
+
dropdownClassName: undefined,
|
|
162
|
+
options: ['undo', 'redo'],
|
|
163
|
+
// undo: { icon: undo, className: undefined },
|
|
164
|
+
// redo: { icon: redo, className: undefined },
|
|
165
|
+
},
|
|
166
|
+
})
|
|
167
|
+
|
|
168
|
+
|
|
169
|
+
|
|
170
|
+
export const WYSIWYG = ({ updateHtml, initialHTML: _initialHTML='', autoFocus, onChange, style, editorStyle, hideEmoji } : {
|
|
171
|
+
initialHTML?: string, onChange: (html: string) => void, autoFocus?: boolean,
|
|
172
|
+
editorStyle?: React.CSSProperties,
|
|
173
|
+
hideEmoji?: boolean,
|
|
174
|
+
updateHtml?: string,
|
|
175
|
+
} & Styled) => {
|
|
176
|
+
const trimmed = _initialHTML.trim()
|
|
177
|
+
const initialHTML = (
|
|
178
|
+
trimmed.startsWith('<p>') && trimmed.endsWith('</p>')
|
|
179
|
+
? trimmed
|
|
180
|
+
: `<p>${trimmed}</p>`
|
|
181
|
+
)
|
|
182
|
+
|
|
183
|
+
const [editorState, setEditorState] = useState(EditorState.createWithContent(
|
|
184
|
+
ContentState.createFromBlockArray(htmlToDraft(initialHTML).contentBlocks)
|
|
185
|
+
))
|
|
186
|
+
const editorStateRef = useRef(editorState)
|
|
187
|
+
|
|
188
|
+
const editorRef: React.MutableRefObject<Editor | null> = useRef(null)
|
|
189
|
+
|
|
190
|
+
useEffect(() => {
|
|
191
|
+
if (!updateHtml) return
|
|
192
|
+
|
|
193
|
+
setEditorState(
|
|
194
|
+
EditorState.createWithContent(
|
|
195
|
+
ContentState.createFromBlockArray(htmlToDraft(updateHtml).contentBlocks)
|
|
196
|
+
)
|
|
197
|
+
)
|
|
198
|
+
}, [updateHtml])
|
|
199
|
+
|
|
200
|
+
useEffect(() => {
|
|
201
|
+
if (!autoFocus) return
|
|
202
|
+
|
|
203
|
+
if (editorRef.current) {
|
|
204
|
+
editorRef.current?.focusEditor?.()
|
|
205
|
+
setEditorState(es => EditorState.moveFocusToEnd(es))
|
|
206
|
+
}
|
|
207
|
+
}, [editorRef, autoFocus])
|
|
208
|
+
|
|
209
|
+
useEffect(() => {
|
|
210
|
+
if (editorStateRef.current === editorState) return
|
|
211
|
+
editorStateRef.current = editorState
|
|
212
|
+
|
|
213
|
+
// unbounce a bit for perf
|
|
214
|
+
const t = setTimeout(() => (
|
|
215
|
+
onChange(draftToHtml(convertToRaw(editorState.getCurrentContent())))
|
|
216
|
+
), 99)
|
|
217
|
+
|
|
218
|
+
return () => { clearTimeout(t) }
|
|
219
|
+
}, [onChange, editorState])
|
|
220
|
+
|
|
221
|
+
const toolbar = useMemo(() => getToolbar({ hideEmoji }), [hideEmoji])
|
|
222
|
+
|
|
223
|
+
return (
|
|
224
|
+
<Paper sx={{ padding: 1 }} style={style}>
|
|
225
|
+
<Editor spellCheck ref={editorRef} editorStyle={editorStyle}
|
|
226
|
+
editorState={editorState}
|
|
227
|
+
wrapperClassName="demo-wrapper"
|
|
228
|
+
editorClassName="demo-editor"
|
|
229
|
+
onEditorStateChange={setEditorState}
|
|
230
|
+
toolbar={toolbar}
|
|
231
|
+
/>
|
|
232
|
+
</Paper>
|
|
233
|
+
)
|
|
234
|
+
}
|
package/src/inputs.tsx
CHANGED
|
@@ -95,7 +95,7 @@ export const useFileDropzone = ({ DropzoneComponent=DefaultDropzoneContent, styl
|
|
|
95
95
|
}
|
|
96
96
|
}
|
|
97
97
|
|
|
98
|
-
type FileUploadHandler = (details: FileDetails & { externalId?: string, }, file: Blob | Buffer | ReactNativeFile, options?: {}) => Promise<FileClientType>
|
|
98
|
+
export type FileUploadHandler = (details: FileDetails & { externalId?: string, }, file: Blob | Buffer | ReactNativeFile, options?: {}) => Promise<FileClientType>
|
|
99
99
|
interface UseFileUploaderOptions {
|
|
100
100
|
enduserId?: string
|
|
101
101
|
publicRead?: boolean,
|
package/src/state.tsx
CHANGED
|
@@ -544,6 +544,7 @@ export const useDataSync____internal = () => {
|
|
|
544
544
|
try {
|
|
545
545
|
// not compatible with React Native
|
|
546
546
|
if (typeof window === 'undefined') { return }
|
|
547
|
+
if (global?.navigator?.product === 'ReactNative') { return }
|
|
547
548
|
|
|
548
549
|
const onMouseMove = () => { lastActiveForSync.at = new Date() }
|
|
549
550
|
window.addEventListener('mousemove', onMouseMove)
|
package/src/table.tsx
CHANGED
|
@@ -1038,7 +1038,7 @@ export const Table = <T extends Item>({
|
|
|
1038
1038
|
onExport ? () => {
|
|
1039
1039
|
onExport({
|
|
1040
1040
|
// use items, not sorted, as sorted only includes first page when paginated
|
|
1041
|
-
data: (paginated ? items :
|
|
1041
|
+
data: (paginated ? items : filtered).map(s => fields.map(f => f.getExportData?.(s) || '')),
|
|
1042
1042
|
labels: fields.map(f => f.label)
|
|
1043
1043
|
})
|
|
1044
1044
|
}
|