@evergis/react 4.0.134 → 4.0.136

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
@@ -6351,6 +6351,7 @@ const useMapImages = ({ images }) => {
6351
6351
  const [loaded, setLoaded] = React.useState(false);
6352
6352
  const [errors, setErrors] = React.useState({});
6353
6353
  const loadedImagesRef = React.useRef(new Set());
6354
+ const previouslyLoadedImages = React.useRef([]);
6354
6355
  const hasImage = React.useCallback((name) => {
6355
6356
  if (!map?.current) {
6356
6357
  return false;
@@ -6358,8 +6359,9 @@ const useMapImages = ({ images }) => {
6358
6359
  return map.current.hasImage(name);
6359
6360
  }, [map]);
6360
6361
  const removeImage = React.useCallback((name) => {
6361
- if (!map?.current)
6362
+ if (!map?.current) {
6362
6363
  return;
6364
+ }
6363
6365
  if (map.current.hasImage(name)) {
6364
6366
  map.current.removeImage(name);
6365
6367
  loadedImagesRef.current.delete(name);
@@ -6370,7 +6372,7 @@ const useMapImages = ({ images }) => {
6370
6372
  throw new Error("Map is not initialized");
6371
6373
  }
6372
6374
  if (map.current.hasImage(config.name)) {
6373
- return;
6375
+ removeImage(config.name);
6374
6376
  }
6375
6377
  const size = config.size ?? DEFAULT_IMAGE_SIZE;
6376
6378
  const pixelRatio = config.pixelRatio ?? 1;
@@ -6431,9 +6433,15 @@ const useMapImages = ({ images }) => {
6431
6433
  setLoaded(true);
6432
6434
  return;
6433
6435
  }
6436
+ if (lodash.isEqual(images, previouslyLoadedImages.current)) {
6437
+ return;
6438
+ }
6434
6439
  const loadAllImages = async () => {
6435
6440
  setLoaded(false);
6436
6441
  const loadPromises = images.map(async (config) => {
6442
+ if (lodash.isEqual(config, previouslyLoadedImages.current.find(item => item.name === config.name))) {
6443
+ return;
6444
+ }
6437
6445
  try {
6438
6446
  await addImage(config);
6439
6447
  }
@@ -6443,9 +6451,10 @@ const useMapImages = ({ images }) => {
6443
6451
  });
6444
6452
  await Promise.all(loadPromises);
6445
6453
  setLoaded(true);
6454
+ previouslyLoadedImages.current = images;
6446
6455
  };
6447
6456
  void loadAllImages();
6448
- }, [mapLoaded, map, images, addImage]);
6457
+ }, [mapLoaded, images, map, addImage]);
6449
6458
  return { loaded, errors, addImage, removeImage, hasImage };
6450
6459
  };
6451
6460
 
@@ -16421,15 +16430,10 @@ const RangeDateFilter = ({ type, filter }) => {
16421
16430
  const updateDebounce = useDebouncedCallback(FILTER_UPDATE_DEBOUNCE);
16422
16431
  const { filters: configFilters } = currentPage;
16423
16432
  const { filterName, label, minValue, maxValue, withTime } = filter.options;
16424
- // Локальный стейт копия значения из общего стора фильтров, поэтому при монтировании поднимаем
16425
- // выбор оттуда. Контейнер фильтров размонтируется на время перезапроса источников (их стор
16426
- // сбрасывается целиком, например, на смену геометрической выборки), и без этого выбранный
16427
- // диапазон терялся бы, а следом его затирал дефолт.
16428
- const [value, setValue] = React.useState(() => [getDate(filters[filterName]?.min)?.toISOString(), getDate(filters[filterName]?.max)?.toISOString()]);
16433
+ const [value, setValue] = React.useState([undefined, undefined]);
16429
16434
  const isInit = React.useRef(false);
16430
- // Ref фиксирует только первое значение выражения: если на момент монтирования выбор уже лежит
16431
- // в сторе, дефолт считается применённым — перемонтирование не должно его затирать.
16432
- const isDefaultApplied = React.useRef(!lodash.isNil(value[0]) || !lodash.isNil(value[1]));
16435
+ const isDefaultApplied = React.useRef(false);
16436
+ const isRestored = React.useRef(false);
16433
16437
  const configFilter = React.useMemo(() => getConfigFilter(filterName, configFilters), [configFilters, filterName]);
16434
16438
  const dataSource = React.useMemo(() => getDataSource(configFilter?.relatedDataSource, dataSources), [configFilter?.relatedDataSource, dataSources]);
16435
16439
  const { minFromData, maxFromData } = React.useMemo(() => dataSource?.features?.reduce((prev, { properties }) => {
@@ -16464,6 +16468,25 @@ const RangeDateFilter = ({ type, filter }) => {
16464
16468
  const onChange = React.useCallback((newValue) => {
16465
16469
  setValue([newValue[0].toISOString(), newValue[1].toISOString()]);
16466
16470
  }, []);
16471
+ // Значение фильтра живёт в общем сторе, локальный стейт — лишь его копия, поэтому при
16472
+ // монтировании поднимаем выбор оттуда: контейнер фильтров размонтируется на время перезапроса
16473
+ // источников (их стор сбрасывается целиком, например, на смену геометрической выборки), и без
16474
+ // восстановления выбранный диапазон терялся бы, а следом его затирал дефолт.
16475
+ // Восстанавливаем эффектом, а не начальным стейтом: `RangeNumberInput` на монтировании затирает
16476
+ // своё внутреннее значение границами календаря и подхватывает диапазон только по изменению
16477
+ // пропа `value`.
16478
+ React.useEffect(() => {
16479
+ if (isRestored.current)
16480
+ return;
16481
+ isRestored.current = true;
16482
+ const from = getDate(filters[filterName]?.min)?.toISOString();
16483
+ const to = getDate(filters[filterName]?.max)?.toISOString();
16484
+ if (lodash.isNil(from) && lodash.isNil(to))
16485
+ return;
16486
+ // Выбор уже сделан — дефолт применять нельзя, иначе перемонтирование затирало бы его.
16487
+ isDefaultApplied.current = true;
16488
+ setValue([from, to]);
16489
+ }, [filterName, filters]);
16467
16490
  // Дефолт применяем однократно — как только обе границы диапазона известны. С `defaultValue`
16468
16491
  // это происходит сразу, без него — после подгрузки фич связанного источника данных.
16469
16492
  React.useEffect(() => {
@@ -18209,29 +18232,14 @@ const VectorLayer = ({ layer, tileUrl, visible, beforeId, getLayerTempStyle, })
18209
18232
  : clientStyle, [clientStyle, getLayerTempStyle, layer.name]);
18210
18233
  const idAttribute = layerConfiguration?.attributesConfiguration?.idAttribute;
18211
18234
  const tiles = React.useMemo(() => [tileUrl], [tileUrl]);
18212
- // Собираем конфигурации иконок для загрузки из clientStyle
18213
18235
  const iconConfigs = React.useMemo(() => {
18214
18236
  if (!currentStyle?.items) {
18215
18237
  return [];
18216
18238
  }
18217
- const iconNames = parseIconNamesFromClientStyle(currentStyle);
18218
- if (iconNames.length === 0) {
18219
- return [];
18220
- }
18221
- return iconNames.map(name => {
18222
- const customIcon = currentStyle.icons?.find((icon) => icon.name === name);
18223
- if (customIcon) {
18224
- return {
18225
- name: customIcon.name,
18226
- url: customIcon.url,
18227
- sdf: customIcon.sdf,
18228
- size: customIcon.size,
18229
- pixelRatio: customIcon.pixelRatio,
18230
- };
18231
- }
18232
- // Fallback - иконка не найдена в конфиге, пропускаем
18233
- return null;
18234
- }).filter((config) => config !== null);
18239
+ return parseIconNamesFromClientStyle(currentStyle).reduce((acc, curr) => {
18240
+ const icon = currentStyle.icons?.find((icon) => icon.name === curr);
18241
+ return icon ? [...acc, icon] : acc;
18242
+ }, []);
18235
18243
  }, [currentStyle]);
18236
18244
  useMapImages({ images: iconConfigs });
18237
18245
  const renderClientStyle = React.useCallback(() => {