@evergis/react 4.0.154 → 4.0.155
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/constants.d.ts +1 -0
- package/dist/components/Dashboard/elements/ElementIcon/components/AttachmentIcon/index.d.ts +7 -0
- package/dist/components/Dashboard/elements/ElementIcon/components/AttachmentIcon/styled.d.ts +3 -0
- package/dist/components/Dashboard/elements/ElementIcon/components/AttachmentIcon/types.d.ts +15 -0
- package/dist/components/Dashboard/elements/ElementIcon/constants.d.ts +2 -0
- package/dist/components/Dashboard/elements/ElementIcon/utils/getAttachmentIcon.d.ts +7 -0
- package/dist/index.js +64 -6
- package/dist/index.js.map +1 -1
- package/dist/react.esm.js +64 -6
- package/dist/react.esm.js.map +1 -1
- package/package.json +2 -2
|
@@ -2,6 +2,7 @@ export declare const GRID_TILE_SIZE = "4.5rem";
|
|
|
2
2
|
export declare const LIST_ICON_SIZE = "1.5rem";
|
|
3
3
|
export declare const JPG_MIME_TYPE = "image/jpeg";
|
|
4
4
|
export declare const PNG_MIME_TYPE = "image/png";
|
|
5
|
+
export declare const SVG_MIME_TYPE = "image/svg+xml";
|
|
5
6
|
export declare const IMAGE_MIME_TYPES: string[];
|
|
6
7
|
export declare const XLSX_MIME_TYPES: string[];
|
|
7
8
|
export declare const PDF_MIME_TYPE = "application/pdf";
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { FC } from 'react';
|
|
2
|
+
import { AttachmentIconProps } from './types';
|
|
3
|
+
/**
|
|
4
|
+
* Иконка из атрибута-вложения. SVG рисуется инлайном и перекрашивается `fontColor`, как у ElementSvg;
|
|
5
|
+
* растровый файл — картинкой как есть. Изображений среди вложений нет — не рендерится ничего.
|
|
6
|
+
*/
|
|
7
|
+
export declare const AttachmentIcon: FC<AttachmentIconProps>;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { CSSProperties } from 'react';
|
|
2
|
+
export interface AttachmentIconProps {
|
|
3
|
+
/** Сырое значение атрибута с `subType: Attachments`. */
|
|
4
|
+
value: unknown;
|
|
5
|
+
/** Размер иконки, px — как у шрифтовой иконки. */
|
|
6
|
+
fontSize?: string;
|
|
7
|
+
/** Цвет заливки SVG; растровое изображение не перекрашивается. */
|
|
8
|
+
fontColor?: string;
|
|
9
|
+
style?: CSSProperties;
|
|
10
|
+
}
|
|
11
|
+
export interface AttachmentIconSource {
|
|
12
|
+
url: string;
|
|
13
|
+
name: string;
|
|
14
|
+
isSvg: boolean;
|
|
15
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { AttachmentIconSource } from '../components/AttachmentIcon/types';
|
|
2
|
+
/**
|
|
3
|
+
* Иконка из значения атрибута-вложения: первое изображение списка, остальные файлы пропускаются.
|
|
4
|
+
* Значение приходит JSON-строкой с сервера или массивом после правки — `parseAttachments` понимает оба.
|
|
5
|
+
* SVG помечается отдельно: его рисуют инлайном, чтобы перекрасить цветом иконки.
|
|
6
|
+
*/
|
|
7
|
+
export declare const getAttachmentIcon: (value: unknown) => AttachmentIconSource | null;
|
package/dist/index.js
CHANGED
|
@@ -5824,13 +5824,14 @@ const GRID_TILE_SIZE = "4.5rem";
|
|
|
5824
5824
|
const LIST_ICON_SIZE = "1.5rem";
|
|
5825
5825
|
const JPG_MIME_TYPE = "image/jpeg";
|
|
5826
5826
|
const PNG_MIME_TYPE = "image/png";
|
|
5827
|
+
const SVG_MIME_TYPE = "image/svg+xml";
|
|
5827
5828
|
const IMAGE_MIME_TYPES = [
|
|
5828
5829
|
"image/apng",
|
|
5829
5830
|
"image/avif",
|
|
5830
5831
|
"image/gif",
|
|
5831
5832
|
"image/jpeg",
|
|
5832
5833
|
"image/png",
|
|
5833
|
-
|
|
5834
|
+
SVG_MIME_TYPE,
|
|
5834
5835
|
"image/webp",
|
|
5835
5836
|
];
|
|
5836
5837
|
const XLSX_MIME_TYPES = [
|
|
@@ -9554,7 +9555,10 @@ const ChartContainer = React.memo(({ elementConfig, isVisible, type, renderEleme
|
|
|
9554
9555
|
const chartElement = children.find(child => child.id === "chart");
|
|
9555
9556
|
const legendElement = children.find(child => child.id === "legend");
|
|
9556
9557
|
const isLineChart = chartElement?.options?.chartType === "line";
|
|
9557
|
-
|
|
9558
|
+
// Подпись оси X — часть макета осей линейного графика, как и подписи осей Y в `Chart`. У других типов
|
|
9559
|
+
// её нет, даже если она осталась в конфиге после смены типа: редактор показывает настройки осей только
|
|
9560
|
+
// линейному графику, и убрать там такую подпись было бы нечем.
|
|
9561
|
+
const xAxisTitle = React.useMemo(() => (isLineChart ? chartElement?.options?.axis?.x?.title : undefined), [isLineChart, chartElement?.options?.axis?.x?.title]);
|
|
9558
9562
|
const footerJustify = React.useMemo(() => CHART_AXIS_ALIGN_JUSTIFY[chartElement?.options?.axis?.x?.align ?? "center"], [chartElement?.options?.axis?.x?.align]);
|
|
9559
9563
|
// Легенда встаёт в строку с подписью оси X только когда та есть и легенда не вынесена вбок.
|
|
9560
9564
|
const isLegendInline = React.useMemo(() => !!legendInline && !twoColumns && !!xAxisTitle, [legendInline, twoColumns, xAxisTitle]);
|
|
@@ -9585,7 +9589,7 @@ const ChartContainer = React.memo(({ elementConfig, isVisible, type, renderEleme
|
|
|
9585
9589
|
if (!loading && !hasItems && hideEmpty)
|
|
9586
9590
|
return null;
|
|
9587
9591
|
const chartSlot = (jsxRuntime.jsx(ContainerChart, { "$fill": !!fill, children: jsxRuntime.jsx(FillContext.Provider, { value: fillContextValue, children: jsxRuntime.jsx(ChartPlotContext.Provider, { value: plotContextValue, children: renderElement({ id: "chart" }) }) }) }));
|
|
9588
|
-
const footer = xAxisTitle ? (jsxRuntime.jsxs(ChartFooter, { "$align": footerJustify, "$insets": footerInsets, "$offsetTop":
|
|
9592
|
+
const footer = xAxisTitle ? (jsxRuntime.jsxs(ChartFooter, { "$align": footerJustify, "$insets": footerInsets, "$offsetTop": X_AXIS_TITLE_GAP - LINE_CHART_X_LABELS_BLANK, "$awaitingPlot": isAwaitingPlot, children: [jsxRuntime.jsx(ChartXAxisTitle, { children: xAxisTitle }), isLegendInline && jsxRuntime.jsx(ContainerLegend, { children: renderElement({ id: "legend" }) })] })) : null;
|
|
9589
9593
|
// Легенда линейного графика: под подписью оси X — через X_AXIS_TITLE_LEGEND_GAP, без подписи — на её
|
|
9590
9594
|
// месте, вплотную под подписями делений оси X. У остальных графиков — прежняя раскладка общей легенды.
|
|
9591
9595
|
const legendRow = isLegendInline ? null : (jsxRuntime.jsx(ChartLegendRow, { justifyContent: legendJustify, "$insets": isPlotLegend ? footerInsets : null, "$gapTop": isPlotLegend ? (xAxisTitle ? X_AXIS_TITLE_LEGEND_GAP : 0) : undefined, "$offsetTop": isPlotLegend && !xAxisTitle ? X_AXIS_TITLE_GAP - LINE_CHART_X_LABELS_BLANK : undefined, "$justify": isPlotLegend ? legendJustify : undefined, "$awaitingPlot": isPlotLegend && isAwaitingPlot, children: renderElement({ id: "legend" }) }));
|
|
@@ -11346,6 +11350,13 @@ const StyledSvg = styled(uilibGl.Flex).withConfig({ displayName: "StyledSvg", co
|
|
|
11346
11350
|
${({ $fontColor }) => !!$fontColor && StyledSvgColorMixin};
|
|
11347
11351
|
`;
|
|
11348
11352
|
|
|
11353
|
+
const AttachmentIconImg = styled.img.withConfig({ displayName: "AttachmentIconImg", componentId: "sc-1qtgzdf" }) `
|
|
11354
|
+
flex-shrink: 0;
|
|
11355
|
+
width: ${({ $size }) => $size}px;
|
|
11356
|
+
height: ${({ $size }) => $size}px;
|
|
11357
|
+
object-fit: contain;
|
|
11358
|
+
`;
|
|
11359
|
+
|
|
11349
11360
|
const ContainerIconValue = styled(uilibGl.Flex).withConfig({ displayName: "ContainerIconValue", componentId: "sc-1adlcb4" }) ``;
|
|
11350
11361
|
/**
|
|
11351
11362
|
* Обёртка иконки плитки. Собственный styled нужен, чтобы до иконки можно было дотянуться стилями:
|
|
@@ -11450,6 +11461,12 @@ const RoundedBackgroundContainerWrapper = styled(uilibGl.Flex).withConfig({ disp
|
|
|
11450
11461
|
width: ${BIG_ICON_SIZE} !important;
|
|
11451
11462
|
height: ${BIG_ICON_SIZE} !important;
|
|
11452
11463
|
}
|
|
11464
|
+
|
|
11465
|
+
/* Растровая иконка из атрибута-вложения: её размер тоже задаёт контейнер. */
|
|
11466
|
+
${AttachmentIconImg} {
|
|
11467
|
+
width: ${BIG_ICON_SIZE};
|
|
11468
|
+
height: ${BIG_ICON_SIZE};
|
|
11469
|
+
}
|
|
11453
11470
|
}
|
|
11454
11471
|
`};
|
|
11455
11472
|
|
|
@@ -15547,14 +15564,55 @@ const StyledIcon = styled(uilibGl.Icon).withConfig({ displayName: "StyledIcon",
|
|
|
15547
15564
|
${({ fontColor }) => !!fontColor && StyledIconFontColorMixin};
|
|
15548
15565
|
`;
|
|
15549
15566
|
|
|
15567
|
+
/** Размер иконки-вложения, px, когда в конфиге не задан `options.fontSize`. */
|
|
15568
|
+
const ATTACHMENT_ICON_DEFAULT_SIZE = 16;
|
|
15569
|
+
|
|
15570
|
+
/**
|
|
15571
|
+
* Иконка из значения атрибута-вложения: первое изображение списка, остальные файлы пропускаются.
|
|
15572
|
+
* Значение приходит JSON-строкой с сервера или массивом после правки — `parseAttachments` понимает оба.
|
|
15573
|
+
* SVG помечается отдельно: его рисуют инлайном, чтобы перекрасить цветом иконки.
|
|
15574
|
+
*/
|
|
15575
|
+
const getAttachmentIcon = (value) => {
|
|
15576
|
+
const image = parseAttachments(value).find(({ mimeType, name }) => IMAGE_FILE_TYPES.includes(getFileType(mimeType, name)));
|
|
15577
|
+
if (!image)
|
|
15578
|
+
return null;
|
|
15579
|
+
return {
|
|
15580
|
+
url: getResourceUrl(image.link),
|
|
15581
|
+
name: image.name,
|
|
15582
|
+
isSvg: image.mimeType === SVG_MIME_TYPE,
|
|
15583
|
+
};
|
|
15584
|
+
};
|
|
15585
|
+
|
|
15586
|
+
/**
|
|
15587
|
+
* Иконка из атрибута-вложения. SVG рисуется инлайном и перекрашивается `fontColor`, как у ElementSvg;
|
|
15588
|
+
* растровый файл — картинкой как есть. Изображений среди вложений нет — не рендерится ничего.
|
|
15589
|
+
*/
|
|
15590
|
+
const AttachmentIcon = React.memo(({ value, fontSize, fontColor, style }) => {
|
|
15591
|
+
const icon = React.useMemo(() => getAttachmentIcon(value), [value]);
|
|
15592
|
+
const size = React.useMemo(() => Number(fontSize) || ATTACHMENT_ICON_DEFAULT_SIZE, [fontSize]);
|
|
15593
|
+
const rasterUrl = React.useMemo(() => (icon && !icon.isSvg ? icon.url : null), [icon]);
|
|
15594
|
+
const imageSrc = useFetchImageWithAuth(rasterUrl);
|
|
15595
|
+
if (!icon)
|
|
15596
|
+
return null;
|
|
15597
|
+
if (icon.isSvg) {
|
|
15598
|
+
return jsxRuntime.jsx(SvgImage, { url: icon.url, width: size, height: size, fontColor: fontColor });
|
|
15599
|
+
}
|
|
15600
|
+
if (!imageSrc)
|
|
15601
|
+
return null;
|
|
15602
|
+
return jsxRuntime.jsx(AttachmentIconImg, { src: imageSrc, alt: icon.name, style: style, "$size": size });
|
|
15603
|
+
});
|
|
15604
|
+
|
|
15550
15605
|
const ElementIcon = React.memo(({ type, elementConfig, ...rest }) => {
|
|
15551
15606
|
const ctx = useWidgetContext(type);
|
|
15552
15607
|
const attributes = rest.attributes || ctx.attributes;
|
|
15553
15608
|
const { value, attributeName, options, style } = elementConfig || {};
|
|
15554
15609
|
const { fontSize, fontColor } = options || {};
|
|
15555
|
-
const
|
|
15556
|
-
|
|
15557
|
-
|
|
15610
|
+
const attribute = React.useMemo(() => (attributeName ? getAttributeByName(attributeName, attributes) : undefined), [attributeName, attributes]);
|
|
15611
|
+
const iconValue = React.useMemo(() => (attributeName ? attribute?.value : value), [attributeName, attribute, value]);
|
|
15612
|
+
// Во вложениях лежит список файлов, а не имя глифа: иконкой становится первое изображение.
|
|
15613
|
+
if (attribute?.subType === api.StringSubType.Attachments) {
|
|
15614
|
+
return jsxRuntime.jsx(AttachmentIcon, { value: attribute.value, fontSize: fontSize, fontColor: fontColor, style: style });
|
|
15615
|
+
}
|
|
15558
15616
|
return (jsxRuntime.jsx(StyledIcon, { kind: iconValue, fontSize: fontSize, fontColor: fontColor, style: style }));
|
|
15559
15617
|
});
|
|
15560
15618
|
|