@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.
@@ -164,9 +164,8 @@ export interface ElementUploaderProps extends Omit<ContainerProps, "elementConfi
164
164
  */
165
165
  export type ContainerBoxOptions = Pick<ConfigOptions, "width" | "height" | "overflow">;
166
166
  export type AddFeatureContainerOptions = Record<string, never>;
167
- export type AddFeatureButtonOptions = Pick<ConfigOptions, "icon" | "title" | "layerName" | "geometryType">;
168
- export interface AddFeatureButtonChild extends Omit<ConfigContainerChild, "options" | "type"> {
169
- type?: "button";
167
+ export type AddFeatureButtonOptions = Pick<ConfigOptions, "layerName" | "geometryType"> & ElementButtonOptions;
168
+ export interface AddFeatureButtonChild extends Omit<ElementButtonConfig, "options"> {
170
169
  options?: AddFeatureButtonOptions;
171
170
  }
172
171
  export interface AddFeatureContainerConfig extends Omit<ConfigContainerChild, "options" | "templateName" | "children"> {
@@ -356,7 +355,7 @@ export interface EditAttachmentContainerConfig extends Omit<ConfigContainerChild
356
355
  export interface EditAttachmentContainerProps extends Omit<ContainerProps, "elementConfig"> {
357
356
  elementConfig?: EditAttachmentContainerConfig;
358
357
  }
359
- export type ExportPdfContainerOptions = Pick<ConfigOptions, "icon" | "title">;
358
+ export type ExportPdfContainerOptions = Record<string, never>;
360
359
  export interface ExportPdfContainerConfig extends Omit<ConfigContainerChild, "options" | "templateName"> {
361
360
  templateName?: ContainerTemplate.ExportPdf;
362
361
  options?: ExportPdfContainerOptions;
@@ -0,0 +1,4 @@
1
+ import { FC } from 'react';
2
+ import { ElementButtonProps } from '../../types';
3
+ /** Кнопка нативного действия контейнера со стандартными подстановками дочернего конфига. */
4
+ export declare const ContainerButton: FC<ElementButtonProps>;
@@ -1,9 +1,9 @@
1
1
  import { FC } from 'react';
2
- import { VoteScreenProps } from '../types';
2
+ import { VoteButtonProps, VoteScreenProps } from '../types';
3
3
  /**
4
4
  * Тело контейнера: выбирает экран по вью-модели голосования.
5
5
  *
6
6
  * Живёт отдельно от `VoteContainer`, потому что тот отвечает за корень контейнера — размеры,
7
7
  * фон и заголовок — и не должен раздуваться ветвлением по состояниям.
8
8
  */
9
- export declare const VoteScreen: FC<VoteScreenProps>;
9
+ export declare const VoteScreen: FC<VoteScreenProps & VoteButtonProps>;
@@ -1,4 +1,11 @@
1
- import { VoteContainerOptions } from '../../componentTypes';
1
+ import { ElementButtonConfig, VoteContainerOptions } from '../../componentTypes';
2
+ import { WidgetType } from '../../types';
3
+ export type VoteButtonSlotId = "submitButton" | "createButton" | "saveButton" | "deleteButton";
4
+ export type VoteButtonConfigs = Partial<Record<VoteButtonSlotId, ElementButtonConfig>>;
5
+ export interface VoteButtonProps {
6
+ type?: WidgetType;
7
+ buttonConfigs: VoteButtonConfigs;
8
+ }
2
9
  /** Экран, который показывает контейнер голосования. */
3
10
  export type VoteScreen = "loading" | "create" | "voting" | "voted" | "unauthenticated";
4
11
  export interface VoteCategory {
@@ -40,7 +47,7 @@ export interface VoteFormVariant {
40
47
  * к данным отношения не имеют, а `Required<VoteContainerOptions>` потребовал бы и их.
41
48
  */
42
49
  export type VoteDataSources = Required<Pick<VoteContainerOptions, "categoryDataSource" | "questionDataSource" | "variantDataSource" | "answerDataSource">>;
43
- export interface VoteCreateFormProps {
50
+ export interface VoteCreateFormProps extends VoteButtonProps {
44
51
  categories: VoteCategory[];
45
52
  initialValues?: VoteFormValues;
46
53
  isEditing: boolean;
@@ -50,7 +57,7 @@ export interface VoteCreateFormProps {
50
57
  onDelete?: () => void;
51
58
  onCancel?: () => void;
52
59
  }
53
- export interface VoteResultsProps {
60
+ export interface VoteResultsProps extends VoteButtonProps {
54
61
  question: VoteQuestion;
55
62
  category?: VoteCategory;
56
63
  results: VoteVariantResult[];
@@ -0,0 +1,4 @@
1
+ import { ElementButtonConfig } from '../componentTypes';
2
+ import { ConfigContainerChild } from '../types';
3
+ /** Слот кнопки существует только при совпадении id и явном type: "button". */
4
+ export declare const getButtonSlot: (children: ConfigContainerChild[] | undefined, id: string) => ElementButtonConfig | undefined;
package/dist/index.js CHANGED
@@ -5154,7 +5154,7 @@ const FeatureControls = styled(uilibGl.Flex).withConfig({ displayName: "FeatureC
5154
5154
  const FiltersContainerWrapper = styled(uilibGl.Flex).withConfig({ displayName: "FiltersContainerWrapper", componentId: "sc-1a6ru74" }) `
5155
5155
  flex-direction: column;
5156
5156
  padding: ${({ $padding }) => $padding ?? `${DEFAULT_FILTER_PADDING}px`};
5157
- background-color: ${({ $bgColor, $fontColor, theme: { palette } }) => $bgColor || ($fontColor ? transparentizeColor($fontColor, 6) : palette.element)};
5157
+ background: ${({ $bgColor, $fontColor, theme: { palette } }) => $bgColor || ($fontColor ? transparentizeColor($fontColor, 6) : palette.element)};
5158
5158
  border-radius: ${({ theme: { borderRadius } }) => borderRadius.medium};
5159
5159
 
5160
5160
  ${uilibGl.DropdownField}, input {
@@ -8948,7 +8948,7 @@ const POLL_SUBTASK_INTERVAL_MS = 500;
8948
8948
  const POLL_SUBTASK_TIMEOUT_MS = 15_000;
8949
8949
 
8950
8950
  const StatusBadge = styled(uilibGl.Chip).withConfig({ displayName: "StatusBadge", componentId: "sc-1xmfl10" }) `
8951
- background-color: ${({ bgColor }) => bgColor};
8951
+ background: ${({ bgColor }) => bgColor};
8952
8952
  color: ${({ theme }) => theme.palette.iconContrast};
8953
8953
  `;
8954
8954
 
@@ -11293,7 +11293,7 @@ const FilterChip = styled.div.withConfig({ displayName: "FilterChip", componentI
11293
11293
  padding: 0.3125rem 0.5rem;
11294
11294
  height: 1.5rem;
11295
11295
  border-radius: 0.25rem;
11296
- background-color: ${({ $isActive, $bgColor, theme }) => $bgColor
11296
+ background: ${({ $isActive, $bgColor, theme }) => $bgColor
11297
11297
  ? $bgColor
11298
11298
  : $isActive
11299
11299
  ? theme.palette?.primary
@@ -11313,7 +11313,7 @@ const FilterChip = styled.div.withConfig({ displayName: "FilterChip", componentI
11313
11313
  box-sizing: border-box;
11314
11314
 
11315
11315
  &:hover {
11316
- background-color: ${({ $isActive, $bgColor, theme }) => $isActive
11316
+ background: ${({ $isActive, $bgColor, theme }) => $isActive
11317
11317
  ? $bgColor || 'inherit'
11318
11318
  : $bgColor || theme.palette?.elementDark};
11319
11319
  }
@@ -14558,12 +14558,21 @@ const ContainerBackground = React.memo(({ elementConfig, renderElement }) => {
14558
14558
  return (jsxRuntime.jsx(ContainerBackgroundLayer, { "$outflow": elementConfig?.options?.outflow, children: renderElement({ id: BG_IMAGE_SLOT_ID, wrap: false }) }));
14559
14559
  });
14560
14560
 
14561
- const AddFeatureContainer = React.memo(({ elementConfig, renderElement }) => {
14561
+ /** Кнопка нативного действия контейнера со стандартными подстановками дочернего конфига. */
14562
+ const ContainerButton = React.memo(({ type = exports.WidgetType.Dashboard, elementConfig, ...props }) => {
14563
+ const sources = useConfigStringSources(type);
14564
+ const node = useActionNode();
14565
+ const attributes = props.attributes ?? node.attributes ?? sources.attributes;
14566
+ const resolvedConfig = React.useMemo(() => resolveElementStrings(elementConfig, { ...sources, attributes }), [elementConfig, sources, attributes]);
14567
+ return jsxRuntime.jsx(ElementButton, { ...props, type: type, attributes: attributes, elementConfig: resolvedConfig });
14568
+ });
14569
+
14570
+ const AddFeatureContainer = React.memo(({ type, elementConfig, renderElement }) => {
14562
14571
  const { id, children, style } = elementConfig || {};
14563
14572
  const bgHost = useBgImageHost(elementConfig);
14564
- return (jsxRuntime.jsxs(Container, { id: id, style: style, ...bgHost, children: [jsxRuntime.jsx(ContainerBackground, { elementConfig: elementConfig, renderElement: renderElement }), children
14565
- .filter(({ type }) => type === "button")
14566
- .map(({ options }, index) => (jsxRuntime.jsx(AddFeatureButton, { icon: options?.icon, title: options?.title, layerName: options?.layerName, geometryType: options?.geometryType }, index)))] }));
14573
+ const handleAddFeature = React.useCallback(() => undefined, []);
14574
+ return (jsxRuntime.jsxs(Container, { id: id, style: style, ...bgHost, children: [jsxRuntime.jsx(ContainerBackground, { elementConfig: elementConfig, renderElement: renderElement }), children?.filter(({ type: childType }) => childType === "button")
14575
+ .map((button, index) => (jsxRuntime.jsx(ContainerButton, { type: type, elementConfig: button, onClick: handleAddFeature }, button.id ?? index)))] }));
14567
14576
  });
14568
14577
 
14569
14578
  /**
@@ -16497,7 +16506,7 @@ const RoundedBackgroundContainerWrapper = styled(uilibGl.Flex).withConfig({ disp
16497
16506
  * иначе фон тонируется цветом иконки, а без неё — цветом текста (colorAttribute/fontColor);
16498
16507
  * если не задан ни один цвет, остаётся токен темы.
16499
16508
  */
16500
- background-color: ${({ $bgColor, $iconColor, $color, theme: { palette } }) => $bgColor || tintedBackground($iconColor || $color) || palette.element};
16509
+ background: ${({ $bgColor, $iconColor, $color, theme: { palette } }) => $bgColor || tintedBackground($iconColor || $color) || palette.element};
16501
16510
  border-radius: ${({ theme: { borderRadius } }) => borderRadius.large};
16502
16511
  flex-wrap: nowrap;
16503
16512
 
@@ -16568,11 +16577,6 @@ const RoundedBackgroundContainerWrapper = styled(uilibGl.Flex).withConfig({ disp
16568
16577
  > * {
16569
16578
  text-align: left;
16570
16579
  }
16571
-
16572
- /* Зазор наружу даёт обёртка иконки, здесь — отступ внутри её бокса. */
16573
- span[kind] {
16574
- margin-right: 0.5rem;
16575
- }
16576
16580
 
16577
16581
  ${ContainerValue} {
16578
16582
  width: auto;
@@ -17286,7 +17290,7 @@ const TabContainer = styled.a.withConfig({ displayName: "TabContainer", componen
17286
17290
  justify-content: center;
17287
17291
  flex-wrap: nowrap;
17288
17292
  padding: ${({ onlyIcon }) => (onlyIcon ? 1 : 0.5)}rem 1rem;
17289
- background-color: ${({ active, bgColor, theme: { palette } }) => active ? bgColor || palette.primary : palette.element};
17293
+ background: ${({ active, bgColor, theme: { palette } }) => active ? bgColor || palette.primary : palette.element};
17290
17294
  border-radius: ${({ column, radius, theme: { borderRadius } }) => radius ? `${radius}px` : column ? borderRadius.medium : borderRadius.xLarge};
17291
17295
  text-decoration: none;
17292
17296
 
@@ -17752,22 +17756,22 @@ const useVoteForm = (initialValues) => {
17752
17756
  };
17753
17757
  };
17754
17758
 
17755
- const VoteCreateForm = ({ categories, initialValues, isEditing, canDelete, submitting, onSubmit, onDelete, onCancel, }) => {
17759
+ const VoteCreateForm = ({ type, buttonConfigs, categories, initialValues, isEditing, canDelete, submitting, onSubmit, onDelete, onCancel, }) => {
17756
17760
  const { t } = useGlobalContext();
17757
17761
  const form = useVoteForm(initialValues);
17758
17762
  const { categoryId, setCategoryId, text, setText, multiSelect, setMultiSelect, variants, addVariant, removeVariant, draft, setDraft, isValid, values, } = form;
17759
17763
  const categoryOptions = React.useMemo(() => categories.map(({ id, name }) => ({ text: name, value: id })), [categories]);
17764
+ const submitButton = React.useMemo(() => isEditing ? buttonConfigs.saveButton : buttonConfigs.createButton, [buttonConfigs, isEditing]);
17765
+ const handleSubmit = React.useCallback(() => onSubmit(values), [onSubmit, values]);
17760
17766
  return (jsxRuntime.jsxs(VoteWrapper, { children: [!isEditing && jsxRuntime.jsx(VoteHeading, { children: t("vote.newVote", { ns: VOTE_NS, defaultValue: "Новое голосование" }) }), jsxRuntime.jsx(uilibGl.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 ?? "")) }), jsxRuntime.jsx(uilibGl.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) }), jsxRuntime.jsx(VoteSectionLabel, { children: t("vote.variants", { ns: VOTE_NS, defaultValue: "Варианты ответов" }) }), !!variants.length && (jsxRuntime.jsx(VoteChipList, { children: variants.map(({ text: variantText }, index) => (jsxRuntime.jsxs(VoteChip, { children: [jsxRuntime.jsx(VoteVariantText, { children: variantText }), jsxRuntime.jsx(uilibGl.IconButton, { kind: "close", onClick: () => removeVariant(index) })] }, `${variantText}:${index}`))) })), jsxRuntime.jsx(uilibGl.Input, { width: "100%", placeholder: t("vote.variantPlaceholder", { ns: VOTE_NS, defaultValue: "Введите вариант и нажмите Enter" }), value: draft, onChange: ({ target }) => setDraft(target.value), onKeyDown: event => {
17761
17767
  if (event.key === "Enter") {
17762
17768
  event.preventDefault();
17763
17769
  addVariant();
17764
17770
  }
17765
- } }), 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
17766
- ? t("vote.save", { ns: VOTE_NS, defaultValue: "Сохранить" })
17767
- : t("vote.create", { ns: VOTE_NS, defaultValue: "Создать голосование" }) }), !isValid && (jsxRuntime.jsx(VoteHint, { children: t("vote.formHint", {
17771
+ } }), 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) })] }), submitButton && (jsxRuntime.jsx(ContainerButton, { type: type, elementConfig: submitButton, disabled: !isValid || submitting, onClick: handleSubmit })), !isValid && (jsxRuntime.jsx(VoteHint, { children: t("vote.formHint", {
17768
17772
  ns: VOTE_NS,
17769
17773
  defaultValue: "Нужны категория, вопрос и минимум два варианта ответа",
17770
- }) })), 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: "Удалить голосование" }) }))] }))] }));
17774
+ }) })), 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 && buttonConfigs.deleteButton && (jsxRuntime.jsx(ContainerButton, { type: type, elementConfig: buttonConfigs.deleteButton, disabled: submitting, onClick: onDelete }))] }))] }));
17771
17775
  };
17772
17776
 
17773
17777
  /** Блок «Поделиться в соцсетях» — пока только вёрстка, без рабочих ссылок. */
@@ -17776,7 +17780,7 @@ const VoteShare = () => {
17776
17780
  return (jsxRuntime.jsxs(VoteShareBlock, { children: [jsxRuntime.jsx(VoteSectionLabel, { children: t("vote.share", { ns: VOTE_NS, defaultValue: "Поделиться в соцсетях" }) }), jsxRuntime.jsx(VoteShareChips, { children: VOTE_SOCIALS.map(name => (jsxRuntime.jsx(VoteShareChip, { children: name }, name))) })] }));
17777
17781
  };
17778
17782
 
17779
- const VoteResults = ({ question, category, results, screen, isOwner, hasAnswers, submitting, onSubmit, onEdit, }) => {
17783
+ const VoteResults = ({ type, buttonConfigs, question, category, results, screen, isOwner, hasAnswers, submitting, onSubmit, onEdit, }) => {
17780
17784
  const { t } = useGlobalContext();
17781
17785
  const [selected, setSelected] = React.useState([]);
17782
17786
  const showControls = screen === "voting";
@@ -17790,8 +17794,9 @@ const VoteResults = ({ question, category, results, screen, isOwner, hasAnswers,
17790
17794
  });
17791
17795
  }, [question.multiSelect]);
17792
17796
  const canSubmit = React.useMemo(() => selected.length > 0 && !submitting, [selected.length, submitting]);
17797
+ const handleSubmit = React.useCallback(() => onSubmit(selected), [onSubmit, selected]);
17793
17798
  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 &&
17794
- (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, {})] }));
17799
+ (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 && buttonConfigs.submitButton && (jsxRuntime.jsx(ContainerButton, { type: type, elementConfig: buttonConfigs.submitButton, disabled: !canSubmit, onClick: handleSubmit })), canEdit && onEdit && (jsxRuntime.jsx(uilibGl.Flex, { children: jsxRuntime.jsx(VoteEditLink, { onClick: onEdit, children: t("vote.edit", { ns: VOTE_NS, defaultValue: "Редактировать" }) }) })), showShare && jsxRuntime.jsx(VoteShare, {})] }));
17795
17800
  };
17796
17801
 
17797
17802
  /**
@@ -17800,7 +17805,7 @@ const VoteResults = ({ question, category, results, screen, isOwner, hasAnswers,
17800
17805
  * Живёт отдельно от `VoteContainer`, потому что тот отвечает за корень контейнера — размеры,
17801
17806
  * фон и заголовок — и не должен раздуваться ветвлением по состояниям.
17802
17807
  */
17803
- const VoteScreen = ({ screen, categories, question, category, results, totalVotes, isOwner, hasAnswers, isEditing, setIsEditing, editInitialValues, submitting, createVote, submitAnswer, editVote, deleteVote, }) => {
17808
+ const VoteScreen = ({ type, buttonConfigs, screen, categories, question, category, results, totalVotes, isOwner, hasAnswers, isEditing, setIsEditing, editInitialValues, submitting, createVote, submitAnswer, editVote, deleteVote, }) => {
17804
17809
  const handleCreate = React.useCallback((values) => void createVote(values), [createVote]);
17805
17810
  const handleEdit = React.useCallback((values) => void editVote(values).then(() => setIsEditing(false)), [editVote, setIsEditing]);
17806
17811
  const handleDelete = React.useCallback(() => void deleteVote().then(() => setIsEditing(false)), [deleteVote, setIsEditing]);
@@ -17810,14 +17815,14 @@ const VoteScreen = ({ screen, categories, question, category, results, totalVote
17810
17815
  if (screen === "loading")
17811
17816
  return jsxRuntime.jsx(ContainerLoading, {});
17812
17817
  if (isEditing && question) {
17813
- return (jsxRuntime.jsx(VoteCreateForm, { categories: categories, initialValues: editInitialValues, isEditing: true, canDelete: !hasAnswers, submitting: submitting, onSubmit: handleEdit, onDelete: handleDelete, onCancel: handleCancel }));
17818
+ return (jsxRuntime.jsx(VoteCreateForm, { type: type, buttonConfigs: buttonConfigs, categories: categories, initialValues: editInitialValues, isEditing: true, canDelete: !hasAnswers, submitting: submitting, onSubmit: handleEdit, onDelete: handleDelete, onCancel: handleCancel }));
17814
17819
  }
17815
17820
  if (screen === "create") {
17816
- return (jsxRuntime.jsx(VoteCreateForm, { categories: categories, isEditing: false, canDelete: false, submitting: submitting, onSubmit: handleCreate }));
17821
+ return (jsxRuntime.jsx(VoteCreateForm, { type: type, buttonConfigs: buttonConfigs, categories: categories, isEditing: false, canDelete: false, submitting: submitting, onSubmit: handleCreate }));
17817
17822
  }
17818
17823
  if (!question)
17819
17824
  return null;
17820
- return (jsxRuntime.jsx(VoteResults, { question: question, category: category, results: results, totalVotes: totalVotes, screen: screen, isOwner: isOwner, hasAnswers: hasAnswers, submitting: submitting, onSubmit: handleSubmitAnswer, onEdit: handleEditOpen }));
17825
+ return (jsxRuntime.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 }));
17821
17826
  };
17822
17827
 
17823
17828
  /** Приводит значение атрибута к строке-идентификатору (id приходят числами/строками). */
@@ -18244,6 +18249,9 @@ const useVoteContainer = (elementConfig) => {
18244
18249
  };
18245
18250
  };
18246
18251
 
18252
+ /** Слот кнопки существует только при совпадении id и явном type: "button". */
18253
+ const getButtonSlot = (children, id) => children?.find((child) => child.id === id && child.type === "button");
18254
+
18247
18255
  /**
18248
18256
  * Контейнер «Голосование»: привязывает опрос к объекту карты через `attributeName`
18249
18257
  * и показывает один из экранов — создание, голосование, после голосования
@@ -18255,6 +18263,13 @@ const useVoteContainer = (elementConfig) => {
18255
18263
  const VoteContainer = React.memo(({ type, elementConfig, isVisible, renderElement }) => {
18256
18264
  const { root, body } = useContainerRoot({ elementConfig });
18257
18265
  const { configured, ...vote } = useVoteContainer(elementConfig);
18266
+ const children = elementConfig?.children;
18267
+ const buttonConfigs = React.useMemo(() => ({
18268
+ submitButton: getButtonSlot(children, "submitButton"),
18269
+ createButton: getButtonSlot(children, "createButton"),
18270
+ saveButton: getButtonSlot(children, "saveButton"),
18271
+ deleteButton: getButtonSlot(children, "deleteButton"),
18272
+ }), [children]);
18258
18273
  // Без имени атрибута или хотя бы одного источника контейнеру не с чем работать. Ошибка вместо
18259
18274
  // пустоты: молчаливый `null` выдавал бы опечатку в конфиге за «блока просто нет».
18260
18275
  if (!configured) {
@@ -18264,7 +18279,7 @@ const VoteContainer = React.memo(({ type, elementConfig, isVisible, renderElemen
18264
18279
  // в карточке в этом случае тоже не нужен, поэтому не рисуем и корень.
18265
18280
  if (!vote.screen)
18266
18281
  return null;
18267
- return (jsxRuntime.jsxs(ContainerRoot, { ...root, children: [jsxRuntime.jsx(ContainerBackground, { elementConfig: elementConfig, renderElement: renderElement }), jsxRuntime.jsx(ExpandableTitle, { elementConfig: elementConfig, type: type, renderElement: renderElement }), isVisible && (jsxRuntime.jsx(Container, { ...body, isColumn: true, children: jsxRuntime.jsx(VoteScreen, { ...vote, screen: vote.screen }) }))] }));
18282
+ return (jsxRuntime.jsxs(ContainerRoot, { ...root, children: [jsxRuntime.jsx(ContainerBackground, { elementConfig: elementConfig, renderElement: renderElement }), jsxRuntime.jsx(ExpandableTitle, { elementConfig: elementConfig, type: type, renderElement: renderElement }), isVisible && (jsxRuntime.jsx(Container, { ...body, isColumn: true, children: jsxRuntime.jsx(VoteScreen, { ...vote, screen: vote.screen, type: type, buttonConfigs: buttonConfigs }) }))] }));
18268
18283
  });
18269
18284
 
18270
18285
  const ExpandableTitle = React.memo(({ elementConfig, type, renderElement }) => {
@@ -18880,12 +18895,11 @@ const ContainersGroupContainer = React.memo(props => {
18880
18895
  });
18881
18896
 
18882
18897
  const ExportPdfContainer = React.memo(({ type, elementConfig, renderElement }) => {
18883
- const { t } = useGlobalContext();
18884
18898
  const { loading, onExport } = useExportPdf(getRootElementId(type));
18885
- const { id, style, options } = elementConfig || {};
18886
- const { icon, title } = options || {};
18899
+ const { id, style, children } = elementConfig || {};
18900
+ const buttonConfig = React.useMemo(() => getButtonSlot(children, "button"), [children]);
18887
18901
  const bgHost = useBgImageHost(elementConfig);
18888
- return (jsxRuntime.jsxs(Container, { id: id, style: style, ...bgHost, children: [jsxRuntime.jsx(ContainerBackground, { elementConfig: elementConfig, renderElement: renderElement }), jsxRuntime.jsx(uilibGl.IconButton, { kind: icon || "download", primary: true, disabled: loading, onClick: onExport, children: title ?? t("downloadPdf", { ns: "dashboard", defaultValue: "Скачать PDF" }) })] }));
18902
+ return (jsxRuntime.jsxs(Container, { id: id, style: style, ...bgHost, children: [jsxRuntime.jsx(ContainerBackground, { elementConfig: elementConfig, renderElement: renderElement }), buttonConfig && jsxRuntime.jsx(ContainerButton, { type: type, elementConfig: buttonConfig, disabled: loading, onClick: onExport })] }));
18889
18903
  });
18890
18904
 
18891
18905
  exports.ThemeName = void 0;