@overmap-ai/core 1.0.35-add-image-to-forms.16 → 1.0.35-add-image-to-forms.18
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/forms/fields/BaseField/BaseField.d.ts +1 -1
- package/dist/forms/fields/BaseField/layouts.d.ts +1 -1
- package/dist/forms/fields/SelectField/BaseSelectField.d.ts +1 -1
- package/dist/forms/typings.d.ts +1 -1
- package/dist/forms/utils.d.ts +2 -0
- package/dist/overmap-core.js +72 -33
- package/dist/overmap-core.js.map +1 -1
- package/dist/overmap-core.umd.cjs +72 -33
- package/dist/overmap-core.umd.cjs.map +1 -1
- package/package.json +1 -1
|
@@ -30,7 +30,7 @@ export declare abstract class BaseField<TValue extends FieldValue, TIdentifier e
|
|
|
30
30
|
private readonly formValidators;
|
|
31
31
|
private readonly fieldValidators;
|
|
32
32
|
readonly label: string;
|
|
33
|
-
readonly image: File | undefined;
|
|
33
|
+
readonly image: File | Promise<File> | undefined;
|
|
34
34
|
/**
|
|
35
35
|
* By default, validation doesn't execute on `onChange` events when editing fields
|
|
36
36
|
* until the field has been `touched`. This can be overridden by setting this to `false`
|
|
@@ -19,7 +19,7 @@ export declare abstract class BaseSelectField<TValue extends FieldValue, TIdenti
|
|
|
19
19
|
options: SelectFieldOption[];
|
|
20
20
|
label: string;
|
|
21
21
|
required: boolean;
|
|
22
|
-
image?: File | undefined;
|
|
22
|
+
image?: File | Promise<File> | undefined;
|
|
23
23
|
description?: string | null | undefined;
|
|
24
24
|
identifier: string;
|
|
25
25
|
type: TIdentifier;
|
package/dist/forms/typings.d.ts
CHANGED
|
@@ -25,7 +25,7 @@ export interface BaseSerializedObject<TIdentifier extends FieldTypeIdentifier =
|
|
|
25
25
|
export interface BaseSerializedField<TIdentifier extends FieldTypeIdentifier = FieldTypeIdentifier> extends BaseSerializedObject<TIdentifier> {
|
|
26
26
|
label: string;
|
|
27
27
|
required: boolean;
|
|
28
|
-
image?: File
|
|
28
|
+
image?: File | Promise<File>;
|
|
29
29
|
}
|
|
30
30
|
/** All the possible field values */
|
|
31
31
|
export type FieldValue = string | number | boolean | string[] | SelectFieldOption[] | File[] | Date | Marker | null;
|
package/dist/forms/utils.d.ts
CHANGED
|
@@ -2,6 +2,8 @@ import { FormikErrors } from "formik";
|
|
|
2
2
|
import { BaseFormElement, ISchema } from "./fields";
|
|
3
3
|
import { Form } from "./typings";
|
|
4
4
|
import { FormikUserFormRevision } from "./builder";
|
|
5
|
+
import { UserFormRevision } from "../typings";
|
|
5
6
|
export declare const hasKeys: (errors: object) => boolean;
|
|
6
7
|
export declare const validateForm: (schema: ISchema, form: Form | FormikUserFormRevision) => FormikErrors<Form> | FormikErrors<import('./builder/typings').NewForm> | undefined;
|
|
7
8
|
export declare const initialFormValues: (fields: BaseFormElement[], values: Form) => Form;
|
|
9
|
+
export declare const useAttachImagesToFormRevisionFields: (revision: UserFormRevision) => UserFormRevision;
|
package/dist/overmap-core.js
CHANGED
|
@@ -5330,6 +5330,9 @@ const separateImageFromFields = (payload) => {
|
|
|
5330
5330
|
const newSectionFields = [];
|
|
5331
5331
|
for (const field of sectionFields) {
|
|
5332
5332
|
if (field.image) {
|
|
5333
|
+
if (!(field.image instanceof File)) {
|
|
5334
|
+
throw new Error(`Expected image to be a File, got ${typeof field.image} instead.`);
|
|
5335
|
+
}
|
|
5333
5336
|
images[field.identifier] = field.image;
|
|
5334
5337
|
delete field.image;
|
|
5335
5338
|
}
|
|
@@ -6859,16 +6862,24 @@ const FullScreenImagePreview = memo((props) => {
|
|
|
6859
6862
|
FullScreenImagePreview.displayName = "FullScreenImagePreview";
|
|
6860
6863
|
const InputWithLabel = (props) => {
|
|
6861
6864
|
const { label, children, size, severity, inputId, labelId, image, flexProps } = props;
|
|
6865
|
+
const [resolvedImage, setResolvedImage] = useState(void 0);
|
|
6862
6866
|
const [showImagePreview, setShowImagePreview] = useState(false);
|
|
6863
|
-
|
|
6867
|
+
useEffect(() => {
|
|
6868
|
+
if (image instanceof Promise) {
|
|
6869
|
+
image.then(setResolvedImage).catch(console.error);
|
|
6870
|
+
} else {
|
|
6871
|
+
setResolvedImage(image);
|
|
6872
|
+
}
|
|
6873
|
+
}, [image]);
|
|
6874
|
+
const resolvedImageURL = resolvedImage ? URL.createObjectURL(resolvedImage) : void 0;
|
|
6864
6875
|
return /* @__PURE__ */ jsxs(Flex, { direction: "column", gap: "2", ...flexProps, children: [
|
|
6865
|
-
|
|
6876
|
+
resolvedImage && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
6866
6877
|
/* @__PURE__ */ jsx(
|
|
6867
6878
|
"img",
|
|
6868
6879
|
{
|
|
6869
6880
|
className: styles$6.previewImage,
|
|
6870
|
-
src:
|
|
6871
|
-
alt:
|
|
6881
|
+
src: resolvedImageURL,
|
|
6882
|
+
alt: resolvedImage.name,
|
|
6872
6883
|
onClick: () => {
|
|
6873
6884
|
setShowImagePreview(true);
|
|
6874
6885
|
}
|
|
@@ -6877,9 +6888,9 @@ const InputWithLabel = (props) => {
|
|
|
6877
6888
|
showImagePreview && /* @__PURE__ */ jsx(
|
|
6878
6889
|
FullScreenImagePreview,
|
|
6879
6890
|
{
|
|
6880
|
-
file:
|
|
6881
|
-
url:
|
|
6882
|
-
name:
|
|
6891
|
+
file: resolvedImage,
|
|
6892
|
+
url: resolvedImageURL,
|
|
6893
|
+
name: resolvedImage.name,
|
|
6883
6894
|
setShowPreview: setShowImagePreview
|
|
6884
6895
|
}
|
|
6885
6896
|
)
|
|
@@ -10112,6 +10123,24 @@ const initialFormValues = (fields, values) => {
|
|
|
10112
10123
|
cloneDeep(values)
|
|
10113
10124
|
);
|
|
10114
10125
|
};
|
|
10126
|
+
const useAttachImagesToFormRevisionFields = (revision) => {
|
|
10127
|
+
const { sdk } = useSDK();
|
|
10128
|
+
const revisionCopy = JSON.parse(JSON.stringify(revision));
|
|
10129
|
+
const attachments = selectRevisionAttachments(revisionCopy.offline_id)(sdk.store.getState()) ?? [];
|
|
10130
|
+
for (const attachment of attachments) {
|
|
10131
|
+
const filePromise = sdk.files.fetchFileFromUrl(attachment.file, attachment.file_sha1, attachment.file_name);
|
|
10132
|
+
let sectionIndex = -1;
|
|
10133
|
+
let fieldIndex = -1;
|
|
10134
|
+
sectionIndex = revisionCopy.fields.findIndex((section) => {
|
|
10135
|
+
fieldIndex = section.fields.findIndex((field) => field.identifier === attachment.field_identifier);
|
|
10136
|
+
return fieldIndex !== -1;
|
|
10137
|
+
});
|
|
10138
|
+
if (sectionIndex !== -1 && fieldIndex !== -1) {
|
|
10139
|
+
set(revisionCopy, `fields[${sectionIndex}].fields[${fieldIndex}].image`, filePromise);
|
|
10140
|
+
}
|
|
10141
|
+
}
|
|
10142
|
+
return revisionCopy;
|
|
10143
|
+
};
|
|
10115
10144
|
const defaultHandleSubmit = () => {
|
|
10116
10145
|
throw new Error("onSubmit must be provided if form is not readonly.");
|
|
10117
10146
|
};
|
|
@@ -10180,9 +10209,10 @@ const FormSubmissionViewer = memo(
|
|
|
10180
10209
|
`Could not find revision ${submission.form_revision} for submission ${submission.offline_id}.`
|
|
10181
10210
|
);
|
|
10182
10211
|
}
|
|
10212
|
+
const revisionWithImages = useAttachImagesToFormRevisionFields(revision);
|
|
10183
10213
|
const schema = useMemo(() => {
|
|
10184
|
-
return formRevisionToSchema(
|
|
10185
|
-
}, [
|
|
10214
|
+
return formRevisionToSchema(revisionWithImages, { readonly: true });
|
|
10215
|
+
}, [revisionWithImages]);
|
|
10186
10216
|
const submissionValuesWithAttachments = useMemo(() => {
|
|
10187
10217
|
const attachments = selectSubmissionAttachments(submission.offline_id)(sdk.store.getState()) ?? [];
|
|
10188
10218
|
const downloadedAttachments = {};
|
|
@@ -10677,6 +10707,9 @@ const useFieldTypeItems = (onSelect = () => null) => {
|
|
|
10677
10707
|
});
|
|
10678
10708
|
}, [onSelect]);
|
|
10679
10709
|
};
|
|
10710
|
+
const isSection = (field) => {
|
|
10711
|
+
return field.type === "section";
|
|
10712
|
+
};
|
|
10680
10713
|
const FieldSettingsPopover = memo((props) => {
|
|
10681
10714
|
const { popoverInputs, hasError } = props;
|
|
10682
10715
|
return /* @__PURE__ */ jsx(
|
|
@@ -10706,6 +10739,8 @@ FieldSettingsPopover.displayName = "FieldSettingsPopover";
|
|
|
10706
10739
|
const FieldBuilder = memo((props) => {
|
|
10707
10740
|
var _a2, _b, _c, _d, _e, _f;
|
|
10708
10741
|
const { parentPath, index: index2, initial, conditionalSourceFields } = props;
|
|
10742
|
+
const { values, setFieldValue, errors } = useFormikContext();
|
|
10743
|
+
const fieldTypeItems = useFieldTypeItems();
|
|
10709
10744
|
const RADIX_SM_MIN_WIDTH = 576;
|
|
10710
10745
|
const [isLargeScreen, setIsLargeScreen] = useState(
|
|
10711
10746
|
window.matchMedia(`(min-width: ${RADIX_SM_MIN_WIDTH}px)`).matches
|
|
@@ -10720,23 +10755,38 @@ const FieldBuilder = memo((props) => {
|
|
|
10720
10755
|
mediaQuery.removeEventListener("change", handleMediaQueryChange);
|
|
10721
10756
|
};
|
|
10722
10757
|
}, []);
|
|
10758
|
+
const [resolvedImage, setResolvedImage] = useState(void 0);
|
|
10723
10759
|
const [showImagePreview, setShowImagePreview] = useState(false);
|
|
10724
|
-
|
|
10725
|
-
|
|
10726
|
-
|
|
10727
|
-
|
|
10728
|
-
|
|
10760
|
+
useEffect(() => {
|
|
10761
|
+
if (!isSection(initial)) {
|
|
10762
|
+
if (initial.image instanceof Promise) {
|
|
10763
|
+
initial.image.then(setResolvedImage).catch(console.error);
|
|
10764
|
+
} else {
|
|
10765
|
+
setResolvedImage(initial.image);
|
|
10766
|
+
}
|
|
10767
|
+
} else {
|
|
10768
|
+
setResolvedImage(void 0);
|
|
10769
|
+
}
|
|
10770
|
+
}, [initial]);
|
|
10771
|
+
const resolvedImageURL = resolvedImage ? URL.createObjectURL(resolvedImage) : void 0;
|
|
10772
|
+
const handleImageDelete = useCallback(
|
|
10773
|
+
(event) => {
|
|
10774
|
+
event.stopPropagation();
|
|
10775
|
+
void setFieldValue(`${parentPath}.${index2}.image`, null).then();
|
|
10776
|
+
},
|
|
10777
|
+
[index2, parentPath, setFieldValue]
|
|
10778
|
+
);
|
|
10729
10779
|
useEffect(() => {
|
|
10730
10780
|
if (isSection(initial) && !initial.conditional) {
|
|
10731
10781
|
void setFieldValue(`${parentPath}.${index2}.condition`, null).then();
|
|
10732
10782
|
}
|
|
10733
|
-
}, [index2, initial,
|
|
10783
|
+
}, [index2, initial, parentPath, setFieldValue]);
|
|
10734
10784
|
const conditionLabel = useMemo(
|
|
10735
10785
|
() => {
|
|
10736
10786
|
var _a3, _b2;
|
|
10737
10787
|
return isSection(initial) ? (_b2 = findFieldByIdentifier(values.fields, (_a3 = initial.condition) == null ? void 0 : _a3.identifier)) == null ? void 0 : _b2.label : void 0;
|
|
10738
10788
|
},
|
|
10739
|
-
[initial,
|
|
10789
|
+
[initial, values.fields]
|
|
10740
10790
|
);
|
|
10741
10791
|
const conditionComparison = isSection(initial) ? Array.isArray((_a2 = initial.condition) == null ? void 0 : _a2.value) ? "contains all of" : "equals" : void 0;
|
|
10742
10792
|
let conditionValue = void 0;
|
|
@@ -10746,17 +10796,6 @@ const FieldBuilder = memo((props) => {
|
|
|
10746
10796
|
}
|
|
10747
10797
|
conditionValue = Array.isArray((_c = initial.condition) == null ? void 0 : _c.value) ? initial.condition.value.map((v) => typeof v === "string" ? v : v.label).join(", ") : (_e = (_d = initial.condition) == null ? void 0 : _d.value) == null ? void 0 : _e.toString();
|
|
10748
10798
|
}
|
|
10749
|
-
let imageURL = void 0;
|
|
10750
|
-
if (!isSection(initial) && initial.image) {
|
|
10751
|
-
imageURL = URL.createObjectURL(initial.image);
|
|
10752
|
-
}
|
|
10753
|
-
const handleImageDelete = useCallback(
|
|
10754
|
-
(event) => {
|
|
10755
|
-
event.stopPropagation();
|
|
10756
|
-
void setFieldValue(`${parentPath}.${index2}.image`, null).then();
|
|
10757
|
-
},
|
|
10758
|
-
[index2, parentPath, setFieldValue]
|
|
10759
|
-
);
|
|
10760
10799
|
const handleInputChangeForInput = useCallback((event) => {
|
|
10761
10800
|
if (event.target.parentNode instanceof HTMLElement) {
|
|
10762
10801
|
event.target.parentNode.dataset.replicatedValue = event.target.value;
|
|
@@ -10859,14 +10898,14 @@ const FieldBuilder = memo((props) => {
|
|
|
10859
10898
|
/* @__PURE__ */ jsx(Badge, { className: styles.typeBadge, children: (_f = fieldTypeItems.flat().find((item) => item.value === type)) == null ? void 0 : _f.content }),
|
|
10860
10899
|
showPopoverInputs && /* @__PURE__ */ jsx(FieldSettingsPopover, { popoverInputs, hasError: popoverHasErrors })
|
|
10861
10900
|
] }),
|
|
10862
|
-
|
|
10901
|
+
resolvedImage && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
10863
10902
|
/* @__PURE__ */ jsxs("div", { className: styles.imageContainer, children: [
|
|
10864
10903
|
/* @__PURE__ */ jsx(
|
|
10865
10904
|
"img",
|
|
10866
10905
|
{
|
|
10867
10906
|
className: styles.previewImage,
|
|
10868
|
-
src:
|
|
10869
|
-
alt:
|
|
10907
|
+
src: resolvedImageURL,
|
|
10908
|
+
alt: resolvedImage.name,
|
|
10870
10909
|
onClick: () => {
|
|
10871
10910
|
setShowImagePreview(true);
|
|
10872
10911
|
}
|
|
@@ -10887,9 +10926,9 @@ const FieldBuilder = memo((props) => {
|
|
|
10887
10926
|
showImagePreview && /* @__PURE__ */ jsx(
|
|
10888
10927
|
FullScreenImagePreview,
|
|
10889
10928
|
{
|
|
10890
|
-
file:
|
|
10891
|
-
url:
|
|
10892
|
-
name:
|
|
10929
|
+
file: resolvedImage,
|
|
10930
|
+
url: resolvedImageURL,
|
|
10931
|
+
name: resolvedImage.name,
|
|
10893
10932
|
setShowPreview: setShowImagePreview
|
|
10894
10933
|
}
|
|
10895
10934
|
)
|