@evergis/react 4.0.61 → 4.0.63

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.
@@ -403,7 +403,7 @@ export interface SlideshowContainerConfig extends Omit<ConfigContainerChild, "op
403
403
  export interface SlideshowContainerProps extends Omit<ContainerProps, "elementConfig"> {
404
404
  elementConfig?: SlideshowContainerConfig;
405
405
  }
406
- export type TabsContainerOptions = Pick<ConfigOptions, "radius" | "column" | "bgColor" | "noBg" | "onlyIcon" | "shownItems" | "maxLength">;
406
+ export type TabsContainerOptions = Pick<ConfigOptions, "radius" | "column" | "bgColor" | "noBg" | "onlyIcon" | "shownItems" | "maxLength" | "wordBreak">;
407
407
  export type TabOptions = Pick<ConfigOptions, "icon">;
408
408
  export interface TabChild extends Omit<ConfigContainerChild, "options" | "type" | "children"> {
409
409
  options?: TabOptions;
@@ -416,7 +416,7 @@ export interface TabsContainerConfig extends Omit<ConfigContainerChild, "options
416
416
  export interface TabsContainerProps extends Omit<ContainerProps, "elementConfig"> {
417
417
  elementConfig?: TabsContainerConfig;
418
418
  }
419
- export type TaskContainerOptions = Pick<ConfigOptions, "title" | "relatedResources" | "center" | "icon" | "statusColors" | "responseFilters">;
419
+ export type TaskContainerOptions = Pick<ConfigOptions, "title" | "relatedResources" | "center" | "icon" | "statusColors" | "responseFilters" | "useNotifications">;
420
420
  export interface TaskContainerConfig extends Omit<ConfigContainerChild, "options" | "templateName"> {
421
421
  templateName?: ContainerTemplate.Task;
422
422
  options?: TaskContainerOptions;
@@ -1,5 +1,7 @@
1
1
  import { FC } from 'react';
2
+ import { ConfigTextDisplayOptions } from '../../types';
2
3
  type TextTrimProps = {
4
+ wordBreak?: ConfigTextDisplayOptions["wordBreak"];
3
5
  maxLength?: number;
4
6
  expandable?: boolean;
5
7
  lineBreak?: string;
@@ -0,0 +1,4 @@
1
+ import { ConfigTextDisplayOptions } from '../../types';
2
+ export declare const TextTrimValue: import('styled-components').StyledComponent<"div", any, {
3
+ wordBreak?: ConfigTextDisplayOptions["wordBreak"];
4
+ }, never>;
@@ -0,0 +1,9 @@
1
+ import { RemoteTaskStatus } from '@evergis/api';
2
+ interface UseTaskNotificationsParams {
3
+ enabled: boolean;
4
+ status: RemoteTaskStatus;
5
+ lastMessage: string | null;
6
+ openLog: () => void;
7
+ }
8
+ export declare const useTaskNotifications: ({ enabled, status, lastMessage, openLog, }: UseTaskNotificationsParams) => void;
9
+ export {};
@@ -0,0 +1,11 @@
1
+ import { ConfigContainerChild, WidgetType } from '../../types';
2
+ interface UseElementImageProps {
3
+ type?: WidgetType;
4
+ elementConfig?: ConfigContainerChild;
5
+ }
6
+ interface UseElementImageResult {
7
+ src: string | null;
8
+ alt: string;
9
+ }
10
+ export declare const useElementImage: ({ type, elementConfig, }: UseElementImageProps) => UseElementImageResult;
11
+ export {};
@@ -5,4 +5,11 @@ export declare const useGlobalContext: () => {
5
5
  themeName: import('../../..').ThemeName;
6
6
  api: import('@evergis/api').Api;
7
7
  ewktGeometry: string;
8
+ notification: {
9
+ add: (item: import('@evergis/uilib-gl').INotificationItem) => void;
10
+ update: (patch: Partial<import('@evergis/uilib-gl').INotificationItem> & {
11
+ id: string;
12
+ }) => void;
13
+ close: (id: string) => void;
14
+ };
8
15
  };
@@ -184,6 +184,7 @@ export interface ConfigTextDisplayOptions {
184
184
  hideTitle?: boolean;
185
185
  simple?: boolean;
186
186
  maxLength?: number;
187
+ wordBreak?: "break-word" | "break-all";
187
188
  separator?: string;
188
189
  lineBreak?: string;
189
190
  }
@@ -261,6 +262,7 @@ export interface ConfigMiscOptions {
261
262
  tabId?: string;
262
263
  downloadById?: string;
263
264
  parentResourceId?: string;
265
+ useNotifications?: boolean;
264
266
  }
265
267
  /**
266
268
  * Flat-объединение всех доменных миксинов. Существующие места, использующие
@@ -1,6 +1,7 @@
1
1
  import { PropsWithChildren } from 'react';
2
2
  import { i18n } from 'i18next';
3
3
  import { Api } from '@evergis/api';
4
+ import { INotificationItem } from '@evergis/uilib-gl';
4
5
  import { ThemeName } from '../../types';
5
6
  export type GlobalContextProps = PropsWithChildren<{
6
7
  t?: i18n["t"];
@@ -8,4 +9,11 @@ export type GlobalContextProps = PropsWithChildren<{
8
9
  ewktGeometry?: string;
9
10
  themeName?: ThemeName;
10
11
  api?: Api;
12
+ notification?: {
13
+ add: (item: INotificationItem) => void;
14
+ update: (patch: Partial<INotificationItem> & {
15
+ id: string;
16
+ }) => void;
17
+ close: (id: string) => void;
18
+ };
11
19
  }>;
@@ -11,6 +11,7 @@ export declare const usePythonTask: () => {
11
11
  stopTask: () => Promise<void>;
12
12
  openLog: () => void;
13
13
  log: string;
14
+ lastMessage: string;
14
15
  error: Error;
15
16
  status: RemoteTaskStatus;
16
17
  loading: boolean;
package/dist/index.js CHANGED
@@ -4217,7 +4217,7 @@ const useAttachmentItems = ({ type, elementConfig, valueOverride, }) => {
4217
4217
  };
4218
4218
 
4219
4219
  const useGlobalContext = () => {
4220
- const { t, language, themeName, api, ewktGeometry } = React.useContext(GlobalContext) || {};
4220
+ const { t, language, themeName, api, ewktGeometry, notification } = React.useContext(GlobalContext) || {};
4221
4221
  const translate = React.useCallback((value, options) => {
4222
4222
  if (t)
4223
4223
  return t(value, options);
@@ -4229,7 +4229,8 @@ const useGlobalContext = () => {
4229
4229
  themeName,
4230
4230
  api,
4231
4231
  ewktGeometry,
4232
- }), [language, translate, api, ewktGeometry, themeName]);
4232
+ notification,
4233
+ }), [language, translate, api, ewktGeometry, themeName, notification]);
4233
4234
  };
4234
4235
 
4235
4236
  const GRID_TILE_SIZE = "4.5rem";
@@ -5622,6 +5623,7 @@ const usePythonTask = () => {
5622
5623
  const { preparePythonSandbox } = usePythonSandbox();
5623
5624
  const [status, setStatus] = React.useState(api.RemoteTaskStatus.Unknown);
5624
5625
  const [log, setLog] = React.useState(null);
5626
+ const [lastMessage, setLastMessage] = React.useState(null);
5625
5627
  const [error, setError] = React.useState(null);
5626
5628
  const [loading, setLoading] = React.useState(false);
5627
5629
  const [executionTime, setExecutionTime] = React.useState(null);
@@ -5643,6 +5645,7 @@ const usePythonTask = () => {
5643
5645
  reset();
5644
5646
  setStatus(api.RemoteTaskStatus.Process);
5645
5647
  setLog(null);
5648
+ setLastMessage(null);
5646
5649
  setLoading(true);
5647
5650
  const start = Date.now();
5648
5651
  let prototypeId = await api$1.remoteTaskManager.createTaskPrototype({
@@ -5683,6 +5686,8 @@ const usePythonTask = () => {
5683
5686
  const isFinished = [api.RemoteTaskStatus.Completed, api.RemoteTaskStatus.Error].includes(data.status);
5684
5687
  setStatus(data.status);
5685
5688
  setLog([logRef.current, data.log].filter(Boolean).join("\n"));
5689
+ if (data.log)
5690
+ setLastMessage(data.log);
5686
5691
  setExecutionTime(Date.now() - start);
5687
5692
  setLoading(false);
5688
5693
  setTaskId(isFinished ? null : newTaskId);
@@ -5735,6 +5740,7 @@ const usePythonTask = () => {
5735
5740
  stopTask,
5736
5741
  openLog,
5737
5742
  log,
5743
+ lastMessage,
5738
5744
  error,
5739
5745
  status,
5740
5746
  loading,
@@ -6254,7 +6260,7 @@ const formatElementValue = ({ t, value, elementConfig, attributes, wrap, }) => {
6254
6260
 
6255
6261
  const getAttributeValue = (element, attributes) => {
6256
6262
  const attribute = getAttributeByName(element?.attributeName, attributes);
6257
- const { maxLength, separator, expandable, lineBreak } = element.options || {};
6263
+ const { maxLength, wordBreak, separator, expandable, lineBreak } = element.options || {};
6258
6264
  let value;
6259
6265
  if (attribute?.type === api.AttributeType.Boolean && typeof attribute.value === "boolean") {
6260
6266
  return jsxRuntime.jsx(DashboardCheckbox, { title: attribute.alias || attribute.attributeName, checked: attribute.value });
@@ -6269,7 +6275,7 @@ const getAttributeValue = (element, attributes) => {
6269
6275
  ? JSON.stringify(rawValue)
6270
6276
  : (rawValue || "");
6271
6277
  }
6272
- return typeof value === "string" && maxLength && maxLength < value.length ? (jsxRuntime.jsx(TextTrim, { maxLength: maxLength, expandable: expandable, lineBreak: lineBreak, children: value })) : (value);
6278
+ return typeof value === "string" && maxLength && maxLength < value.length ? (jsxRuntime.jsx(TextTrim, { maxLength: maxLength, wordBreak: wordBreak, expandable: expandable, lineBreak: lineBreak, children: value })) : (value);
6273
6279
  };
6274
6280
 
6275
6281
  const getChartAxes = (chartElement) => chartElement?.options?.relatedDataSources?.filter(({ chartAxis }) => chartAxis === "y");
@@ -7399,7 +7405,7 @@ const TabsContainer = React.memo(({ elementConfig, type }) => {
7399
7405
  const { palette } = styled.useTheme();
7400
7406
  const { selectedTabId, setSelectedTabId } = useWidgetContext(type);
7401
7407
  const { id, options, style, children: tabs } = elementConfig || {};
7402
- const { radius, column, bgColor, noBg, onlyIcon, shownItems, maxLength = 12 } = options || {};
7408
+ const { radius, column, bgColor, noBg, onlyIcon, shownItems, maxLength = 12, wordBreak } = options || {};
7403
7409
  const renderIcon = React.useCallback((icon, active) => {
7404
7410
  if (!icon)
7405
7411
  return null;
@@ -7407,16 +7413,16 @@ const TabsContainer = React.memo(({ elementConfig, type }) => {
7407
7413
  return jsxRuntime.jsx(uilibGl.Icon, { kind: icon });
7408
7414
  return icon.endsWith(".svg") ? (jsxRuntime.jsx(SvgImage, { url: icon, width: 16, fontColor: active ? palette.textContrast : palette.textSecondary })) : (jsxRuntime.jsx("img", { src: icon, alt: "" }));
7409
7415
  }, [palette.textContrast, palette.textSecondary]);
7410
- const onClick = React.useCallback((id) => {
7411
- setSelectedTabId(id);
7412
- window.location.hash = `#${id}`;
7416
+ const onClick = React.useCallback((tabId) => {
7417
+ setSelectedTabId(tabId);
7418
+ window.location.hash = `#${tabId}`;
7413
7419
  }, [setSelectedTabId]);
7414
7420
  React.useEffect(() => {
7415
7421
  if (!selectedTabId) {
7416
7422
  setSelectedTabId(tabs[0].id);
7417
7423
  }
7418
7424
  }, []);
7419
- return (jsxRuntime.jsx(SwiperContainer, { id: id, style: style, children: jsxRuntime.jsx(react.Swiper, { spaceBetween: 0, slidesPerView: shownItems || 2, children: tabs.map(({ id, value, options: tabOptions }) => (jsxRuntime.jsxs(react.SwiperSlide, { children: [jsxRuntime.jsxs(TabContainer, { href: `#${id}`, active: selectedTabId === id, column: column, bgColor: bgColor, noBg: noBg, radius: radius, onlyIcon: onlyIcon, hasIcon: !!tabOptions?.icon, onClick: () => onClick(id), children: [renderIcon(tabOptions?.icon, selectedTabId === id), !onlyIcon && (jsxRuntime.jsx(TabValue, { children: jsxRuntime.jsx(TextTrim, { maxLength: maxLength, children: value }) }))] }), jsxRuntime.jsx(TabAnchor, { id: id })] }, id))) }) }));
7425
+ return (jsxRuntime.jsx(SwiperContainer, { id: id, style: style, children: jsxRuntime.jsx(react.Swiper, { spaceBetween: 0, slidesPerView: shownItems || 2, children: tabs.map(({ id: tabId, value, options: tabOptions }) => (jsxRuntime.jsxs(react.SwiperSlide, { children: [jsxRuntime.jsxs(TabContainer, { href: `#${tabId}`, active: selectedTabId === tabId, column: column, bgColor: bgColor, noBg: noBg, radius: radius, onlyIcon: onlyIcon, hasIcon: !!tabOptions?.icon, onClick: () => onClick(tabId), children: [renderIcon(tabOptions?.icon, selectedTabId === tabId), !onlyIcon && (jsxRuntime.jsx(TabValue, { children: jsxRuntime.jsx(TextTrim, { maxLength: maxLength, wordBreak: wordBreak, children: value }) }))] }), jsxRuntime.jsx(TabAnchor, { id: tabId })] }, tabId))) }) }));
7420
7426
  });
7421
7427
 
7422
7428
  const ContainerIconValue = styled(uilibGl.Flex) ``;
@@ -7524,7 +7530,7 @@ const RoundedBackgroundContainer = React.memo(({ type, elementConfig, feature, r
7524
7530
  feature,
7525
7531
  });
7526
7532
  const { id, options, style, children } = elementConfig || {};
7527
- const { maxLength, center, fontColor, innerTemplateStyle, inlineUnits, big, bigIcon, hideEmpty, colorAttribute } = options || {};
7533
+ const { maxLength, wordBreak, center, fontColor, innerTemplateStyle, inlineUnits, big, bigIcon, hideEmpty, colorAttribute } = options || {};
7528
7534
  const iconElement = children?.find(item => item.id === "icon");
7529
7535
  const aliasElement = children?.find(item => item.id === "alias");
7530
7536
  const unitsElement = children?.find(item => item.id === "units");
@@ -7543,7 +7549,7 @@ const RoundedBackgroundContainer = React.memo(({ type, elementConfig, feature, r
7543
7549
  return null;
7544
7550
  return (jsxRuntime.jsx(uilibGl.FlexSpan, { width: iconElement.options?.width || "1rem", alignItems: "center", mr: "0.5rem", children: renderElement({ id: "icon", wrap: false }) }));
7545
7551
  }, [iconElement, renderElement]);
7546
- const renderAlias = React.useMemo(() => (jsxRuntime.jsx(ContainerAlias, { style: aliasElement?.style, children: jsxRuntime.jsx(TextTrim, { maxLength: maxLength || ALIAS_DEFAULT_MAX_LENGTH, children: renderElement({ id: "alias", wrap: false }) }) })), [aliasElement?.style, maxLength, renderElement]);
7552
+ const renderAlias = React.useMemo(() => (jsxRuntime.jsx(ContainerAlias, { style: aliasElement?.style, children: jsxRuntime.jsx(TextTrim, { maxLength: maxLength || ALIAS_DEFAULT_MAX_LENGTH, wordBreak: wordBreak, children: renderElement({ id: "alias", wrap: false }) }) })), [aliasElement?.style, maxLength, renderElement, wordBreak]);
7547
7553
  const renderValue = React.useMemo(() => lodash.isNil(value) ? null : (jsxRuntime.jsxs(ContainerValue, { style: valueElement?.style, big: true, children: [value, !!unitsElement && (jsxRuntime.jsx(ContainerUnits, { style: unitsElement?.style, children: renderElement({ id: "units" }) }))] })), [valueElement?.style, value, unitsElement, renderElement]);
7548
7554
  if (lodash.isNil(value) && hideEmpty)
7549
7555
  return null;
@@ -7708,14 +7714,93 @@ const buildFiltersFromResponse = (responseFilters, result) => {
7708
7714
  return Object.keys(filters).length ? filters : null;
7709
7715
  };
7710
7716
 
7717
+ const RUN_ID_RADIX = 36;
7718
+ const RUN_ID_LENGTH = 8;
7719
+ const generateRunId = () => `task-${Date.now()}-${Math.random().toString(RUN_ID_RADIX).slice(2, RUN_ID_LENGTH)}`;
7720
+ const useTaskNotifications = ({ enabled, status, lastMessage, openLog, }) => {
7721
+ const { t, notification } = useGlobalContext();
7722
+ const runIdRef = React.useRef(null);
7723
+ const prevStatusRef = React.useRef(api.RemoteTaskStatus.Unknown);
7724
+ React.useEffect(() => {
7725
+ if (!enabled) {
7726
+ if (runIdRef.current) {
7727
+ notification?.close(runIdRef.current);
7728
+ runIdRef.current = null;
7729
+ }
7730
+ prevStatusRef.current = status;
7731
+ return;
7732
+ }
7733
+ if (status === api.RemoteTaskStatus.Unknown) {
7734
+ prevStatusRef.current = status;
7735
+ return;
7736
+ }
7737
+ const isFreshRun = status === api.RemoteTaskStatus.Process && prevStatusRef.current !== api.RemoteTaskStatus.Process;
7738
+ if (isFreshRun) {
7739
+ runIdRef.current = generateRunId();
7740
+ }
7741
+ if (!runIdRef.current) {
7742
+ runIdRef.current = generateRunId();
7743
+ }
7744
+ const id = runIdRef.current;
7745
+ const description = lastMessage || t("taskStarted", { ns: "dashboard", defaultValue: "Запуск задачи…" });
7746
+ const button = t("details", { ns: "dashboard", defaultValue: "Подробнее" });
7747
+ const base = {
7748
+ id,
7749
+ title: "",
7750
+ description,
7751
+ duration: Number.MAX_SAFE_INTEGER,
7752
+ button,
7753
+ buttonIcon: "info",
7754
+ buttonColor: "primary",
7755
+ onButtonClick: openLog,
7756
+ };
7757
+ if (status === api.RemoteTaskStatus.Process) {
7758
+ const item = {
7759
+ ...base,
7760
+ title: t("taskInProgress", { ns: "dashboard", defaultValue: "Выполняется" }),
7761
+ progress: true,
7762
+ };
7763
+ if (isFreshRun) {
7764
+ notification?.add(item);
7765
+ }
7766
+ else {
7767
+ notification?.update(item);
7768
+ }
7769
+ }
7770
+ else if (status === api.RemoteTaskStatus.Completed) {
7771
+ notification?.update({
7772
+ ...base,
7773
+ title: t("taskCompleted", { ns: "dashboard", defaultValue: "Выполнено" }),
7774
+ success: true,
7775
+ progress: false,
7776
+ });
7777
+ }
7778
+ else if (status === api.RemoteTaskStatus.Error) {
7779
+ notification?.update({
7780
+ ...base,
7781
+ title: t("taskError", { ns: "dashboard", defaultValue: "Ошибка" }),
7782
+ error: true,
7783
+ progress: false,
7784
+ });
7785
+ }
7786
+ prevStatusRef.current = status;
7787
+ }, [enabled, status, lastMessage, openLog, t, notification]);
7788
+ };
7789
+
7711
7790
  const TaskContainer = React.memo(({ type, elementConfig, renderElement }) => {
7712
7791
  const { t, ewktGeometry } = useGlobalContext();
7713
7792
  const { dataSources, filters: selectedFilters, attributes, layerInfo, changeFilters, } = useWidgetContext(type);
7714
7793
  const { dataSources: projectDataSources } = useWidgetContext(exports.WidgetType.Dashboard);
7715
7794
  const { currentPage } = useWidgetPage(type);
7716
- const { taskId, runTask, stopTask, status, openLog, loading, isLogDialogOpen, closeLog, log, result, } = usePythonTask();
7795
+ const { taskId, runTask, stopTask, status, openLog, loading, isLogDialogOpen, closeLog, log, lastMessage, result, } = usePythonTask();
7717
7796
  const { options } = elementConfig || {};
7718
- const { title, relatedResources, center, icon, statusColors, responseFilters } = options || {};
7797
+ const { title, relatedResources, center, icon, statusColors, responseFilters, useNotifications, } = options || {};
7798
+ useTaskNotifications({
7799
+ enabled: !!useNotifications,
7800
+ status,
7801
+ lastMessage,
7802
+ openLog,
7803
+ });
7719
7804
  React.useEffect(() => {
7720
7805
  const filtersToApply = buildFiltersFromResponse(responseFilters, result);
7721
7806
  if (filtersToApply)
@@ -8787,15 +8872,7 @@ const RowHeaderMixin = styled.css `
8787
8872
  const OverlayHeaderMixin = (overlay) => styled.css `
8788
8873
  &&& {
8789
8874
  :after {
8790
- content: "";
8791
- z-index: 2;
8792
- position: absolute;
8793
- top: 0;
8794
- left: 0;
8795
- width: 100%;
8796
- height: 100%;
8797
8875
  background: ${overlay};
8798
- pointer-events: none;
8799
8876
  }
8800
8877
  }
8801
8878
  `;
@@ -8851,8 +8928,10 @@ const LayerIconContainer = styled.div `
8851
8928
  display: flex;
8852
8929
  align-items: center;
8853
8930
  justify-content: center;
8854
- min-width: 2rem;
8855
- margin-right: 0.5rem;
8931
+ min-width: 1.5rem;
8932
+ width: 1.5rem;
8933
+ height: 1.5rem;
8934
+ margin-right: 1rem;
8856
8935
  `;
8857
8936
  const AlertIconContainer = styled(uilibGl.Flex) `
8858
8937
  align-items: center;
@@ -9484,29 +9563,49 @@ const ElementIcon = React.memo(({ type, elementConfig }) => {
9484
9563
  return (jsxRuntime.jsx(StyledIcon, { kind: iconValue, fontSize: fontSize, fontColor: fontColor, style: style }));
9485
9564
  });
9486
9565
 
9487
- const ElementImage = React.memo(({ type, elementConfig }) => {
9566
+ const useElementImage = ({ type, elementConfig, }) => {
9488
9567
  const { attributes } = useWidgetContext(type);
9489
- const { value, attributeName, options, style } = elementConfig || {};
9490
- const { width } = options || {};
9491
- const firstImage = React.useMemo(() => {
9492
- if (value) {
9568
+ const { value, attributeName } = elementConfig || {};
9569
+ const attribute = React.useMemo(() => {
9570
+ if (!attributeName || Array.isArray(attributeName))
9571
+ return undefined;
9572
+ return attributes?.find(item => item.attributeName === attributeName);
9573
+ }, [attributeName, attributes]);
9574
+ const isAttachmentAttribute = attribute?.subType === api.StringSubType.Attachments;
9575
+ const { items } = useAttachmentItems({ type, elementConfig });
9576
+ const imageItems = React.useMemo(() => items
9577
+ .filter(item => IMAGE_FILE_TYPES.includes(getFileType(item.mimeType, item.name)))
9578
+ .slice(0, 1), [items]);
9579
+ const attachmentImages = useAttachmentPreviewImages({
9580
+ items: imageItems,
9581
+ active: isAttachmentAttribute,
9582
+ });
9583
+ const stringUrl = React.useMemo(() => {
9584
+ if (value)
9493
9585
  return getResourceUrl(value.toString());
9494
- }
9495
- if (!attributeName || Array.isArray(attributeName)) {
9586
+ if (isAttachmentAttribute)
9587
+ return null;
9588
+ if (!attributeName || Array.isArray(attributeName))
9496
9589
  return null;
9497
- }
9498
- const attribute = attributes?.find(item => item.attributeName === attributeName);
9499
9590
  const imageUrl = attribute?.value?.split(";")?.[0];
9500
- if (!imageUrl) {
9591
+ if (!imageUrl)
9501
9592
  return null;
9502
- }
9503
9593
  return getResourceUrl(imageUrl);
9504
- }, [attributeName, attributes, value]);
9505
- const blobUrl = useFetchImageWithAuth(firstImage);
9506
- if (!blobUrl) {
9594
+ }, [value, isAttachmentAttribute, attributeName, attribute]);
9595
+ const stringBlobUrl = useFetchImageWithAuth(stringUrl);
9596
+ const attachmentSrc = attachmentImages[0]?.src || null;
9597
+ const src = isAttachmentAttribute ? attachmentSrc : stringBlobUrl;
9598
+ const alt = isAttachmentAttribute ? attachmentImages[0]?.fileName ?? "" : stringUrl ?? "";
9599
+ return { src, alt };
9600
+ };
9601
+
9602
+ const ElementImage = React.memo(({ type, elementConfig }) => {
9603
+ const { options, style } = elementConfig || {};
9604
+ const { width } = options || {};
9605
+ const { src, alt } = useElementImage({ type, elementConfig });
9606
+ if (!src)
9507
9607
  return null;
9508
- }
9509
- return (jsxRuntime.jsx("img", { src: blobUrl, alt: firstImage ?? "", width: width, style: style }));
9608
+ return jsxRuntime.jsx("img", { src: src, alt: alt, width: width, style: style });
9510
9609
  });
9511
9610
 
9512
9611
  const ElementLegend = React.memo(({ type, element, elementConfig }) => {
@@ -9874,7 +9973,8 @@ const SlideshowHeaderWrapper = styled.div `
9874
9973
  position: absolute;
9875
9974
  top: 0;
9876
9975
  left: 0;
9877
- right: 0;
9976
+ width: 100%;
9977
+ height: 100%;
9878
9978
  pointer-events: none;
9879
9979
  }
9880
9980
 
@@ -9884,8 +9984,7 @@ const SlideshowHeaderWrapper = styled.div `
9884
9984
  }
9885
9985
 
9886
9986
  :after {
9887
- height: 4.5rem;
9888
- background: linear-gradient(180deg, #000000 0%, rgba(0, 0, 0, 0) 100%);
9987
+ background: linear-gradient(180deg, rgba(17, 37, 47, 0.75) 0%, rgba(17, 37, 47, 0.00) 100%);
9889
9988
  }
9890
9989
 
9891
9990
  :hover {
@@ -9933,12 +10032,13 @@ const HeaderSlideshow = styled.div `
9933
10032
  `;
9934
10033
 
9935
10034
  const FeatureCardBackgroundHeader = () => {
10035
+ const { themeName: pageThemeName } = useGlobalContext();
9936
10036
  const { config } = useWidgetConfig(exports.WidgetType.FeatureCard);
9937
10037
  const { header } = config || {};
9938
10038
  const { options } = header || {};
9939
10039
  const { fontColor, bgColor, height, overlay, bigIcon, withPadding, bottomBlur, themeName, column } = options || {};
9940
10040
  const renderElement = useHeaderRender(header);
9941
- return (jsxRuntime.jsx(BackgroundHeaderWrapper, { "$fontColor": fontColor, "$bgColor": bgColor, "$height": height, "$bigIcon": bigIcon, "$withPadding": withPadding, "$bottomBlur": bottomBlur, children: jsxRuntime.jsx(uilibGl.ThemeProvider, { theme: getThemeByName(themeName), children: jsxRuntime.jsxs(Header, { "$overlay": overlay, "$isRow": !column, children: [jsxRuntime.jsxs(HeaderFrontView, { children: [jsxRuntime.jsxs(HeaderContainer, { column: column, children: [jsxRuntime.jsx(HeaderLayerIcon, {}), jsxRuntime.jsx(FeatureCardTitle, { title: renderElement({
10041
+ return (jsxRuntime.jsx(BackgroundHeaderWrapper, { "$fontColor": fontColor, "$bgColor": bgColor, "$height": height, "$bigIcon": bigIcon, "$withPadding": withPadding, "$bottomBlur": bottomBlur, children: jsxRuntime.jsx(uilibGl.ThemeProvider, { theme: getThemeByName(themeName ?? pageThemeName), children: jsxRuntime.jsxs(Header, { "$overlay": overlay, "$isRow": !column, children: [jsxRuntime.jsxs(HeaderFrontView, { children: [jsxRuntime.jsxs(HeaderContainer, { column: column, children: [jsxRuntime.jsx(HeaderLayerIcon, {}), jsxRuntime.jsx(FeatureCardTitle, { title: renderElement({
9942
10042
  id: "title",
9943
10043
  wrap: false,
9944
10044
  }), description: renderElement({
@@ -10324,8 +10424,8 @@ const getElementValue = ({ getDefaultContainer, ...props }) => {
10324
10424
  return "";
10325
10425
  }
10326
10426
  const alias = attribute?.alias || attributeName || "";
10327
- const { maxLength, lineBreak, expandable } = options || {};
10328
- return alias && maxLength && maxLength < alias.length ? (jsxRuntime.jsx(TextTrim, { maxLength: maxLength, expandable: expandable, lineBreak: lineBreak, children: alias })) : (alias);
10427
+ const { maxLength, wordBreak, lineBreak, expandable } = options || {};
10428
+ return alias && maxLength && maxLength < alias.length ? (jsxRuntime.jsx(TextTrim, { maxLength: maxLength, wordBreak: wordBreak, expandable: expandable, lineBreak: lineBreak, children: alias })) : (alias);
10329
10429
  }
10330
10430
  if (type === "attributeValue") {
10331
10431
  /* return isHandbookAttribute(attribute?.name, layerInfo) ? (
@@ -13187,15 +13287,20 @@ const SvgImage = React.memo(({ url, width, height, fontColor }) => {
13187
13287
  return (jsxRuntime.jsx(StyledSvg, { "$width": width, "$height": height, "$fontColor": fontColor, dangerouslySetInnerHTML: { __html: svg } }));
13188
13288
  });
13189
13289
 
13190
- const TextTrim = React.memo(({ maxLength, expandable, lineBreak, children }) => {
13290
+ const TextTrimValue = styled.div `
13291
+ word-break: ${({ wordBreak }) => wordBreak ?? "break-word"};
13292
+ overflow: hidden;
13293
+ `;
13294
+
13295
+ const TextTrim = React.memo(({ maxLength, expandable, lineBreak, wordBreak, children }) => {
13191
13296
  const { t } = useGlobalContext();
13192
13297
  const [expanded, toggleExpanded] = useToggle();
13193
13298
  const text = children?.toString();
13194
13299
  const formatValue = React.useCallback((value) => {
13195
13300
  if (!lineBreak)
13196
- return value;
13197
- return jsxRuntime.jsx("div", { dangerouslySetInnerHTML: { __html: lodash.unescape(value).split(lineBreak).join("<br />") } });
13198
- }, [lineBreak]);
13301
+ return jsxRuntime.jsx(TextTrimValue, { wordBreak: wordBreak, children: value });
13302
+ return jsxRuntime.jsx(TextTrimValue, { wordBreak: wordBreak, dangerouslySetInnerHTML: { __html: lodash.unescape(value).split(lineBreak).join("<br />") } });
13303
+ }, [lineBreak, wordBreak]);
13199
13304
  if (!text?.length || !maxLength || text.length <= maxLength)
13200
13305
  return jsxRuntime.jsx(jsxRuntime.Fragment, { children: formatValue(text) });
13201
13306
  const substring = `${text.substring(0, maxLength)}...`;