@evergis/react 4.0.54 → 4.0.55
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/components/Dashboard/containers/AttachmentContainer/usePreviewImages.d.ts +8 -0
- package/dist/components/Dashboard/hooks/useEditControl.d.ts +1 -1
- package/dist/components/Dashboard/types.d.ts +1 -1
- package/dist/index.js +93 -30
- package/dist/index.js.map +1 -1
- package/dist/react.esm.js +93 -30
- package/dist/react.esm.js.map +1 -1
- package/package.json +3 -3
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { IPreviewImage } from '@evergis/uilib-gl';
|
|
2
|
+
import { Attachment } from './types';
|
|
3
|
+
interface UsePreviewImagesParams {
|
|
4
|
+
items: Attachment[];
|
|
5
|
+
active: boolean;
|
|
6
|
+
}
|
|
7
|
+
export declare const usePreviewImages: ({ items, active }: UsePreviewImagesParams) => IPreviewImage[];
|
|
8
|
+
export {};
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { ConfigContainerChild, EditAttributeValue, WidgetType } from '../types';
|
|
2
2
|
export declare const useEditControl: (type: WidgetType, elementConfig: ConfigContainerChild) => {
|
|
3
3
|
control: import('../types').ConfigControl;
|
|
4
|
-
value: Date | import('../../..').FeaturedDcExtendedGeometry |
|
|
4
|
+
value: Date | import('../../..').FeaturedDcExtendedGeometry | EditAttributeValue;
|
|
5
5
|
dataSource: import('../types').WidgetDataSource;
|
|
6
6
|
items: any[];
|
|
7
7
|
onChange: (newValue: EditAttributeValue) => void;
|
|
@@ -44,7 +44,7 @@ export interface BaseMapSettings {
|
|
|
44
44
|
opacity?: number;
|
|
45
45
|
showBuildings?: boolean;
|
|
46
46
|
}
|
|
47
|
-
export type EditAttributeValue = string | number | boolean
|
|
47
|
+
export type EditAttributeValue = string | number | boolean | unknown[] | Record<string, unknown>;
|
|
48
48
|
export interface CustomFeatureSelect {
|
|
49
49
|
point?: {
|
|
50
50
|
paint?: CircleLayerSpecification["paint"];
|
package/dist/index.js
CHANGED
|
@@ -8042,10 +8042,31 @@ const useGlobalContext = () => {
|
|
|
8042
8042
|
}), [language, translate, api, ewktGeometry, themeName]);
|
|
8043
8043
|
};
|
|
8044
8044
|
|
|
8045
|
+
const ImagePreviewError = styled.div `
|
|
8046
|
+
display: flex;
|
|
8047
|
+
align-items: center;
|
|
8048
|
+
justify-content: center;
|
|
8049
|
+
width: 100%;
|
|
8050
|
+
height: 100%;
|
|
8051
|
+
background-color: ${({ theme }) => theme.palette.elementDark};
|
|
8052
|
+
border-radius: ${({ theme: { borderRadius: themeBorder }, borderRadius }) => borderRadius || themeBorder.smallest};
|
|
8053
|
+
|
|
8054
|
+
${uilibGl.Icon} {
|
|
8055
|
+
width: 37.5%;
|
|
8056
|
+
height: 37.5%;
|
|
8057
|
+
}
|
|
8058
|
+
|
|
8059
|
+
${uilibGl.Icon}:after {
|
|
8060
|
+
font-size: 1.5rem;
|
|
8061
|
+
color: ${({ theme }) => theme.palette.textSecondary};
|
|
8062
|
+
}
|
|
8063
|
+
`;
|
|
8045
8064
|
const FileImagePreview = ({ link, isExternal, size, borderRadius, }) => {
|
|
8046
8065
|
const { api } = useGlobalContext();
|
|
8047
8066
|
const [imageSrc, setImageSrc] = React.useState();
|
|
8067
|
+
const [hasError, setHasError] = React.useState(false);
|
|
8048
8068
|
React.useEffect(() => {
|
|
8069
|
+
setHasError(false);
|
|
8049
8070
|
if (isExternal) {
|
|
8050
8071
|
setImageSrc(link);
|
|
8051
8072
|
return;
|
|
@@ -8063,14 +8084,18 @@ const FileImagePreview = ({ link, isExternal, size, borderRadius, }) => {
|
|
|
8063
8084
|
objectUrl = URL.createObjectURL(blob);
|
|
8064
8085
|
setImageSrc(objectUrl);
|
|
8065
8086
|
})
|
|
8066
|
-
.catch(() => {
|
|
8087
|
+
.catch(() => {
|
|
8088
|
+
if (cancelled)
|
|
8089
|
+
return;
|
|
8090
|
+
setHasError(true);
|
|
8091
|
+
});
|
|
8067
8092
|
return () => {
|
|
8068
8093
|
cancelled = true;
|
|
8069
8094
|
if (objectUrl)
|
|
8070
8095
|
URL.revokeObjectURL(objectUrl);
|
|
8071
8096
|
};
|
|
8072
8097
|
}, [api, link, isExternal]);
|
|
8073
|
-
return (jsxRuntime.jsxs(ImagePreviewContainer, { size: size, children: [!imageSrc && (jsxRuntime.jsx(ImagePreviewLoaderContainer, { children: jsxRuntime.jsx(uilibGl.LinearProgress, {}) })), imageSrc && (jsxRuntime.jsx(GridImagePreview, { borderRadius: borderRadius, size: size, src: imageSrc, alt: "" }))] }));
|
|
8098
|
+
return (jsxRuntime.jsxs(ImagePreviewContainer, { size: size, children: [hasError && (jsxRuntime.jsx(ImagePreviewError, { borderRadius: borderRadius, children: jsxRuntime.jsx(uilibGl.Icon, { kind: "alert" }) })), !hasError && !imageSrc && (jsxRuntime.jsx(ImagePreviewLoaderContainer, { children: jsxRuntime.jsx(uilibGl.LinearProgress, {}) })), !hasError && imageSrc && (jsxRuntime.jsx(GridImagePreview, { borderRadius: borderRadius, size: size, src: imageSrc, alt: "", onError: () => setHasError(true) }))] }));
|
|
8074
8099
|
};
|
|
8075
8100
|
|
|
8076
8101
|
const getFileType = (mimeType = "", name = "") => {
|
|
@@ -8223,6 +8248,60 @@ const useAttachmentContainer = ({ type, elementConfig, valueOverride, }) => {
|
|
|
8223
8248
|
};
|
|
8224
8249
|
};
|
|
8225
8250
|
|
|
8251
|
+
const usePreviewImages = ({ items, active }) => {
|
|
8252
|
+
const { api } = useGlobalContext();
|
|
8253
|
+
const [blobUrls, setBlobUrls] = React.useState({});
|
|
8254
|
+
const [failedLinks, setFailedLinks] = React.useState({});
|
|
8255
|
+
const inFlightRef = React.useRef(new Set());
|
|
8256
|
+
const blobUrlsRef = React.useRef(blobUrls);
|
|
8257
|
+
blobUrlsRef.current = blobUrls;
|
|
8258
|
+
React.useEffect(() => {
|
|
8259
|
+
if (!active || !api?.catalog?.getFile)
|
|
8260
|
+
return;
|
|
8261
|
+
items.forEach(item => {
|
|
8262
|
+
const fileType = getFileType(item.mimeType, item.name);
|
|
8263
|
+
const isImage = IMAGE_FILE_TYPES.includes(fileType);
|
|
8264
|
+
if (!isImage || item.isExternal)
|
|
8265
|
+
return;
|
|
8266
|
+
if (blobUrlsRef.current[item.link] || inFlightRef.current.has(item.link))
|
|
8267
|
+
return;
|
|
8268
|
+
inFlightRef.current.add(item.link);
|
|
8269
|
+
api.catalog
|
|
8270
|
+
.getFile(item.link)
|
|
8271
|
+
.then(blob => {
|
|
8272
|
+
const objectUrl = URL.createObjectURL(blob);
|
|
8273
|
+
setBlobUrls(prev => ({ ...prev, [item.link]: objectUrl }));
|
|
8274
|
+
})
|
|
8275
|
+
.catch(() => {
|
|
8276
|
+
setFailedLinks(prev => (prev[item.link] ? prev : { ...prev, [item.link]: true }));
|
|
8277
|
+
})
|
|
8278
|
+
.finally(() => {
|
|
8279
|
+
inFlightRef.current.delete(item.link);
|
|
8280
|
+
});
|
|
8281
|
+
});
|
|
8282
|
+
}, [active, api, items]);
|
|
8283
|
+
React.useEffect(() => () => {
|
|
8284
|
+
Object.values(blobUrlsRef.current).forEach(URL.revokeObjectURL);
|
|
8285
|
+
}, []);
|
|
8286
|
+
return React.useMemo(() => items.map(item => {
|
|
8287
|
+
const fileType = getFileType(item.mimeType, item.name);
|
|
8288
|
+
const isImage = IMAGE_FILE_TYPES.includes(fileType);
|
|
8289
|
+
const fileName = item.name;
|
|
8290
|
+
if (!isImage)
|
|
8291
|
+
return { src: getFileTypeIcon(fileType), fileName };
|
|
8292
|
+
if (item.isExternal)
|
|
8293
|
+
return { src: item.link, fileName };
|
|
8294
|
+
const hasError = !!failedLinks[item.link];
|
|
8295
|
+
const blobUrl = blobUrls[item.link];
|
|
8296
|
+
return {
|
|
8297
|
+
src: blobUrl ?? "",
|
|
8298
|
+
fileName,
|
|
8299
|
+
hasError,
|
|
8300
|
+
isLoading: !hasError && !blobUrl,
|
|
8301
|
+
};
|
|
8302
|
+
}), [items, blobUrls, failedLinks]);
|
|
8303
|
+
};
|
|
8304
|
+
|
|
8226
8305
|
const EXTENSION_TO_MIME = {
|
|
8227
8306
|
apng: "image/apng",
|
|
8228
8307
|
avif: "image/avif",
|
|
@@ -8269,20 +8348,6 @@ const getFileNameFromUrl = (url) => {
|
|
|
8269
8348
|
}
|
|
8270
8349
|
};
|
|
8271
8350
|
|
|
8272
|
-
const getResourceUrl = (url) => {
|
|
8273
|
-
return url ? (url.startsWith("http") ? url : `/sp/resources/file/${url}`) : "";
|
|
8274
|
-
};
|
|
8275
|
-
|
|
8276
|
-
const buildPreviewImage$1 = (item) => {
|
|
8277
|
-
const fileType = getFileType(item.mimeType, item.name);
|
|
8278
|
-
const isImage = IMAGE_FILE_TYPES.includes(fileType);
|
|
8279
|
-
const src = isImage
|
|
8280
|
-
? item.isExternal
|
|
8281
|
-
? item.link
|
|
8282
|
-
: getResourceUrl(item.link)
|
|
8283
|
-
: getFileTypeIcon(fileType);
|
|
8284
|
-
return { src, fileName: item.name };
|
|
8285
|
-
};
|
|
8286
8351
|
const EditAttachmentContainer = React.memo(({ type, elementConfig, renderElement }) => {
|
|
8287
8352
|
const { api } = useGlobalContext();
|
|
8288
8353
|
const { selectAttachmentsFromCatalog } = useWidgetContext(type);
|
|
@@ -8293,7 +8358,7 @@ const EditAttachmentContainer = React.memo(({ type, elementConfig, renderElement
|
|
|
8293
8358
|
const [previewIndex, setPreviewIndex] = React.useState(null);
|
|
8294
8359
|
const [uploading, setUploading] = React.useState(false);
|
|
8295
8360
|
const [isLinkDialogOpen, , setLinkDialogOpen] = useToggle(false);
|
|
8296
|
-
const previewImages =
|
|
8361
|
+
const previewImages = usePreviewImages({ items, active: previewIndex !== null });
|
|
8297
8362
|
const orderedPreviewImages = React.useMemo(() => {
|
|
8298
8363
|
if (previewIndex === null)
|
|
8299
8364
|
return previewImages;
|
|
@@ -8302,7 +8367,7 @@ const EditAttachmentContainer = React.memo(({ type, elementConfig, renderElement
|
|
|
8302
8367
|
...previewImages.filter((_, idx) => idx !== previewIndex),
|
|
8303
8368
|
];
|
|
8304
8369
|
}, [previewImages, previewIndex]);
|
|
8305
|
-
const persist = React.useCallback((next) => onChange(
|
|
8370
|
+
const persist = React.useCallback((next) => onChange(next), [onChange]);
|
|
8306
8371
|
const handlePreview = React.useCallback((link) => {
|
|
8307
8372
|
const idx = items.findIndex(item => item.link === link);
|
|
8308
8373
|
if (idx >= 0)
|
|
@@ -8362,23 +8427,14 @@ const EditAttachmentContainer = React.memo(({ type, elementConfig, renderElement
|
|
|
8362
8427
|
return (jsxRuntime.jsxs(AttachmentsContainer, { id: id, style: { ...BASE_CONTAINER_STYLE, ...style }, children: [jsxRuntime.jsx(AttachmentsHeader, { alias: renderElement?.({ id: "alias" }), count: items.length, viewMode: viewMode, onChangeViewMode: setViewMode }), jsxRuntime.jsx(AttachmentsContent, { children: viewMode === "grid" ? (jsxRuntime.jsx(AttachmentsGrid, { items: visibleItems, isEdit: true, onPreview: handlePreview, onDelete: handleDelete })) : (jsxRuntime.jsx(AttachmentsList, { items: visibleItems, isEdit: true, onPreview: handlePreview, onDelete: handleDelete })) }), hasMore && !showMore && (jsxRuntime.jsx(ShowMoreButton, { hiddenCount: hiddenCount, onClick: handleShowMore })), jsxRuntime.jsx(AddButton, { accept: fileExtensions, onSelectFiles: uploading ? () => undefined : handleUpload, onSelectFromCatalog: handleSelectFromCatalog, onSelectFromLink: handleOpenLinkDialog }), jsxRuntime.jsx(AttachmentLinkDialog, { isOpen: isLinkDialogOpen, onClose: handleCloseLinkDialog, onSubmit: handleAddByLink }), previewIndex !== null && (jsxRuntime.jsx(uilibGl.Preview, { images: orderedPreviewImages, isOpen: previewIndex !== null, onClose: handleClosePreview }))] }));
|
|
8363
8428
|
});
|
|
8364
8429
|
|
|
8365
|
-
const buildPreviewImage = (item) => {
|
|
8366
|
-
const fileType = getFileType(item.mimeType, item.name);
|
|
8367
|
-
const isImage = IMAGE_FILE_TYPES.includes(fileType);
|
|
8368
|
-
const src = isImage
|
|
8369
|
-
? item.isExternal
|
|
8370
|
-
? item.link
|
|
8371
|
-
: getResourceUrl(item.link)
|
|
8372
|
-
: getFileTypeIcon(fileType);
|
|
8373
|
-
return { src, fileName: item.name };
|
|
8374
|
-
};
|
|
8375
8430
|
const AttachmentContainer = React.memo(({ type, elementConfig, renderElement }) => {
|
|
8431
|
+
const { t } = useGlobalContext();
|
|
8376
8432
|
const { expandedContainers } = useWidgetContext(type);
|
|
8377
8433
|
const { items, visibleItems, viewMode, setViewMode, showMore, setShowMore, hasMore, hiddenCount } = useAttachmentContainer({ type, elementConfig });
|
|
8378
8434
|
const { id, style, options } = elementConfig || {};
|
|
8379
8435
|
const { expandable, expanded } = options || {};
|
|
8380
8436
|
const [previewIndex, setPreviewIndex] = React.useState(null);
|
|
8381
|
-
const previewImages =
|
|
8437
|
+
const previewImages = usePreviewImages({ items, active: previewIndex !== null });
|
|
8382
8438
|
const orderedPreviewImages = React.useMemo(() => {
|
|
8383
8439
|
if (previewIndex === null)
|
|
8384
8440
|
return previewImages;
|
|
@@ -8395,7 +8451,10 @@ const AttachmentContainer = React.memo(({ type, elementConfig, renderElement })
|
|
|
8395
8451
|
const handleClosePreview = React.useCallback(() => setPreviewIndex(null), []);
|
|
8396
8452
|
const handleShowMore = React.useCallback(() => setShowMore(true), [setShowMore]);
|
|
8397
8453
|
const isVisible = isVisibleContainer(id, expandable, expanded, expandedContainers);
|
|
8398
|
-
return (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsx(ExpandableTitle, { elementConfig: elementConfig, type: type, renderElement: renderElement }), isVisible && (jsxRuntime.jsxs(Container, { id: id, isColumn: true, style: style, children: [jsxRuntime.jsx(AttachmentsHeader, { alias: renderElement?.({ id: "alias" }), count: items.length, viewMode: viewMode, onChangeViewMode: setViewMode }), jsxRuntime.jsx(AttachmentsContent, { children: viewMode === "grid" ? (jsxRuntime.jsx(AttachmentsGrid, { items: visibleItems, isEdit: false, onPreview: handlePreview })) : (jsxRuntime.jsx(AttachmentsList, { items: visibleItems, isEdit: false, onPreview: handlePreview })) }), hasMore && !showMore && (jsxRuntime.jsx(ShowMoreButton, { hiddenCount: hiddenCount, onClick: handleShowMore })), previewIndex !== null && (jsxRuntime.jsx(uilibGl.Preview, { images: orderedPreviewImages, isOpen: previewIndex !== null, onClose: handleClosePreview
|
|
8454
|
+
return (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsx(ExpandableTitle, { elementConfig: elementConfig, type: type, renderElement: renderElement }), isVisible && (jsxRuntime.jsxs(Container, { id: id, isColumn: true, style: style, children: [jsxRuntime.jsx(AttachmentsHeader, { alias: renderElement?.({ id: "alias" }), count: items.length, viewMode: viewMode, onChangeViewMode: setViewMode }), jsxRuntime.jsx(AttachmentsContent, { children: viewMode === "grid" ? (jsxRuntime.jsx(AttachmentsGrid, { items: visibleItems, isEdit: false, onPreview: handlePreview })) : (jsxRuntime.jsx(AttachmentsList, { items: visibleItems, isEdit: false, onPreview: handlePreview })) }), hasMore && !showMore && (jsxRuntime.jsx(ShowMoreButton, { hiddenCount: hiddenCount, onClick: handleShowMore })), previewIndex !== null && (jsxRuntime.jsx(uilibGl.Preview, { images: orderedPreviewImages, isOpen: previewIndex !== null, onClose: handleClosePreview, errorTitleText: t("attachments.resourceUnavailable", {
|
|
8455
|
+
ns: "common",
|
|
8456
|
+
defaultValue: "Ресурс недоступен",
|
|
8457
|
+
}) }))] }))] }));
|
|
8399
8458
|
});
|
|
8400
8459
|
|
|
8401
8460
|
const ContainerDivider = styled(uilibGl.Divider) `
|
|
@@ -11174,6 +11233,10 @@ const getRelatedAttribute = (layerInfo, sourceAttributeName, relatedLayerName) =
|
|
|
11174
11233
|
return attributeConfig?.options?.relatedAttributes?.find(({ layerName }) => layerName === relatedLayerName);
|
|
11175
11234
|
};
|
|
11176
11235
|
|
|
11236
|
+
const getResourceUrl = (url) => {
|
|
11237
|
+
return url ? (url.startsWith("http") ? url : `/sp/resources/file/${url}`) : "";
|
|
11238
|
+
};
|
|
11239
|
+
|
|
11177
11240
|
const getSlideshowImages = ({ element, attribute, }) => {
|
|
11178
11241
|
const { defaultValue, options } = element;
|
|
11179
11242
|
const { separator } = options || {};
|