@evergis/react 4.0.138 → 4.0.140
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/components/Dashboard/containers/VoteContainer/styled.d.ts +2 -1
- package/dist/hooks/map/index.d.ts +0 -1
- package/dist/index.js +248 -295
- package/dist/index.js.map +1 -1
- package/dist/react.esm.js +250 -296
- package/dist/react.esm.js.map +1 -1
- package/package.json +2 -2
|
@@ -23,7 +23,8 @@ export declare const VoteVariantHead: import('styled-components').StyledComponen
|
|
|
23
23
|
export declare const VoteVariantText: import('styled-components').StyledComponent<"span", any, {}, never>;
|
|
24
24
|
export declare const VoteVariantCount: import('styled-components').StyledComponent<"span", any, {}, never>;
|
|
25
25
|
export declare const VoteAcceptedBadge: import('styled-components').StyledComponent<"div", any, import('@evergis/uilib-gl').FlexProps, never>;
|
|
26
|
-
|
|
26
|
+
/** Мелкая серая подпись под контролами: почему нельзя голосовать или почему кнопка неактивна. */
|
|
27
|
+
export declare const VoteHint: import('styled-components').StyledComponent<"div", any, {}, never>;
|
|
27
28
|
export declare const VoteEditLink: import('styled-components').StyledComponent<"button", any, {}, never>;
|
|
28
29
|
export declare const VoteShareBlock: import('styled-components').StyledComponent<"div", any, import('@evergis/uilib-gl').FlexProps, never>;
|
|
29
30
|
export declare const VoteShareChips: import('styled-components').StyledComponent<"div", any, import('@evergis/uilib-gl').FlexProps, never>;
|
package/dist/index.js
CHANGED
|
@@ -6355,300 +6355,23 @@ const useMapImages = ({ images }) => {
|
|
|
6355
6355
|
};
|
|
6356
6356
|
void loadAllImages();
|
|
6357
6357
|
}, [mapLoaded, images, map, addImage]);
|
|
6358
|
-
|
|
6359
|
-
|
|
6360
|
-
|
|
6361
|
-
const enrichStyleItemsWithIds = (style) => {
|
|
6362
|
-
return {
|
|
6363
|
-
...style,
|
|
6364
|
-
items: style.items.map(item => {
|
|
6365
|
-
return {
|
|
6366
|
-
...item,
|
|
6367
|
-
id: item.id || uuid.v4(),
|
|
6368
|
-
};
|
|
6369
|
-
}),
|
|
6370
|
-
};
|
|
6371
|
-
};
|
|
6372
|
-
|
|
6373
|
-
const enrichStyleModelsWithIds = (style) => {
|
|
6374
|
-
return {
|
|
6375
|
-
...style,
|
|
6376
|
-
models: style.models.map(model => {
|
|
6377
|
-
return {
|
|
6378
|
-
...model,
|
|
6379
|
-
id: model.id || uuid.v4(),
|
|
6380
|
-
};
|
|
6381
|
-
}),
|
|
6382
|
-
};
|
|
6383
|
-
};
|
|
6384
|
-
|
|
6385
|
-
const findAttributeInExpression = (expression) => {
|
|
6386
|
-
if (Array.isArray(expression) && expression.length === 2 && expression[0] === "get") {
|
|
6387
|
-
return [expression[1]];
|
|
6388
|
-
}
|
|
6389
|
-
return expression.reduce((acc, curr) => {
|
|
6390
|
-
if (!Array.isArray(curr)) {
|
|
6391
|
-
return acc;
|
|
6392
|
-
}
|
|
6393
|
-
if (curr[0] === "get") {
|
|
6394
|
-
return [...new Set([...acc, curr[1]])];
|
|
6395
|
-
}
|
|
6396
|
-
return [...new Set([...acc, ...findAttributeInExpression(curr)])];
|
|
6397
|
-
}, []);
|
|
6398
|
-
};
|
|
6399
|
-
|
|
6400
|
-
const getActualExtrusionHeight = (paint) => {
|
|
6401
|
-
return Array.isArray(paint?.["fill-extrusion-height"]) && paint?.["fill-extrusion-height"][0] === "+"
|
|
6402
|
-
? paint?.["fill-extrusion-height"][1]
|
|
6403
|
-
: paint?.["fill-extrusion-height"];
|
|
6404
|
-
};
|
|
6405
|
-
|
|
6406
|
-
const getLayerClientStyle = (layer) => {
|
|
6407
|
-
const clientStyle = layer?.configuration?.clientStyle;
|
|
6408
|
-
return {
|
|
6409
|
-
...clientStyle,
|
|
6410
|
-
items: clientStyle?.items ?? [],
|
|
6411
|
-
};
|
|
6412
|
-
};
|
|
6413
|
-
|
|
6414
|
-
const extractAttributesFromObject = (obj) => {
|
|
6415
|
-
if (!obj || lodash.isEmpty(obj)) {
|
|
6416
|
-
return [];
|
|
6417
|
-
}
|
|
6418
|
-
return Object.entries(obj).reduce((acc, [, value]) => {
|
|
6419
|
-
if (!Array.isArray(value)) {
|
|
6420
|
-
return acc;
|
|
6358
|
+
React.useEffect(() => {
|
|
6359
|
+
if (!mapLoaded) {
|
|
6360
|
+
return;
|
|
6421
6361
|
}
|
|
6422
|
-
|
|
6423
|
-
|
|
6424
|
-
|
|
6425
|
-
|
|
6426
|
-
|
|
6427
|
-
return [];
|
|
6428
|
-
}
|
|
6429
|
-
return style?.items?.reduce((acc, curr) => {
|
|
6430
|
-
const paintAttributes = extractAttributesFromObject(curr.paint);
|
|
6431
|
-
const layoutAttributes = extractAttributesFromObject(curr.layout);
|
|
6432
|
-
const filterAttributes = curr.filter
|
|
6433
|
-
? findAttributeInExpression(curr.filter)
|
|
6434
|
-
: [];
|
|
6435
|
-
return [...new Set([...acc, ...paintAttributes, ...layoutAttributes, ...filterAttributes])];
|
|
6436
|
-
}, []);
|
|
6437
|
-
};
|
|
6438
|
-
|
|
6439
|
-
/**
|
|
6440
|
-
* Извлекает имена иконок из выражения icon-image.
|
|
6441
|
-
*
|
|
6442
|
-
* Поддерживает:
|
|
6443
|
-
* - Строки: "parking" → ["parking"]
|
|
6444
|
-
* - match: ["match", ["get", "type"], "a", "icon-a", "b", "icon-b", "default"] → ["icon-a", "icon-b", "default"]
|
|
6445
|
-
* - case: ["case", [...], "icon-a", "icon-b"] → ["icon-a", "icon-b"]
|
|
6446
|
-
* - coalesce: ["coalesce", ["image", "icon-a"], ["image", "icon-b"]] → ["icon-a", "icon-b"]
|
|
6447
|
-
* - image: ["image", "icon-a"] → ["icon-a"]
|
|
6448
|
-
*
|
|
6449
|
-
* @param iconImage - значение icon-image из layout
|
|
6450
|
-
* @returns массив имён иконок
|
|
6451
|
-
*/
|
|
6452
|
-
const parseIconNames = (iconImage) => {
|
|
6453
|
-
if (!iconImage) {
|
|
6454
|
-
return [];
|
|
6455
|
-
}
|
|
6456
|
-
// Простая строка: "parking"
|
|
6457
|
-
if (typeof iconImage === "string") {
|
|
6458
|
-
return [iconImage];
|
|
6459
|
-
}
|
|
6460
|
-
// Выражение Mapbox
|
|
6461
|
-
if (Array.isArray(iconImage) && iconImage.length > 0) {
|
|
6462
|
-
const [operator, ...args] = iconImage;
|
|
6463
|
-
switch (operator) {
|
|
6464
|
-
// ["match", input, label1, output1, label2, output2, ..., fallback]
|
|
6465
|
-
case "match": {
|
|
6466
|
-
const results = [];
|
|
6467
|
-
// Пропускаем первый аргумент (input), берём каждый второй начиная с индекса 2
|
|
6468
|
-
for (let i = 2; i < args.length; i += 2) {
|
|
6469
|
-
if (typeof args[i] === "string") {
|
|
6470
|
-
results.push(args[i]);
|
|
6471
|
-
}
|
|
6472
|
-
else if (Array.isArray(args[i])) {
|
|
6473
|
-
results.push(...parseIconNames(args[i]));
|
|
6474
|
-
}
|
|
6475
|
-
}
|
|
6476
|
-
// Последний аргумент - fallback (если нечётное количество после input)
|
|
6477
|
-
const lastArg = args[args.length - 1];
|
|
6478
|
-
if (typeof lastArg === "string") {
|
|
6479
|
-
results.push(lastArg);
|
|
6480
|
-
}
|
|
6481
|
-
else if (Array.isArray(lastArg)) {
|
|
6482
|
-
results.push(...parseIconNames(lastArg));
|
|
6483
|
-
}
|
|
6484
|
-
return [...new Set(results)];
|
|
6485
|
-
}
|
|
6486
|
-
// ["case", condition1, output1, condition2, output2, ..., fallback]
|
|
6487
|
-
case "case": {
|
|
6488
|
-
const results = [];
|
|
6489
|
-
for (let i = 1; i < args.length; i += 2) {
|
|
6490
|
-
if (typeof args[i] === "string") {
|
|
6491
|
-
results.push(args[i]);
|
|
6492
|
-
}
|
|
6493
|
-
else if (Array.isArray(args[i])) {
|
|
6494
|
-
results.push(...parseIconNames(args[i]));
|
|
6495
|
-
}
|
|
6362
|
+
map.current.on("styleimagemissing", async (e) => {
|
|
6363
|
+
const missingImage = images.find(item => item.name === e.id);
|
|
6364
|
+
if (missingImage && !map.current.hasImage(e.id)) {
|
|
6365
|
+
try {
|
|
6366
|
+
await addImage(missingImage);
|
|
6496
6367
|
}
|
|
6497
|
-
|
|
6498
|
-
|
|
6499
|
-
const lastArg = args[args.length - 1];
|
|
6500
|
-
if (typeof lastArg === "string") {
|
|
6501
|
-
results.push(lastArg);
|
|
6502
|
-
}
|
|
6503
|
-
else if (Array.isArray(lastArg)) {
|
|
6504
|
-
results.push(...parseIconNames(lastArg));
|
|
6505
|
-
}
|
|
6368
|
+
catch {
|
|
6369
|
+
// Ошибка уже записана в errors
|
|
6506
6370
|
}
|
|
6507
|
-
return [...new Set(results)];
|
|
6508
|
-
}
|
|
6509
|
-
// ["coalesce", expr1, expr2, ...]
|
|
6510
|
-
case "coalesce": {
|
|
6511
|
-
const results = [];
|
|
6512
|
-
args.forEach(arg => {
|
|
6513
|
-
if (typeof arg === "string") {
|
|
6514
|
-
results.push(arg);
|
|
6515
|
-
}
|
|
6516
|
-
else if (Array.isArray(arg)) {
|
|
6517
|
-
results.push(...parseIconNames(arg));
|
|
6518
|
-
}
|
|
6519
|
-
});
|
|
6520
|
-
return [...new Set(results)];
|
|
6521
|
-
}
|
|
6522
|
-
// ["image", name] или ["image", name1, name2, ...]
|
|
6523
|
-
case "image": {
|
|
6524
|
-
return args.filter((arg) => typeof arg === "string");
|
|
6525
|
-
}
|
|
6526
|
-
// ["concat", ...] или другие - рекурсивно ищем строки
|
|
6527
|
-
default: {
|
|
6528
|
-
const results = [];
|
|
6529
|
-
args.forEach(arg => {
|
|
6530
|
-
if (Array.isArray(arg)) {
|
|
6531
|
-
results.push(...parseIconNames(arg));
|
|
6532
|
-
}
|
|
6533
|
-
});
|
|
6534
|
-
return [...new Set(results)];
|
|
6535
|
-
}
|
|
6536
|
-
}
|
|
6537
|
-
}
|
|
6538
|
-
return [];
|
|
6539
|
-
};
|
|
6540
|
-
/**
|
|
6541
|
-
* Свойства, содержащие имена изображений (иконки и паттерны).
|
|
6542
|
-
*/
|
|
6543
|
-
const IMAGE_PROPERTIES = {
|
|
6544
|
-
layout: ["icon-image"],
|
|
6545
|
-
paint: ["fill-pattern", "line-pattern", "fill-extrusion-pattern"],
|
|
6546
|
-
};
|
|
6547
|
-
/**
|
|
6548
|
-
* Извлекает все имена изображений из clientStyle.
|
|
6549
|
-
* Включает иконки (icon-image) и паттерны (fill-pattern, line-pattern, fill-extrusion-pattern).
|
|
6550
|
-
*
|
|
6551
|
-
* @param clientStyle - конфигурация стиля слоя
|
|
6552
|
-
* @returns массив уникальных имён изображений
|
|
6553
|
-
*/
|
|
6554
|
-
const parseIconNamesFromClientStyle = (clientStyle) => {
|
|
6555
|
-
if (!clientStyle?.items) {
|
|
6556
|
-
return [];
|
|
6557
|
-
}
|
|
6558
|
-
const imageNames = new Set();
|
|
6559
|
-
clientStyle.items.forEach(item => {
|
|
6560
|
-
// Парсим icon-image из layout
|
|
6561
|
-
IMAGE_PROPERTIES.layout.forEach(prop => {
|
|
6562
|
-
const value = item.layout?.[prop];
|
|
6563
|
-
if (value) {
|
|
6564
|
-
parseIconNames(value).forEach(name => imageNames.add(name));
|
|
6565
|
-
}
|
|
6566
|
-
});
|
|
6567
|
-
// Парсим fill-pattern, line-pattern, fill-extrusion-pattern из paint
|
|
6568
|
-
IMAGE_PROPERTIES.paint.forEach(prop => {
|
|
6569
|
-
const value = item.paint?.[prop];
|
|
6570
|
-
if (value) {
|
|
6571
|
-
parseIconNames(value).forEach(name => imageNames.add(name));
|
|
6572
|
-
}
|
|
6573
|
-
});
|
|
6574
|
-
});
|
|
6575
|
-
return [...imageNames];
|
|
6576
|
-
};
|
|
6577
|
-
|
|
6578
|
-
/**
|
|
6579
|
-
* Находит конфигурацию иконки в clientStyle.icons по имени.
|
|
6580
|
-
*/
|
|
6581
|
-
const findIconConfig = (layers, iconName) => {
|
|
6582
|
-
for (const layer of layers) {
|
|
6583
|
-
const icon = layer.clientStyle?.icons?.find(i => i.name === iconName);
|
|
6584
|
-
if (icon) {
|
|
6585
|
-
return icon;
|
|
6586
|
-
}
|
|
6587
|
-
}
|
|
6588
|
-
return undefined;
|
|
6589
|
-
};
|
|
6590
|
-
/**
|
|
6591
|
-
* Хук для автоматической загрузки иконок из clientStyle слоёв.
|
|
6592
|
-
*
|
|
6593
|
-
* Парсит все icon-image выражения из clientStyle.items и загружает
|
|
6594
|
-
* соответствующие иконки из clientStyle.icons или по конвенции baseUrl.
|
|
6595
|
-
*
|
|
6596
|
-
* @example
|
|
6597
|
-
* ```tsx
|
|
6598
|
-
* const layers = [
|
|
6599
|
-
* {
|
|
6600
|
-
* layerId: 'parking',
|
|
6601
|
-
* clientStyle: {
|
|
6602
|
-
* icons: [
|
|
6603
|
-
* { name: 'parking-icon', url: '/icons/parking.svg', sdf: true }
|
|
6604
|
-
* ],
|
|
6605
|
-
* items: [{
|
|
6606
|
-
* type: 'symbol',
|
|
6607
|
-
* layout: { 'icon-image': 'parking-icon' }
|
|
6608
|
-
* }]
|
|
6609
|
-
* }
|
|
6610
|
-
* }
|
|
6611
|
-
* ];
|
|
6612
|
-
*
|
|
6613
|
-
* const { loaded, errors } = useIconsFromLayers({ layers });
|
|
6614
|
-
*
|
|
6615
|
-
* if (!loaded) return <Loading />;
|
|
6616
|
-
* ```
|
|
6617
|
-
*/
|
|
6618
|
-
const useIconsFromLayers = ({ layers, baseUrl = "/icons", defaultExtension = "svg", }) => {
|
|
6619
|
-
// Собираем все уникальные имена иконок из всех слоёв
|
|
6620
|
-
const requestedIcons = React.useMemo(() => {
|
|
6621
|
-
const iconNames = new Set();
|
|
6622
|
-
layers.forEach(layer => {
|
|
6623
|
-
const names = parseIconNamesFromClientStyle(layer.clientStyle);
|
|
6624
|
-
names.forEach(name => iconNames.add(name));
|
|
6625
|
-
});
|
|
6626
|
-
return [...iconNames];
|
|
6627
|
-
}, [layers]);
|
|
6628
|
-
// Формируем конфигурации для загрузки
|
|
6629
|
-
const imageConfigs = React.useMemo(() => {
|
|
6630
|
-
return requestedIcons.map(name => {
|
|
6631
|
-
// Ищем в clientStyle.icons
|
|
6632
|
-
const customIcon = findIconConfig(layers, name);
|
|
6633
|
-
if (customIcon) {
|
|
6634
|
-
return {
|
|
6635
|
-
name: customIcon.name,
|
|
6636
|
-
url: customIcon.url,
|
|
6637
|
-
sdf: customIcon.sdf,
|
|
6638
|
-
size: customIcon.size,
|
|
6639
|
-
pixelRatio: customIcon.pixelRatio,
|
|
6640
|
-
};
|
|
6641
6371
|
}
|
|
6642
|
-
// Fallback: конструируем URL по конвенции
|
|
6643
|
-
return {
|
|
6644
|
-
name,
|
|
6645
|
-
url: `${baseUrl}/${name}.${defaultExtension}`,
|
|
6646
|
-
sdf: true,
|
|
6647
|
-
};
|
|
6648
6372
|
});
|
|
6649
|
-
}, [
|
|
6650
|
-
|
|
6651
|
-
return { loaded, errors, requestedIcons };
|
|
6373
|
+
}, [mapLoaded]);
|
|
6374
|
+
return { loaded, errors, addImage, removeImage, hasImage };
|
|
6652
6375
|
};
|
|
6653
6376
|
|
|
6654
6377
|
const useRedrawLayer = () => {
|
|
@@ -12185,7 +11908,8 @@ const VoteAcceptedBadge = styled(uilibGl.Flex).withConfig({ displayName: "VoteAc
|
|
|
12185
11908
|
color: #ffffff;
|
|
12186
11909
|
font-size: 0.875rem;
|
|
12187
11910
|
`;
|
|
12188
|
-
|
|
11911
|
+
/** Мелкая серая подпись под контролами: почему нельзя голосовать или почему кнопка неактивна. */
|
|
11912
|
+
const VoteHint = styled.div.withConfig({ displayName: "VoteHint", componentId: "sc-1ortkdd" }) `
|
|
12189
11913
|
font-size: 0.8125rem;
|
|
12190
11914
|
color: ${({ theme: { palette } }) => palette.textSecondary};
|
|
12191
11915
|
`;
|
|
@@ -12287,8 +12011,18 @@ const useVoteForm = (initialValues) => {
|
|
|
12287
12011
|
const removeVariant = React.useCallback((index) => {
|
|
12288
12012
|
setVariants(prev => prev.filter((_, itemIndex) => itemIndex !== index));
|
|
12289
12013
|
}, []);
|
|
12290
|
-
|
|
12291
|
-
|
|
12014
|
+
/**
|
|
12015
|
+
* Варианты вместе с недобавленным черновиком.
|
|
12016
|
+
*
|
|
12017
|
+
* Последний вариант часто набирают и жмут «Создать», не нажав Enter: чипсом он ещё не стал, но
|
|
12018
|
+
* пользователь его уже ввёл. Считать такой текст вариантом честнее, чем гасить кнопку и молчать.
|
|
12019
|
+
*/
|
|
12020
|
+
const allVariants = React.useMemo(() => {
|
|
12021
|
+
const pending = draft.trim();
|
|
12022
|
+
return pending ? [...variants, { text: pending }] : variants;
|
|
12023
|
+
}, [variants, draft]);
|
|
12024
|
+
const isValid = React.useMemo(() => Boolean(categoryId && text.trim() && allVariants.length >= MIN_VARIANTS), [categoryId, text, allVariants.length]);
|
|
12025
|
+
const values = React.useMemo(() => ({ categoryId, text: text.trim(), multiSelect, variants: allVariants }), [categoryId, text, multiSelect, allVariants]);
|
|
12292
12026
|
return {
|
|
12293
12027
|
categoryId,
|
|
12294
12028
|
setCategoryId,
|
|
@@ -12318,7 +12052,10 @@ const VoteCreateForm = ({ categories, initialValues, isEditing, canDelete, submi
|
|
|
12318
12052
|
}
|
|
12319
12053
|
} }), jsxRuntime.jsxs(uilibGl.Flex, { alignItems: "center", justifyContent: "space-between", children: [jsxRuntime.jsx(VoteSectionLabel, { children: t("vote.multiSelect", { ns: VOTE_NS, defaultValue: "Множественный выбор" }) }), jsxRuntime.jsx(uilibGl.Switch, { checked: multiSelect, onChange: () => setMultiSelect(prev => !prev) })] }), jsxRuntime.jsx(uilibGl.RaisedButton, { primary: true, disabled: !isValid || submitting, onClick: () => onSubmit(values), children: isEditing
|
|
12320
12054
|
? t("vote.save", { ns: VOTE_NS, defaultValue: "Сохранить" })
|
|
12321
|
-
: t("vote.create", { ns: VOTE_NS, defaultValue: "Создать голосование" }) }),
|
|
12055
|
+
: t("vote.create", { ns: VOTE_NS, defaultValue: "Создать голосование" }) }), !isValid && (jsxRuntime.jsx(VoteHint, { children: t("vote.formHint", {
|
|
12056
|
+
ns: VOTE_NS,
|
|
12057
|
+
defaultValue: "Нужны категория, вопрос и минимум два варианта ответа",
|
|
12058
|
+
}) })), isEditing && (jsxRuntime.jsxs(uilibGl.Flex, { alignItems: "center", justifyContent: "space-between", children: [onCancel && (jsxRuntime.jsx(VoteEditLink, { onClick: onCancel, children: t("vote.cancel", { ns: VOTE_NS, defaultValue: "Отмена" }) })), canDelete && onDelete && (jsxRuntime.jsx(uilibGl.RaisedButton, { error: true, disabled: submitting, onClick: onDelete, children: t("vote.delete", { ns: VOTE_NS, defaultValue: "Удалить голосование" }) }))] }))] }));
|
|
12322
12059
|
};
|
|
12323
12060
|
|
|
12324
12061
|
/** Блок «Поделиться в соцсетях» — пока только вёрстка, без рабочих ссылок. */
|
|
@@ -12342,7 +12079,7 @@ const VoteResults = ({ question, category, results, screen, isOwner, hasAnswers,
|
|
|
12342
12079
|
}, [question.multiSelect]);
|
|
12343
12080
|
const canSubmit = React.useMemo(() => selected.length > 0 && !submitting, [selected.length, submitting]);
|
|
12344
12081
|
return (jsxRuntime.jsxs(VoteWrapper, { children: [category && jsxRuntime.jsx(VoteCategoryLabel, { children: category.name }), jsxRuntime.jsx(VoteQuestionText, { children: question.text }), jsxRuntime.jsx(VoteVariantList, { column: true, value: selected[0] ?? "", children: results.map(({ id, text, count, percent }) => (jsxRuntime.jsxs(VoteVariantRow, { children: [jsxRuntime.jsxs(VoteVariantHead, { children: [showControls &&
|
|
12345
|
-
(question.multiSelect ? (jsxRuntime.jsx(uilibGl.Checkbox, { checked: selected.includes(id), onChange: () => toggle(id) })) : (jsxRuntime.jsx(uilibGl.Radio, { value: id, checked: selected.includes(id), onChange: () => toggle(id) }))), jsxRuntime.jsx(VoteVariantText, { children: text }), jsxRuntime.jsx(VoteVariantCount, { children: count })] }), jsxRuntime.jsx(uilibGl.LinearProgress, { done: percent })] }, id))) }), screen === "unauthenticated" && (jsxRuntime.jsx(
|
|
12082
|
+
(question.multiSelect ? (jsxRuntime.jsx(uilibGl.Checkbox, { checked: selected.includes(id), onChange: () => toggle(id) })) : (jsxRuntime.jsx(uilibGl.Radio, { value: id, checked: selected.includes(id), onChange: () => toggle(id) }))), jsxRuntime.jsx(VoteVariantText, { children: text }), jsxRuntime.jsx(VoteVariantCount, { children: count })] }), jsxRuntime.jsx(uilibGl.LinearProgress, { done: percent })] }, id))) }), screen === "unauthenticated" && (jsxRuntime.jsx(VoteHint, { children: t("vote.authHint", { ns: VOTE_NS, defaultValue: "Чтобы проголосовать, пожалуйста, авторизуйтесь" }) })), screen === "voted" && (jsxRuntime.jsxs(VoteAcceptedBadge, { children: [jsxRuntime.jsx(uilibGl.Icon, { kind: "success" }), t("vote.accepted", { ns: VOTE_NS, defaultValue: "Ваш ответ принят" })] })), showControls && (jsxRuntime.jsx(uilibGl.RaisedButton, { primary: true, disabled: !canSubmit, onClick: () => onSubmit(selected), children: t("vote.submit", { ns: VOTE_NS, defaultValue: "Отправить ответ" }) })), canEdit && onEdit && (jsxRuntime.jsx(uilibGl.Flex, { children: jsxRuntime.jsx(VoteEditLink, { onClick: onEdit, children: t("vote.edit", { ns: VOTE_NS, defaultValue: "Редактировать" }) }) })), showShare && jsxRuntime.jsx(VoteShare, {})] }));
|
|
12346
12083
|
};
|
|
12347
12084
|
|
|
12348
12085
|
/**
|
|
@@ -19021,6 +18758,223 @@ const RasterLayer = ({ layer, tileUrl, visible, beforeId, }) => {
|
|
|
19021
18758
|
return (jsxRuntime.jsx(MapGL.Source, { id: layer.name, type: "raster", tiles: tiles, children: jsxRuntime.jsx(MapGL.Layer, { id: layer.name, type: "raster", "source-layer": "default", beforeId: beforeId, layout: { visibility: visible ? "visible" : "none" } }) }, `${layer.name}-${tileUrl}`));
|
|
19022
18759
|
};
|
|
19023
18760
|
|
|
18761
|
+
const enrichStyleItemsWithIds = (style) => {
|
|
18762
|
+
return {
|
|
18763
|
+
...style,
|
|
18764
|
+
items: style.items.map(item => {
|
|
18765
|
+
return {
|
|
18766
|
+
...item,
|
|
18767
|
+
id: item.id || uuid.v4(),
|
|
18768
|
+
};
|
|
18769
|
+
}),
|
|
18770
|
+
};
|
|
18771
|
+
};
|
|
18772
|
+
|
|
18773
|
+
const enrichStyleModelsWithIds = (style) => {
|
|
18774
|
+
return {
|
|
18775
|
+
...style,
|
|
18776
|
+
models: style.models.map(model => {
|
|
18777
|
+
return {
|
|
18778
|
+
...model,
|
|
18779
|
+
id: model.id || uuid.v4(),
|
|
18780
|
+
};
|
|
18781
|
+
}),
|
|
18782
|
+
};
|
|
18783
|
+
};
|
|
18784
|
+
|
|
18785
|
+
const findAttributeInExpression = (expression) => {
|
|
18786
|
+
if (Array.isArray(expression) && expression.length === 2 && expression[0] === "get") {
|
|
18787
|
+
return [expression[1]];
|
|
18788
|
+
}
|
|
18789
|
+
return expression.reduce((acc, curr) => {
|
|
18790
|
+
if (!Array.isArray(curr)) {
|
|
18791
|
+
return acc;
|
|
18792
|
+
}
|
|
18793
|
+
if (curr[0] === "get") {
|
|
18794
|
+
return [...new Set([...acc, curr[1]])];
|
|
18795
|
+
}
|
|
18796
|
+
return [...new Set([...acc, ...findAttributeInExpression(curr)])];
|
|
18797
|
+
}, []);
|
|
18798
|
+
};
|
|
18799
|
+
|
|
18800
|
+
const getActualExtrusionHeight = (paint) => {
|
|
18801
|
+
return Array.isArray(paint?.["fill-extrusion-height"]) && paint?.["fill-extrusion-height"][0] === "+"
|
|
18802
|
+
? paint?.["fill-extrusion-height"][1]
|
|
18803
|
+
: paint?.["fill-extrusion-height"];
|
|
18804
|
+
};
|
|
18805
|
+
|
|
18806
|
+
const getLayerClientStyle = (layer) => {
|
|
18807
|
+
const clientStyle = layer?.configuration?.clientStyle;
|
|
18808
|
+
return {
|
|
18809
|
+
...clientStyle,
|
|
18810
|
+
items: clientStyle?.items ?? [],
|
|
18811
|
+
};
|
|
18812
|
+
};
|
|
18813
|
+
|
|
18814
|
+
const extractAttributesFromObject = (obj) => {
|
|
18815
|
+
if (!obj || lodash.isEmpty(obj)) {
|
|
18816
|
+
return [];
|
|
18817
|
+
}
|
|
18818
|
+
return Object.entries(obj).reduce((acc, [, value]) => {
|
|
18819
|
+
if (!Array.isArray(value)) {
|
|
18820
|
+
return acc;
|
|
18821
|
+
}
|
|
18822
|
+
return [...new Set([...acc, ...findAttributeInExpression(value)])];
|
|
18823
|
+
}, []);
|
|
18824
|
+
};
|
|
18825
|
+
const getStyleAttributes = (style) => {
|
|
18826
|
+
if (!style) {
|
|
18827
|
+
return [];
|
|
18828
|
+
}
|
|
18829
|
+
return style?.items?.reduce((acc, curr) => {
|
|
18830
|
+
const paintAttributes = extractAttributesFromObject(curr.paint);
|
|
18831
|
+
const layoutAttributes = extractAttributesFromObject(curr.layout);
|
|
18832
|
+
const filterAttributes = curr.filter
|
|
18833
|
+
? findAttributeInExpression(curr.filter)
|
|
18834
|
+
: [];
|
|
18835
|
+
return [...new Set([...acc, ...paintAttributes, ...layoutAttributes, ...filterAttributes])];
|
|
18836
|
+
}, []);
|
|
18837
|
+
};
|
|
18838
|
+
|
|
18839
|
+
/**
|
|
18840
|
+
* Извлекает имена иконок из выражения icon-image.
|
|
18841
|
+
*
|
|
18842
|
+
* Поддерживает:
|
|
18843
|
+
* - Строки: "parking" → ["parking"]
|
|
18844
|
+
* - match: ["match", ["get", "type"], "a", "icon-a", "b", "icon-b", "default"] → ["icon-a", "icon-b", "default"]
|
|
18845
|
+
* - case: ["case", [...], "icon-a", "icon-b"] → ["icon-a", "icon-b"]
|
|
18846
|
+
* - coalesce: ["coalesce", ["image", "icon-a"], ["image", "icon-b"]] → ["icon-a", "icon-b"]
|
|
18847
|
+
* - image: ["image", "icon-a"] → ["icon-a"]
|
|
18848
|
+
*
|
|
18849
|
+
* @param iconImage - значение icon-image из layout
|
|
18850
|
+
* @returns массив имён иконок
|
|
18851
|
+
*/
|
|
18852
|
+
const parseIconNames = (iconImage) => {
|
|
18853
|
+
if (!iconImage) {
|
|
18854
|
+
return [];
|
|
18855
|
+
}
|
|
18856
|
+
// Простая строка: "parking"
|
|
18857
|
+
if (typeof iconImage === "string") {
|
|
18858
|
+
return [iconImage];
|
|
18859
|
+
}
|
|
18860
|
+
// Выражение Mapbox
|
|
18861
|
+
if (Array.isArray(iconImage) && iconImage.length > 0) {
|
|
18862
|
+
const [operator, ...args] = iconImage;
|
|
18863
|
+
switch (operator) {
|
|
18864
|
+
// ["match", input, label1, output1, label2, output2, ..., fallback]
|
|
18865
|
+
case "match": {
|
|
18866
|
+
const results = [];
|
|
18867
|
+
// Пропускаем первый аргумент (input), берём каждый второй начиная с индекса 2
|
|
18868
|
+
for (let i = 2; i < args.length; i += 2) {
|
|
18869
|
+
if (typeof args[i] === "string") {
|
|
18870
|
+
results.push(args[i]);
|
|
18871
|
+
}
|
|
18872
|
+
else if (Array.isArray(args[i])) {
|
|
18873
|
+
results.push(...parseIconNames(args[i]));
|
|
18874
|
+
}
|
|
18875
|
+
}
|
|
18876
|
+
// Последний аргумент - fallback (если нечётное количество после input)
|
|
18877
|
+
const lastArg = args[args.length - 1];
|
|
18878
|
+
if (typeof lastArg === "string") {
|
|
18879
|
+
results.push(lastArg);
|
|
18880
|
+
}
|
|
18881
|
+
else if (Array.isArray(lastArg)) {
|
|
18882
|
+
results.push(...parseIconNames(lastArg));
|
|
18883
|
+
}
|
|
18884
|
+
return [...new Set(results)];
|
|
18885
|
+
}
|
|
18886
|
+
// ["case", condition1, output1, condition2, output2, ..., fallback]
|
|
18887
|
+
case "case": {
|
|
18888
|
+
const results = [];
|
|
18889
|
+
for (let i = 1; i < args.length; i += 2) {
|
|
18890
|
+
if (typeof args[i] === "string") {
|
|
18891
|
+
results.push(args[i]);
|
|
18892
|
+
}
|
|
18893
|
+
else if (Array.isArray(args[i])) {
|
|
18894
|
+
results.push(...parseIconNames(args[i]));
|
|
18895
|
+
}
|
|
18896
|
+
}
|
|
18897
|
+
// Fallback
|
|
18898
|
+
if (args.length % 2 === 0) {
|
|
18899
|
+
const lastArg = args[args.length - 1];
|
|
18900
|
+
if (typeof lastArg === "string") {
|
|
18901
|
+
results.push(lastArg);
|
|
18902
|
+
}
|
|
18903
|
+
else if (Array.isArray(lastArg)) {
|
|
18904
|
+
results.push(...parseIconNames(lastArg));
|
|
18905
|
+
}
|
|
18906
|
+
}
|
|
18907
|
+
return [...new Set(results)];
|
|
18908
|
+
}
|
|
18909
|
+
// ["coalesce", expr1, expr2, ...]
|
|
18910
|
+
case "coalesce": {
|
|
18911
|
+
const results = [];
|
|
18912
|
+
args.forEach(arg => {
|
|
18913
|
+
if (typeof arg === "string") {
|
|
18914
|
+
results.push(arg);
|
|
18915
|
+
}
|
|
18916
|
+
else if (Array.isArray(arg)) {
|
|
18917
|
+
results.push(...parseIconNames(arg));
|
|
18918
|
+
}
|
|
18919
|
+
});
|
|
18920
|
+
return [...new Set(results)];
|
|
18921
|
+
}
|
|
18922
|
+
// ["image", name] или ["image", name1, name2, ...]
|
|
18923
|
+
case "image": {
|
|
18924
|
+
return args.filter((arg) => typeof arg === "string");
|
|
18925
|
+
}
|
|
18926
|
+
// ["concat", ...] или другие - рекурсивно ищем строки
|
|
18927
|
+
default: {
|
|
18928
|
+
const results = [];
|
|
18929
|
+
args.forEach(arg => {
|
|
18930
|
+
if (Array.isArray(arg)) {
|
|
18931
|
+
results.push(...parseIconNames(arg));
|
|
18932
|
+
}
|
|
18933
|
+
});
|
|
18934
|
+
return [...new Set(results)];
|
|
18935
|
+
}
|
|
18936
|
+
}
|
|
18937
|
+
}
|
|
18938
|
+
return [];
|
|
18939
|
+
};
|
|
18940
|
+
/**
|
|
18941
|
+
* Свойства, содержащие имена изображений (иконки и паттерны).
|
|
18942
|
+
*/
|
|
18943
|
+
const IMAGE_PROPERTIES = {
|
|
18944
|
+
layout: ["icon-image"],
|
|
18945
|
+
paint: ["fill-pattern", "line-pattern", "fill-extrusion-pattern"],
|
|
18946
|
+
};
|
|
18947
|
+
/**
|
|
18948
|
+
* Извлекает все имена изображений из clientStyle.
|
|
18949
|
+
* Включает иконки (icon-image) и паттерны (fill-pattern, line-pattern, fill-extrusion-pattern).
|
|
18950
|
+
*
|
|
18951
|
+
* @param clientStyle - конфигурация стиля слоя
|
|
18952
|
+
* @returns массив уникальных имён изображений
|
|
18953
|
+
*/
|
|
18954
|
+
const parseIconNamesFromClientStyle = (clientStyle) => {
|
|
18955
|
+
if (!clientStyle?.items) {
|
|
18956
|
+
return [];
|
|
18957
|
+
}
|
|
18958
|
+
const imageNames = new Set();
|
|
18959
|
+
clientStyle.items.forEach(item => {
|
|
18960
|
+
// Парсим icon-image из layout
|
|
18961
|
+
IMAGE_PROPERTIES.layout.forEach(prop => {
|
|
18962
|
+
const value = item.layout?.[prop];
|
|
18963
|
+
if (value) {
|
|
18964
|
+
parseIconNames(value).forEach(name => imageNames.add(name));
|
|
18965
|
+
}
|
|
18966
|
+
});
|
|
18967
|
+
// Парсим fill-pattern, line-pattern, fill-extrusion-pattern из paint
|
|
18968
|
+
IMAGE_PROPERTIES.paint.forEach(prop => {
|
|
18969
|
+
const value = item.paint?.[prop];
|
|
18970
|
+
if (value) {
|
|
18971
|
+
parseIconNames(value).forEach(name => imageNames.add(name));
|
|
18972
|
+
}
|
|
18973
|
+
});
|
|
18974
|
+
});
|
|
18975
|
+
return [...imageNames];
|
|
18976
|
+
};
|
|
18977
|
+
|
|
19024
18978
|
const VectorLayer = ({ layer, tileUrl, visible, beforeId, getLayerTempStyle, }) => {
|
|
19025
18979
|
const layerConfiguration = layer?.configuration;
|
|
19026
18980
|
const clientStyle = layerConfiguration?.clientStyle;
|
|
@@ -19680,7 +19634,6 @@ exports.useGetConfigLayer = useGetConfigLayer;
|
|
|
19680
19634
|
exports.useGlobalContext = useGlobalContext;
|
|
19681
19635
|
exports.useHeaderRender = useHeaderRender;
|
|
19682
19636
|
exports.useHideIfEmptyDataSource = useHideIfEmptyDataSource;
|
|
19683
|
-
exports.useIconsFromLayers = useIconsFromLayers;
|
|
19684
19637
|
exports.useLayerHiddenAttributes = useLayerHiddenAttributes;
|
|
19685
19638
|
exports.useLayerParams = useLayerParams;
|
|
19686
19639
|
exports.useMapContext = useMapContext;
|