@gooddata/sdk-ui-kit 11.41.0 → 11.42.0-alpha.1
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/esm/@ui/UiAddGranteeDialog/UiAddGranteeDialog.d.ts +6 -4
- package/esm/@ui/UiAddGranteeDialog/UiAddGranteeDialog.d.ts.map +1 -1
- package/esm/@ui/UiAddGranteeDialog/UiAddGranteeDialog.js +6 -6
- package/esm/@ui/UiConfirmDialog/UiConfirmDialog.d.ts +10 -30
- package/esm/@ui/UiConfirmDialog/UiConfirmDialog.d.ts.map +1 -1
- package/esm/@ui/UiConfirmDialog/UiConfirmDialog.js +10 -22
- package/esm/@ui/UiConfirmDialog/UiConfirmDialogCard.d.ts +40 -0
- package/esm/@ui/UiConfirmDialog/UiConfirmDialogCard.d.ts.map +1 -0
- package/esm/@ui/UiConfirmDialog/UiConfirmDialogCard.js +26 -0
- package/esm/@ui/UiGranteeRowControls/UiGranteeRowControls.js +1 -1
- package/esm/@ui/UiModalDialog/UiDialogBody.d.ts +17 -0
- package/esm/@ui/UiModalDialog/UiDialogBody.d.ts.map +1 -0
- package/esm/@ui/UiModalDialog/UiDialogBody.js +24 -0
- package/esm/@ui/{UiDialogShell → UiModalDialog}/UiDialogFooter.d.ts.map +1 -1
- package/esm/@ui/{UiDialogShell → UiModalDialog}/UiDialogHeader.d.ts.map +1 -1
- package/esm/@ui/{UiDialogShell → UiModalDialog}/UiDialogHeader.js +1 -1
- package/esm/@ui/UiModalDialog/UiModalDialog.d.ts +51 -0
- package/esm/@ui/UiModalDialog/UiModalDialog.d.ts.map +1 -0
- package/esm/@ui/UiModalDialog/UiModalDialog.js +135 -0
- package/esm/@ui/UiObjectShareDialog/UiObjectShareDialog.d.ts +8 -49
- package/esm/@ui/UiObjectShareDialog/UiObjectShareDialog.d.ts.map +1 -1
- package/esm/@ui/UiObjectShareDialog/UiObjectShareDialog.js +9 -23
- package/esm/@ui/UiObjectShareDialog/UiObjectShareDialogCard.d.ts +59 -0
- package/esm/@ui/UiObjectShareDialog/UiObjectShareDialogCard.d.ts.map +1 -0
- package/esm/@ui/UiObjectShareDialog/UiObjectShareDialogCard.js +26 -0
- package/esm/@ui/UiTextInput/UiTextInput.d.ts +10 -1
- package/esm/@ui/UiTextInput/UiTextInput.d.ts.map +1 -1
- package/esm/@ui/UiTextInput/UiTextInput.js +3 -3
- package/esm/Dialog/ShareDialog/ShareDialog.d.ts +1 -1
- package/esm/Dialog/ShareDialog/ShareDialog.d.ts.map +1 -1
- package/esm/Dialog/ShareDialog/ShareDialog.js +2 -2
- package/esm/Dialog/ShareDialog/ShareDialogBase/ShareDialogBase.d.ts.map +1 -1
- package/esm/Dialog/ShareDialog/ShareDialogBase/ShareDialogBase.js +2 -2
- package/esm/Dialog/ShareDialog/ShareDialogBase/ShareGranteeBase.d.ts +1 -1
- package/esm/Dialog/ShareDialog/ShareDialogBase/ShareGranteeBase.d.ts.map +1 -1
- package/esm/Dialog/ShareDialog/ShareDialogBase/ShareGranteeBase.js +2 -2
- package/esm/Dialog/ShareDialog/ShareDialogBase/ShareLink.d.ts +1 -1
- package/esm/Dialog/ShareDialog/ShareDialogBase/ShareLink.d.ts.map +1 -1
- package/esm/Dialog/ShareDialog/ShareDialogBase/ShareLink.js +3 -3
- package/esm/Dialog/ShareDialog/ShareDialogBase/types.d.ts +3 -0
- package/esm/Dialog/ShareDialog/ShareDialogBase/types.d.ts.map +1 -1
- package/esm/Dialog/ShareDialog/types.d.ts +5 -0
- package/esm/Dialog/ShareDialog/types.d.ts.map +1 -1
- package/esm/Header/generateHeaderMenuItemsGroups.js +3 -3
- package/esm/Overlay/OverlayContext.d.ts +1 -1
- package/esm/Overlay/OverlayContext.d.ts.map +1 -1
- package/esm/Overlay/OverlayContext.js +13 -5
- package/esm/index.d.ts +8 -5
- package/esm/index.d.ts.map +1 -1
- package/esm/index.js +7 -4
- package/esm/sdk-ui-kit.d.ts +147 -92
- package/esm/typings/utilities.d.ts.map +1 -1
- package/esm/typings/utilities.js +3 -1
- package/package.json +11 -11
- package/src/@ui/UiConfirmDialog/UiConfirmDialog.scss +0 -7
- package/src/@ui/UiMenu/UiMenu.scss +0 -1
- package/src/@ui/{UiDialogShell/UiDialogShell.scss → UiModalDialog/UiModalDialog.scss} +23 -6
- package/src/@ui/UiPermissionMenu/UiPermissionMenu.scss +15 -2
- package/src/@ui/index.scss +1 -1
- package/styles/css/list.css +6 -1
- package/styles/css/list.css.map +1 -1
- package/styles/css/main.css +80 -60
- package/styles/css/main.css.map +1 -1
- package/styles/css/menu.css +6 -1
- package/styles/css/menu.css.map +1 -1
- package/styles/icons/dashboard.svg +5 -0
- package/styles/scss/list.scss +6 -1
- package/esm/@ui/UiDialogShell/UiDialogShell.d.ts +0 -59
- package/esm/@ui/UiDialogShell/UiDialogShell.d.ts.map +0 -1
- package/esm/@ui/UiDialogShell/UiDialogShell.js +0 -36
- /package/esm/@ui/{UiDialogShell → UiModalDialog}/UiDialogFooter.d.ts +0 -0
- /package/esm/@ui/{UiDialogShell → UiModalDialog}/UiDialogFooter.js +0 -0
- /package/esm/@ui/{UiDialogShell → UiModalDialog}/UiDialogHeader.d.ts +0 -0
|
@@ -3,6 +3,8 @@ import { type ReactNode } from "react";
|
|
|
3
3
|
* @internal
|
|
4
4
|
*/
|
|
5
5
|
export interface IUiAddGranteeDialogProps {
|
|
6
|
+
/** Whether the dialog is shown. */
|
|
7
|
+
isOpen: boolean;
|
|
6
8
|
/** Object title shown in the header — wrapped into `Share "\{title\}"`. */
|
|
7
9
|
objectTitle: string;
|
|
8
10
|
/** Current search query. */
|
|
@@ -18,7 +20,7 @@ export interface IUiAddGranteeDialogProps {
|
|
|
18
20
|
selectedGrantee?: ReactNode;
|
|
19
21
|
/** Fires when the user clicks the header back-arrow button. */
|
|
20
22
|
onBack: () => void;
|
|
21
|
-
/** Fires when the user clicks the header X close button. */
|
|
23
|
+
/** Fires when the user clicks the header X close button or dismisses the modal. */
|
|
22
24
|
onClose: () => void;
|
|
23
25
|
/** Fires when the user clicks Cancel in the footer. */
|
|
24
26
|
onCancel: () => void;
|
|
@@ -26,15 +28,15 @@ export interface IUiAddGranteeDialogProps {
|
|
|
26
28
|
onAdd: () => void;
|
|
27
29
|
/** When true, the primary Add button is disabled. */
|
|
28
30
|
isAddDisabled?: boolean;
|
|
29
|
-
/** Test id forwarded to the
|
|
31
|
+
/** Test id forwarded to the modal overlay. */
|
|
30
32
|
dataTestId?: string;
|
|
31
33
|
}
|
|
32
34
|
/**
|
|
33
|
-
*
|
|
35
|
+
* Modal dialog for adding a grantee, opened from the share dialog's
|
|
34
36
|
* "+ Add" action. Lets the author search for a user or group, preview the
|
|
35
37
|
* grantee they picked, and confirm adding them with the footer Add button.
|
|
36
38
|
*
|
|
37
39
|
* @internal
|
|
38
40
|
*/
|
|
39
|
-
export declare function UiAddGranteeDialog({ objectTitle, searchQuery, onSearchQueryChange, selectedGrantee, onBack, onClose, onCancel, onAdd, isAddDisabled, dataTestId }: IUiAddGranteeDialogProps): import("react/jsx-runtime").JSX.Element;
|
|
41
|
+
export declare function UiAddGranteeDialog({ isOpen, objectTitle, searchQuery, onSearchQueryChange, selectedGrantee, onBack, onClose, onCancel, onAdd, isAddDisabled, dataTestId }: IUiAddGranteeDialogProps): import("react/jsx-runtime").JSX.Element;
|
|
40
42
|
//# sourceMappingURL=UiAddGranteeDialog.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"UiAddGranteeDialog.d.ts","sourceRoot":"","sources":["../../../src/@ui/UiAddGranteeDialog/UiAddGranteeDialog.tsx"],"names":[],"mappings":"AAEA,OAAO,EAAE,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AAmBvC;;GAEG;AACH,MAAM,WAAW,wBAAwB;IACrC,6EAA2E;IAC3E,WAAW,EAAE,MAAM,CAAC;IACpB,4BAA4B;IAC5B,WAAW,EAAE,MAAM,CAAC;IACpB,kDAAkD;IAClD,mBAAmB,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IAC5C;;;;;OAKG;IACH,eAAe,CAAC,EAAE,SAAS,CAAC;IAE5B,+DAA+D;IAC/D,MAAM,EAAE,MAAM,IAAI,CAAC;IACnB,
|
|
1
|
+
{"version":3,"file":"UiAddGranteeDialog.d.ts","sourceRoot":"","sources":["../../../src/@ui/UiAddGranteeDialog/UiAddGranteeDialog.tsx"],"names":[],"mappings":"AAEA,OAAO,EAAE,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AAmBvC;;GAEG;AACH,MAAM,WAAW,wBAAwB;IACrC,mCAAmC;IACnC,MAAM,EAAE,OAAO,CAAC;IAChB,6EAA2E;IAC3E,WAAW,EAAE,MAAM,CAAC;IACpB,4BAA4B;IAC5B,WAAW,EAAE,MAAM,CAAC;IACpB,kDAAkD;IAClD,mBAAmB,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IAC5C;;;;;OAKG;IACH,eAAe,CAAC,EAAE,SAAS,CAAC;IAE5B,+DAA+D;IAC/D,MAAM,EAAE,MAAM,IAAI,CAAC;IACnB,mFAAmF;IACnF,OAAO,EAAE,MAAM,IAAI,CAAC;IACpB,uDAAuD;IACvD,QAAQ,EAAE,MAAM,IAAI,CAAC;IACrB,uEAAuE;IACvE,KAAK,EAAE,MAAM,IAAI,CAAC;IAClB,qDAAqD;IACrD,aAAa,CAAC,EAAE,OAAO,CAAC;IAExB,8CAA8C;IAC9C,UAAU,CAAC,EAAE,MAAM,CAAC;CACvB;AAED;;;;;;GAMG;AACH,wBAAgB,kBAAkB,CAAC,EAC/B,MAAM,EACN,WAAW,EACX,WAAW,EACX,mBAAmB,EACnB,eAAe,EACf,MAAM,EACN,OAAO,EACP,QAAQ,EACR,KAAK,EACL,aAAa,EACb,UAAU,EACb,EAAE,wBAAwB,2CAmD1B"}
|
|
@@ -3,24 +3,24 @@ import { useIntl } from "react-intl";
|
|
|
3
3
|
import { commonDialogMessages, olpAddGranteeDialogMessages, olpObjectShareDialogMessages, } from "../../locales.js";
|
|
4
4
|
import { bem } from "../@utils/bem.js";
|
|
5
5
|
import { UiButton } from "../UiButton/UiButton.js";
|
|
6
|
-
import { UiDialogFooter } from "../UiDialogShell/UiDialogFooter.js";
|
|
7
|
-
import { UiDialogHeader } from "../UiDialogShell/UiDialogHeader.js";
|
|
8
|
-
import { UiDialogShell } from "../UiDialogShell/UiDialogShell.js";
|
|
9
6
|
import { UiIconButton } from "../UiIconButton/UiIconButton.js";
|
|
7
|
+
import { UiDialogFooter } from "../UiModalDialog/UiDialogFooter.js";
|
|
8
|
+
import { UiDialogHeader } from "../UiModalDialog/UiDialogHeader.js";
|
|
9
|
+
import { UiModalDialog } from "../UiModalDialog/UiModalDialog.js";
|
|
10
10
|
import { UiTextInput } from "../UiTextInput/UiTextInput.js";
|
|
11
11
|
const { b, e } = bem("gd-ui-kit-add-grantee-dialog");
|
|
12
12
|
/**
|
|
13
|
-
*
|
|
13
|
+
* Modal dialog for adding a grantee, opened from the share dialog's
|
|
14
14
|
* "+ Add" action. Lets the author search for a user or group, preview the
|
|
15
15
|
* grantee they picked, and confirm adding them with the footer Add button.
|
|
16
16
|
*
|
|
17
17
|
* @internal
|
|
18
18
|
*/
|
|
19
|
-
export function UiAddGranteeDialog({ objectTitle, searchQuery, onSearchQueryChange, selectedGrantee, onBack, onClose, onCancel, onAdd, isAddDisabled, dataTestId, }) {
|
|
19
|
+
export function UiAddGranteeDialog({ isOpen, objectTitle, searchQuery, onSearchQueryChange, selectedGrantee, onBack, onClose, onCancel, onAdd, isAddDisabled, dataTestId, }) {
|
|
20
20
|
const intl = useIntl();
|
|
21
21
|
const dialogTitle = intl.formatMessage(olpObjectShareDialogMessages.title, { title: objectTitle });
|
|
22
22
|
const backButton = (_jsx(UiIconButton, { icon: "chevronLeft", variant: "tertiary", size: "small", onClick: onBack, accessibilityConfig: { ariaLabel: intl.formatMessage(olpAddGranteeDialogMessages.back) } }));
|
|
23
|
-
return (_jsxs(
|
|
23
|
+
return (_jsxs(UiModalDialog, { isOpen: isOpen, onClose: onClose, dataTestId: dataTestId, children: [
|
|
24
24
|
_jsx(UiDialogHeader, { title: dialogTitle, titleSize: "large", onClose: onClose, leading: backButton }), _jsxs("div", { className: b(), children: [
|
|
25
25
|
_jsx(UiTextInput, { type: "search", value: searchQuery, onChange: onSearchQueryChange, label: intl.formatMessage(olpAddGranteeDialogMessages.userOrGroup), placeholder: intl.formatMessage(olpAddGranteeDialogMessages.searchPlaceholder) }), _jsx("div", { className: e("preview"), children: selectedGrantee ?? (_jsx("span", { className: e("empty-state"), children: intl.formatMessage(olpAddGranteeDialogMessages.emptyState) })) })
|
|
26
26
|
] }), _jsxs(UiDialogFooter, { divider: true, children: [
|
|
@@ -1,39 +1,19 @@
|
|
|
1
|
-
import { type
|
|
2
|
-
import { type VariantDanger, type VariantPrimary } from "../@types/variant.js";
|
|
3
|
-
/**
|
|
4
|
-
* Visual variant of the confirm button.
|
|
5
|
-
*
|
|
6
|
-
* @internal
|
|
7
|
-
*/
|
|
8
|
-
export type ConfirmDialogVariant = VariantPrimary | VariantDanger;
|
|
1
|
+
import { type IUiConfirmDialogCardProps } from "./UiConfirmDialogCard.js";
|
|
9
2
|
/**
|
|
10
3
|
* @internal
|
|
11
4
|
*/
|
|
12
|
-
export interface IUiConfirmDialogProps {
|
|
13
|
-
/**
|
|
14
|
-
|
|
15
|
-
/** Body content — typically a sentence or two of description. */
|
|
16
|
-
description: ReactNode;
|
|
17
|
-
/** Label for the confirm button — e.g. "Confirm", "Remove", "Transfer". */
|
|
18
|
-
confirmLabel: string;
|
|
19
|
-
/** Visual variant of the confirm button. */
|
|
20
|
-
confirmVariant?: ConfirmDialogVariant;
|
|
21
|
-
/** Fires when the user clicks the header X close button. */
|
|
22
|
-
onClose: () => void;
|
|
23
|
-
/** Fires when the user clicks the footer Cancel button. */
|
|
24
|
-
onCancel: () => void;
|
|
25
|
-
/** Fires when the user clicks the footer confirm button. */
|
|
26
|
-
onConfirm: () => void;
|
|
27
|
-
/** Test id forwarded to the root element. */
|
|
28
|
-
dataTestId?: string;
|
|
5
|
+
export interface IUiConfirmDialogProps extends IUiConfirmDialogCardProps {
|
|
6
|
+
/** Whether the dialog is shown. */
|
|
7
|
+
isOpen: boolean;
|
|
29
8
|
}
|
|
30
9
|
/**
|
|
31
|
-
*
|
|
32
|
-
*
|
|
33
|
-
*
|
|
34
|
-
*
|
|
10
|
+
* Modal confirm dialog used for actions that need explicit user confirmation
|
|
11
|
+
* (granting workspace access, restricting access, removing a grantee,
|
|
12
|
+
* transferring ownership). Wraps `UiConfirmDialogCard` in `UiModalDialog`
|
|
13
|
+
* for the full modal contract — portal, dimmed backdrop, focus trap,
|
|
14
|
+
* Esc and backdrop dismiss.
|
|
35
15
|
*
|
|
36
16
|
* @internal
|
|
37
17
|
*/
|
|
38
|
-
export declare function UiConfirmDialog({
|
|
18
|
+
export declare function UiConfirmDialog({ isOpen, ...cardProps }: IUiConfirmDialogProps): import("react/jsx-runtime").JSX.Element;
|
|
39
19
|
//# sourceMappingURL=UiConfirmDialog.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"UiConfirmDialog.d.ts","sourceRoot":"","sources":["../../../src/@ui/UiConfirmDialog/UiConfirmDialog.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"UiConfirmDialog.d.ts","sourceRoot":"","sources":["../../../src/@ui/UiConfirmDialog/UiConfirmDialog.tsx"],"names":[],"mappings":"AAIA,OAAO,EAAE,KAAK,yBAAyB,EAAuB,MAAM,0BAA0B,CAAC;AAE/F;;GAEG;AACH,MAAM,WAAW,qBAAsB,SAAQ,yBAAyB;IACpE,mCAAmC;IACnC,MAAM,EAAE,OAAO,CAAC;CACnB;AAED;;;;;;;;GAQG;AACH,wBAAgB,eAAe,CAAC,EAAE,MAAM,EAAE,GAAG,SAAS,EAAE,EAAE,qBAAqB,2CAM9E"}
|
|
@@ -1,28 +1,16 @@
|
|
|
1
|
-
import { jsx as _jsx
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
2
|
// (C) 2026 GoodData Corporation
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import { commonDialogMessages } from "../../locales.js";
|
|
6
|
-
import { bem } from "../@utils/bem.js";
|
|
7
|
-
import { UiButton } from "../UiButton/UiButton.js";
|
|
8
|
-
import { UiDialogFooter } from "../UiDialogShell/UiDialogFooter.js";
|
|
9
|
-
import { UiDialogHeader } from "../UiDialogShell/UiDialogHeader.js";
|
|
10
|
-
import { UiDialogShell } from "../UiDialogShell/UiDialogShell.js";
|
|
11
|
-
const { b, e } = bem("gd-ui-kit-confirm-dialog");
|
|
3
|
+
import { UiModalDialog } from "../UiModalDialog/UiModalDialog.js";
|
|
4
|
+
import { UiConfirmDialogCard } from "./UiConfirmDialogCard.js";
|
|
12
5
|
/**
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
6
|
+
* Modal confirm dialog used for actions that need explicit user confirmation
|
|
7
|
+
* (granting workspace access, restricting access, removing a grantee,
|
|
8
|
+
* transferring ownership). Wraps `UiConfirmDialogCard` in `UiModalDialog`
|
|
9
|
+
* for the full modal contract — portal, dimmed backdrop, focus trap,
|
|
10
|
+
* Esc and backdrop dismiss.
|
|
17
11
|
*
|
|
18
12
|
* @internal
|
|
19
13
|
*/
|
|
20
|
-
export function UiConfirmDialog({
|
|
21
|
-
|
|
22
|
-
const descriptionId = useId();
|
|
23
|
-
return (_jsx(UiDialogShell, { width: 420, isModal: true, onClose: onClose, dataTestId: dataTestId, accessibilityConfig: { ariaDescribedBy: descriptionId }, children: _jsxs("div", { className: b(), children: [
|
|
24
|
-
_jsx(UiDialogHeader, { title: title, onClose: onClose }), _jsx("div", { className: e("body"), id: descriptionId, children: description }), _jsxs(UiDialogFooter, { children: [
|
|
25
|
-
_jsx(UiButton, { label: intl.formatMessage(commonDialogMessages.cancel), variant: "secondary", size: "medium", onClick: onCancel, autoFocus: true }), _jsx(UiButton, { label: confirmLabel, variant: confirmVariant, size: "medium", onClick: onConfirm })
|
|
26
|
-
] })
|
|
27
|
-
] }) }));
|
|
14
|
+
export function UiConfirmDialog({ isOpen, ...cardProps }) {
|
|
15
|
+
return (_jsx(UiModalDialog, { isOpen: isOpen, onClose: cardProps.onClose, width: 420, children: _jsx(UiConfirmDialogCard, { ...cardProps }) }));
|
|
28
16
|
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { type ReactNode } from "react";
|
|
2
|
+
import { type VariantDanger, type VariantPrimary } from "../@types/variant.js";
|
|
3
|
+
/**
|
|
4
|
+
* Visual variant of the confirm button.
|
|
5
|
+
*
|
|
6
|
+
* @internal
|
|
7
|
+
*/
|
|
8
|
+
export type ConfirmDialogVariant = VariantPrimary | VariantDanger;
|
|
9
|
+
/**
|
|
10
|
+
* @internal
|
|
11
|
+
*/
|
|
12
|
+
export interface IUiConfirmDialogCardProps {
|
|
13
|
+
/** Dialog title rendered inside the header. */
|
|
14
|
+
title: string;
|
|
15
|
+
/** Body content — typically a sentence or two of description. */
|
|
16
|
+
description: ReactNode;
|
|
17
|
+
/** Label for the confirm button — e.g. "Confirm", "Remove", "Transfer". */
|
|
18
|
+
confirmLabel: string;
|
|
19
|
+
/** Visual variant of the confirm button. */
|
|
20
|
+
confirmVariant?: ConfirmDialogVariant;
|
|
21
|
+
/** Fires when the user clicks the header X close button. */
|
|
22
|
+
onClose: () => void;
|
|
23
|
+
/** Fires when the user clicks the footer Cancel button. */
|
|
24
|
+
onCancel: () => void;
|
|
25
|
+
/** Fires when the user clicks the footer confirm button. */
|
|
26
|
+
onConfirm: () => void;
|
|
27
|
+
/** Test id forwarded to the root of the card composition. */
|
|
28
|
+
dataTestId?: string;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Confirm dialog composition — header, description body, footer with Cancel
|
|
32
|
+
* and Confirm buttons. Designed to be rendered inside `UiModalDialog`, which
|
|
33
|
+
* provides the modal chrome (portal, backdrop, card surface, focus trap,
|
|
34
|
+
* dismiss). `UiConfirmDialog` wraps this composition in `UiModalDialog`
|
|
35
|
+
* with the right width and exposes the combined surface to callers.
|
|
36
|
+
*
|
|
37
|
+
* @internal
|
|
38
|
+
*/
|
|
39
|
+
export declare function UiConfirmDialogCard({ title, description, confirmLabel, confirmVariant, onClose, onCancel, onConfirm, dataTestId }: IUiConfirmDialogCardProps): import("react/jsx-runtime").JSX.Element;
|
|
40
|
+
//# sourceMappingURL=UiConfirmDialogCard.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"UiConfirmDialogCard.d.ts","sourceRoot":"","sources":["../../../src/@ui/UiConfirmDialog/UiConfirmDialogCard.tsx"],"names":[],"mappings":"AAEA,OAAO,EAAE,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AAKvC,OAAO,EAAE,KAAK,aAAa,EAAE,KAAK,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAS/E;;;;GAIG;AACH,MAAM,MAAM,oBAAoB,GAAG,cAAc,GAAG,aAAa,CAAC;AAElE;;GAEG;AACH,MAAM,WAAW,yBAAyB;IACtC,+CAA+C;IAC/C,KAAK,EAAE,MAAM,CAAC;IACd,mEAAiE;IACjE,WAAW,EAAE,SAAS,CAAC;IACvB,6EAA2E;IAC3E,YAAY,EAAE,MAAM,CAAC;IACrB,4CAA4C;IAC5C,cAAc,CAAC,EAAE,oBAAoB,CAAC;IACtC,4DAA4D;IAC5D,OAAO,EAAE,MAAM,IAAI,CAAC;IACpB,2DAA2D;IAC3D,QAAQ,EAAE,MAAM,IAAI,CAAC;IACrB,4DAA4D;IAC5D,SAAS,EAAE,MAAM,IAAI,CAAC;IACtB,6DAA6D;IAC7D,UAAU,CAAC,EAAE,MAAM,CAAC;CACvB;AAED;;;;;;;;GAQG;AACH,wBAAgB,mBAAmB,CAAC,EAChC,KAAK,EACL,WAAW,EACX,YAAY,EACZ,cAA0B,EAC1B,OAAO,EACP,QAAQ,EACR,SAAS,EACT,UAAU,EACb,EAAE,yBAAyB,2CAoB3B"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { useIntl } from "react-intl";
|
|
3
|
+
import { commonDialogMessages } from "../../locales.js";
|
|
4
|
+
import { bem } from "../@utils/bem.js";
|
|
5
|
+
import { UiButton } from "../UiButton/UiButton.js";
|
|
6
|
+
import { UiDialogBody } from "../UiModalDialog/UiDialogBody.js";
|
|
7
|
+
import { UiDialogFooter } from "../UiModalDialog/UiDialogFooter.js";
|
|
8
|
+
import { UiDialogHeader } from "../UiModalDialog/UiDialogHeader.js";
|
|
9
|
+
const { b } = bem("gd-ui-kit-confirm-dialog");
|
|
10
|
+
/**
|
|
11
|
+
* Confirm dialog composition — header, description body, footer with Cancel
|
|
12
|
+
* and Confirm buttons. Designed to be rendered inside `UiModalDialog`, which
|
|
13
|
+
* provides the modal chrome (portal, backdrop, card surface, focus trap,
|
|
14
|
+
* dismiss). `UiConfirmDialog` wraps this composition in `UiModalDialog`
|
|
15
|
+
* with the right width and exposes the combined surface to callers.
|
|
16
|
+
*
|
|
17
|
+
* @internal
|
|
18
|
+
*/
|
|
19
|
+
export function UiConfirmDialogCard({ title, description, confirmLabel, confirmVariant = "primary", onClose, onCancel, onConfirm, dataTestId, }) {
|
|
20
|
+
const intl = useIntl();
|
|
21
|
+
return (_jsxs("div", { className: b(), "data-testid": dataTestId, children: [
|
|
22
|
+
_jsx(UiDialogHeader, { title: title, onClose: onClose }), _jsx(UiDialogBody, { children: description }), _jsxs(UiDialogFooter, { children: [
|
|
23
|
+
_jsx(UiButton, { label: intl.formatMessage(commonDialogMessages.cancel), variant: "secondary", size: "medium", onClick: onCancel, autoFocus: true }), _jsx(UiButton, { label: confirmLabel, variant: confirmVariant, size: "medium", onClick: onConfirm })
|
|
24
|
+
] })
|
|
25
|
+
] }));
|
|
26
|
+
}
|
|
@@ -26,6 +26,6 @@ export function UiGranteeRowControls({ labels, selectedLabelIds, permissionLevel
|
|
|
26
26
|
: intl.formatMessage(olpGranteeControlsMessages.labelsCount, { selected, total });
|
|
27
27
|
const permissionTriggerText = intl.formatMessage(permissionLevel === "SHARE" ? olpPermissionMessages.canViewAndShare : olpPermissionMessages.canView);
|
|
28
28
|
return (_jsxs("div", { className: b(), "data-testid": dataTestId, children: [
|
|
29
|
-
_jsx(UiLabelsPicker, { anchor: _jsx(UiButton, { label: labelsTriggerText, size: "small", variant: "
|
|
29
|
+
_jsx(UiLabelsPicker, { anchor: _jsx(UiButton, { label: labelsTriggerText, size: "small", variant: "dropdownInline", iconAfter: "navigateDown" }), items: labels, defaultSelectedIds: selectedLabelIds, onApply: onLabelsChange }), _jsx(UiPermissionMenu, { anchor: _jsx(UiButton, { label: permissionTriggerText, size: "small", variant: "dropdownInline", iconAfter: "navigateDown" }), selectedLevel: permissionLevel, onPermissionChange: onPermissionChange, onTransferOwnership: onTransferOwnership, onRemoveAccess: onRemoveAccess })
|
|
30
30
|
] }));
|
|
31
31
|
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { type ReactNode } from "react";
|
|
2
|
+
/**
|
|
3
|
+
* @internal
|
|
4
|
+
*/
|
|
5
|
+
export interface IUiDialogBodyProps {
|
|
6
|
+
/** Description content — typically a sentence or two of body text. */
|
|
7
|
+
children: ReactNode;
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* Dialog description body — slot for cards whose meaning lives in a single
|
|
11
|
+
* block of text (confirm dialogs). Carries the dialog's `descriptionId` so
|
|
12
|
+
* the modal landmark's `aria-describedby` resolves to this element.
|
|
13
|
+
*
|
|
14
|
+
* @internal
|
|
15
|
+
*/
|
|
16
|
+
export declare function UiDialogBody({ children }: IUiDialogBodyProps): import("react/jsx-runtime").JSX.Element;
|
|
17
|
+
//# sourceMappingURL=UiDialogBody.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"UiDialogBody.d.ts","sourceRoot":"","sources":["../../../src/@ui/UiModalDialog/UiDialogBody.tsx"],"names":[],"mappings":"AAEA,OAAO,EAAE,KAAK,SAAS,EAAmB,MAAM,OAAO,CAAC;AAQxD;;GAEG;AACH,MAAM,WAAW,kBAAkB;IAC/B,wEAAsE;IACtE,QAAQ,EAAE,SAAS,CAAC;CACvB;AAED;;;;;;GAMG;AACH,wBAAgB,YAAY,CAAC,EAAE,QAAQ,EAAE,EAAE,kBAAkB,2CAc5D"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
// (C) 2026 GoodData Corporation
|
|
3
|
+
import { useLayoutEffect } from "react";
|
|
4
|
+
import { bem } from "../@utils/bem.js";
|
|
5
|
+
import { useUiDialogContext } from "./UiModalDialog.js";
|
|
6
|
+
const { b } = bem("gd-ui-kit-dialog-body");
|
|
7
|
+
/**
|
|
8
|
+
* Dialog description body — slot for cards whose meaning lives in a single
|
|
9
|
+
* block of text (confirm dialogs). Carries the dialog's `descriptionId` so
|
|
10
|
+
* the modal landmark's `aria-describedby` resolves to this element.
|
|
11
|
+
*
|
|
12
|
+
* @internal
|
|
13
|
+
*/
|
|
14
|
+
export function UiDialogBody({ children }) {
|
|
15
|
+
const dialogContext = useUiDialogContext();
|
|
16
|
+
// useLayoutEffect commits synchronously before paint, so the modal's
|
|
17
|
+
// `aria-describedby` is wired up before the focus manager moves focus
|
|
18
|
+
// and the screen reader announces the dialog. Cleanup restores the
|
|
19
|
+
// counter when the body unmounts (modal stays open, content switched).
|
|
20
|
+
useLayoutEffect(() => {
|
|
21
|
+
return dialogContext?.registerBody();
|
|
22
|
+
}, [dialogContext]);
|
|
23
|
+
return (_jsx("div", { className: b(), id: dialogContext?.descriptionId, children: children }));
|
|
24
|
+
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"UiDialogFooter.d.ts","sourceRoot":"","sources":["../../../src/@ui/
|
|
1
|
+
{"version":3,"file":"UiDialogFooter.d.ts","sourceRoot":"","sources":["../../../src/@ui/UiModalDialog/UiDialogFooter.tsx"],"names":[],"mappings":"AAEA,OAAO,EAAE,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AAMvC;;GAEG;AACH,MAAM,WAAW,oBAAoB;IACjC,6EAA6E;IAC7E,QAAQ,EAAE,SAAS,CAAC;IACpB;;;;OAIG;IACH,OAAO,CAAC,EAAE,OAAO,CAAC;CACrB;AAED;;;;;GAKG;AACH,wBAAgB,cAAc,CAAC,EAAE,QAAQ,EAAE,OAAe,EAAE,EAAE,oBAAoB,2CAEjF"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"UiDialogHeader.d.ts","sourceRoot":"","sources":["../../../src/@ui/
|
|
1
|
+
{"version":3,"file":"UiDialogHeader.d.ts","sourceRoot":"","sources":["../../../src/@ui/UiModalDialog/UiDialogHeader.tsx"],"names":[],"mappings":"AAEA,OAAO,EAAE,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AAYvC;;;;GAIG;AACH,MAAM,MAAM,qBAAqB,GAAG,SAAS,GAAG,OAAO,CAAC;AAExD;;GAEG;AACH,MAAM,WAAW,oBAAoB;IACjC,iCAAiC;IACjC,KAAK,EAAE,MAAM,CAAC;IACd,6DAA2D;IAC3D,SAAS,CAAC,EAAE,qBAAqB,CAAC;IAClC,yEAAyE;IACzE,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;IACrB,4EAA4E;IAC5E,OAAO,CAAC,EAAE,SAAS,CAAC;CACvB;AAED;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,EAAE,KAAK,EAAE,SAAqB,EAAE,OAAO,EAAE,OAAO,EAAE,EAAE,oBAAoB,2CAsBtG"}
|
|
@@ -3,7 +3,7 @@ import { useIntl } from "react-intl";
|
|
|
3
3
|
import { commonDialogMessages } from "../../locales.js";
|
|
4
4
|
import { bem } from "../@utils/bem.js";
|
|
5
5
|
import { UiIconButton } from "../UiIconButton/UiIconButton.js";
|
|
6
|
-
import { useUiDialogContext } from "./
|
|
6
|
+
import { useUiDialogContext } from "./UiModalDialog.js";
|
|
7
7
|
const { b, e } = bem("gd-ui-kit-dialog-header");
|
|
8
8
|
/**
|
|
9
9
|
* Dialog header: optional leading slot + title + optional close X.
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { type ReactNode } from "react";
|
|
2
|
+
import { type IAccessibilityConfigBase } from "../../typings/accessibility.js";
|
|
3
|
+
interface IUiDialogContext {
|
|
4
|
+
titleId: string;
|
|
5
|
+
descriptionId: string;
|
|
6
|
+
/**
|
|
7
|
+
* Called by `UiDialogBody` from `useLayoutEffect` on mount; returns a
|
|
8
|
+
* cleanup to call on unmount. The modal counts mounted bodies so
|
|
9
|
+
* `aria-describedby` is set when at least one body is rendered and
|
|
10
|
+
* cleared when the last one unmounts.
|
|
11
|
+
*/
|
|
12
|
+
registerBody: () => () => void;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* @internal
|
|
16
|
+
*/
|
|
17
|
+
export declare function useUiDialogContext(): IUiDialogContext | null;
|
|
18
|
+
/**
|
|
19
|
+
* @internal
|
|
20
|
+
*/
|
|
21
|
+
export interface IUiModalDialogProps {
|
|
22
|
+
/** Dialog content composed by the caller — typically `UiDialogHeader`,
|
|
23
|
+
* an optional `UiDialogBody`, and `UiDialogFooter`. */
|
|
24
|
+
children: ReactNode;
|
|
25
|
+
/** Whether the modal is shown. */
|
|
26
|
+
isOpen: boolean;
|
|
27
|
+
/** Fires when the user dismisses via Esc, backdrop click, or `onClose` from inside. */
|
|
28
|
+
onClose: () => void;
|
|
29
|
+
/** Card width in px. Defaults to 540. */
|
|
30
|
+
width?: number;
|
|
31
|
+
/**
|
|
32
|
+
* Overrides for the dialog landmark's accessible name. Usually unnecessary —
|
|
33
|
+
* the landmark auto-wires `aria-labelledby` to the `UiDialogHeader` title
|
|
34
|
+
* via context. For headerless dialogs, pass `ariaLabel`; to point at an
|
|
35
|
+
* external title, pass `ariaLabelledBy`.
|
|
36
|
+
*/
|
|
37
|
+
accessibilityConfig?: Pick<IAccessibilityConfigBase, "ariaLabel" | "ariaLabelledBy">;
|
|
38
|
+
/** Test id forwarded to the overlay element. */
|
|
39
|
+
dataTestId?: string;
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Modal dialog — portal, dimmed backdrop, card chrome (radius, shadow, fill,
|
|
43
|
+
* padding), focus management, dismiss-on-outside / Esc, and the dialog
|
|
44
|
+
* landmark (`role="dialog"`, `aria-modal="true"`). Compose `UiDialogHeader`,
|
|
45
|
+
* an optional `UiDialogBody`, and `UiDialogFooter` as children.
|
|
46
|
+
*
|
|
47
|
+
* @internal
|
|
48
|
+
*/
|
|
49
|
+
export declare function UiModalDialog({ children, isOpen, onClose, width, accessibilityConfig, dataTestId }: IUiModalDialogProps): import("react/jsx-runtime").JSX.Element | null;
|
|
50
|
+
export {};
|
|
51
|
+
//# sourceMappingURL=UiModalDialog.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"UiModalDialog.d.ts","sourceRoot":"","sources":["../../../src/@ui/UiModalDialog/UiModalDialog.tsx"],"names":[],"mappings":"AAEA,OAAO,EAEH,KAAK,SAAS,EAQjB,MAAM,OAAO,CAAC;AAcf,OAAO,EAAE,KAAK,wBAAwB,EAAE,MAAM,gCAAgC,CAAC;AAK/E,UAAU,gBAAgB;IACtB,OAAO,EAAE,MAAM,CAAC;IAChB,aAAa,EAAE,MAAM,CAAC;IACtB;;;;;OAKG;IACH,YAAY,EAAE,MAAM,MAAM,IAAI,CAAC;CAClC;AAID;;GAEG;AACH,wBAAgB,kBAAkB,IAAI,gBAAgB,GAAG,IAAI,CAE5D;AAED;;GAEG;AACH,MAAM,WAAW,mBAAmB;IAChC;4DACwD;IACxD,QAAQ,EAAE,SAAS,CAAC;IACpB,kCAAkC;IAClC,MAAM,EAAE,OAAO,CAAC;IAChB,uFAAuF;IACvF,OAAO,EAAE,MAAM,IAAI,CAAC;IACpB,yCAAyC;IACzC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf;;;;;OAKG;IACH,mBAAmB,CAAC,EAAE,IAAI,CAAC,wBAAwB,EAAE,WAAW,GAAG,gBAAgB,CAAC,CAAC;IACrF,gDAAgD;IAChD,UAAU,CAAC,EAAE,MAAM,CAAC;CACvB;AAED;;;;;;;GAOG;AACH,wBAAgB,aAAa,CAAC,EAC1B,QAAQ,EACR,MAAM,EACN,OAAO,EACP,KAAK,EACL,mBAAmB,EACnB,UAAU,EACb,EAAE,mBAAmB,kDAcrB"}
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
// (C) 2026 GoodData Corporation
|
|
3
|
+
import { createContext, useCallback, useContext, useId, useMemo, useRef, useState, } from "react";
|
|
4
|
+
import { FloatingFocusManager, FloatingOverlay, FloatingPortal, useDismiss, useFloating, useInteractions, } from "@floating-ui/react";
|
|
5
|
+
import { ConditionalScopedThemeProvider } from "@gooddata/sdk-ui-theme-provider";
|
|
6
|
+
import { useOverlayZIndexWithRegister } from "../../Overlay/OverlayContext.js";
|
|
7
|
+
import { bem } from "../@utils/bem.js";
|
|
8
|
+
const { b, e } = bem("gd-ui-kit-modal-dialog");
|
|
9
|
+
const UiDialogContext = createContext(null);
|
|
10
|
+
/**
|
|
11
|
+
* @internal
|
|
12
|
+
*/
|
|
13
|
+
export function useUiDialogContext() {
|
|
14
|
+
return useContext(UiDialogContext);
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Modal dialog — portal, dimmed backdrop, card chrome (radius, shadow, fill,
|
|
18
|
+
* padding), focus management, dismiss-on-outside / Esc, and the dialog
|
|
19
|
+
* landmark (`role="dialog"`, `aria-modal="true"`). Compose `UiDialogHeader`,
|
|
20
|
+
* an optional `UiDialogBody`, and `UiDialogFooter` as children.
|
|
21
|
+
*
|
|
22
|
+
* @internal
|
|
23
|
+
*/
|
|
24
|
+
export function UiModalDialog({ children, isOpen, onClose, width, accessibilityConfig, dataTestId, }) {
|
|
25
|
+
if (!isOpen) {
|
|
26
|
+
return null;
|
|
27
|
+
}
|
|
28
|
+
return (_jsx(OpenModalDialog, { onClose: onClose, width: width, accessibilityConfig: accessibilityConfig, dataTestId: dataTestId, children: children }));
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Inner body — only mounted while the modal is open so the z-index slot is
|
|
32
|
+
* reserved for the open lifetime only. Splitting this out matters because
|
|
33
|
+
* `useOverlayZIndexWithRegister` registers in a mount effect.
|
|
34
|
+
*/
|
|
35
|
+
function OpenModalDialog({ children, onClose, width = 540, accessibilityConfig, dataTestId, }) {
|
|
36
|
+
const zIndex = useOverlayZIndexWithRegister();
|
|
37
|
+
const titleId = useId();
|
|
38
|
+
const descriptionId = useId();
|
|
39
|
+
// Ref-counted so multiple UiDialogBody siblings + dynamic mount/unmount
|
|
40
|
+
// (multi-step cards, conditional descriptions) keep `aria-describedby` in
|
|
41
|
+
// sync with whether a description element is actually rendered.
|
|
42
|
+
const [bodyCount, setBodyCount] = useState(0);
|
|
43
|
+
const registerBody = useCallback(() => {
|
|
44
|
+
setBodyCount((n) => n + 1);
|
|
45
|
+
return () => setBodyCount((n) => n - 1);
|
|
46
|
+
}, []);
|
|
47
|
+
const hasBody = bodyCount > 0;
|
|
48
|
+
const { refs, context } = useFloating({
|
|
49
|
+
open: true,
|
|
50
|
+
onOpenChange: (open) => {
|
|
51
|
+
if (!open) {
|
|
52
|
+
onClose();
|
|
53
|
+
}
|
|
54
|
+
},
|
|
55
|
+
});
|
|
56
|
+
// Prefer a deliberate `autoFocus` target (e.g. `UiConfirmDialogCard`'s
|
|
57
|
+
// Cancel button) over `FloatingFocusManager`'s default of first-tabbable
|
|
58
|
+
// — which would land focus on the header close icon and break the safe
|
|
59
|
+
// initial keyboard target for confirm dialogs. We resolve the target via
|
|
60
|
+
// a callback ref on the floating element so the lookup happens before
|
|
61
|
+
// `FloatingFocusManager` reads `initialFocusRef.current` on mount.
|
|
62
|
+
// When no `[autofocus]` child exists we leave the ref null and pass
|
|
63
|
+
// `undefined` to `FloatingFocusManager` so it uses its default
|
|
64
|
+
// first-tabbable behavior — passing a ref whose `.current` is `null`
|
|
65
|
+
// makes it focus the dialog card itself instead of the first action.
|
|
66
|
+
const initialFocusRef = useRef(null);
|
|
67
|
+
const [hasAutofocusTarget, setHasAutofocusTarget] = useState(false);
|
|
68
|
+
const setFloatingRef = useCallback((node) => {
|
|
69
|
+
refs.setFloating(node);
|
|
70
|
+
const target = node?.querySelector("[autofocus]") ?? null;
|
|
71
|
+
initialFocusRef.current = target;
|
|
72
|
+
setHasAutofocusTarget(target !== null);
|
|
73
|
+
}, [refs]);
|
|
74
|
+
const dismiss = useDismiss(context, {
|
|
75
|
+
outsidePressEvent: "mousedown",
|
|
76
|
+
// Nested kit floating popups (dropdowns, menus, autocomplete listbox)
|
|
77
|
+
// portal their bodies outside our `refs.floating`, so a click on a
|
|
78
|
+
// popup option looks like a backdrop press. Suppress dismiss when
|
|
79
|
+
// the press lands inside any kit floating element (canonical kit
|
|
80
|
+
// marker) or inside another floating-ui portal sibling.
|
|
81
|
+
outsidePress: (event) => {
|
|
82
|
+
const target = event.target;
|
|
83
|
+
if (target?.closest("[data-gd-floating-element]")) {
|
|
84
|
+
return false;
|
|
85
|
+
}
|
|
86
|
+
const pressedPortal = target?.closest("[data-floating-ui-portal]");
|
|
87
|
+
const ownPortal = refs.floating.current?.closest("[data-floating-ui-portal]");
|
|
88
|
+
return !(pressedPortal && pressedPortal !== ownPortal);
|
|
89
|
+
},
|
|
90
|
+
// Escape is handled locally on the card (see `onKeyDown` below) so
|
|
91
|
+
// that pressing Escape inside a portaled child popover dismisses the
|
|
92
|
+
// popover only — not the modal underneath. floating-ui's default
|
|
93
|
+
// document-level Escape listener would fire on the modal first.
|
|
94
|
+
escapeKey: false,
|
|
95
|
+
});
|
|
96
|
+
const { getFloatingProps } = useInteractions([dismiss]);
|
|
97
|
+
const onCardKeyDown = useCallback((event) => {
|
|
98
|
+
if (event.key !== "Escape" || event.defaultPrevented) {
|
|
99
|
+
return;
|
|
100
|
+
}
|
|
101
|
+
// React events bubble through the JSX parent chain, so a keydown
|
|
102
|
+
// inside a portaled child popover still reaches this handler.
|
|
103
|
+
// Only act when the original target sits inside the card's DOM
|
|
104
|
+
// subtree — otherwise the inner popover handles its own dismiss.
|
|
105
|
+
const card = refs.floating.current;
|
|
106
|
+
if (card && event.target instanceof Node && !card.contains(event.target)) {
|
|
107
|
+
return;
|
|
108
|
+
}
|
|
109
|
+
event.stopPropagation();
|
|
110
|
+
onClose();
|
|
111
|
+
}, [onClose, refs]);
|
|
112
|
+
const ariaLabelledBy = accessibilityConfig?.ariaLabelledBy ?? (accessibilityConfig?.ariaLabel ? undefined : titleId);
|
|
113
|
+
const dialogContextValue = useMemo(() => ({ titleId, descriptionId, registerBody }), [titleId, descriptionId, registerBody]);
|
|
114
|
+
// Nested kit popovers/menus (UiPopover, UiTooltip, dropdowns) portal
|
|
115
|
+
// out of the modal card into sibling `[data-floating-ui-portal]` nodes.
|
|
116
|
+
// FloatingFocusManager defaults to `modal=true`, which treats everything
|
|
117
|
+
// outside `refs.floating` as inaccessible and blocks Tab into those
|
|
118
|
+
// portals. Surface them as inside elements so keyboard navigation can
|
|
119
|
+
// reach the menus while the modal trap remains in effect.
|
|
120
|
+
//
|
|
121
|
+
// Narrow scope: snapshot the portals present at modal mount and treat
|
|
122
|
+
// only later-added portals as nested. Without the snapshot, foreign
|
|
123
|
+
// floating UI mounted elsewhere on the page (toasts, persistent
|
|
124
|
+
// pickers) would be considered inside the trap and Tab could escape
|
|
125
|
+
// the modal.
|
|
126
|
+
const portalsAtMountRef = useRef(null);
|
|
127
|
+
if (portalsAtMountRef.current === null) {
|
|
128
|
+
portalsAtMountRef.current = new Set(Array.from(document.querySelectorAll("[data-floating-ui-portal]")));
|
|
129
|
+
}
|
|
130
|
+
const getInsideElements = useCallback(() => {
|
|
131
|
+
const snapshot = portalsAtMountRef.current ?? new Set();
|
|
132
|
+
return Array.from(document.querySelectorAll("[data-floating-ui-portal]")).filter((node) => !snapshot.has(node) && !node.contains(refs.floating.current));
|
|
133
|
+
}, [refs]);
|
|
134
|
+
return (_jsx(FloatingPortal, { children: _jsx(ConditionalScopedThemeProvider, { children: _jsx(FloatingOverlay, { lockScroll: true, className: b(), "data-testid": dataTestId, style: { zIndex }, children: _jsx(FloatingFocusManager, { context: context, initialFocus: hasAutofocusTarget ? initialFocusRef : undefined, getInsideElements: getInsideElements, children: _jsx("div", { ref: setFloatingRef, className: e("card"), style: { width }, role: "dialog", "aria-modal": "true", "aria-label": accessibilityConfig?.ariaLabel, "aria-labelledby": ariaLabelledBy, "aria-describedby": hasBody ? descriptionId : undefined, ...getFloatingProps(), onKeyDown: onCardKeyDown, children: _jsx(UiDialogContext.Provider, { value: dialogContextValue, children: children }) }) }) }) }) }));
|
|
135
|
+
}
|
|
@@ -1,58 +1,17 @@
|
|
|
1
|
-
import { type
|
|
2
|
-
import { type GeneralAccessValue } from "../UiGeneralAccessRadio/UiGeneralAccessRadio.js";
|
|
3
|
-
import { type GranteeAvatarKind } from "../UiGranteeAvatar/UiGranteeAvatar.js";
|
|
4
|
-
/**
|
|
5
|
-
* Visual data for a single grantee row inside the dialog. The `controls`
|
|
6
|
-
* slot lets the caller plug in the per-row controls (typically
|
|
7
|
-
* `UiGranteeRowControls`).
|
|
8
|
-
*
|
|
9
|
-
* @internal
|
|
10
|
-
*/
|
|
11
|
-
export interface IUiObjectShareDialogGrantee {
|
|
12
|
-
/** Stable identifier — used as the React key for the row. */
|
|
13
|
-
id: string;
|
|
14
|
-
/** Avatar variant. */
|
|
15
|
-
kind: GranteeAvatarKind;
|
|
16
|
-
/** Display name. */
|
|
17
|
-
name: string;
|
|
18
|
-
/** Optional email subline. */
|
|
19
|
-
email?: string;
|
|
20
|
-
/** When true, the row is rendered with the "Owner" tag instead of controls. */
|
|
21
|
-
isOwner?: boolean;
|
|
22
|
-
/** Per-row controls — usually `UiGranteeRowControls`. Owner rows leave this empty. */
|
|
23
|
-
controls?: ReactNode;
|
|
24
|
-
}
|
|
1
|
+
import { type IUiObjectShareDialogCardProps } from "./UiObjectShareDialogCard.js";
|
|
25
2
|
/**
|
|
26
3
|
* @internal
|
|
27
4
|
*/
|
|
28
|
-
export interface IUiObjectShareDialogProps {
|
|
29
|
-
/**
|
|
30
|
-
|
|
31
|
-
/** Fires when the user clicks the header X button OR the footer Close button. */
|
|
32
|
-
onClose: () => void;
|
|
33
|
-
/** Grantee rows shown inside the SHARED WITH section, in render order. */
|
|
34
|
-
grantees: IUiObjectShareDialogGrantee[];
|
|
35
|
-
/** Fires when the user clicks the + Add link in the SHARED WITH heading. */
|
|
36
|
-
onAddClick: () => void;
|
|
37
|
-
/** Selected general-access option. */
|
|
38
|
-
generalAccess: GeneralAccessValue;
|
|
39
|
-
/** Fires when the user picks a different general-access option. */
|
|
40
|
-
onGeneralAccessChange: (value: GeneralAccessValue) => void;
|
|
41
|
-
/**
|
|
42
|
-
* Optional slot rendered next to the "All workspace members" row — typically a
|
|
43
|
-
* `UiGranteeRowControls` pair for the workspace-wide labels picker
|
|
44
|
-
* and permission level.
|
|
45
|
-
*/
|
|
46
|
-
workspaceControls?: ReactNode;
|
|
47
|
-
/** Test id forwarded to the root element. */
|
|
48
|
-
dataTestId?: string;
|
|
5
|
+
export interface IUiObjectShareDialogProps extends IUiObjectShareDialogCardProps {
|
|
6
|
+
/** Whether the dialog is shown. */
|
|
7
|
+
isOpen: boolean;
|
|
49
8
|
}
|
|
50
9
|
/**
|
|
51
|
-
*
|
|
52
|
-
*
|
|
53
|
-
*
|
|
10
|
+
* Object share dialog — wraps `UiObjectShareDialogCard` in `UiModalDialog`
|
|
11
|
+
* for the full modal contract (portal, dimmed backdrop, focus trap, Esc
|
|
12
|
+
* and backdrop dismiss).
|
|
54
13
|
*
|
|
55
14
|
* @internal
|
|
56
15
|
*/
|
|
57
|
-
export declare function UiObjectShareDialog({
|
|
16
|
+
export declare function UiObjectShareDialog({ isOpen, ...cardProps }: IUiObjectShareDialogProps): import("react/jsx-runtime").JSX.Element;
|
|
58
17
|
//# sourceMappingURL=UiObjectShareDialog.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"UiObjectShareDialog.d.ts","sourceRoot":"","sources":["../../../src/@ui/UiObjectShareDialog/UiObjectShareDialog.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"UiObjectShareDialog.d.ts","sourceRoot":"","sources":["../../../src/@ui/UiObjectShareDialog/UiObjectShareDialog.tsx"],"names":[],"mappings":"AAIA,OAAO,EAAE,KAAK,6BAA6B,EAA2B,MAAM,8BAA8B,CAAC;AAE3G;;GAEG;AACH,MAAM,WAAW,yBAA0B,SAAQ,6BAA6B;IAC5E,mCAAmC;IACnC,MAAM,EAAE,OAAO,CAAC;CACnB;AAED;;;;;;GAMG;AACH,wBAAgB,mBAAmB,CAAC,EAAE,MAAM,EAAE,GAAG,SAAS,EAAE,EAAE,yBAAyB,2CAMtF"}
|