@evergis/react 3.1.41 → 3.1.46

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/index.js CHANGED
@@ -22,6 +22,8 @@ var MapGL = require('react-map-gl/mapbox');
22
22
  require('@mapbox/mapbox-gl-draw/dist/mapbox-gl-draw.css');
23
23
  require('mapbox-gl/dist/mapbox-gl.css');
24
24
  var react = require('swiper/react');
25
+ var ReactMarkdown = require('react-markdown');
26
+ var remarkGfm = require('remark-gfm');
25
27
 
26
28
  const AddFeatureButton = ({ title, icon = "feature_add" /* , layerName, geometryType*/ }) => {
27
29
  // const [, handleAddFeature] = useFeatureCreator(layerName, geometryType);
@@ -4448,24 +4450,48 @@ const formatDataSourceCondition = ({ condition, configFilters, filters, attribut
4448
4450
  const DashboardChipsContainer = styled(uilibGl.Flex) `
4449
4451
  flex-wrap: wrap;
4450
4452
  `;
4453
+ const DefaultChipColorMixin = styled.css `
4454
+ && {
4455
+ color: ${({ theme: { palette } }) => palette.textPrimary};
4456
+ }
4457
+
4458
+ && > * {
4459
+ color: ${({ theme: { palette } }) => palette.textPrimary};
4460
+ }
4461
+
4462
+ && span[kind]:after {
4463
+ color: ${({ theme: { palette } }) => palette.icon};
4464
+ }
4465
+ `;
4466
+ const CustomChipColorMixin = styled.css `
4467
+ && {
4468
+ color: ${({ $fontColor }) => $fontColor};
4469
+ }
4470
+
4471
+ && > * {
4472
+ color: ${({ $fontColor }) => $fontColor};
4473
+ }
4474
+
4475
+ && span[kind]:after {
4476
+ color: ${({ $fontColor }) => $fontColor};
4477
+ }
4478
+ `;
4451
4479
  const DashboardChip$1 = styled(uilibGl.Chip) `
4452
4480
  margin: 0 0.25rem 0.25rem 0;
4453
4481
  background: ${({ $isDefault, $bgColor, theme: { palette } }) => $isDefault ? palette.element : $bgColor || palette.primary};
4454
4482
  border-radius: ${({ $radius, theme: { borderRadius } }) => $radius || borderRadius.medium};
4455
4483
  white-space: nowrap;
4456
4484
  font-size: ${({ $fontSize }) => $fontSize || "0.875rem"};
4457
- color: ${({ $isDefault, $fontColor, theme: { palette } }) => $isDefault ? palette.textPrimary : $fontColor || "#fff"};
4485
+ color: ${({ theme: { palette } }) => palette.iconContrast};
4458
4486
 
4459
4487
  > * {
4460
4488
  font-size: ${({ $fontSize }) => $fontSize || "0.875rem"};
4461
- color: ${({ $isDefault, $fontColor, theme: { palette } }) => $isDefault ? palette.textPrimary : $fontColor || "#fff"};
4462
4489
  }
4463
4490
 
4464
4491
  span[kind] {
4465
4492
  height: 0.875rem;
4466
4493
 
4467
4494
  :after {
4468
- color: ${({ $isDefault, $fontColor, theme: { palette } }) => ($isDefault ? palette.icon : $fontColor || "#fff")};
4469
4495
  font-size: 0.875rem;
4470
4496
  }
4471
4497
  }
@@ -4474,6 +4500,9 @@ const DashboardChip$1 = styled(uilibGl.Chip) `
4474
4500
  width: auto;
4475
4501
  padding: 0 0.5rem;
4476
4502
  }
4503
+
4504
+ ${({ $isDefault }) => $isDefault && DefaultChipColorMixin}
4505
+ ${({ $fontColor, $isDefault }) => !!$fontColor && !$isDefault && CustomChipColorMixin}
4477
4506
  `;
4478
4507
 
4479
4508
  const ChartLegendContainer = styled(uilibGl.Flex) `
@@ -4500,7 +4529,7 @@ const ChartLegendColor = styled.div `
4500
4529
  `;
4501
4530
  const ChartLegendName = styled.div `
4502
4531
  flex: 1;
4503
- font-size: 0.625rem;
4532
+ font-size: ${({ $fontSize }) => $fontSize || "0.625rem"};
4504
4533
  color: ${({ theme: { palette }, $fontColor }) => $fontColor || palette.textPrimary};
4505
4534
  `;
4506
4535
 
@@ -5040,7 +5069,7 @@ const LayerGroup = ({ group, onlyMainTools }) => {
5040
5069
  if (!group) {
5041
5070
  return null;
5042
5071
  }
5043
- return (jsxRuntime.jsx(LayerGroupContainer, { visible: group.isVisible, children: jsxRuntime.jsxs(LayerGroupMain, { children: [jsxRuntime.jsx(uilibGl.Icon, { kind: group.isExpanded ? "tree_folder_open" : "tree_folder_closed", style: { color: group.clientData.color } }), jsxRuntime.jsxs(uilibGl.Description, { children: [jsxRuntime.jsx("div", { style: { wordBreak: "break-word" }, children: group?.alias || group?.name }), jsxRuntime.jsx(uilibGl.IconButton, { kind: group.isExpanded ? "reduce" : "expand", onClick: () => onToggleExpand(group.name, !group.isExpanded) })] }), jsxRuntime.jsx(uilibGl.FlexSpan, { children: jsxRuntime.jsxs(uilibGl.Flex, { flexWrap: "nowrap", p: "0 0.5rem", children: [jsxRuntime.jsx(uilibGl.FlexSpan, { children: jsxRuntime.jsx(uilibGl.IconToggle, { kind: group.isVisible ? "password_show" : "password_hide", className: "feature-visible", isSelected: group.isVisible, onClick: () => onToggleVisibility(group.name, !group.isVisible) }) }), !onlyMainTools && (jsxRuntime.jsx(uilibGl.Popup, { distance: -14, isVisible: isMenuOpen, onRequestClose: toggleMenu, anchor: ref => (jsxRuntime.jsx(uilibGl.FlexSpan, { children: jsxRuntime.jsx(uilibGl.IconButton, { innerRef: ref, kind: "menu_vertical", onClick: toggleMenu }) })), children: jsxRuntime.jsx(uilibGl.Menu, { options: options, selectOption: selectOption }) }))] }) })] }) }));
5072
+ return (jsxRuntime.jsx(LayerGroupContainer, { visible: group.isVisible, children: jsxRuntime.jsxs(LayerGroupMain, { children: [jsxRuntime.jsx(uilibGl.Icon, { kind: group.isExpanded ? "tree_folder_opened" : "tree_folder_closed", style: { color: group.clientData.color } }), jsxRuntime.jsxs(uilibGl.Description, { children: [jsxRuntime.jsx("div", { style: { wordBreak: "break-word" }, children: group?.alias || group?.name }), jsxRuntime.jsx(uilibGl.IconButton, { kind: group.isExpanded ? "reduce" : "expand", onClick: () => onToggleExpand(group.name, !group.isExpanded) })] }), jsxRuntime.jsx(uilibGl.FlexSpan, { children: jsxRuntime.jsxs(uilibGl.Flex, { flexWrap: "nowrap", p: "0 0.5rem", children: [jsxRuntime.jsx(uilibGl.FlexSpan, { children: jsxRuntime.jsx(uilibGl.IconToggle, { kind: group.isVisible ? "password_show" : "password_hide", className: "feature-visible", isSelected: group.isVisible, onClick: () => onToggleVisibility(group.name, !group.isVisible) }) }), !onlyMainTools && (jsxRuntime.jsx(uilibGl.Popup, { distance: -14, isVisible: isMenuOpen, onRequestClose: toggleMenu, anchor: ref => (jsxRuntime.jsx(uilibGl.FlexSpan, { children: jsxRuntime.jsx(uilibGl.IconButton, { innerRef: ref, kind: "menu_vertical", onClick: toggleMenu }) })), children: jsxRuntime.jsx(uilibGl.Menu, { options: options, selectOption: selectOption }) }))] }) })] }) }));
5044
5073
  };
5045
5074
 
5046
5075
  const createTreeNode = (layer, Component, onlyMainTools) => {
@@ -5103,6 +5132,9 @@ const LayerListContainer = styled(uilibGl.Flex) `
5103
5132
  const ElementValueWrapper = styled.div `
5104
5133
  transition: background-color ${uilibGl.transition.toggle};
5105
5134
  `;
5135
+ const InnerContainerWrapper$1 = styled.div `
5136
+ width: 100%;
5137
+ `;
5106
5138
  const ContainerWrapper = styled(uilibGl.Flex) `
5107
5139
  position: relative;
5108
5140
  min-height: 1rem;
@@ -6171,12 +6203,29 @@ const SvgContainer = styled.div `
6171
6203
  const ContainerIconTitle = styled(uilibGl.Flex) `
6172
6204
  align-items: center;
6173
6205
  flex-wrap: nowrap;
6206
+ flex-shrink: 1;
6207
+ flex-grow: 0;
6174
6208
  color: ${({ fontColor, theme: { palette } }) => fontColor || palette.textSecondary};
6175
6209
 
6210
+ > div {
6211
+ flex-shrink: 1;
6212
+ flex-grow: 0;
6213
+ width: auto;
6214
+ }
6215
+
6216
+ ${SvgContainer} {
6217
+ flex-shrink: 0;
6218
+ flex-grow: 0;
6219
+ margin-right: 0.5rem;
6220
+ }
6221
+
6222
+ > * {
6223
+ width: auto;
6224
+ }
6225
+
6176
6226
  svg,
6177
6227
  img,
6178
- span[kind],
6179
- ${SvgContainer} {
6228
+ span[kind] {
6180
6229
  margin-right: 0.5rem;
6181
6230
  }
6182
6231
 
@@ -6197,6 +6246,17 @@ const ContainerIconTitle = styled(uilibGl.Flex) `
6197
6246
  ${uilibGl.LegendToggler} {
6198
6247
  margin-left: 0.25rem;
6199
6248
  }
6249
+
6250
+ span[kind="download"] {
6251
+ opacity: 0;
6252
+ transition: opacity ${uilibGl.transition.hover};
6253
+ }
6254
+
6255
+ :hover {
6256
+ span[kind="download"] {
6257
+ opacity: 1;
6258
+ }
6259
+ }
6200
6260
  `;
6201
6261
  const ContainerTitle = styled(uilibGl.Flex) `
6202
6262
  align-items: center;
@@ -6232,8 +6292,9 @@ const TitleContainer = React.memo(({ containerId, templateName, layerNames, font
6232
6292
  const [layersVisibility, toggleVisibility] = useToggle(true);
6233
6293
  const { palette } = styled.useTheme();
6234
6294
  const { style, options } = elementConfig || {};
6235
- const { simple } = options || {};
6295
+ const { simple, downloadById } = options || {};
6236
6296
  const isLayers = templateName === exports.ContainerTemplate.Layers;
6297
+ const { onExport } = useExportPdf(downloadById);
6237
6298
  const onClick = React.useCallback(() => {
6238
6299
  if (!expandable)
6239
6300
  return;
@@ -6248,7 +6309,7 @@ const TitleContainer = React.memo(({ containerId, templateName, layerNames, font
6248
6309
  const renderVisibility = React.useMemo(() => isLayers && (jsxRuntime.jsx(uilibGl.FlexSpan, { mr: "-1rem", children: jsxRuntime.jsx(uilibGl.IconToggle, { kind: layersVisibility ? "password_show" : "password_hide", className: "feature-visible", isSelected: layersVisibility, onClick: onToggleVisibility }) })), [isLayers, layersVisibility, onToggleVisibility]);
6249
6310
  const renderToggler = React.useMemo(() => !!containerId &&
6250
6311
  expandable && (jsxRuntime.jsx("div", { children: jsxRuntime.jsx(uilibGl.LegendToggler, { color: palette.icon, toggled: expandedContainers?.[containerId] !== undefined ? expandedContainers[containerId] : expanded, onClick: onClick }) })), [containerId, expandable, expanded, expandedContainers, onClick, palette.icon]);
6251
- return (jsxRuntime.jsx(Container, { isTitle: isVisible, style: style, children: jsxRuntime.jsxs(ContainerTitle, { simple: simple, children: [jsxRuntime.jsxs(ContainerIconTitle, { fontColor: fontColor, children: [renderElement({ id: "titleIcon", wrap: false }), renderElement({ id: "title" }), isLayers && renderToggler] }), !isLayers && renderToggler, renderVisibility] }) }));
6312
+ return (jsxRuntime.jsx(Container, { isTitle: isVisible, style: style, children: jsxRuntime.jsxs(ContainerTitle, { simple: simple, children: [jsxRuntime.jsxs(ContainerIconTitle, { fontColor: fontColor, children: [renderElement({ id: "titleIcon", wrap: false }), renderElement({ id: "title" }), !!downloadById && (jsxRuntime.jsx(uilibGl.IconButton, { kind: "download", onClick: onExport })), isLayers && renderToggler] }), !isLayers && renderToggler, renderVisibility] }) }));
6252
6313
  });
6253
6314
 
6254
6315
  const ContainerDivider = styled(uilibGl.Divider) `
@@ -7437,7 +7498,7 @@ const ElementImage = React.memo(({ type, elementConfig }) => {
7437
7498
  const ElementLegend = React.memo(({ type, element, elementConfig, expandedContainers }) => {
7438
7499
  const { attributes, dataSources } = useWidgetContext(type);
7439
7500
  const { options } = elementConfig || {};
7440
- const { twoColumns, chartId, relatedDataSources } = options || {};
7501
+ const { twoColumns, chartId, relatedDataSources, fontSize } = options || {};
7441
7502
  const chartElement = React.useMemo(() => findAnd.returnFound(element?.children, { id: chartId }), [chartId, element?.children]);
7442
7503
  const { data, loading } = useChartData({
7443
7504
  element: chartElement,
@@ -7464,7 +7525,7 @@ const ElementLegend = React.memo(({ type, element, elementConfig, expandedContai
7464
7525
  return { ...item, name: attribute?.alias || item.name };
7465
7526
  });
7466
7527
  }, [attributes, axes, data, options.chartType, relatedDataSources, dataSources]);
7467
- return !chartElement?.options?.expanded || expandedContainers?.[chartElement.id] ? (jsxRuntime.jsx(ChartLegend, { data: legendData, loading: loading, chartElement: chartElement, twoColumns: twoColumns, type: type })) : null;
7528
+ return !chartElement?.options?.expanded || expandedContainers?.[chartElement.id] ? (jsxRuntime.jsx(ChartLegend, { data: legendData, loading: loading, chartElement: chartElement, twoColumns: twoColumns, fontSize: fontSize, type: type })) : null;
7468
7529
  });
7469
7530
 
7470
7531
  const ExternalLink = styled(uilibGl.IconButton).attrs(() => ({
@@ -7535,6 +7596,169 @@ const ElementLink = React.memo(({ type, elementConfig }) => {
7535
7596
  return link.startsWith("http") ? jsxRuntime.jsx(ExternalLink, { onClick: () => window.open(link) }) : jsxRuntime.jsx(LocalLink, { link: link });
7536
7597
  });
7537
7598
 
7599
+ const MarkdownWrapper = styled.div `
7600
+ padding: 0;
7601
+ background: transparent;
7602
+ border-radius: 0.5rem;
7603
+ font-family: 'Nunito Sans', sans-serif;
7604
+ color: ${({ theme: { palette } }) => palette.textPrimary};
7605
+
7606
+ /* Paragraphs */
7607
+ p {
7608
+ font-size: 0.875rem;
7609
+ line-height: 1rem;
7610
+ letter-spacing: 0.0052rem;
7611
+ margin: 0 0 1rem 0;
7612
+ font-weight: 400;
7613
+
7614
+ &:last-child {
7615
+ margin-bottom: 0;
7616
+ }
7617
+ }
7618
+
7619
+ /* Headings */
7620
+ h1, h2, h3, h4, h5, h6 {
7621
+ margin: 0 0 0.75rem 0;
7622
+ font-weight: 300;
7623
+ }
7624
+
7625
+ h1 {
7626
+ font-size: 1.5rem;
7627
+ line-height: 1.75rem;
7628
+ }
7629
+
7630
+ h2 {
7631
+ font-size: 1.25rem;
7632
+ line-height: 1.5rem;
7633
+ }
7634
+
7635
+ h3 {
7636
+ font-size: 1rem;
7637
+ line-height: 1.25rem;
7638
+ }
7639
+
7640
+ /* Images */
7641
+ img {
7642
+ max-width: 100%;
7643
+ height: auto;
7644
+ border-radius: 0.5rem;
7645
+ object-fit: cover;
7646
+ margin: 0.75rem 0;
7647
+ }
7648
+
7649
+ /* Links */
7650
+ a {
7651
+ color: ${({ theme: { palette } }) => palette.primary};
7652
+ text-decoration: none;
7653
+
7654
+ &:hover {
7655
+ text-decoration: underline;
7656
+ }
7657
+ }
7658
+
7659
+ /* Lists */
7660
+ ul, ol {
7661
+ margin: 0 0 1rem 0;
7662
+ padding-left: 1.25rem;
7663
+
7664
+ li {
7665
+ font-size: 0.875rem;
7666
+ line-height: 1rem;
7667
+ margin-bottom: 0.5rem;
7668
+ }
7669
+ }
7670
+
7671
+ /* Code */
7672
+ code {
7673
+ background: ${({ theme: { palette } }) => palette.element};
7674
+ padding: 0.125rem 0.375rem;
7675
+ border-radius: 0.25rem;
7676
+ font-family: monospace;
7677
+ font-size: 0.8125rem;
7678
+ }
7679
+
7680
+ pre {
7681
+ background: ${({ theme: { palette } }) => palette.element};
7682
+ padding: 0.75rem;
7683
+ border-radius: 0.25rem;
7684
+ overflow-x: auto;
7685
+ margin: 0.75rem 0;
7686
+
7687
+ code {
7688
+ background: transparent;
7689
+ padding: 0;
7690
+ }
7691
+ }
7692
+
7693
+ /* Hide horizontal rules */
7694
+ hr {
7695
+ display: none;
7696
+ }
7697
+ `;
7698
+ styled(uilibGl.Flex) `
7699
+ align-items: center;
7700
+ gap: 1rem;
7701
+ margin-top: 1rem;
7702
+ `;
7703
+ styled.span `
7704
+ display: block;
7705
+ font-size: 0.75rem;
7706
+ line-height: 0.875rem;
7707
+ opacity: 0.36;
7708
+ margin: 0 0 0.5rem 0;
7709
+ `;
7710
+ styled.div `
7711
+ width: 1.25rem;
7712
+ height: 1.25rem;
7713
+ cursor: pointer;
7714
+ transition: opacity 0.2s;
7715
+
7716
+ &:hover {
7717
+ opacity: 0.7;
7718
+ }
7719
+
7720
+ img, svg {
7721
+ width: 100%;
7722
+ height: 100%;
7723
+ display: block;
7724
+ }
7725
+ `;
7726
+ const ExpandButton = styled(uilibGl.IconButton) `
7727
+ margin-bottom: 1rem;
7728
+ `;
7729
+
7730
+ const ElementMarkdown = React.memo(({ elementConfig, type }) => {
7731
+ const { attributes } = useWidgetContext(type);
7732
+ const { t } = useGlobalContext();
7733
+ const [expanded, setExpanded] = React.useState(false);
7734
+ const { attributeName, value, options } = elementConfig || {};
7735
+ const expandLength = options?.expandLength || 0;
7736
+ // Get markdown content from:
7737
+ // 1. value (static content)
7738
+ // 2. attribute by attributeName (dynamic content from data)
7739
+ let content = value;
7740
+ if (!content && attributeName && attributes) {
7741
+ const attribute = attributes.find(attr => attr.name === attributeName);
7742
+ content = attribute?.value;
7743
+ }
7744
+ if (!content)
7745
+ return null;
7746
+ const markdownString = String(content);
7747
+ const shouldShowExpand = expandLength > 0 && markdownString.length > expandLength;
7748
+ // If expand is not needed, show full content
7749
+ if (!shouldShowExpand) {
7750
+ return (jsxRuntime.jsx(MarkdownWrapper, { children: jsxRuntime.jsx(ReactMarkdown, { remarkPlugins: [remarkGfm], children: markdownString }) }));
7751
+ }
7752
+ // Truncated content for collapsed state
7753
+ const truncatedContent = markdownString.substring(0, expandLength);
7754
+ // Collapsed state
7755
+ if (!expanded) {
7756
+ return (jsxRuntime.jsxs(MarkdownWrapper, { children: [jsxRuntime.jsx(ExpandButton, { primary: true, icon: jsxRuntime.jsx(uilibGl.Expander, { isSelected: false }), onClick: () => setExpanded(true), children: t("more", { ns: "dashboard", defaultValue: "Подробнее" }) }), jsxRuntime.jsx(ReactMarkdown, { remarkPlugins: [remarkGfm], children: truncatedContent })] }));
7757
+ }
7758
+ // Expanded state
7759
+ return (jsxRuntime.jsxs(MarkdownWrapper, { children: [jsxRuntime.jsx(ExpandButton, { primary: true, icon: jsxRuntime.jsx(uilibGl.Expander, { isSelected: true }), onClick: () => setExpanded(false), children: t("hide", { ns: "dashboard", defaultValue: "Свернуть" }) }), jsxRuntime.jsx(ReactMarkdown, { remarkPlugins: [remarkGfm], children: markdownString })] }));
7760
+ });
7761
+
7538
7762
  const SmallPreviewContainer = styled.div `
7539
7763
  width: 100%;
7540
7764
  height: 100%;
@@ -7814,6 +8038,7 @@ const elementComponents = {
7814
8038
  camera: ElementCamera,
7815
8039
  chart: ElementChart,
7816
8040
  legend: ElementLegend,
8041
+ markdown: ElementMarkdown,
7817
8042
  };
7818
8043
 
7819
8044
  const getElementValue = ({ getDefaultContainer, ...props }) => {
@@ -8405,6 +8630,268 @@ const RangeDateFilter = ({ type, filter }) => {
8405
8630
  return (jsxRuntime.jsx(uilibGl.RangeNumberInput, { label: label || t("interval", { ns: "dashboard", defaultValue: "Интервал" }), selectedOption: { range: true }, minDate: getDate(minDate), maxDate: getDate(maxDate), value: [getDate(value[0]), getDate(value[1])], zIndex: 100, prefix: jsxRuntime.jsx(uilibGl.Icon, { kind: "date", disabled: true }), suffix: !isEmpty && !isDefault && jsxRuntime.jsx(StyledIconButton, { kind: "error", onClick: reset }), withTime: withTime, isDate: true, onChange: onChange }));
8406
8631
  };
8407
8632
 
8633
+ const getJustifyContent = (align) => {
8634
+ switch (align) {
8635
+ case "center":
8636
+ return "center";
8637
+ case "right":
8638
+ return "flex-end";
8639
+ case "left":
8640
+ default:
8641
+ return "flex-start";
8642
+ }
8643
+ };
8644
+ const ChipsContainer = styled(uilibGl.Flex) `
8645
+ flex-wrap: wrap;
8646
+ gap: 0.25rem;
8647
+ background: transparent;
8648
+ justify-content: ${({ $align }) => getJustifyContent($align)};
8649
+ `;
8650
+
8651
+ const FilterChip = styled.div `
8652
+ display: inline-flex;
8653
+ align-items: center;
8654
+ gap: 0.25rem;
8655
+ padding: 0.3125rem 0.5rem;
8656
+ height: 1.5rem;
8657
+ border-radius: 0.25rem;
8658
+ background-color: ${({ $isActive, $bgColor, theme }) => $bgColor
8659
+ ? $bgColor
8660
+ : $isActive
8661
+ ? theme.palette?.primary
8662
+ : theme.palette?.elementLight};
8663
+ color: ${({ $isActive, $textColor, theme }) => $textColor
8664
+ ? $textColor
8665
+ : $isActive
8666
+ ? theme.palette?.textContrast
8667
+ : theme.palette?.textSecondary};
8668
+ cursor: pointer;
8669
+ font-size: 0.75rem;
8670
+ line-height: 0.875rem;
8671
+ white-space: nowrap;
8672
+ flex-shrink: 0;
8673
+ transition: all 0.2s ease-in-out;
8674
+ margin: 0 0.25rem 0 0;
8675
+ box-sizing: border-box;
8676
+
8677
+ &:hover {
8678
+ background-color: ${({ $isActive, $bgColor, theme }) => $isActive
8679
+ ? $bgColor || 'inherit'
8680
+ : $bgColor || theme.palette?.elementDark};
8681
+ }
8682
+ `;
8683
+ const ChipIconWrapper = styled.span `
8684
+ display: inline-flex;
8685
+ align-items: center;
8686
+ justify-content: center;
8687
+ width: 0.875rem;
8688
+ height: 0.875rem;
8689
+ flex-shrink: 0;
8690
+
8691
+ svg, img {
8692
+ width: 100%;
8693
+ height: 100%;
8694
+ display: block;
8695
+ }
8696
+ `;
8697
+ const ChipText = styled.span `
8698
+ overflow: hidden;
8699
+ text-overflow: ellipsis;
8700
+ white-space: nowrap;
8701
+ ${({ $maxTextWidth }) => $maxTextWidth && `max-width: ${$maxTextWidth / 16}rem;`}
8702
+ `;
8703
+
8704
+ const CustomChip = ({ text, icon, color, primary, secondary, error, disabled, isActive, maxTextWidth, fontColor: customFontColor, backgroundColor: customBackgroundColor, ...props }) => {
8705
+ const theme = styled.useTheme();
8706
+ const { palette } = theme;
8707
+ // Helper to add transparency to hex color
8708
+ const addTransparency = (hex, transparency = '1f') => {
8709
+ // Ensure hex starts with #
8710
+ const cleanHex = hex.startsWith('#') ? hex : `#${hex}`;
8711
+ return `${cleanHex}${transparency}`;
8712
+ };
8713
+ // Calculate colors based on priority:
8714
+ // 1. customFontColor / customBackgroundColor (highest, from options)
8715
+ // 2. color (from attribute)
8716
+ // 3. primary/secondary/error
8717
+ // 4. default theme colors
8718
+ let bgColor;
8719
+ let textColor;
8720
+ if (isActive) {
8721
+ // Priority 1: Custom colors from options
8722
+ if (customFontColor) {
8723
+ textColor = customFontColor;
8724
+ bgColor = customBackgroundColor || addTransparency(customFontColor); // 12% opacity
8725
+ }
8726
+ // Priority 2: Color from attribute
8727
+ else if (color) {
8728
+ textColor = palette.textPrimary; // White text for active chip
8729
+ bgColor = color; // Full color without transparency
8730
+ }
8731
+ // Priority 3: Variant colors
8732
+ else if (primary) {
8733
+ bgColor = theme.message.color.success; // Green
8734
+ textColor = palette.textContrast;
8735
+ }
8736
+ else if (secondary) {
8737
+ bgColor = palette.primary;
8738
+ textColor = palette.textContrast;
8739
+ }
8740
+ else if (error) {
8741
+ bgColor = theme.message.color.warning; // Yellow
8742
+ textColor = palette.textPrimary;
8743
+ }
8744
+ // Priority 4: Default - no colors specified
8745
+ else {
8746
+ textColor = palette.primary;
8747
+ bgColor = addTransparency(palette.primary); // palette.primary + 12%
8748
+ }
8749
+ }
8750
+ else {
8751
+ // Inactive state
8752
+ if (color) {
8753
+ textColor = color; // Use color for text
8754
+ bgColor = addTransparency(color); // Uses default 1f (12%) transparency
8755
+ }
8756
+ // else: No color attribute - leave bgColor and textColor undefined
8757
+ // Styled component will use fallback for inactive: bg = rgba(0,0,0,0.06), text = palette.textSecondary
8758
+ }
8759
+ const renderIcon = React.useCallback((iconValue) => {
8760
+ if (!iconValue) {
8761
+ return null;
8762
+ }
8763
+ // If icon doesn't contain a dot and doesn't start with /sp/, it's a built-in icon from uilib-gl
8764
+ if (!iconValue.includes(".") && !iconValue.startsWith("/sp/")) {
8765
+ return jsxRuntime.jsx(uilibGl.Icon, { kind: iconValue });
8766
+ }
8767
+ // If it's an SVG file or resourceId path, use SvgImage component
8768
+ const isSvg = iconValue.endsWith(".svg") || iconValue.startsWith("/sp/resources/file/");
8769
+ if (isSvg) {
8770
+ const iconColor = textColor
8771
+ ? textColor
8772
+ : isActive
8773
+ ? palette.textContrast
8774
+ : palette.textSecondary;
8775
+ return (jsxRuntime.jsx(SvgImage, { url: iconValue, width: 14, height: 14, fontColor: iconColor }));
8776
+ }
8777
+ // Otherwise, it's a regular image
8778
+ return jsxRuntime.jsx("img", { src: iconValue, alt: "" });
8779
+ }, [isActive, textColor, palette.textContrast, palette.textSecondary]);
8780
+ return (jsxRuntime.jsxs(FilterChip, { "$isActive": isActive, "$bgColor": bgColor, "$textColor": textColor, ...props, children: [icon && jsxRuntime.jsx(ChipIconWrapper, { children: renderIcon(icon) }), jsxRuntime.jsx(ChipText, { "$maxTextWidth": maxTextWidth, children: text })] }));
8781
+ };
8782
+
8783
+ const ChipsFilter = ({ type, filter, elementConfig, }) => {
8784
+ const { filters, dataSources, changeFilters } = useWidgetContext(type);
8785
+ const { currentPage } = useWidgetPage(type);
8786
+ const theme = styled.useTheme();
8787
+ const { filters: configFilters } = currentPage;
8788
+ const { options } = elementConfig || {};
8789
+ const { align } = options || {};
8790
+ const { filterName, colorAttribute, iconAttribute, maxTextWidth, icon, fontColor, backgroundColor, } = filter.options;
8791
+ const configFilter = getConfigFilter(filterName, configFilters);
8792
+ const multiSelect = configFilter?.valueType === "array";
8793
+ // Process icon URL (resourceId or direct URL)
8794
+ const processedIcon = icon ? getResourceUrl(icon) : undefined;
8795
+ const chipOptions = React.useMemo(() => {
8796
+ if (!configFilter)
8797
+ return [];
8798
+ const dataSource = getDataSource(configFilter.relatedDataSource, dataSources);
8799
+ if (!dataSource?.features)
8800
+ return [];
8801
+ const features = dataSource.features;
8802
+ return features.map(feature => {
8803
+ const attrs = feature.attributes;
8804
+ const text = attrs[configFilter.attributeAlias || DEFAULT_ATTRIBUTE_NAME];
8805
+ const value = attrs[configFilter.attributeValue || DEFAULT_ATTRIBUTE_NAME];
8806
+ const chipIcon = iconAttribute
8807
+ ? getIconFromAttribute(attrs, iconAttribute)
8808
+ : undefined;
8809
+ const chipColor = colorAttribute
8810
+ ? getColorFromAttribute(attrs, colorAttribute, theme)
8811
+ : undefined;
8812
+ return {
8813
+ text,
8814
+ value,
8815
+ color: chipColor,
8816
+ icon: chipIcon,
8817
+ };
8818
+ });
8819
+ }, [configFilter, dataSources, colorAttribute, iconAttribute, theme]);
8820
+ const isChipActive = React.useCallback((chipValue) => {
8821
+ const currentValue = filters?.[filterName]?.value;
8822
+ if (currentValue === undefined) {
8823
+ return checkEqualOrIncludes(configFilter?.defaultValue, chipValue);
8824
+ }
8825
+ return checkEqualOrIncludes(currentValue, chipValue);
8826
+ }, [filters, filterName, configFilter]);
8827
+ const handleChipClick = React.useCallback((chipValue) => {
8828
+ const currentValue = filters?.[filterName]?.value;
8829
+ let newValue;
8830
+ if (multiSelect) {
8831
+ const currentArray = Array.isArray(currentValue)
8832
+ ? currentValue
8833
+ : currentValue
8834
+ ? [currentValue]
8835
+ : [];
8836
+ const valueIndex = currentArray.indexOf(chipValue);
8837
+ if (valueIndex >= 0) {
8838
+ const filtered = currentArray.filter(v => v !== chipValue);
8839
+ if (filtered.length === 0) {
8840
+ newValue = configFilter?.defaultValue || null;
8841
+ }
8842
+ else {
8843
+ newValue = filtered;
8844
+ }
8845
+ }
8846
+ else {
8847
+ newValue = [...currentArray, chipValue];
8848
+ }
8849
+ }
8850
+ else {
8851
+ if (currentValue === chipValue) {
8852
+ newValue = configFilter?.defaultValue || null;
8853
+ }
8854
+ else {
8855
+ newValue = chipValue;
8856
+ }
8857
+ }
8858
+ changeFilters({
8859
+ [filterName]: { value: newValue },
8860
+ });
8861
+ }, [filters, filterName, multiSelect, changeFilters, configFilter]);
8862
+ if (!configFilter)
8863
+ return null;
8864
+ return (jsxRuntime.jsx(ChipsContainer, { "$align": align, children: chipOptions.map((chip, index) => {
8865
+ const isActive = isChipActive(chip.value);
8866
+ // Use chip.icon from attribute or fallback to static icon
8867
+ const chipIcon = chip.icon || processedIcon;
8868
+ return (jsxRuntime.jsx(CustomChip, { text: chip.text, icon: chipIcon, color: chip.color, isActive: isActive, maxTextWidth: maxTextWidth, fontColor: fontColor, backgroundColor: backgroundColor, onClick: () => handleChipClick(chip.value), title: chip.text }, index));
8869
+ }) }));
8870
+ };
8871
+ function getColorFromAttribute(option, colorAttribute, theme) {
8872
+ const value = option[colorAttribute];
8873
+ // If value is already a hex color (starts with #), return it directly
8874
+ if (value && typeof value === 'string' && value.startsWith('#')) {
8875
+ return value;
8876
+ }
8877
+ // Otherwise, map string values to theme colors
8878
+ const colorMap = {
8879
+ active: theme?.message?.color?.success,
8880
+ warning: theme?.message?.color?.warning,
8881
+ info: theme?.message?.color?.info,
8882
+ inactive: theme?.palette?.textDisabled,
8883
+ };
8884
+ return value && typeof value === 'string' ? colorMap[value.toLowerCase()] : undefined;
8885
+ }
8886
+ function getIconFromAttribute(option, iconAttribute) {
8887
+ const iconValue = option[iconAttribute];
8888
+ if (!iconValue || typeof iconValue !== 'string') {
8889
+ return undefined;
8890
+ }
8891
+ // Process through getResourceUrl to handle both URLs and resourceIds
8892
+ return getResourceUrl(iconValue);
8893
+ }
8894
+
8408
8895
  const getFilterComponent = (filterType) => {
8409
8896
  switch (filterType) {
8410
8897
  case "checkbox":
@@ -8417,6 +8904,8 @@ const getFilterComponent = (filterType) => {
8417
8904
  return RangeDateFilter;
8418
8905
  case "text":
8419
8906
  return TextFilter;
8907
+ case "chips":
8908
+ return ChipsFilter;
8420
8909
  case "dropdown":
8421
8910
  default:
8422
8911
  return DropdownFilter;
@@ -8602,7 +9091,9 @@ const getRenderElement = ({ t, config, elementConfig, attributes = [], layerInfo
8602
9091
  return formatElementValue({ t, value, elementConfig: element, attributes, wrap });
8603
9092
  };
8604
9093
 
8605
- const getResourceUrl = (url) => url ? (url.startsWith("http") ? url : `/sp/resources/file/${url}`) : "";
9094
+ const getResourceUrl = (url) => {
9095
+ return url ? (url.startsWith("http") ? url : `/sp/resources/file/${url}`) : "";
9096
+ };
8606
9097
 
8607
9098
  const getSlideshowImages = ({ element, attribute, }) => {
8608
9099
  const { defaultValue, options } = element;
@@ -9582,7 +10073,7 @@ const Chart = React.memo(({ config, element, elementConfig, type, renderElement
9582
10073
  return (jsxRuntime.jsx(ChartWrapper, { width: width, height: isStackBar ? "auto" : isPieChart ? width : height, column: column, loading: loading, children: renderChart }));
9583
10074
  });
9584
10075
 
9585
- const ChartLegend = ({ data, chartElement, type, twoColumns, loading }) => {
10076
+ const ChartLegend = ({ data, chartElement, fontSize, type, twoColumns, loading }) => {
9586
10077
  const { t } = useGlobalContext();
9587
10078
  const { sliceItems, showMore, onShowMore } = useShownOtherItems(chartElement?.options);
9588
10079
  const axes = React.useMemo(() => getChartAxes(chartElement), [chartElement]);
@@ -9591,7 +10082,7 @@ const ChartLegend = ({ data, chartElement, type, twoColumns, loading }) => {
9591
10082
  const showMoreBtn = !!shownItems && data.length > shownItems;
9592
10083
  if (!loading && !data?.length && !!hideEmpty)
9593
10084
  return null;
9594
- return (jsxRuntime.jsxs(uilibGl.Flex, { flexDirection: "column", opacity: loading ? FILTERED_VALUE_OPACITY / 100 : 1, children: [jsxRuntime.jsx(ChartLegendContainer, { twoColumns: twoColumns, children: sliceItems(data)?.map(({ name, color }, index) => (jsxRuntime.jsxs(ChartLegendItem, { hasAnyFilter: hasAnyFilter, isFiltered: isFiltered(name), onClick: axes?.[0]?.filterName ? () => onFilter(name) : undefined, children: [jsxRuntime.jsx(ChartLegendColor, { color: color }), jsxRuntime.jsx(ChartLegendName, { "$fontColor": fontColor, children: name })] }, index))) }), showMoreBtn && (jsxRuntime.jsx(uilibGl.LegendToggler, { onClick: onShowMore, toggled: showMore, children: t("other", { ns: "dashboard", defaultValue: "Другое" }) }))] }));
10085
+ return (jsxRuntime.jsxs(uilibGl.Flex, { flexDirection: "column", opacity: loading ? FILTERED_VALUE_OPACITY / 100 : 1, children: [jsxRuntime.jsx(ChartLegendContainer, { twoColumns: twoColumns, children: sliceItems(data)?.map(({ name, color }, index) => (jsxRuntime.jsxs(ChartLegendItem, { hasAnyFilter: hasAnyFilter, isFiltered: isFiltered(name), onClick: axes?.[0]?.filterName ? () => onFilter(name) : undefined, children: [jsxRuntime.jsx(ChartLegendColor, { color: color }), jsxRuntime.jsx(ChartLegendName, { "$fontSize": fontSize, "$fontColor": fontColor, children: name })] }, index))) }), showMoreBtn && (jsxRuntime.jsx(uilibGl.LegendToggler, { onClick: onShowMore, toggled: showMore, children: t("other", { ns: "dashboard", defaultValue: "Другое" }) }))] }));
9595
10086
  };
9596
10087
 
9597
10088
  const ContainerChildren = React.memo(({ items, isColumn, isMain, renderElement }) => {
@@ -9603,7 +10094,7 @@ const ContainerChildren = React.memo(({ items, isColumn, isMain, renderElement }
9603
10094
  index,
9604
10095
  wrap: isColumn || isMain,
9605
10096
  });
9606
- return isMain ? (jsxRuntime.jsx(ContainerWrapper, { "data-id": item.id, "data-templatename": item.templateName, children: jsxRuntime.jsx(DashboardWrapper, { children: render }) }, index)) : (jsxRuntime.jsx(React.Fragment, { children: render }, index));
10097
+ return isMain ? (jsxRuntime.jsx(ContainerWrapper, { id: item.id, "data-templatename": item.templateName, children: jsxRuntime.jsx(DashboardWrapper, { children: render }) }, index)) : (jsxRuntime.jsx(InnerContainerWrapper$1, { id: item.id, children: render }, index));
9607
10098
  }) }));
9608
10099
  });
9609
10100
 
@@ -10154,6 +10645,7 @@ exports.ElementIcon = ElementIcon;
10154
10645
  exports.ElementImage = ElementImage;
10155
10646
  exports.ElementLegend = ElementLegend;
10156
10647
  exports.ElementLink = ElementLink;
10648
+ exports.ElementMarkdown = ElementMarkdown;
10157
10649
  exports.ElementSlideshow = ElementSlideshow;
10158
10650
  exports.ElementSvg = ElementSvg;
10159
10651
  exports.ElementTooltip = ElementTooltip;
@@ -10185,6 +10677,7 @@ exports.HeaderTitleContainer = HeaderTitleContainer;
10185
10677
  exports.HiddenTitleItems = HiddenTitleItems;
10186
10678
  exports.IconContainer = IconContainer;
10187
10679
  exports.ImageContainer = ImageContainer;
10680
+ exports.InnerContainerWrapper = InnerContainerWrapper$1;
10188
10681
  exports.LEFT_PANEL_HEADER_HEIGHT = LEFT_PANEL_HEADER_HEIGHT;
10189
10682
  exports.Layer = Layer;
10190
10683
  exports.LayerDescription = LayerDescription;