@evergis/react 4.0.167 → 4.0.168

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/react.esm.js CHANGED
@@ -5152,7 +5152,7 @@ const FeatureControls = styled(Flex).withConfig({ displayName: "FeatureControls"
5152
5152
  const FiltersContainerWrapper = styled(Flex).withConfig({ displayName: "FiltersContainerWrapper", componentId: "sc-1a6ru74" }) `
5153
5153
  flex-direction: column;
5154
5154
  padding: ${({ $padding }) => $padding ?? `${DEFAULT_FILTER_PADDING}px`};
5155
- background-color: ${({ $bgColor, $fontColor, theme: { palette } }) => $bgColor || ($fontColor ? transparentizeColor($fontColor, 6) : palette.element)};
5155
+ background: ${({ $bgColor, $fontColor, theme: { palette } }) => $bgColor || ($fontColor ? transparentizeColor($fontColor, 6) : palette.element)};
5156
5156
  border-radius: ${({ theme: { borderRadius } }) => borderRadius.medium};
5157
5157
 
5158
5158
  ${DropdownField}, input {
@@ -8946,7 +8946,7 @@ const POLL_SUBTASK_INTERVAL_MS = 500;
8946
8946
  const POLL_SUBTASK_TIMEOUT_MS = 15_000;
8947
8947
 
8948
8948
  const StatusBadge = styled(Chip).withConfig({ displayName: "StatusBadge", componentId: "sc-1xmfl10" }) `
8949
- background-color: ${({ bgColor }) => bgColor};
8949
+ background: ${({ bgColor }) => bgColor};
8950
8950
  color: ${({ theme }) => theme.palette.iconContrast};
8951
8951
  `;
8952
8952
 
@@ -11291,7 +11291,7 @@ const FilterChip = styled.div.withConfig({ displayName: "FilterChip", componentI
11291
11291
  padding: 0.3125rem 0.5rem;
11292
11292
  height: 1.5rem;
11293
11293
  border-radius: 0.25rem;
11294
- background-color: ${({ $isActive, $bgColor, theme }) => $bgColor
11294
+ background: ${({ $isActive, $bgColor, theme }) => $bgColor
11295
11295
  ? $bgColor
11296
11296
  : $isActive
11297
11297
  ? theme.palette?.primary
@@ -11311,7 +11311,7 @@ const FilterChip = styled.div.withConfig({ displayName: "FilterChip", componentI
11311
11311
  box-sizing: border-box;
11312
11312
 
11313
11313
  &:hover {
11314
- background-color: ${({ $isActive, $bgColor, theme }) => $isActive
11314
+ background: ${({ $isActive, $bgColor, theme }) => $isActive
11315
11315
  ? $bgColor || 'inherit'
11316
11316
  : $bgColor || theme.palette?.elementDark};
11317
11317
  }
@@ -14556,12 +14556,21 @@ const ContainerBackground = memo(({ elementConfig, renderElement }) => {
14556
14556
  return (jsx(ContainerBackgroundLayer, { "$outflow": elementConfig?.options?.outflow, children: renderElement({ id: BG_IMAGE_SLOT_ID, wrap: false }) }));
14557
14557
  });
14558
14558
 
14559
- const AddFeatureContainer = memo(({ elementConfig, renderElement }) => {
14559
+ /** Кнопка нативного действия контейнера со стандартными подстановками дочернего конфига. */
14560
+ const ContainerButton = memo(({ type = WidgetType.Dashboard, elementConfig, ...props }) => {
14561
+ const sources = useConfigStringSources(type);
14562
+ const node = useActionNode();
14563
+ const attributes = props.attributes ?? node.attributes ?? sources.attributes;
14564
+ const resolvedConfig = useMemo(() => resolveElementStrings(elementConfig, { ...sources, attributes }), [elementConfig, sources, attributes]);
14565
+ return jsx(ElementButton, { ...props, type: type, attributes: attributes, elementConfig: resolvedConfig });
14566
+ });
14567
+
14568
+ const AddFeatureContainer = memo(({ type, elementConfig, renderElement }) => {
14560
14569
  const { id, children, style } = elementConfig || {};
14561
14570
  const bgHost = useBgImageHost(elementConfig);
14562
- return (jsxs(Container, { id: id, style: style, ...bgHost, children: [jsx(ContainerBackground, { elementConfig: elementConfig, renderElement: renderElement }), children
14563
- .filter(({ type }) => type === "button")
14564
- .map(({ options }, index) => (jsx(AddFeatureButton, { icon: options?.icon, title: options?.title, layerName: options?.layerName, geometryType: options?.geometryType }, index)))] }));
14571
+ const handleAddFeature = useCallback(() => undefined, []);
14572
+ return (jsxs(Container, { id: id, style: style, ...bgHost, children: [jsx(ContainerBackground, { elementConfig: elementConfig, renderElement: renderElement }), children?.filter(({ type: childType }) => childType === "button")
14573
+ .map((button, index) => (jsx(ContainerButton, { type: type, elementConfig: button, onClick: handleAddFeature }, button.id ?? index)))] }));
14565
14574
  });
14566
14575
 
14567
14576
  /**
@@ -16495,7 +16504,7 @@ const RoundedBackgroundContainerWrapper = styled(Flex).withConfig({ displayName:
16495
16504
  * иначе фон тонируется цветом иконки, а без неё — цветом текста (colorAttribute/fontColor);
16496
16505
  * если не задан ни один цвет, остаётся токен темы.
16497
16506
  */
16498
- background-color: ${({ $bgColor, $iconColor, $color, theme: { palette } }) => $bgColor || tintedBackground($iconColor || $color) || palette.element};
16507
+ background: ${({ $bgColor, $iconColor, $color, theme: { palette } }) => $bgColor || tintedBackground($iconColor || $color) || palette.element};
16499
16508
  border-radius: ${({ theme: { borderRadius } }) => borderRadius.large};
16500
16509
  flex-wrap: nowrap;
16501
16510
 
@@ -16566,11 +16575,6 @@ const RoundedBackgroundContainerWrapper = styled(Flex).withConfig({ displayName:
16566
16575
  > * {
16567
16576
  text-align: left;
16568
16577
  }
16569
-
16570
- /* Зазор наружу даёт обёртка иконки, здесь — отступ внутри её бокса. */
16571
- span[kind] {
16572
- margin-right: 0.5rem;
16573
- }
16574
16578
 
16575
16579
  ${ContainerValue} {
16576
16580
  width: auto;
@@ -17284,7 +17288,7 @@ const TabContainer = styled.a.withConfig({ displayName: "TabContainer", componen
17284
17288
  justify-content: center;
17285
17289
  flex-wrap: nowrap;
17286
17290
  padding: ${({ onlyIcon }) => (onlyIcon ? 1 : 0.5)}rem 1rem;
17287
- background-color: ${({ active, bgColor, theme: { palette } }) => active ? bgColor || palette.primary : palette.element};
17291
+ background: ${({ active, bgColor, theme: { palette } }) => active ? bgColor || palette.primary : palette.element};
17288
17292
  border-radius: ${({ column, radius, theme: { borderRadius } }) => radius ? `${radius}px` : column ? borderRadius.medium : borderRadius.xLarge};
17289
17293
  text-decoration: none;
17290
17294
 
@@ -17750,22 +17754,22 @@ const useVoteForm = (initialValues) => {
17750
17754
  };
17751
17755
  };
17752
17756
 
17753
- const VoteCreateForm = ({ categories, initialValues, isEditing, canDelete, submitting, onSubmit, onDelete, onCancel, }) => {
17757
+ const VoteCreateForm = ({ type, buttonConfigs, categories, initialValues, isEditing, canDelete, submitting, onSubmit, onDelete, onCancel, }) => {
17754
17758
  const { t } = useGlobalContext();
17755
17759
  const form = useVoteForm(initialValues);
17756
17760
  const { categoryId, setCategoryId, text, setText, multiSelect, setMultiSelect, variants, addVariant, removeVariant, draft, setDraft, isValid, values, } = form;
17757
17761
  const categoryOptions = useMemo(() => categories.map(({ id, name }) => ({ text: name, value: id })), [categories]);
17762
+ const submitButton = useMemo(() => isEditing ? buttonConfigs.saveButton : buttonConfigs.createButton, [buttonConfigs, isEditing]);
17763
+ const handleSubmit = useCallback(() => onSubmit(values), [onSubmit, values]);
17758
17764
  return (jsxs(VoteWrapper, { children: [!isEditing && jsx(VoteHeading, { children: t("vote.newVote", { ns: VOTE_NS, defaultValue: "Новое голосование" }) }), jsx(Dropdown, { zIndex: 110000, label: t("vote.category", { ns: VOTE_NS, defaultValue: "Категория" }), width: "100%", placeholder: t("vote.categoryPlaceholder", { ns: VOTE_NS, defaultValue: "Выберите категорию" }), options: categoryOptions, value: categoryId, onChange: items => setCategoryId(String(items[0]?.value ?? "")) }), jsx(Input, { label: t("vote.question", { ns: VOTE_NS, defaultValue: "Вопрос" }), width: "100%", placeholder: t("vote.questionPlaceholder", { ns: VOTE_NS, defaultValue: "Текст вопроса" }), value: text, onChange: ({ target }) => setText(target.value) }), jsx(VoteSectionLabel, { children: t("vote.variants", { ns: VOTE_NS, defaultValue: "Варианты ответов" }) }), !!variants.length && (jsx(VoteChipList, { children: variants.map(({ text: variantText }, index) => (jsxs(VoteChip, { children: [jsx(VoteVariantText, { children: variantText }), jsx(IconButton, { kind: "close", onClick: () => removeVariant(index) })] }, `${variantText}:${index}`))) })), jsx(Input, { width: "100%", placeholder: t("vote.variantPlaceholder", { ns: VOTE_NS, defaultValue: "Введите вариант и нажмите Enter" }), value: draft, onChange: ({ target }) => setDraft(target.value), onKeyDown: event => {
17759
17765
  if (event.key === "Enter") {
17760
17766
  event.preventDefault();
17761
17767
  addVariant();
17762
17768
  }
17763
- } }), jsxs(Flex, { alignItems: "center", justifyContent: "space-between", children: [jsx(VoteSectionLabel, { children: t("vote.multiSelect", { ns: VOTE_NS, defaultValue: "Множественный выбор" }) }), jsx(Switch, { checked: multiSelect, onChange: () => setMultiSelect(prev => !prev) })] }), jsx(RaisedButton, { primary: true, disabled: !isValid || submitting, onClick: () => onSubmit(values), children: isEditing
17764
- ? t("vote.save", { ns: VOTE_NS, defaultValue: "Сохранить" })
17765
- : t("vote.create", { ns: VOTE_NS, defaultValue: "Создать голосование" }) }), !isValid && (jsx(VoteHint, { children: t("vote.formHint", {
17769
+ } }), jsxs(Flex, { alignItems: "center", justifyContent: "space-between", children: [jsx(VoteSectionLabel, { children: t("vote.multiSelect", { ns: VOTE_NS, defaultValue: "Множественный выбор" }) }), jsx(Switch, { checked: multiSelect, onChange: () => setMultiSelect(prev => !prev) })] }), submitButton && (jsx(ContainerButton, { type: type, elementConfig: submitButton, disabled: !isValid || submitting, onClick: handleSubmit })), !isValid && (jsx(VoteHint, { children: t("vote.formHint", {
17766
17770
  ns: VOTE_NS,
17767
17771
  defaultValue: "Нужны категория, вопрос и минимум два варианта ответа",
17768
- }) })), isEditing && (jsxs(Flex, { alignItems: "center", justifyContent: "space-between", children: [onCancel && (jsx(VoteEditLink, { onClick: onCancel, children: t("vote.cancel", { ns: VOTE_NS, defaultValue: "Отмена" }) })), canDelete && onDelete && (jsx(RaisedButton, { error: true, disabled: submitting, onClick: onDelete, children: t("vote.delete", { ns: VOTE_NS, defaultValue: "Удалить голосование" }) }))] }))] }));
17772
+ }) })), isEditing && (jsxs(Flex, { alignItems: "center", justifyContent: "space-between", children: [onCancel && (jsx(VoteEditLink, { onClick: onCancel, children: t("vote.cancel", { ns: VOTE_NS, defaultValue: "Отмена" }) })), canDelete && onDelete && buttonConfigs.deleteButton && (jsx(ContainerButton, { type: type, elementConfig: buttonConfigs.deleteButton, disabled: submitting, onClick: onDelete }))] }))] }));
17769
17773
  };
17770
17774
 
17771
17775
  /** Блок «Поделиться в соцсетях» — пока только вёрстка, без рабочих ссылок. */
@@ -17774,7 +17778,7 @@ const VoteShare = () => {
17774
17778
  return (jsxs(VoteShareBlock, { children: [jsx(VoteSectionLabel, { children: t("vote.share", { ns: VOTE_NS, defaultValue: "Поделиться в соцсетях" }) }), jsx(VoteShareChips, { children: VOTE_SOCIALS.map(name => (jsx(VoteShareChip, { children: name }, name))) })] }));
17775
17779
  };
17776
17780
 
17777
- const VoteResults = ({ question, category, results, screen, isOwner, hasAnswers, submitting, onSubmit, onEdit, }) => {
17781
+ const VoteResults = ({ type, buttonConfigs, question, category, results, screen, isOwner, hasAnswers, submitting, onSubmit, onEdit, }) => {
17778
17782
  const { t } = useGlobalContext();
17779
17783
  const [selected, setSelected] = useState([]);
17780
17784
  const showControls = screen === "voting";
@@ -17788,8 +17792,9 @@ const VoteResults = ({ question, category, results, screen, isOwner, hasAnswers,
17788
17792
  });
17789
17793
  }, [question.multiSelect]);
17790
17794
  const canSubmit = useMemo(() => selected.length > 0 && !submitting, [selected.length, submitting]);
17795
+ const handleSubmit = useCallback(() => onSubmit(selected), [onSubmit, selected]);
17791
17796
  return (jsxs(VoteWrapper, { children: [category && jsx(VoteCategoryLabel, { children: category.name }), jsx(VoteQuestionText, { children: question.text }), jsx(VoteVariantList, { column: true, value: selected[0] ?? "", children: results.map(({ id, text, count, percent }) => (jsxs(VoteVariantRow, { children: [jsxs(VoteVariantHead, { children: [showControls &&
17792
- (question.multiSelect ? (jsx(Checkbox, { checked: selected.includes(id), onChange: () => toggle(id) })) : (jsx(Radio, { value: id, checked: selected.includes(id), onChange: () => toggle(id) }))), jsx(VoteVariantText, { children: text }), jsx(VoteVariantCount, { children: count })] }), jsx(LinearProgress, { done: percent })] }, id))) }), screen === "unauthenticated" && (jsx(VoteHint, { children: t("vote.authHint", { ns: VOTE_NS, defaultValue: "Чтобы проголосовать, пожалуйста, авторизуйтесь" }) })), screen === "voted" && (jsxs(VoteAcceptedBadge, { children: [jsx(Icon, { kind: "success" }), t("vote.accepted", { ns: VOTE_NS, defaultValue: "Ваш ответ принят" })] })), showControls && (jsx(RaisedButton, { primary: true, disabled: !canSubmit, onClick: () => onSubmit(selected), children: t("vote.submit", { ns: VOTE_NS, defaultValue: "Отправить ответ" }) })), canEdit && onEdit && (jsx(Flex, { children: jsx(VoteEditLink, { onClick: onEdit, children: t("vote.edit", { ns: VOTE_NS, defaultValue: "Редактировать" }) }) })), showShare && jsx(VoteShare, {})] }));
17797
+ (question.multiSelect ? (jsx(Checkbox, { checked: selected.includes(id), onChange: () => toggle(id) })) : (jsx(Radio, { value: id, checked: selected.includes(id), onChange: () => toggle(id) }))), jsx(VoteVariantText, { children: text }), jsx(VoteVariantCount, { children: count })] }), jsx(LinearProgress, { done: percent })] }, id))) }), screen === "unauthenticated" && (jsx(VoteHint, { children: t("vote.authHint", { ns: VOTE_NS, defaultValue: "Чтобы проголосовать, пожалуйста, авторизуйтесь" }) })), screen === "voted" && (jsxs(VoteAcceptedBadge, { children: [jsx(Icon, { kind: "success" }), t("vote.accepted", { ns: VOTE_NS, defaultValue: "Ваш ответ принят" })] })), showControls && buttonConfigs.submitButton && (jsx(ContainerButton, { type: type, elementConfig: buttonConfigs.submitButton, disabled: !canSubmit, onClick: handleSubmit })), canEdit && onEdit && (jsx(Flex, { children: jsx(VoteEditLink, { onClick: onEdit, children: t("vote.edit", { ns: VOTE_NS, defaultValue: "Редактировать" }) }) })), showShare && jsx(VoteShare, {})] }));
17793
17798
  };
17794
17799
 
17795
17800
  /**
@@ -17798,7 +17803,7 @@ const VoteResults = ({ question, category, results, screen, isOwner, hasAnswers,
17798
17803
  * Живёт отдельно от `VoteContainer`, потому что тот отвечает за корень контейнера — размеры,
17799
17804
  * фон и заголовок — и не должен раздуваться ветвлением по состояниям.
17800
17805
  */
17801
- const VoteScreen = ({ screen, categories, question, category, results, totalVotes, isOwner, hasAnswers, isEditing, setIsEditing, editInitialValues, submitting, createVote, submitAnswer, editVote, deleteVote, }) => {
17806
+ const VoteScreen = ({ type, buttonConfigs, screen, categories, question, category, results, totalVotes, isOwner, hasAnswers, isEditing, setIsEditing, editInitialValues, submitting, createVote, submitAnswer, editVote, deleteVote, }) => {
17802
17807
  const handleCreate = useCallback((values) => void createVote(values), [createVote]);
17803
17808
  const handleEdit = useCallback((values) => void editVote(values).then(() => setIsEditing(false)), [editVote, setIsEditing]);
17804
17809
  const handleDelete = useCallback(() => void deleteVote().then(() => setIsEditing(false)), [deleteVote, setIsEditing]);
@@ -17808,14 +17813,14 @@ const VoteScreen = ({ screen, categories, question, category, results, totalVote
17808
17813
  if (screen === "loading")
17809
17814
  return jsx(ContainerLoading, {});
17810
17815
  if (isEditing && question) {
17811
- return (jsx(VoteCreateForm, { categories: categories, initialValues: editInitialValues, isEditing: true, canDelete: !hasAnswers, submitting: submitting, onSubmit: handleEdit, onDelete: handleDelete, onCancel: handleCancel }));
17816
+ return (jsx(VoteCreateForm, { type: type, buttonConfigs: buttonConfigs, categories: categories, initialValues: editInitialValues, isEditing: true, canDelete: !hasAnswers, submitting: submitting, onSubmit: handleEdit, onDelete: handleDelete, onCancel: handleCancel }));
17812
17817
  }
17813
17818
  if (screen === "create") {
17814
- return (jsx(VoteCreateForm, { categories: categories, isEditing: false, canDelete: false, submitting: submitting, onSubmit: handleCreate }));
17819
+ return (jsx(VoteCreateForm, { type: type, buttonConfigs: buttonConfigs, categories: categories, isEditing: false, canDelete: false, submitting: submitting, onSubmit: handleCreate }));
17815
17820
  }
17816
17821
  if (!question)
17817
17822
  return null;
17818
- return (jsx(VoteResults, { question: question, category: category, results: results, totalVotes: totalVotes, screen: screen, isOwner: isOwner, hasAnswers: hasAnswers, submitting: submitting, onSubmit: handleSubmitAnswer, onEdit: handleEditOpen }));
17823
+ return (jsx(VoteResults, { type: type, buttonConfigs: buttonConfigs, question: question, category: category, results: results, totalVotes: totalVotes, screen: screen, isOwner: isOwner, hasAnswers: hasAnswers, submitting: submitting, onSubmit: handleSubmitAnswer, onEdit: handleEditOpen }));
17819
17824
  };
17820
17825
 
17821
17826
  /** Приводит значение атрибута к строке-идентификатору (id приходят числами/строками). */
@@ -18242,6 +18247,9 @@ const useVoteContainer = (elementConfig) => {
18242
18247
  };
18243
18248
  };
18244
18249
 
18250
+ /** Слот кнопки существует только при совпадении id и явном type: "button". */
18251
+ const getButtonSlot = (children, id) => children?.find((child) => child.id === id && child.type === "button");
18252
+
18245
18253
  /**
18246
18254
  * Контейнер «Голосование»: привязывает опрос к объекту карты через `attributeName`
18247
18255
  * и показывает один из экранов — создание, голосование, после голосования
@@ -18253,6 +18261,13 @@ const useVoteContainer = (elementConfig) => {
18253
18261
  const VoteContainer = memo(({ type, elementConfig, isVisible, renderElement }) => {
18254
18262
  const { root, body } = useContainerRoot({ elementConfig });
18255
18263
  const { configured, ...vote } = useVoteContainer(elementConfig);
18264
+ const children = elementConfig?.children;
18265
+ const buttonConfigs = useMemo(() => ({
18266
+ submitButton: getButtonSlot(children, "submitButton"),
18267
+ createButton: getButtonSlot(children, "createButton"),
18268
+ saveButton: getButtonSlot(children, "saveButton"),
18269
+ deleteButton: getButtonSlot(children, "deleteButton"),
18270
+ }), [children]);
18256
18271
  // Без имени атрибута или хотя бы одного источника контейнеру не с чем работать. Ошибка вместо
18257
18272
  // пустоты: молчаливый `null` выдавал бы опечатку в конфиге за «блока просто нет».
18258
18273
  if (!configured) {
@@ -18262,7 +18277,7 @@ const VoteContainer = memo(({ type, elementConfig, isVisible, renderElement }) =
18262
18277
  // в карточке в этом случае тоже не нужен, поэтому не рисуем и корень.
18263
18278
  if (!vote.screen)
18264
18279
  return null;
18265
- return (jsxs(ContainerRoot, { ...root, children: [jsx(ContainerBackground, { elementConfig: elementConfig, renderElement: renderElement }), jsx(ExpandableTitle, { elementConfig: elementConfig, type: type, renderElement: renderElement }), isVisible && (jsx(Container, { ...body, isColumn: true, children: jsx(VoteScreen, { ...vote, screen: vote.screen }) }))] }));
18280
+ return (jsxs(ContainerRoot, { ...root, children: [jsx(ContainerBackground, { elementConfig: elementConfig, renderElement: renderElement }), jsx(ExpandableTitle, { elementConfig: elementConfig, type: type, renderElement: renderElement }), isVisible && (jsx(Container, { ...body, isColumn: true, children: jsx(VoteScreen, { ...vote, screen: vote.screen, type: type, buttonConfigs: buttonConfigs }) }))] }));
18266
18281
  });
18267
18282
 
18268
18283
  const ExpandableTitle = memo(({ elementConfig, type, renderElement }) => {
@@ -18878,12 +18893,11 @@ const ContainersGroupContainer = memo(props => {
18878
18893
  });
18879
18894
 
18880
18895
  const ExportPdfContainer = memo(({ type, elementConfig, renderElement }) => {
18881
- const { t } = useGlobalContext();
18882
18896
  const { loading, onExport } = useExportPdf(getRootElementId(type));
18883
- const { id, style, options } = elementConfig || {};
18884
- const { icon, title } = options || {};
18897
+ const { id, style, children } = elementConfig || {};
18898
+ const buttonConfig = useMemo(() => getButtonSlot(children, "button"), [children]);
18885
18899
  const bgHost = useBgImageHost(elementConfig);
18886
- return (jsxs(Container, { id: id, style: style, ...bgHost, children: [jsx(ContainerBackground, { elementConfig: elementConfig, renderElement: renderElement }), jsx(IconButton, { kind: icon || "download", primary: true, disabled: loading, onClick: onExport, children: title ?? t("downloadPdf", { ns: "dashboard", defaultValue: "Скачать PDF" }) })] }));
18900
+ return (jsxs(Container, { id: id, style: style, ...bgHost, children: [jsx(ContainerBackground, { elementConfig: elementConfig, renderElement: renderElement }), buttonConfig && jsx(ContainerButton, { type: type, elementConfig: buttonConfig, disabled: loading, onClick: onExport })] }));
18887
18901
  });
18888
18902
 
18889
18903
  var ThemeName;