diff --git a/frontend/src/webparts/approvalAdmin/components/ui/ConfirmDialog.tsx b/frontend/src/webparts/approvalAdmin/components/ui/ConfirmDialog.tsx index e90a50c..57d1f03 100644 --- a/frontend/src/webparts/approvalAdmin/components/ui/ConfirmDialog.tsx +++ b/frontend/src/webparts/approvalAdmin/components/ui/ConfirmDialog.tsx @@ -1,6 +1,7 @@ import * as React from 'react'; import styles from './Modal.module.scss'; import { Button } from './Button'; +import { ModalOverlay } from './ModalOverlay'; import { texts } from '../../texts'; export interface IConfirmDialogProps { @@ -20,7 +21,7 @@ export const ConfirmDialog: React.FC = ({ onCancel, busy }) => ( -
{ if (e.target === e.currentTarget) onCancel(); }}> +
{title}

{text}

@@ -29,5 +30,5 @@ export const ConfirmDialog: React.FC = ({
- + ); diff --git a/frontend/src/webparts/approvalAdmin/components/ui/Modal.module.scss b/frontend/src/webparts/approvalAdmin/components/ui/Modal.module.scss index 3ea7bf3..880e239 100644 --- a/frontend/src/webparts/approvalAdmin/components/ui/Modal.module.scss +++ b/frontend/src/webparts/approvalAdmin/components/ui/Modal.module.scss @@ -7,9 +7,17 @@ display: flex; align-items: center; justify-content: center; - z-index: 300; + // Выше шапки SharePoint, но ниже слоёв Fluent UI (1000000). Оверлей рендерится + // порталом в body (см. ModalOverlay), поэтому сравнивается с шапкой напрямую. + z-index: 100000; backdrop-filter: blur(6px); padding: 20px; + // Портал вне корня веб-части — шрифт и метрики .shell (AdminApp.module.scss) + // сюда не наследуются, задаём заново. + font-family: $font-sans; + font-size: $fs-body; + line-height: 1.55; + box-sizing: border-box; } .box { diff --git a/frontend/src/webparts/approvalAdmin/components/ui/Modal.tsx b/frontend/src/webparts/approvalAdmin/components/ui/Modal.tsx index 25cf093..338f974 100644 --- a/frontend/src/webparts/approvalAdmin/components/ui/Modal.tsx +++ b/frontend/src/webparts/approvalAdmin/components/ui/Modal.tsx @@ -1,6 +1,7 @@ import * as React from 'react'; import styles from './Modal.module.scss'; import { IconButton } from './IconButton'; +import { ModalOverlay } from './ModalOverlay'; import { texts } from '../../texts'; export interface IModalProps { @@ -11,8 +12,7 @@ export interface IModalProps { } export const Modal: React.FC = ({ title, onClose, footer, children }) => ( - // Клик по подложке закрывает окно, клик внутри — нет (проверяем сам currentTarget). -
{ if (e.target === e.currentTarget) onClose(); }}> +
{title}
@@ -21,5 +21,5 @@ export const Modal: React.FC = ({ title, onClose, footer, children
{children}
{footer &&
{footer}
}
-
+
); diff --git a/frontend/src/webparts/approvalAdmin/components/ui/ModalOverlay.tsx b/frontend/src/webparts/approvalAdmin/components/ui/ModalOverlay.tsx new file mode 100644 index 0000000..5588166 --- /dev/null +++ b/frontend/src/webparts/approvalAdmin/components/ui/ModalOverlay.tsx @@ -0,0 +1,25 @@ +import * as React from 'react'; +import * as ReactDOM from 'react-dom'; +import styles from './Modal.module.scss'; + +export interface IModalOverlayProps { + /** Клик по подложке (не по содержимому окна). */ + onBackdropClick: () => void; + children: React.ReactNode; +} + +/** + * Затемнение под модалкой — порталом в document.body, а не внутри веб-части. + * На живой странице SharePoint канва веб-части лежит в своём контексте наложения + * ниже шапки (suite bar), и position: fixed-оверлей изнутри неё оказывался ПОД + * шапкой: верх окна, центрированного по высоте экрана, уезжал за неё. В workbench + * шапки нет — там было незаметно. + */ +export const ModalOverlay: React.FC = ({ onBackdropClick, children }) => + ReactDOM.createPortal( + // Клик по подложке закрывает окно, клик внутри — нет (проверяем сам currentTarget). +
{ if (e.target === e.currentTarget) onBackdropClick(); }}> + {children} +
, + document.body + ); diff --git a/frontend/src/webparts/approvalAdmin/components/ui/ProgressOverlay.module.scss b/frontend/src/webparts/approvalAdmin/components/ui/ProgressOverlay.module.scss index a6068ca..5b722c6 100644 --- a/frontend/src/webparts/approvalAdmin/components/ui/ProgressOverlay.module.scss +++ b/frontend/src/webparts/approvalAdmin/components/ui/ProgressOverlay.module.scss @@ -1,6 +1,6 @@ @import '../../../../styles/design-tokens'; -// Ниже Modal.module.scss/.overlay (z-index 300) — диалоги, которые может +// Ниже Modal.module.scss/.overlay (z-index 100000) — диалоги, которые может // открыть сама длительная операция (например, разрешение конфликта), должны // быть ПОВЕРХ этой подложки, а не под ней. .overlay { diff --git a/frontend/src/webparts/approvalAdmin/components/ui/SearchableSelect.module.scss b/frontend/src/webparts/approvalAdmin/components/ui/SearchableSelect.module.scss index 01fd05e..806c5f4 100644 --- a/frontend/src/webparts/approvalAdmin/components/ui/SearchableSelect.module.scss +++ b/frontend/src/webparts/approvalAdmin/components/ui/SearchableSelect.module.scss @@ -73,7 +73,7 @@ box-shadow: $sh-modal; border: 1px solid $gray-200; padding: 6px; - z-index: 400; + z-index: 100001; // над оверлеем модалки (Modal.module.scss) max-height: 320px; display: flex; flex-direction: column; diff --git a/frontend/src/webparts/approvalAdmin/components/ui/index.ts b/frontend/src/webparts/approvalAdmin/components/ui/index.ts index 6dd1176..0cc9a0c 100644 --- a/frontend/src/webparts/approvalAdmin/components/ui/index.ts +++ b/frontend/src/webparts/approvalAdmin/components/ui/index.ts @@ -17,6 +17,7 @@ export * from './PrimaryCell'; export * from './ActionsCell'; export * from './CellNote'; export * from './Modal'; +export * from './ModalOverlay'; export * from './ConfirmDialog'; export * from './FormModal'; export * from './FormGrid';