@evergis/react 4.0.101 → 4.0.103

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
@@ -102,7 +102,30 @@ const ChartWrapperContainer = styled.div.withConfig({ displayName: "ChartWrapper
102
102
  position: relative;
103
103
  width: 100%;
104
104
  `;
105
- const Tooltip = styled.div.withConfig({ displayName: "Tooltip", componentId: "sc-2prpr" }) `
105
+ /*
106
+ * fill-режим: обёртка забирает всю доступную ячейку (её высоту задаёт флекс-цепочка, а не контент графика),
107
+ * на неё вешается ref для ResizeObserver — меряем обе оси без цикла. Плоский div (не Flex uilib), как соседний
108
+ * ChartWrapperContainer, чтобы ref гарантированно дошёл до DOM-узла. Тело графика центрируется внутри.
109
+ */
110
+ const ChartFillMeasure = styled.div.withConfig({ displayName: "ChartFillMeasure", componentId: "sc-1r4oerb" }) `
111
+ position: relative;
112
+ display: flex;
113
+ align-items: center;
114
+ justify-content: center;
115
+ width: 100%;
116
+ height: 100%;
117
+ min-width: 0;
118
+ min-height: 0;
119
+ overflow: hidden;
120
+
121
+ /* SVG по умолчанию inline, поэтому под ним остаётся зазор базовой линии (~4px при line-height
122
+ 18.4px): вне fill его скрывал запас высоты, а тело, точно заполнившее ячейку, из-за него
123
+ вылезает за нижнюю границу. Блочный SVG зазора не даёт. */
124
+ svg {
125
+ display: block;
126
+ }
127
+ `;
128
+ const Tooltip = styled.div.withConfig({ displayName: "Tooltip", componentId: "sc-1va8cy3" }) `
106
129
  position: relative;
107
130
  border-radius: 0.25rem;
108
131
  background-color: rgba(28, 33, 48);
@@ -195,7 +218,7 @@ const LineChartStyles = styled.createGlobalStyle `
195
218
  fill: ${({ theme: { palette } }) => palette.textDisabled};
196
219
  }
197
220
  `;
198
- const StyledBarChart = styled(charts.BarChart).withConfig({ displayName: "StyledBarChart", componentId: "sc-1i0hrvl" }) `
221
+ const StyledBarChart = styled(charts.BarChart).withConfig({ displayName: "StyledBarChart", componentId: "sc-1l1kx80" }) `
199
222
  .domain {
200
223
  display: none;
201
224
  }
@@ -3383,6 +3406,8 @@ const ALIGNMENTS = ["left", "center", "right"];
3383
3406
  const ALIGN_ITEMS = ["flex-start", "center", "flex-end", "stretch", "baseline"];
3384
3407
  /** Масштабирование изображения внутри своего бокса (CSS `object-fit`). */
3385
3408
  const OBJECT_FITS = ["cover", "contain", "fill", "none", "scale-down"];
3409
+ /** Поведение контента, выходящего за бокс контейнера (CSS `overflow`). */
3410
+ const OVERFLOWS = ["visible", "hidden", "scroll", "auto"];
3386
3411
  /** Режим отображения коллекций. */
3387
3412
  const VIEW_MODES = ["grid", "list"];
3388
3413
  exports.ContainerTemplate = void 0;
@@ -3497,6 +3522,13 @@ const BASE_CONTAINER_STYLE = {
3497
3522
  const StackBarContainer = styled(uilibGl.Flex).withConfig({ displayName: "StackBarContainer", componentId: "sc-stc97k" }) `
3498
3523
  flex-wrap: nowrap;
3499
3524
  width: 100%;
3525
+
3526
+ ${({ $fill }) => $fill &&
3527
+ styled.css `
3528
+ /* fill: полоса забирает остаток высоты обёртки (вся ячейка минус шапка с итогом). */
3529
+ flex: 1 1 auto;
3530
+ min-height: 0;
3531
+ `}
3500
3532
  `;
3501
3533
  const StackBarHeader = styled(uilibGl.Flex).withConfig({ displayName: "StackBarHeader", componentId: "sc-8mc354" }) `
3502
3534
  justify-content: space-between;
@@ -3506,7 +3538,8 @@ const StackBarHeader = styled(uilibGl.Flex).withConfig({ displayName: "StackBarH
3506
3538
  const StackBarSection = styled.div.withConfig({ displayName: "StackBarSection", componentId: "sc-i3gdu" }) `
3507
3539
  cursor: ${({ onClick }) => (onClick ? "pointer" : "default")};
3508
3540
  width: ${({ $width }) => $width}%;
3509
- height: ${({ $height }) => ($height ? `${$height}px` : "0.5rem")};
3541
+ /* В fill толщину полосы задаёт растянутый контейнер, а не options.height элемента chart. */
3542
+ height: ${({ $fill, $height }) => ($fill ? "100%" : $height ? `${$height}px` : "0.5rem")};
3510
3543
  margin: 0 0.5px;
3511
3544
  background-color: ${({ $color }) => $color};
3512
3545
  opacity: ${({ hasAnyFilter, isFiltered }) => (isFiltered ? 1 : hasAnyFilter ? FILTERED_VALUE_OPACITY / 100 : 1)};
@@ -7632,30 +7665,33 @@ const useRenderElement = (type = exports.WidgetType.Dashboard, elementConfig) =>
7632
7665
  ]);
7633
7666
  };
7634
7667
 
7668
+ /** Пустой бокс на отключённом пути — стабильная ссылка, чтобы не плодить ре-рендеры. */
7669
+ const EMPTY_BOX = {};
7635
7670
  /**
7636
- * Измеряет фактическую ширину DOM-элемента и обновляет её на любой ресайз (ResizeObserver).
7671
+ * Измеряет фактические ширину и высоту DOM-элемента и обновляет их на любой ресайз (ResizeObserver).
7637
7672
  *
7638
- * Возвращает `[ref, width]`, где `width` — число пикселей либо `undefined`, пока элемент ещё
7639
- * не измерен. Используется для «резинового» графика: d3-графикам нужна конкретная пиксельная
7640
- * ширина, а не CSS `100%`.
7673
+ * Возвращает `[ref, box]`, где `box` — `{ width, height }` в пикселях (content-box) либо пустой объект,
7674
+ * пока элемент ещё не измерен. Используется для «резинового» графика: d3-графикам нужны конкретные
7675
+ * пиксельные размеры, а не CSS `100%`, а для вписывания (fit) нужны обе оси.
7641
7676
  *
7642
7677
  * `enabled: false` полностью отключает наблюдение — обычные (не fill) графики не измеряются
7643
7678
  * и не вызывают лишних ре-рендеров.
7644
7679
  */
7645
- const useResizeWidth = (enabled) => {
7680
+ const useResizeBox = (enabled) => {
7646
7681
  const ref = React.useRef(null);
7647
- const [width, setWidth] = React.useState();
7682
+ const [box, setBox] = React.useState(EMPTY_BOX);
7648
7683
  React.useEffect(() => {
7649
7684
  const node = ref.current;
7650
7685
  if (!enabled || !node)
7651
7686
  return;
7652
7687
  const observer = new ResizeObserver(([entry]) => {
7653
- setWidth(entry.contentRect.width);
7688
+ const { width, height } = entry.contentRect;
7689
+ setBox({ width, height });
7654
7690
  });
7655
7691
  observer.observe(node);
7656
7692
  return () => observer.disconnect();
7657
7693
  }, [enabled]);
7658
- return [ref, enabled ? width : undefined];
7694
+ return [ref, enabled ? box : EMPTY_BOX];
7659
7695
  };
7660
7696
 
7661
7697
  const useShownOtherItems = (options) => {
@@ -7701,13 +7737,13 @@ const useUpdateDataSource = ({ dataSource, config, filters, attributes, layerPar
7701
7737
  */
7702
7738
  const useWrapperSize = ({ elementConfig, defaults }) => {
7703
7739
  const { id, style, templateName, options } = elementConfig || {};
7704
- const { width, height } = options || {};
7740
+ const { width, height, overflow } = options || {};
7705
7741
  return React.useMemo(() => ({
7706
7742
  id,
7707
7743
  "data-templatename": templateName,
7708
7744
  style,
7709
- $sizeCss: getWrapperSizeStyle({ style, width, height, defaults, defaultWidth: FILL_SIZE }),
7710
- }), [id, templateName, style, width, height, defaults]);
7745
+ $sizeCss: getWrapperSizeStyle({ style, width, height, overflow, defaults, defaultWidth: FILL_SIZE }),
7746
+ }), [id, templateName, style, width, height, overflow, defaults]);
7711
7747
  };
7712
7748
 
7713
7749
  const ContainersGroupContainer = React.memo(({ elementConfig, type, renderElement }) => {
@@ -7777,6 +7813,19 @@ const ContainerChart = styled(uilibGl.Flex).withConfig({ displayName: "Container
7777
7813
  justify-content: center;
7778
7814
  width: 100%;
7779
7815
  }
7816
+
7817
+ /* fill: слот забирает остаток высоты ячейки (под слотами title/alias/legend) и центрирует тело графика. */
7818
+ ${({ $fill }) => $fill &&
7819
+ styled.css `
7820
+ flex: 1 1 auto;
7821
+ min-height: 0;
7822
+ align-items: center;
7823
+ justify-content: center;
7824
+
7825
+ > * {
7826
+ height: 100%;
7827
+ }
7828
+ `}
7780
7829
  `;
7781
7830
  const ContainerLegend = styled(uilibGl.Flex).withConfig({ displayName: "ContainerLegend", componentId: "sc-z1n1s8" }) ``;
7782
7831
  const ContainerUnits = styled.div.withConfig({ displayName: "ContainerUnits", componentId: "sc-1vurgy9" }) `
@@ -7792,6 +7841,13 @@ const ContainerValue = styled(uilibGl.Flex).withConfig({ displayName: "Container
7792
7841
  font-size: ${({ big }) => (big ? 1.5 : 1)}rem;
7793
7842
  color: ${({ fontColor, theme: { palette } }) => fontColor || palette.textPrimary};
7794
7843
 
7844
+ /* fill: строка со слотом chart+legend забирает остаток высоты Container'а (гейт — только у Chart-контейнера). */
7845
+ ${({ $fill }) => $fill &&
7846
+ styled.css `
7847
+ flex: 1 1 auto;
7848
+ min-height: 0;
7849
+ `}
7850
+
7795
7851
  > * {
7796
7852
  width: ${({ column }) => (column ? "100%" : "auto")};
7797
7853
  }
@@ -7898,15 +7954,16 @@ const useRenderContainer = ({ elementConfig, type, renderElement, renderBody, })
7898
7954
  };
7899
7955
 
7900
7956
  const OneColumnContainer = React.memo(({ type, elementConfig, renderElement }) => {
7901
- const { width, height } = elementConfig?.options || {};
7957
+ const { width, height, overflow } = elementConfig?.options || {};
7902
7958
  const templateName = elementConfig?.templateName;
7903
7959
  const renderBody = React.useCallback(({ id, value, style, hasUnits, render }) => (jsxRuntime.jsxs(Container, { id: id, isColumn: true, "data-templatename": templateName, style: style, "$sizeCss": getWrapperSizeStyle({
7904
7960
  style,
7905
7961
  width,
7906
7962
  height,
7963
+ overflow,
7907
7964
  defaults: BASE_CONTAINER_STYLE,
7908
7965
  defaultWidth: FILL_SIZE,
7909
- }), children: [jsxRuntime.jsxs(ContainerAlias, { hasBottomMargin: true, children: [render({ id: "alias" }), render({ id: "tooltip" }), render({ id: "modal" })] }), jsxRuntime.jsxs(ContainerValue, { children: [value, hasUnits && (jsxRuntime.jsx(ContainerUnits, { children: render({ id: "units" }) }))] })] })), [width, height, templateName]);
7966
+ }), children: [jsxRuntime.jsxs(ContainerAlias, { hasBottomMargin: true, children: [render({ id: "alias" }), render({ id: "tooltip" }), render({ id: "modal" })] }), jsxRuntime.jsxs(ContainerValue, { children: [value, hasUnits && (jsxRuntime.jsx(ContainerUnits, { children: render({ id: "units" }) }))] })] })), [width, height, overflow, templateName]);
7910
7967
  const { renderContainer, attributesToRender } = useRenderContainer({
7911
7968
  type,
7912
7969
  elementConfig,
@@ -7917,9 +7974,9 @@ const OneColumnContainer = React.memo(({ type, elementConfig, renderElement }) =
7917
7974
  });
7918
7975
 
7919
7976
  const TwoColumnContainer = React.memo(({ elementConfig, type, renderElement }) => {
7920
- const { width, height } = elementConfig?.options || {};
7977
+ const { width, height, overflow } = elementConfig?.options || {};
7921
7978
  const templateName = elementConfig?.templateName;
7922
- const renderBody = React.useCallback(({ id, value, style, hasIcon, hasUnits, render }) => (jsxRuntime.jsxs(TwoColumnContainerWrapper, { id: id, "data-templatename": templateName, style: style, "$sizeCss": getWrapperSizeStyle({ style, width, height, defaultWidth: FILL_SIZE }), children: [jsxRuntime.jsxs(ContainerAlias, { children: [hasIcon && (jsxRuntime.jsx(ContainerAliasIcon, { children: render({ id: "icon" }) })), render({ id: "alias" }), render({ id: "tooltip" }), render({ id: "modal" })] }), jsxRuntime.jsxs(ContainerValue, { big: true, children: [value, hasUnits && (jsxRuntime.jsx(ContainerUnits, { children: render({ id: "units" }) }))] })] })), [width, height, templateName]);
7979
+ const renderBody = React.useCallback(({ id, value, style, hasIcon, hasUnits, render }) => (jsxRuntime.jsxs(TwoColumnContainerWrapper, { id: id, "data-templatename": templateName, style: style, "$sizeCss": getWrapperSizeStyle({ style, width, height, overflow, defaultWidth: FILL_SIZE }), children: [jsxRuntime.jsxs(ContainerAlias, { children: [hasIcon && (jsxRuntime.jsx(ContainerAliasIcon, { children: render({ id: "icon" }) })), render({ id: "alias" }), render({ id: "tooltip" }), render({ id: "modal" })] }), jsxRuntime.jsxs(ContainerValue, { big: true, children: [value, hasUnits && (jsxRuntime.jsx(ContainerUnits, { children: render({ id: "units" }) }))] })] })), [width, height, overflow, templateName]);
7923
7980
  const { renderContainer, attributesToRender } = useRenderContainer({
7924
7981
  type,
7925
7982
  elementConfig,
@@ -8301,6 +8358,15 @@ const BarChartContainer = styled.div.withConfig({ displayName: "BarChartContaine
8301
8358
  const AnyChartWrapper = styled.div.withConfig({ displayName: "AnyChartWrapper", componentId: "sc-1txgly0" }) `
8302
8359
  width: 100%;
8303
8360
  height: ${({ height }) => height}px;
8361
+
8362
+ ${({ $fill }) => $fill &&
8363
+ styled.css `
8364
+ /* fill: обёртке задана ВСЯ доступная высота ячейки, поэтому тело внутри забирает её остаток
8365
+ флексом (полоса stack тянется под строкой итога), а не вычисляется арифметикой. */
8366
+ display: flex;
8367
+ flex-direction: column;
8368
+ min-height: 0;
8369
+ `}
8304
8370
  `;
8305
8371
  const BarChartWrapper = styled(AnyChartWrapper).withConfig({ displayName: "BarChartWrapper", componentId: "sc-98mm1q" }) `
8306
8372
  width: 100%;
@@ -8423,6 +8489,10 @@ const ChartContainerWrapper = styled(uilibGl.FlexSpan).withConfig({ displayName:
8423
8489
  /* Заданная высота контейнера достаётся телу графика — за вычетом заголовка. */
8424
8490
  ${({ $sizeCss }) => !!$sizeCss?.height &&
8425
8491
  styled.css `
8492
+ /* Раздача высоты требует, чтобы обёртка была flex-колонкой (FlexSpan сам по себе не flex),
8493
+ иначе Container с flex:1 1 auto не растянется на заданную высоту, а fill-график не впишется по высоте. */
8494
+ display: flex;
8495
+
8426
8496
  > ${Container} {
8427
8497
  flex: 1 1 auto;
8428
8498
  min-height: 0;
@@ -8433,17 +8503,19 @@ const ChartContainerWrapper = styled(uilibGl.FlexSpan).withConfig({ displayName:
8433
8503
  `;
8434
8504
 
8435
8505
  /**
8436
- * Флаг «растянуть график на всю ширину контейнера» (`options.chartFill` контейнера Chart).
8506
+ * Контекст вписывания графика (`options.fill` контейнера Chart).
8437
8507
  *
8438
8508
  * Компонент `Chart` рендерится через `renderElement({ id: "chart" })` и получает только дочерний
8439
8509
  * узел `{ id: "chart" }` — опции контейнера до него не доходят. `ChartContainer` оборачивает
8440
- * график в провайдер этого контекста, а `Chart` читает флаг через `useContext`.
8510
+ * график в провайдер этого контекста, а `Chart` читает значение через `useContext`.
8441
8511
  */
8442
- const ChartFillContext = React.createContext(false);
8512
+ const FillContext = React.createContext({ fill: false, fitHeight: false });
8443
8513
 
8444
8514
  const ChartContainer = React.memo(({ elementConfig, isVisible, type, renderElement }) => {
8445
8515
  const { options, children } = elementConfig || {};
8446
- const { twoColumns, hideEmpty, chartFill } = options || {};
8516
+ const { twoColumns, hideEmpty, height } = options || {};
8517
+ const fill = options?.fill;
8518
+ const fillContextValue = React.useMemo(() => ({ fill: !!fill, fitHeight: !!fill && height != null }), [fill, height]);
8447
8519
  const aliasElement = children.find(child => child.id === "alias");
8448
8520
  const chartElement = children.find(child => child.id === "chart");
8449
8521
  const legendElement = children.find(child => child.id === "legend");
@@ -8458,7 +8530,7 @@ const ChartContainer = React.memo(({ elementConfig, isVisible, type, renderEleme
8458
8530
  const hasItems = !!data[0]?.items?.length;
8459
8531
  if (!loading && !hasItems && hideEmpty)
8460
8532
  return null;
8461
- return (jsxRuntime.jsxs(ChartContainerWrapper, { ...root, children: [jsxRuntime.jsx(ExpandableTitle, { elementConfig: elementConfig, type: type, renderElement: renderElement }), isVisible && (jsxRuntime.jsxs(Container, { isColumn: true, children: [aliasElement && jsxRuntime.jsx(ContainerAlias, { hasBottomMargin: true, children: renderElement({ id: "alias" }) }), jsxRuntime.jsx(ContainerValue, { column: !twoColumns, alignItems: "center", children: hasItems ? (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsx(ContainerChart, { children: jsxRuntime.jsx(ChartFillContext.Provider, { value: !!chartFill, children: renderElement({ id: "chart" }) }) }), jsxRuntime.jsx(ContainerLegend, { justifyContent: legendElement?.options?.center ? "center" : "flex-start", children: renderElement({ id: "legend" }) })] })) : (jsxRuntime.jsx(jsxRuntime.Fragment, { children: "\u2014" })) })] }))] }));
8533
+ return (jsxRuntime.jsxs(ChartContainerWrapper, { ...root, children: [jsxRuntime.jsx(ExpandableTitle, { elementConfig: elementConfig, type: type, renderElement: renderElement }), isVisible && (jsxRuntime.jsxs(Container, { isColumn: true, children: [aliasElement && jsxRuntime.jsx(ContainerAlias, { hasBottomMargin: true, children: renderElement({ id: "alias" }) }), jsxRuntime.jsx(ContainerValue, { column: !twoColumns, alignItems: twoColumns && fill ? "stretch" : "center", "$fill": !!fill, children: hasItems ? (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsx(ContainerChart, { "$fill": !!fill, children: jsxRuntime.jsx(FillContext.Provider, { value: fillContextValue, children: renderElement({ id: "chart" }) }) }), jsxRuntime.jsx(ContainerLegend, { justifyContent: legendElement?.options?.center ? "center" : "flex-start", children: renderElement({ id: "legend" }) })] })) : (jsxRuntime.jsx(jsxRuntime.Fragment, { children: "\u2014" })) })] }))] }));
8462
8534
  });
8463
8535
 
8464
8536
  const PagesContainer = React.memo(({ type = exports.WidgetType.Dashboard, noBorders }) => {
@@ -11465,6 +11537,8 @@ const tagTypography = (tag) => ({ $typography }) => {
11465
11537
  ${style.fontSize && `font-size: ${style.fontSize};`}
11466
11538
  ${style.lineHeight && `line-height: ${style.lineHeight};`}
11467
11539
  ${style.fontWeight != null && `font-weight: ${style.fontWeight};`}
11540
+ ${style.marginTop && `margin-top: ${style.marginTop};`}
11541
+ ${style.marginBottom && `margin-bottom: ${style.marginBottom};`}
11468
11542
  `;
11469
11543
  };
11470
11544
  const MarkdownWrapper = styled.div.withConfig({ displayName: "MarkdownWrapper", componentId: "sc-1iv8z8a" }) `
@@ -12697,7 +12771,8 @@ const ChartLoading = ({ column }) => (jsxRuntime.jsx(uilibGl.Flex, { position: "
12697
12771
 
12698
12772
  const ContainerLoading = () => (jsxRuntime.jsx(uilibGl.Flex, { alignContent: "center", justifyContent: "center", width: "100%", children: jsxRuntime.jsx(uilibGl.CircularProgress, { diameter: 1.5, mono: true }) }));
12699
12773
 
12700
- // forwardRef чтобы Chart мог измерить фактическую ширину обёртки (fill-режим, useResizeWidth).
12774
+ // forwardRef сохранён для совместимости; в fill-режиме ResizeObserver меряет внешнюю обёртку
12775
+ // ChartFillMeasure (см. Chart/index.tsx), а не сам ChartWrapper.
12701
12776
  const ChartWrapper = React.memo(React.forwardRef(({ width, height, column, loading, children }, ref) => {
12702
12777
  return (jsxRuntime.jsxs(ChartWrapperContainer, { ref: ref, column: column, style: { width, height }, children: [loading && jsxRuntime.jsx(ChartLoading, { column: column }), jsxRuntime.jsx(uilibGl.Flex, { opacity: loading ? FILTERED_VALUE_OPACITY / 100 : 1, children: children })] }));
12703
12778
  }));
@@ -13853,13 +13928,17 @@ const omitKeys = (source, keys = []) => {
13853
13928
  * конфликтующие внутренние дефолты обёртки, а контент лишается возможности её распирать
13854
13929
  * (`min-width`/`min-height: 0`). Для fill-высоты добавляется `flex: 1 1 auto` — в колонке
13855
13930
  * контейнер забирает остаток ячейки под заголовком, а не переполняет её на его высоту.
13931
+ *
13932
+ * `overflow` уходит в CSS как есть и ничем не подменяется: не задан — работает браузерный
13933
+ * `visible`, то есть контент крупнее бокса вытекает на соседние слоты.
13856
13934
  */
13857
- const getWrapperSizeStyle = ({ style, width: widthOption, height, defaults, defaultWidth, }) => {
13935
+ const getWrapperSizeStyle = ({ style, width: widthOption, height, overflow, defaults, defaultWidth, }) => {
13858
13936
  // Ширина по умолчанию (контейнеры передают FILL_SIZE): явный `options.width` её перекрывает.
13859
13937
  const width = widthOption ?? defaultWidth;
13860
13938
  const hasWidth = width != null;
13861
13939
  const hasHeight = height != null;
13862
- if (!hasWidth && !hasHeight) {
13940
+ const hasOverflow = overflow != null;
13941
+ if (!hasWidth && !hasHeight && !hasOverflow) {
13863
13942
  return defaults;
13864
13943
  }
13865
13944
  const fillWidth = isFillSize(width);
@@ -13868,13 +13947,18 @@ const getWrapperSizeStyle = ({ style, width: widthOption, height, defaults, defa
13868
13947
  ...(fillWidth ? FILL_WIDTH_CONFLICTS : []),
13869
13948
  ...(fillHeight ? FILL_HEIGHT_CONFLICTS : []),
13870
13949
  ];
13871
- const sizeKeys = [...(hasWidth ? ["width"] : []), ...(hasHeight ? ["height"] : [])];
13950
+ const sizeKeys = [
13951
+ ...(hasWidth ? ["width"] : []),
13952
+ ...(hasHeight ? ["height"] : []),
13953
+ ...(hasOverflow ? ["overflow"] : []),
13954
+ ];
13872
13955
  return {
13873
13956
  ...omitKeys(defaults, conflicts),
13874
13957
  // `options` перекрывают одноимённые поля `style` — приоритет тот же, что был у inline-варианта.
13875
13958
  ...omitKeys(style, sizeKeys),
13876
13959
  ...(hasWidth && { width, ...(fillWidth && { minWidth: 0 }) }),
13877
13960
  ...(hasHeight && { height, ...(fillHeight && { minHeight: 0, flex: "1 1 auto" }) }),
13961
+ ...(hasOverflow && { overflow }),
13878
13962
  };
13879
13963
  };
13880
13964
 
@@ -14007,7 +14091,7 @@ const tooltipValueFromRelatedFeatures = (t, value, relatedAttributes, layerInfo)
14007
14091
  return formatChartRelatedValue(t, value, layerInfo, relatedAttributes);
14008
14092
  };
14009
14093
 
14010
- const StackBar = ({ data, filterName, type, alias, options, renderElement, renderTooltip }) => {
14094
+ const StackBar = ({ data, filterName, type, alias, options, fill, renderElement, renderTooltip }) => {
14011
14095
  const { height, showTotal, cornerRadius, groupTooltip } = options || {};
14012
14096
  const { t } = useGlobalContext();
14013
14097
  const { hasAnyFilter, isFiltered, onFilter } = useWidgetFilters(type, filterName, data?.[0]?.items);
@@ -14021,11 +14105,11 @@ const StackBar = ({ data, filterName, type, alias, options, renderElement, rende
14021
14105
  const visibleItems = React.useMemo(() => items?.filter(({ value }) => Number(value) > 0), [items]);
14022
14106
  const getWidth = React.useCallback(value => ((Number(value) / total) * 100).toFixed(2), [total]);
14023
14107
  const renderGroupTooltip = React.useMemo(() => (jsxRuntime.jsx(uilibGl.ThemeProvider, { children: jsxRuntime.jsx(ChartTooltipTable, { cellPadding: 0, cellSpacing: 0, children: visibleItems?.map(({ name, value, color }, index) => (jsxRuntime.jsxs("tr", { children: [jsxRuntime.jsx("td", { children: jsxRuntime.jsxs(ChartTooltip, { alignItems: "center", children: [jsxRuntime.jsx(ChartTooltipColor, { "$color": color }), jsxRuntime.jsx(ChartTooltipName, { children: name })] }) }), jsxRuntime.jsx("td", { children: formatValue(value) })] }, index))) }) })), [visibleItems, formatValue]);
14024
- const renderItem = React.useCallback(({ name, value, color }, ref) => (jsxRuntime.jsx(StackBarSection, { ref: ref, "$width": getWidth(value), "$height": height, "$color": color, cornerRadius: cornerRadius, hasAnyFilter: hasAnyFilter, isFiltered: isFiltered(name), onClick: filterName ? () => onFilter(name) : undefined })), [cornerRadius, filterName, getWidth, hasAnyFilter, height, isFiltered, onFilter]);
14108
+ const renderItem = React.useCallback(({ name, value, color }, ref) => (jsxRuntime.jsx(StackBarSection, { ref: ref, "$width": getWidth(value), "$height": height, "$fill": fill, "$color": color, cornerRadius: cornerRadius, hasAnyFilter: hasAnyFilter, isFiltered: isFiltered(name), onClick: filterName ? () => onFilter(name) : undefined })), [cornerRadius, fill, filterName, getWidth, hasAnyFilter, height, isFiltered, onFilter]);
14025
14109
  const renderItems = React.useMemo(() => (jsxRuntime.jsx(jsxRuntime.Fragment, { children: visibleItems?.map((item, index) => (jsxRuntime.jsx(React.Fragment, { children: groupTooltip ? (renderItem(item)) : (jsxRuntime.jsx(uilibGl.ThemeProvider, { children: jsxRuntime.jsx(uilibGl.Tooltip, { placement: "top", arrow: true, content: renderTooltip([item]), children: ref => renderItem(item, ref) }) })) }, index))) })), [groupTooltip, visibleItems, renderItem, renderTooltip]);
14026
14110
  if (!total)
14027
14111
  return null;
14028
- return (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [(alias || showTotal) && (jsxRuntime.jsxs(StackBarHeader, { children: [jsxRuntime.jsx(StackBarAlias, { children: renderElement({ id: "alias" }) }), showTotal && (jsxRuntime.jsxs(StackBarTotal, { children: [jsxRuntime.jsx(StackBarValue, { children: formatValue(total) }), !!units && jsxRuntime.jsx(StackBarUnits, { children: units })] }))] })), groupTooltip ? (jsxRuntime.jsx(uilibGl.Tooltip, { placement: "top", arrow: true, content: renderGroupTooltip, children: ref => jsxRuntime.jsx(StackBarContainer, { ref: ref, children: renderItems }) })) : (jsxRuntime.jsx(StackBarContainer, { children: renderItems }))] }));
14112
+ return (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [(alias || showTotal) && (jsxRuntime.jsxs(StackBarHeader, { children: [jsxRuntime.jsx(StackBarAlias, { children: renderElement({ id: "alias" }) }), showTotal && (jsxRuntime.jsxs(StackBarTotal, { children: [jsxRuntime.jsx(StackBarValue, { children: formatValue(total) }), !!units && jsxRuntime.jsx(StackBarUnits, { children: units })] }))] })), groupTooltip ? (jsxRuntime.jsx(uilibGl.Tooltip, { placement: "top", arrow: true, content: renderGroupTooltip, children: ref => (jsxRuntime.jsx(StackBarContainer, { ref: ref, "$fill": fill, children: renderItems })) })) : (jsxRuntime.jsx(StackBarContainer, { "$fill": fill, children: renderItems }))] }));
14029
14113
  };
14030
14114
 
14031
14115
  const Chart = React.memo(({ config, element, elementConfig, type, renderElement }) => {
@@ -14034,10 +14118,10 @@ const Chart = React.memo(({ config, element, elementConfig, type, renderElement
14034
14118
  const primaryColor = palette.primary;
14035
14119
  const { t } = useGlobalContext();
14036
14120
  const { expandedContainers, attributes, dataSources } = useWidgetContext(type);
14037
- // chartFill контейнера: график тянется на всю ширину. Ширину измеряем реально (ResizeObserver),
14038
- // т.к. d3-графики (и useChartChange для line) требуют пиксельное число, а не CSS "100%".
14039
- const fill = React.useContext(ChartFillContext);
14040
- const [chartRef, measuredWidth] = useResizeWidth(fill);
14121
+ // fill контейнера: вписываем тело графика в контейнер. Размеры ячейки измеряем реально (ResizeObserver),
14122
+ // т.к. d3-графики (и useChartChange для line) требуют пиксельные числа, а не CSS "100%".
14123
+ const { fill, fitHeight } = React.useContext(FillContext);
14124
+ const [chartRef, { width: measuredWidth, height: measuredHeight }] = useResizeBox(fill);
14041
14125
  const { id, options, children } = element || {};
14042
14126
  const { column, markers: configMarkers, showLabels, showMarkers, showTotal, totalWord: configTotalWord, totalAttribute, expandable, expanded, chartType, relatedDataSources, defaultColor, dotSnapping, } = options || {};
14043
14127
  const isLineChart = chartType === "line";
@@ -14073,11 +14157,19 @@ const Chart = React.memo(({ config, element, elementConfig, type, renderElement
14073
14157
  const chartWidth = fill
14074
14158
  ? measuredWidth ?? DEFAULT_CHART_WIDTH
14075
14159
  : toPxNumber(width) ?? DEFAULT_CHART_WIDTH;
14160
+ // Фит по высоте включается только при заданной высоте контейнера (fitHeight) и уже измеренной
14161
+ // ячейке; иначе — прежняя фикс. высота options.height. Флаг важен и ниже: он различает два
14162
+ // смысла chartHeight — «высота тела» (вне fill) и «вся доступная высота» (в fill).
14163
+ const fitsHeight = React.useMemo(() => !!(fill && fitHeight && measuredHeight), [fill, fitHeight, measuredHeight]);
14164
+ // fill по высоте: тянем тело графика на измеренную доступную высоту ячейки (content-box минус слоты).
14165
+ const chartHeight = React.useMemo(() => (fitsHeight && measuredHeight ? measuredHeight : height), [fitsHeight, measuredHeight, height]);
14166
+ // Круглый график вписываем по короткой стороне (object-fit: contain), центрируя в ячейке.
14167
+ const pieSide = React.useMemo(() => (fitsHeight && measuredHeight ? Math.min(chartWidth, measuredHeight) : chartWidth), [fitsHeight, measuredHeight, chartWidth]);
14076
14168
  const [customize] = useChartChange({
14077
14169
  dataSources: config.dataSources,
14078
14170
  chartId: elementConfig?.id,
14079
14171
  width: chartWidth,
14080
- height,
14172
+ height: chartHeight,
14081
14173
  fontColor,
14082
14174
  relatedAttributes,
14083
14175
  defaultColor: primaryColor,
@@ -14177,26 +14269,37 @@ const Chart = React.memo(({ config, element, elementConfig, type, renderElement
14177
14269
  .flat()
14178
14270
  .map(({ values }) => values)
14179
14271
  .flat();
14180
- return (jsxRuntime.jsxs(AnyChartWrapper, { height: height, children: [jsxRuntime.jsx(LineChartStyles, {}), jsxRuntime.jsx(charts.LineChart, { data: lineChartData, labels: labels, markers: markers, width: chartWidth, height: height, xAxisPadding: 15, yAxisPadding: 0, min: Math.min(...chartValues), customYAxisSelection: yAxis => {
14272
+ return (jsxRuntime.jsxs(AnyChartWrapper, { height: chartHeight, children: [jsxRuntime.jsx(LineChartStyles, {}), jsxRuntime.jsx(charts.LineChart, { data: lineChartData, labels: labels, markers: markers, width: chartWidth, height: chartHeight, xAxisPadding: 15, yAxisPadding: 0, min: Math.min(...chartValues), customYAxisSelection: yAxis => {
14181
14273
  if (isHidedY) {
14182
14274
  yAxis.remove();
14183
14275
  }
14184
14276
  }, customYAxis: yAxis => yAxis.ticks(4), renderTooltip: renderLineChartTooltip, customize: customize, dotSnapping: dotSnapping, dynamicTooltipEnable: true, stackedTooltip: true, tooltipClassName: "dashboardLineChartTooltip", drawGridX: !isHidedY, margin: margin })] }));
14185
14277
  }
14186
14278
  if (isStackBar) {
14187
- const stackBarHeight = showTotal ? height + STACK_BAR_TOTAL_HEIGHT : height;
14188
- return (jsxRuntime.jsx(AnyChartWrapper, { height: stackBarHeight, children: jsxRuntime.jsx(StackBar, { data: data, filterName: filterName, type: type, alias: elementConfig?.children?.find(child => child.id === "alias"), options: options, renderTooltip: renderPieChartTooltip, renderElement: renderElement }) }));
14279
+ // Вне fill chartHeight высота самой полосы, и обёртка честно становится выше на строку
14280
+ // итога. В fill chartHeight уже ВСЯ доступная высота ячейки: обёртка занимает её целиком,
14281
+ // а полоса забирает остаток под шапкой флексом ($fill), поэтому прибавлять/вычитать
14282
+ // STACK_BAR_TOTAL_HEIGHT не нужно — иначе тело вылезло бы за нижнюю границу.
14283
+ const stackBarHeight = showTotal && !fitsHeight ? chartHeight + STACK_BAR_TOTAL_HEIGHT : chartHeight;
14284
+ return (jsxRuntime.jsx(AnyChartWrapper, { height: stackBarHeight, "$fill": fitsHeight, children: jsxRuntime.jsx(StackBar, { data: data, filterName: filterName, type: type, alias: elementConfig?.children?.find(child => child.id === "alias"), options: options, fill: fitsHeight, renderTooltip: renderPieChartTooltip, renderElement: renderElement }) }));
14189
14285
  }
14190
14286
  if (isPieChart) {
14191
- return (jsxRuntime.jsx(AnyChartWrapper, { height: height, children: jsxRuntime.jsx(charts.PieChart, { data: (data[0]?.items
14287
+ return (jsxRuntime.jsx(AnyChartWrapper, { height: fill ? pieSide : height, children: jsxRuntime.jsx(charts.PieChart, { data: (data[0]?.items
14192
14288
  ?.filter(({ value }) => !isEmptyValue(value))
14193
14289
  ?.map(item => ({
14194
14290
  ...item,
14195
14291
  color: formatFilterColor(item.name, item.color, defaultColor),
14196
- })) || []), width: chartWidth, height: chartWidth, padAngle: angle, outerRadius: radius, cornerRadius: cornerRadius, renderTooltip: renderPieChartTooltip, withTooltip: true, onClick: filterName ? item => onFilter(item.name) : undefined, children: showTotal && (jsxRuntime.jsx(PieChartCenter, { children: totalWord || roundTotalSum(+totalSum) })) }) }));
14292
+ })) || []), width: pieSide, height: pieSide, padAngle: angle, outerRadius: radius, cornerRadius: cornerRadius, renderTooltip: renderPieChartTooltip, withTooltip: true, onClick: filterName ? item => onFilter(item.name) : undefined, children: showTotal && (jsxRuntime.jsx(PieChartCenter, { children: totalWord || roundTotalSum(+totalSum) })) }) }));
14197
14293
  }
14198
14294
  const barChartData = getDataFromFilterItems(data[0]?.items);
14199
- return (jsxRuntime.jsx(BarChartWrapper, { height: height + margin.bottom, children: jsxRuntime.jsx(BarChartContainer, { children: jsxRuntime.jsx(StyledBarChart, { data: barChartData, colors: getColorsFromFilterItems(data[0]?.items, defaultColor, formatFilterColor), minValue: getMinValueFromFilterItems(data[0]?.items), markers: markers, width: chartWidth, height: height, barWidth: barWidth, barPadding: padding, customYAxisLeft: customYAxisLeft, customXAxisBottom: xAxisBottom => customXAxisBottom(xAxisBottom, barChartData), customYAxis: axis => !showLabels && axis.remove(), customBars: ({ bars }) => {
14295
+ // Тот же случай, что у stack: обёртка выше тела на подписи оси X (margin.bottom). В fill
14296
+ // chartHeight — вся доступная высота, поэтому подписи вычитаем из неё, а не прибавляем.
14297
+ // BAR_CHART_FOOTER_MARGIN — это внешний margin-bottom самой BarChartWrapper: в её height он
14298
+ // не входит, но место в ячейке занимает, поэтому его тоже вычитаем.
14299
+ const barBodyHeight = fitsHeight
14300
+ ? chartHeight - margin.bottom - BAR_CHART_FOOTER_MARGIN
14301
+ : chartHeight;
14302
+ return (jsxRuntime.jsx(BarChartWrapper, { height: barBodyHeight + margin.bottom, children: jsxRuntime.jsx(BarChartContainer, { children: jsxRuntime.jsx(StyledBarChart, { data: barChartData, colors: getColorsFromFilterItems(data[0]?.items, defaultColor, formatFilterColor), minValue: getMinValueFromFilterItems(data[0]?.items), markers: markers, width: chartWidth, height: barBodyHeight, barWidth: barWidth, barPadding: padding, customYAxisLeft: customYAxisLeft, customXAxisBottom: xAxisBottom => customXAxisBottom(xAxisBottom, barChartData), customYAxis: axis => !showLabels && axis.remove(), customBars: ({ bars }) => {
14200
14303
  bars.attr("rx", radius);
14201
14304
  bars.attr("ry", radius);
14202
14305
  }, margin: margin, xAxisPadding: 0, yAxisPadding: 0, formatTooltipValue: formatTooltipValue, formatTooltipName: formatTooltipName, hideTooltipGroupName: true, dynamicTooltipEnable: true, isBarTooltip: true, onBarClick: filterName ? item => onFilter(item.name) : undefined }) }) }));
@@ -14214,6 +14317,10 @@ const Chart = React.memo(({ config, element, elementConfig, type, renderElement
14214
14317
  defaultColor,
14215
14318
  formatFilterColor,
14216
14319
  chartWidth,
14320
+ chartHeight,
14321
+ fitsHeight,
14322
+ pieSide,
14323
+ fill,
14217
14324
  barWidth,
14218
14325
  showLabels,
14219
14326
  padding,
@@ -14241,7 +14348,11 @@ const Chart = React.memo(({ config, element, elementConfig, type, renderElement
14241
14348
  ]);
14242
14349
  if (!isVisibleContainer(id, expandable, expanded, expandedContainers))
14243
14350
  return null;
14244
- return (jsxRuntime.jsx(ChartWrapper, { ref: chartRef, width: width, height: isStackBar ? "auto" : isPieChart ? (fill ? chartWidth : width) : height, column: column, loading: loading, children: renderChart }));
14351
+ const chartBody = (jsxRuntime.jsx(ChartWrapper, { width: isPieChart && fill ? pieSide : width, height: isStackBar ? "auto" : isPieChart ? (fill ? pieSide : width) : chartHeight, column: column, loading: loading, children: renderChart }));
14352
+ if (!fill)
14353
+ return chartBody;
14354
+ // fill: тело центрируется в измеряемой обёртке, ref которой питает ResizeObserver обеими осями.
14355
+ return jsxRuntime.jsx(ChartFillMeasure, { ref: chartRef, children: chartBody });
14245
14356
  });
14246
14357
 
14247
14358
  const ChartLegend = ({ data, chartElement, fontSize, type, twoColumns, loading }) => {
@@ -15097,6 +15208,7 @@ exports.NO_CONTENT_VALUE = NO_CONTENT_VALUE;
15097
15208
  exports.NUMERIC_ATTRIBUTE_TYPES = NUMERIC_ATTRIBUTE_TYPES;
15098
15209
  exports.NoLiveSnapshotContainer = NoLiveSnapshotContainer;
15099
15210
  exports.OBJECT_FITS = OBJECT_FITS;
15211
+ exports.OVERFLOWS = OVERFLOWS;
15100
15212
  exports.OneColumnContainer = OneColumnContainer;
15101
15213
  exports.POLL_SUBTASK_INTERVAL_MS = POLL_SUBTASK_INTERVAL_MS;
15102
15214
  exports.POLL_SUBTASK_TIMEOUT_MS = POLL_SUBTASK_TIMEOUT_MS;
@@ -15298,7 +15410,7 @@ exports.useRedrawLayer = useRedrawLayer;
15298
15410
  exports.useRelatedDataSourceAttributes = useRelatedDataSourceAttributes;
15299
15411
  exports.useRemoteTask = useRemoteTask;
15300
15412
  exports.useRenderElement = useRenderElement;
15301
- exports.useResizeWidth = useResizeWidth;
15413
+ exports.useResizeBox = useResizeBox;
15302
15414
  exports.useSavePrototypeBuilder = useSavePrototypeBuilder;
15303
15415
  exports.useServerNotificationsContext = useServerNotificationsContext;
15304
15416
  exports.useShownOtherItems = useShownOtherItems;