@gooddata/sdk-ui-kit 11.39.0-alpha.2 → 11.39.0-alpha.4
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/@types/icon.d.ts +1 -1
- package/esm/@ui/UiAddGranteeDialog/UiAddGranteeDialog.d.ts +39 -0
- package/esm/@ui/UiAddGranteeDialog/UiAddGranteeDialog.js +30 -0
- package/esm/@ui/UiAvatar/UiAvatar.d.ts +40 -0
- package/esm/@ui/UiAvatar/UiAvatar.js +19 -0
- package/esm/@ui/UiButton/UiButton.d.ts +7 -0
- package/esm/@ui/UiButton/UiButton.js +2 -2
- package/esm/@ui/UiConfirmDialog/UiConfirmDialog.d.ts +38 -0
- package/esm/@ui/UiConfirmDialog/UiConfirmDialog.js +28 -0
- package/esm/@ui/UiDialogShell/UiDialogFooter.d.ts +21 -0
- package/esm/@ui/UiDialogShell/UiDialogFooter.js +12 -0
- package/esm/@ui/UiDialogShell/UiDialogHeader.d.ts +26 -0
- package/esm/@ui/UiDialogShell/UiDialogHeader.js +19 -0
- package/esm/@ui/UiDialogShell/UiDialogShell.d.ts +58 -0
- package/esm/@ui/UiDialogShell/UiDialogShell.js +36 -0
- package/esm/@ui/UiGeneralAccessRadio/UiGeneralAccessRadio.d.ts +32 -0
- package/esm/@ui/UiGeneralAccessRadio/UiGeneralAccessRadio.js +22 -0
- package/esm/@ui/UiGranteeAvatar/UiGranteeAvatar.d.ts +30 -0
- package/esm/@ui/UiGranteeAvatar/UiGranteeAvatar.js +25 -0
- package/esm/@ui/UiGranteeRow/UiGranteeRow.d.ts +26 -0
- package/esm/@ui/UiGranteeRow/UiGranteeRow.js +19 -0
- package/esm/@ui/UiIcon/icons.js +5 -0
- package/esm/@ui/UiMenu/hooks.js +2 -4
- package/esm/@ui/UiObjectShareDialog/UiObjectShareDialog.d.ts +57 -0
- package/esm/@ui/UiObjectShareDialog/UiObjectShareDialog.js +28 -0
- package/esm/@ui/UiRadio/UiRadio.d.ts +40 -0
- package/esm/@ui/UiRadio/UiRadio.js +23 -0
- package/esm/@ui/UiRadioRow/UiRadioRow.d.ts +33 -0
- package/esm/@ui/UiRadioRow/UiRadioRow.js +19 -0
- package/esm/@ui/UiSectionHeading/UiSectionHeading.d.ts +18 -0
- package/esm/@ui/UiSectionHeading/UiSectionHeading.js +14 -0
- package/esm/@ui/UiTextInput/UiTextInput.d.ts +55 -0
- package/esm/@ui/UiTextInput/UiTextInput.js +24 -0
- package/esm/index.d.ts +14 -0
- package/esm/index.js +14 -0
- package/esm/locales.d.ts +69 -0
- package/esm/locales.js +32 -1
- package/esm/sdk-ui-kit.d.ts +528 -1
- package/package.json +11 -11
- package/src/@ui/UiAddGranteeDialog/UiAddGranteeDialog.scss +22 -0
- package/src/@ui/UiAvatar/UiAvatar.scss +22 -0
- package/src/@ui/UiConfirmDialog/UiConfirmDialog.scss +13 -0
- package/src/@ui/UiDialogShell/UiDialogShell.scss +56 -0
- package/src/@ui/UiGeneralAccessRadio/UiGeneralAccessRadio.scss +8 -0
- package/src/@ui/UiGranteeRow/UiGranteeRow.scss +36 -0
- package/src/@ui/UiObjectShareDialog/UiObjectShareDialog.scss +12 -0
- package/src/@ui/UiRadio/UiRadio.scss +63 -0
- package/src/@ui/UiRadioRow/UiRadioRow.scss +44 -0
- package/src/@ui/UiSectionHeading/UiSectionHeading.scss +28 -0
- package/src/@ui/UiTextInput/UiTextInput.scss +68 -0
- package/src/@ui/index.scss +20 -0
- package/src/FilterGroupItem/FilterGroupItem.scss +13 -24
- package/styles/css/main.css +370 -18
- package/styles/css/main.css.map +1 -1
package/esm/@ui/@types/icon.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* @internal
|
|
3
3
|
*/
|
|
4
|
-
export type IconType = "aiAgent" | "aiAgentDisabled" | "brain" | "brainDisabled" | "check" | "checkCircle" | "certification" | "plus" | "plusCircle" | "sync" | "alert" | "alertPaused" | "close" | "cross" | "edit" | "crossCircle" | "question" | "chevronUp" | "chevronRight" | "chevronDown" | "chevronLeft" | "date" | "navigateUp" | "navigateDown" | "navigateRight" | "navigateLeft" | "download" | "slack" | "expand" | "exclamationCircle" | "book" | "visible" | "invisible" | "lock" | "unlock" | "ai" | "aiFill" | "drawer" | "drawerEmpty" | "prohibited" | "dropDown" | "dropRight" | "clock" | "clockPaused" | "questionMark" | "upload" | "expandRectangle" | "file" | "number" | "code" | "user" | "userPlus" | "users" | "magic" | "tab" | "pauseCircle" | "filter" | "timer" | "mail" | "envelope" | "copy" | "rain" | "earth" | "geoCollection" | "geoCollectionUpload" | "minimize" | "shrink" | "copyright" | "ellipsis" | "pencil" | "folder" | "folderPlus" | "trash" | "arrowUp" | "arrowRight" | "arrowDown" | "arrowLeft" | "undo" | "redo" | "trendDown" | "trendUp" | "save" | "minus" | "minusCircle" | "percent" | "enter" | "enterRight" | "money" | "ghost" | "warning" | "home" | "settings" | "search" | "university" | "printer" | "picture" | "visualization" | "dashboard" | "metric" | "fact" | "ldmAttribute" | "sharp" | "attribute" | "horn" | "cw" | "ccw" | "table" | "directionColumn" | "directionRow" | "header" | "genai" | "genai2" | "explainai" | "hiddenForAi" | "box" | "ellipsisVertical" | "list" | "drillTo" | "hierarchy" | "history" | "history2" | "thumbsUp" | "thumbsDown" | "send" | "visualizationArea" | "visualizationTable" | "visualizationTreemap" | "visualizationScatter" | "visualizationDonut" | "visualizationHeadline" | "visualizationColumn" | "visualizationLine" | "visualizationPyramid" | "visualizationFunnel" | "visualizationHeatmap" | "visualizationBubble" | "visualizationPie" | "visualizationBar" | "visualizationCombo" | "visualizationBullet" | "visualizationWaterfall" | "visualizationDependencywheel" | "visualizationSankey" | "visualizationPushpin" | "visualizationRepeater" | "visualizationXirr" | "link" | "externalLink" | "click" | "fileXlsx" | "filePptx" | "filePdf" | "fileImage" | "fileCsvFormatted" | "fileCsvRaw" | "aiDocument" | "recommendation" | "streamUp" | "streamDown" | "stream" | "density" | "parameter" | "pin" | "unpin";
|
|
4
|
+
export type IconType = "aiAgent" | "aiAgentDisabled" | "brain" | "brainDisabled" | "check" | "checkCircle" | "certification" | "plus" | "plusCircle" | "sync" | "alert" | "alertPaused" | "close" | "cross" | "edit" | "crossCircle" | "question" | "chevronUp" | "chevronRight" | "chevronDown" | "chevronLeft" | "date" | "navigateUp" | "navigateDown" | "navigateRight" | "navigateLeft" | "download" | "slack" | "expand" | "exclamationCircle" | "book" | "visible" | "invisible" | "lock" | "unlock" | "ai" | "aiFill" | "drawer" | "drawerEmpty" | "prohibited" | "dropDown" | "dropRight" | "clock" | "clockPaused" | "questionMark" | "upload" | "expandRectangle" | "file" | "number" | "code" | "user" | "userPlus" | "users" | "magic" | "tab" | "pauseCircle" | "filter" | "timer" | "mail" | "envelope" | "copy" | "rain" | "earth" | "geoCollection" | "geoCollectionUpload" | "minimize" | "shrink" | "copyright" | "ellipsis" | "pencil" | "folder" | "folderSmall" | "folderPlus" | "trash" | "arrowUp" | "arrowRight" | "arrowDown" | "arrowLeft" | "undo" | "redo" | "trendDown" | "trendUp" | "save" | "minus" | "minusCircle" | "percent" | "enter" | "enterRight" | "money" | "ghost" | "warning" | "home" | "settings" | "search" | "university" | "printer" | "picture" | "visualization" | "dashboard" | "metric" | "fact" | "ldmAttribute" | "ldmKey" | "ldmLabel" | "sharp" | "attribute" | "horn" | "cw" | "ccw" | "table" | "directionColumn" | "directionRow" | "header" | "genai" | "genai2" | "explainai" | "hiddenForAi" | "box" | "ellipsisVertical" | "list" | "drillTo" | "hierarchy" | "history" | "history2" | "thumbsUp" | "thumbsDown" | "send" | "visualizationArea" | "visualizationTable" | "visualizationTreemap" | "visualizationScatter" | "visualizationDonut" | "visualizationHeadline" | "visualizationColumn" | "visualizationLine" | "visualizationPyramid" | "visualizationFunnel" | "visualizationHeatmap" | "visualizationBubble" | "visualizationPie" | "visualizationBar" | "visualizationCombo" | "visualizationBullet" | "visualizationWaterfall" | "visualizationDependencywheel" | "visualizationSankey" | "visualizationPushpin" | "visualizationRepeater" | "visualizationXirr" | "link" | "externalLink" | "click" | "fileXlsx" | "filePptx" | "filePdf" | "fileImage" | "fileCsvFormatted" | "fileCsvRaw" | "aiDocument" | "recommendation" | "streamUp" | "streamDown" | "stream" | "density" | "parameter" | "pin" | "unpin";
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { type ReactNode } from "react";
|
|
2
|
+
/**
|
|
3
|
+
* @internal
|
|
4
|
+
*/
|
|
5
|
+
export interface IUiAddGranteeDialogProps {
|
|
6
|
+
/** Object title shown in the header — wrapped into `Share "\{title\}"`. */
|
|
7
|
+
objectTitle: string;
|
|
8
|
+
/** Current search query. */
|
|
9
|
+
searchQuery: string;
|
|
10
|
+
/** Fires when the user edits the search query. */
|
|
11
|
+
onSearchQueryChange: (next: string) => void;
|
|
12
|
+
/**
|
|
13
|
+
* Optional slot rendered between the search input and the bottom divider.
|
|
14
|
+
* When empty, the screen falls back to a "No user or group selected"
|
|
15
|
+
* placeholder. Callers typically render a single `UiGranteeRow`
|
|
16
|
+
* here to preview the grantee they've picked from the search dropdown.
|
|
17
|
+
*/
|
|
18
|
+
selectedGrantee?: ReactNode;
|
|
19
|
+
/** Fires when the user clicks the header back-arrow button. */
|
|
20
|
+
onBack: () => void;
|
|
21
|
+
/** Fires when the user clicks the header X close button. */
|
|
22
|
+
onClose: () => void;
|
|
23
|
+
/** Fires when the user clicks Cancel in the footer. */
|
|
24
|
+
onCancel: () => void;
|
|
25
|
+
/** Fires when the user clicks the primary Add button in the footer. */
|
|
26
|
+
onAdd: () => void;
|
|
27
|
+
/** When true, the primary Add button is disabled. */
|
|
28
|
+
isAddDisabled?: boolean;
|
|
29
|
+
/** Test id forwarded to the root element. */
|
|
30
|
+
dataTestId?: string;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Standalone dialog for adding a grantee, opened from the share dialog's
|
|
34
|
+
* "+ Add" action. Lets the author search for a user or group, preview the
|
|
35
|
+
* grantee they picked, and confirm adding them with the footer Add button.
|
|
36
|
+
*
|
|
37
|
+
* @internal
|
|
38
|
+
*/
|
|
39
|
+
export declare function UiAddGranteeDialog({ objectTitle, searchQuery, onSearchQueryChange, selectedGrantee, onBack, onClose, onCancel, onAdd, isAddDisabled, dataTestId }: IUiAddGranteeDialogProps): import("react/jsx-runtime").JSX.Element;
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { useIntl } from "react-intl";
|
|
3
|
+
import { commonDialogMessages, olpAddGranteeDialogMessages, olpObjectShareDialogMessages, } from "../../locales.js";
|
|
4
|
+
import { bem } from "../@utils/bem.js";
|
|
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
|
+
import { UiIconButton } from "../UiIconButton/UiIconButton.js";
|
|
10
|
+
import { UiTextInput } from "../UiTextInput/UiTextInput.js";
|
|
11
|
+
const { b, e } = bem("gd-ui-kit-add-grantee-dialog");
|
|
12
|
+
/**
|
|
13
|
+
* Standalone dialog for adding a grantee, opened from the share dialog's
|
|
14
|
+
* "+ Add" action. Lets the author search for a user or group, preview the
|
|
15
|
+
* grantee they picked, and confirm adding them with the footer Add button.
|
|
16
|
+
*
|
|
17
|
+
* @internal
|
|
18
|
+
*/
|
|
19
|
+
export function UiAddGranteeDialog({ objectTitle, searchQuery, onSearchQueryChange, selectedGrantee, onBack, onClose, onCancel, onAdd, isAddDisabled, dataTestId, }) {
|
|
20
|
+
const intl = useIntl();
|
|
21
|
+
const dialogTitle = intl.formatMessage(olpObjectShareDialogMessages.title, { title: objectTitle });
|
|
22
|
+
const backButton = (_jsx(UiIconButton, { icon: "chevronLeft", variant: "tertiary", size: "small", onClick: onBack, accessibilityConfig: { ariaLabel: intl.formatMessage(olpAddGranteeDialogMessages.back) } }));
|
|
23
|
+
return (_jsxs(UiDialogShell, { dataTestId: dataTestId, children: [
|
|
24
|
+
_jsx(UiDialogHeader, { title: dialogTitle, titleSize: "large", onClose: onClose, leading: backButton }), _jsxs("div", { className: b(), children: [
|
|
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
|
+
] }), _jsxs(UiDialogFooter, { divider: true, children: [
|
|
27
|
+
_jsx(UiButton, { label: intl.formatMessage(commonDialogMessages.cancel), variant: "secondary", size: "medium", onClick: onCancel }), _jsx(UiButton, { label: intl.formatMessage(olpAddGranteeDialogMessages.add), variant: "primary", size: "medium", onClick: onAdd, isDisabled: isAddDisabled })
|
|
28
|
+
] })
|
|
29
|
+
] }));
|
|
30
|
+
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { type IconType } from "../@types/icon.js";
|
|
2
|
+
import { type ThemeColor } from "../@types/themeColors.js";
|
|
3
|
+
/**
|
|
4
|
+
* @internal
|
|
5
|
+
*/
|
|
6
|
+
export interface IUiAvatarProps {
|
|
7
|
+
/** Icon rendered inside the circle. */
|
|
8
|
+
icon: IconType;
|
|
9
|
+
/** Outer circle size in px. Defaults to 32. */
|
|
10
|
+
size?: number;
|
|
11
|
+
/** Background tone of the circle. Defaults to `complementary-2`. */
|
|
12
|
+
backgroundColor?: ThemeColor;
|
|
13
|
+
/** Icon tone. Defaults to `complementary-5`. */
|
|
14
|
+
iconColor?: ThemeColor;
|
|
15
|
+
/**
|
|
16
|
+
* Icon size in px. Defaults to `Math.round(size * ICON_TO_AVATAR_RATIO)`,
|
|
17
|
+
* which mirrors the 14/32 proportion used across the kit's avatars.
|
|
18
|
+
*/
|
|
19
|
+
iconSize?: number;
|
|
20
|
+
/**
|
|
21
|
+
* Accessibility config for the avatar. Provide an `ariaLabel`
|
|
22
|
+
* when the avatar carries meaning (e.g. a stand-alone "who" indicator).
|
|
23
|
+
* Use `ariaHidden: true` when the avatar sits next to a visible
|
|
24
|
+
* name and would only duplicate that name for screen-reader users.
|
|
25
|
+
*/
|
|
26
|
+
accessibilityConfig?: {
|
|
27
|
+
ariaLabel?: string;
|
|
28
|
+
ariaHidden?: boolean;
|
|
29
|
+
};
|
|
30
|
+
/** Test id forwarded to the root element. */
|
|
31
|
+
dataTestId?: string;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Circle avatar with a centered icon. Generic small "who" indicator
|
|
35
|
+
* (grantees, presence, audit log, activity feed, ...). Wrap in a
|
|
36
|
+
* domain-specific component to pick the right icon + label per kind.
|
|
37
|
+
*
|
|
38
|
+
* @internal
|
|
39
|
+
*/
|
|
40
|
+
export declare function UiAvatar({ icon, size, backgroundColor, iconColor, iconSize, accessibilityConfig, dataTestId }: IUiAvatarProps): import("react/jsx-runtime").JSX.Element;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { bem } from "../@utils/bem.js";
|
|
3
|
+
import { UiIcon } from "../UiIcon/UiIcon.js";
|
|
4
|
+
const { b } = bem("gd-ui-kit-avatar");
|
|
5
|
+
const DEFAULT_SIZE = 32;
|
|
6
|
+
const DEFAULT_BACKGROUND = "complementary-2";
|
|
7
|
+
const DEFAULT_ICON_COLOR = "complementary-5";
|
|
8
|
+
const ICON_TO_AVATAR_RATIO = 0.44;
|
|
9
|
+
/**
|
|
10
|
+
* Circle avatar with a centered icon. Generic small "who" indicator
|
|
11
|
+
* (grantees, presence, audit log, activity feed, ...). Wrap in a
|
|
12
|
+
* domain-specific component to pick the right icon + label per kind.
|
|
13
|
+
*
|
|
14
|
+
* @internal
|
|
15
|
+
*/
|
|
16
|
+
export function UiAvatar({ icon, size = DEFAULT_SIZE, backgroundColor = DEFAULT_BACKGROUND, iconColor = DEFAULT_ICON_COLOR, iconSize, accessibilityConfig, dataTestId, }) {
|
|
17
|
+
const resolvedIconSize = iconSize ?? Math.round(size * ICON_TO_AVATAR_RATIO);
|
|
18
|
+
return (_jsx("span", { className: b({ background: backgroundColor }), "data-testid": dataTestId, style: { "--gd-avatar-size": `${size}px` }, children: _jsx(UiIcon, { type: icon, size: resolvedIconSize, color: iconColor, accessibilityConfig: accessibilityConfig }) }));
|
|
19
|
+
}
|
|
@@ -34,6 +34,13 @@ export interface IUiButtonProps {
|
|
|
34
34
|
accessibilityConfig?: IUiButtonAccessibilityConfig;
|
|
35
35
|
maxWidth?: number;
|
|
36
36
|
tabIndex?: number;
|
|
37
|
+
/**
|
|
38
|
+
* When true, the button is focused on mount via the native HTML
|
|
39
|
+
* `autofocus` attribute. Use sparingly — best fit is the safest
|
|
40
|
+
* action in a confirmation dialog so accidental Enter presses cancel
|
|
41
|
+
* rather than confirm a destructive action.
|
|
42
|
+
*/
|
|
43
|
+
autoFocus?: boolean;
|
|
37
44
|
}
|
|
38
45
|
/**
|
|
39
46
|
* @internal
|
|
@@ -11,7 +11,7 @@ const getGeneratedTestId = (label, ariaLabel) => {
|
|
|
11
11
|
/**
|
|
12
12
|
* @internal
|
|
13
13
|
*/
|
|
14
|
-
export const UiButton = forwardRef(({ id, size = "medium", variant = "secondary", tabIndex = 0, label, isDisabled, isSelected, isLoading, disableIconAnimation, iconBefore, iconBeforeSize: iconBeforeSizeProp, iconAfter, iconAfterSize: iconAfterSizeProp, badgeAfter, onClick, onKeyDown, dataId, dataTestId, accessibilityConfig, maxWidth, }, ref) => {
|
|
14
|
+
export const UiButton = forwardRef(({ id, size = "medium", variant = "secondary", tabIndex = 0, label, isDisabled, isSelected, isLoading, disableIconAnimation, iconBefore, iconBeforeSize: iconBeforeSizeProp, iconAfter, iconAfterSize: iconAfterSizeProp, badgeAfter, onClick, onKeyDown, dataId, dataTestId, accessibilityConfig, maxWidth, autoFocus, }, ref) => {
|
|
15
15
|
const iconBeforeSize = iconBeforeSizeProp ?? (size === "small" ? 16 : 18);
|
|
16
16
|
const iconAfterSize = iconAfterSizeProp ?? (size === "small" ? 16 : 18);
|
|
17
17
|
const hasIconBefore = !!iconBefore;
|
|
@@ -24,6 +24,6 @@ export const UiButton = forwardRef(({ id, size = "medium", variant = "secondary"
|
|
|
24
24
|
hasIconBefore,
|
|
25
25
|
hasIconAfter,
|
|
26
26
|
isSelected: isSelected ?? false,
|
|
27
|
-
}), disabled: isDisabled, tabIndex: tabIndex, onClick: onClick, onKeyDown: onKeyDown, "data-id": dataId, "data-testid": testId, "aria-label": accessibilityConfig?.ariaLabel, "aria-labelledby": accessibilityConfig?.ariaLabelledBy, "aria-describedby": accessibilityConfig?.ariaDescribedBy, "aria-expanded": accessibilityConfig?.ariaExpanded, "aria-description": accessibilityConfig?.ariaDescription, "aria-controls": accessibilityConfig?.ariaControls, "aria-haspopup": accessibilityConfig?.ariaHaspopup, role: accessibilityConfig?.role, children: [iconBefore ? (_jsx(UiIcon, { type: iconBefore, size: iconBeforeSize, accessibilityConfig: { ariaHidden: accessibilityConfig?.iconAriaHidden }, disableAnimation: disableIconAnimation })) : null, _jsx("span", { className: e("text"), style: { maxWidth }, children: label }), badgeAfter !== undefined && typeof badgeAfter === "number" ? (_jsxs("span", { className: e("badge"), children: ["(", badgeAfter, ")"] })) : null, badgeAfter !== undefined && typeof badgeAfter === "string" ? (_jsx("span", { className: e("badge"), children: badgeAfter })) : null, iconAfter ? (_jsx(UiIcon, { type: iconAfter, size: iconAfterSize, accessibilityConfig: { ariaHidden: accessibilityConfig?.iconAriaHidden }, disableAnimation: disableIconAnimation })) : null] }));
|
|
27
|
+
}), disabled: isDisabled, tabIndex: tabIndex, autoFocus: autoFocus, onClick: onClick, onKeyDown: onKeyDown, "data-id": dataId, "data-testid": testId, "aria-label": accessibilityConfig?.ariaLabel, "aria-labelledby": accessibilityConfig?.ariaLabelledBy, "aria-describedby": accessibilityConfig?.ariaDescribedBy, "aria-expanded": accessibilityConfig?.ariaExpanded, "aria-description": accessibilityConfig?.ariaDescription, "aria-controls": accessibilityConfig?.ariaControls, "aria-haspopup": accessibilityConfig?.ariaHaspopup, role: accessibilityConfig?.role, children: [iconBefore ? (_jsx(UiIcon, { type: iconBefore, size: iconBeforeSize, accessibilityConfig: { ariaHidden: accessibilityConfig?.iconAriaHidden }, disableAnimation: disableIconAnimation })) : null, _jsx("span", { className: e("text"), style: { maxWidth }, children: label }), badgeAfter !== undefined && typeof badgeAfter === "number" ? (_jsxs("span", { className: e("badge"), children: ["(", badgeAfter, ")"] })) : null, badgeAfter !== undefined && typeof badgeAfter === "string" ? (_jsx("span", { className: e("badge"), children: badgeAfter })) : null, iconAfter ? (_jsx(UiIcon, { type: iconAfter, size: iconAfterSize, accessibilityConfig: { ariaHidden: accessibilityConfig?.iconAriaHidden }, disableAnimation: disableIconAnimation })) : null] }));
|
|
28
28
|
});
|
|
29
29
|
UiButton.displayName = "UiButton";
|
|
@@ -0,0 +1,38 @@
|
|
|
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 IUiConfirmDialogProps {
|
|
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 element. */
|
|
28
|
+
dataTestId?: string;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Compact modal confirm dialog used by the OLP share flow for actions that
|
|
32
|
+
* need explicit user confirmation (granting workspace access, restricting
|
|
33
|
+
* access, removing a grantee, transferring ownership). Always modal — focus
|
|
34
|
+
* is trapped inside, autofocus + return-focus apply, and ESC fires onClose.
|
|
35
|
+
*
|
|
36
|
+
* @internal
|
|
37
|
+
*/
|
|
38
|
+
export declare function UiConfirmDialog({ title, description, confirmLabel, confirmVariant, onClose, onCancel, onConfirm, dataTestId }: IUiConfirmDialogProps): import("react/jsx-runtime").JSX.Element;
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
// (C) 2026 GoodData Corporation
|
|
3
|
+
import { useId } from "react";
|
|
4
|
+
import { useIntl } from "react-intl";
|
|
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");
|
|
12
|
+
/**
|
|
13
|
+
* Compact modal confirm dialog used by the OLP share flow for actions that
|
|
14
|
+
* need explicit user confirmation (granting workspace access, restricting
|
|
15
|
+
* access, removing a grantee, transferring ownership). Always modal — focus
|
|
16
|
+
* is trapped inside, autofocus + return-focus apply, and ESC fires onClose.
|
|
17
|
+
*
|
|
18
|
+
* @internal
|
|
19
|
+
*/
|
|
20
|
+
export function UiConfirmDialog({ title, description, confirmLabel, confirmVariant = "primary", onClose, onCancel, onConfirm, dataTestId, }) {
|
|
21
|
+
const intl = useIntl();
|
|
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
|
+
] }) }));
|
|
28
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { type ReactNode } from "react";
|
|
2
|
+
/**
|
|
3
|
+
* @internal
|
|
4
|
+
*/
|
|
5
|
+
export interface IUiDialogFooterProps {
|
|
6
|
+
/** Right-aligned cluster of footer controls (typically Cancel + primary). */
|
|
7
|
+
children: ReactNode;
|
|
8
|
+
/**
|
|
9
|
+
* When true, draws a 1px complementary-3 divider above the footer and adds
|
|
10
|
+
* matching top padding. ObjectShareDialog and AddGranteeDialog want this;
|
|
11
|
+
* ConfirmDialog does not.
|
|
12
|
+
*/
|
|
13
|
+
divider?: boolean;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Dialog footer: right-aligned cluster of action buttons. Optionally renders
|
|
17
|
+
* a 1px divider above the actions.
|
|
18
|
+
*
|
|
19
|
+
* @internal
|
|
20
|
+
*/
|
|
21
|
+
export declare function UiDialogFooter({ children, divider }: IUiDialogFooterProps): import("react/jsx-runtime").JSX.Element;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { bem } from "../@utils/bem.js";
|
|
3
|
+
const { b } = bem("gd-ui-kit-dialog-footer");
|
|
4
|
+
/**
|
|
5
|
+
* Dialog footer: right-aligned cluster of action buttons. Optionally renders
|
|
6
|
+
* a 1px divider above the actions.
|
|
7
|
+
*
|
|
8
|
+
* @internal
|
|
9
|
+
*/
|
|
10
|
+
export function UiDialogFooter({ children, divider = false }) {
|
|
11
|
+
return _jsx("div", { className: b({ divider }), children: children });
|
|
12
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { type ReactNode } from "react";
|
|
2
|
+
/**
|
|
3
|
+
* Title sizing variant.
|
|
4
|
+
*
|
|
5
|
+
* @internal
|
|
6
|
+
*/
|
|
7
|
+
export type DialogHeaderTitleSize = "default" | "large";
|
|
8
|
+
/**
|
|
9
|
+
* @internal
|
|
10
|
+
*/
|
|
11
|
+
export interface IUiDialogHeaderProps {
|
|
12
|
+
/** Title shown in the header. */
|
|
13
|
+
title: string;
|
|
14
|
+
/** Title size — `"default"` = 18/26, `"large"` = 20/26. */
|
|
15
|
+
titleSize?: DialogHeaderTitleSize;
|
|
16
|
+
/** Fires when the user clicks the X close button. Omit to hide the X. */
|
|
17
|
+
onClose?: () => void;
|
|
18
|
+
/** Optional leading slot rendered before the title (e.g. a back button). */
|
|
19
|
+
leading?: ReactNode;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Dialog header: optional leading slot + title + optional close X.
|
|
23
|
+
*
|
|
24
|
+
* @internal
|
|
25
|
+
*/
|
|
26
|
+
export declare function UiDialogHeader({ title, titleSize, onClose, leading }: IUiDialogHeaderProps): import("react/jsx-runtime").JSX.Element;
|
|
@@ -0,0 +1,19 @@
|
|
|
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 { UiIconButton } from "../UiIconButton/UiIconButton.js";
|
|
6
|
+
import { useUiDialogContext } from "./UiDialogShell.js";
|
|
7
|
+
const { b, e } = bem("gd-ui-kit-dialog-header");
|
|
8
|
+
/**
|
|
9
|
+
* Dialog header: optional leading slot + title + optional close X.
|
|
10
|
+
*
|
|
11
|
+
* @internal
|
|
12
|
+
*/
|
|
13
|
+
export function UiDialogHeader({ title, titleSize = "default", onClose, leading }) {
|
|
14
|
+
const intl = useIntl();
|
|
15
|
+
const dialogContext = useUiDialogContext();
|
|
16
|
+
return (_jsxs("div", { className: b(), children: [leading ? _jsx("span", { className: e("leading"), children: leading }) : null, _jsx("h2", { id: dialogContext?.titleId, className: e("title", { size: titleSize }), children: title }), onClose ? (_jsx(UiIconButton, { icon: "cross", variant: "tertiary", size: "small", onClick: onClose, accessibilityConfig: {
|
|
17
|
+
ariaLabel: intl.formatMessage(commonDialogMessages.close),
|
|
18
|
+
} })) : null] }));
|
|
19
|
+
}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { type ReactNode } from "react";
|
|
2
|
+
/**
|
|
3
|
+
* Accessibility config for a dialog. By default the shell wires
|
|
4
|
+
* `aria-labelledby` to the `UiDialogHeader` title via
|
|
5
|
+
* context — no config is needed when a header is present. For headerless
|
|
6
|
+
* dialogs, pass `ariaLabel`; to point at an external title
|
|
7
|
+
* element, pass `ariaLabelledBy`.
|
|
8
|
+
*
|
|
9
|
+
* @internal
|
|
10
|
+
*/
|
|
11
|
+
export interface IUiDialogShellAccessibilityConfig {
|
|
12
|
+
ariaLabel?: string;
|
|
13
|
+
ariaLabelledBy?: string;
|
|
14
|
+
ariaDescribedBy?: string;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* @internal
|
|
18
|
+
*/
|
|
19
|
+
export interface IUiDialogShellProps {
|
|
20
|
+
/** Header / body / footer composed by the caller. */
|
|
21
|
+
children: ReactNode;
|
|
22
|
+
/** Dialog width in px. Defaults to 540. */
|
|
23
|
+
width?: number;
|
|
24
|
+
/**
|
|
25
|
+
* When true, the dialog acts as a modal: focus is trapped inside,
|
|
26
|
+
* autofocus + return-focus-on-unmount apply, ESC fires `onClose`,
|
|
27
|
+
* and `aria-modal="true"` is set. Leave off for inline
|
|
28
|
+
* non-blocking dialog cards.
|
|
29
|
+
*/
|
|
30
|
+
isModal?: boolean;
|
|
31
|
+
/** Fires when the user dismisses via ESC. Only active when `isModal`. */
|
|
32
|
+
onClose?: () => void;
|
|
33
|
+
/**
|
|
34
|
+
* Accessibility config. Usually unnecessary — when `UiDialogHeader`
|
|
35
|
+
* is used as a child the shell auto-wires `aria-labelledby` to
|
|
36
|
+
* the header's title.
|
|
37
|
+
*/
|
|
38
|
+
accessibilityConfig?: IUiDialogShellAccessibilityConfig;
|
|
39
|
+
/** Test id forwarded to the root element. */
|
|
40
|
+
dataTestId?: string;
|
|
41
|
+
}
|
|
42
|
+
interface IUiDialogContext {
|
|
43
|
+
titleId: string;
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* @internal
|
|
47
|
+
*/
|
|
48
|
+
export declare function useUiDialogContext(): IUiDialogContext | null;
|
|
49
|
+
/**
|
|
50
|
+
* Plain dialog card chrome — 4px radius, soft shadow, complementary-0 fill,
|
|
51
|
+
* 20px padding. Holds whatever the caller composes inside. Set
|
|
52
|
+
* `isModal` for blocking dialogs (adds focus trap, autofocus,
|
|
53
|
+
* return-focus, ESC handling and `aria-modal`).
|
|
54
|
+
*
|
|
55
|
+
* @internal
|
|
56
|
+
*/
|
|
57
|
+
export declare function UiDialogShell({ children, width, isModal, onClose, accessibilityConfig, dataTestId }: IUiDialogShellProps): import("react/jsx-runtime").JSX.Element;
|
|
58
|
+
export {};
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
// (C) 2026 GoodData Corporation
|
|
3
|
+
import { createContext, useContext, useId } from "react";
|
|
4
|
+
import { bem } from "../@utils/bem.js";
|
|
5
|
+
import { UiFocusManager } from "../UiFocusManager/UiFocusManager.js";
|
|
6
|
+
const { b } = bem("gd-ui-kit-dialog-shell");
|
|
7
|
+
const UiDialogContext = createContext(null);
|
|
8
|
+
/**
|
|
9
|
+
* @internal
|
|
10
|
+
*/
|
|
11
|
+
export function useUiDialogContext() {
|
|
12
|
+
return useContext(UiDialogContext);
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Plain dialog card chrome — 4px radius, soft shadow, complementary-0 fill,
|
|
16
|
+
* 20px padding. Holds whatever the caller composes inside. Set
|
|
17
|
+
* `isModal` for blocking dialogs (adds focus trap, autofocus,
|
|
18
|
+
* return-focus, ESC handling and `aria-modal`).
|
|
19
|
+
*
|
|
20
|
+
* @internal
|
|
21
|
+
*/
|
|
22
|
+
export function UiDialogShell({ children, width = 540, isModal = false, onClose, accessibilityConfig, dataTestId, }) {
|
|
23
|
+
const titleId = useId();
|
|
24
|
+
const ariaLabelledBy = accessibilityConfig?.ariaLabelledBy ?? (accessibilityConfig?.ariaLabel ? undefined : titleId);
|
|
25
|
+
const handleKeyDown = (event) => {
|
|
26
|
+
if (isModal && event.key === "Escape" && onClose) {
|
|
27
|
+
event.stopPropagation();
|
|
28
|
+
onClose();
|
|
29
|
+
}
|
|
30
|
+
};
|
|
31
|
+
const card = (_jsx("div", { className: b(), "data-testid": dataTestId, style: { width }, role: "dialog", "aria-modal": isModal || undefined, "aria-label": accessibilityConfig?.ariaLabel, "aria-labelledby": ariaLabelledBy, "aria-describedby": accessibilityConfig?.ariaDescribedBy, onKeyDown: handleKeyDown, children: _jsx(UiDialogContext.Provider, { value: { titleId }, children: children }) }));
|
|
32
|
+
if (!isModal) {
|
|
33
|
+
return card;
|
|
34
|
+
}
|
|
35
|
+
return (_jsx(UiFocusManager, { enableAutofocus: true, enableFocusTrap: true, enableReturnFocusOnUnmount: true, children: card }));
|
|
36
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { type ReactNode } from "react";
|
|
2
|
+
/**
|
|
3
|
+
* Which general-access option is currently selected.
|
|
4
|
+
*
|
|
5
|
+
* @internal
|
|
6
|
+
*/
|
|
7
|
+
export type GeneralAccessValue = "RESTRICTED" | "WORKSPACE";
|
|
8
|
+
/**
|
|
9
|
+
* @internal
|
|
10
|
+
*/
|
|
11
|
+
export interface IUiGeneralAccessRadioProps {
|
|
12
|
+
/** Selected option. */
|
|
13
|
+
value: GeneralAccessValue;
|
|
14
|
+
/** Fired when the user picks a different option. */
|
|
15
|
+
onChange: (value: GeneralAccessValue) => void;
|
|
16
|
+
/**
|
|
17
|
+
* Optional slot rendered to the right of the `All workspace members`
|
|
18
|
+
* row — typically the `UiGranteeRowControls` pair that lets the
|
|
19
|
+
* author pick labels and the workspace-wide permission level.
|
|
20
|
+
*/
|
|
21
|
+
workspaceControls?: ReactNode;
|
|
22
|
+
/** Test id forwarded to the root element. */
|
|
23
|
+
dataTestId?: string;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Two-row radio used by the OLP share dialog to choose between restricting
|
|
27
|
+
* access to the listed grantees and granting access to every workspace
|
|
28
|
+
* member. Composes `UiRadioRow` for each option.
|
|
29
|
+
*
|
|
30
|
+
* @internal
|
|
31
|
+
*/
|
|
32
|
+
export declare function UiGeneralAccessRadio({ value, onChange, workspaceControls, dataTestId }: IUiGeneralAccessRadioProps): import("react/jsx-runtime").JSX.Element;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
// (C) 2026 GoodData Corporation
|
|
3
|
+
import { useId } from "react";
|
|
4
|
+
import { useIntl } from "react-intl";
|
|
5
|
+
import { olpGeneralAccessMessages } from "../../locales.js";
|
|
6
|
+
import { bem } from "../@utils/bem.js";
|
|
7
|
+
import { UiRadioRow } from "../UiRadioRow/UiRadioRow.js";
|
|
8
|
+
const { b } = bem("gd-ui-kit-general-access-radio");
|
|
9
|
+
/**
|
|
10
|
+
* Two-row radio used by the OLP share dialog to choose between restricting
|
|
11
|
+
* access to the listed grantees and granting access to every workspace
|
|
12
|
+
* member. Composes `UiRadioRow` for each option.
|
|
13
|
+
*
|
|
14
|
+
* @internal
|
|
15
|
+
*/
|
|
16
|
+
export function UiGeneralAccessRadio({ value, onChange, workspaceControls, dataTestId, }) {
|
|
17
|
+
const intl = useIntl();
|
|
18
|
+
const name = useId();
|
|
19
|
+
return (_jsxs("div", { className: b(), "data-testid": dataTestId, role: "radiogroup", "aria-label": intl.formatMessage(olpGeneralAccessMessages.groupLabel), children: [
|
|
20
|
+
_jsx(UiRadioRow, { name: name, value: "RESTRICTED", checked: value === "RESTRICTED", title: intl.formatMessage(olpGeneralAccessMessages.restrictedTitle), description: intl.formatMessage(olpGeneralAccessMessages.restrictedDescription), onChange: () => onChange("RESTRICTED") }), _jsx(UiRadioRow, { name: name, value: "WORKSPACE", checked: value === "WORKSPACE", title: intl.formatMessage(olpGeneralAccessMessages.workspaceTitle), description: intl.formatMessage(olpGeneralAccessMessages.workspaceDescription), onChange: () => onChange("WORKSPACE"), trailing: workspaceControls })
|
|
21
|
+
] }));
|
|
22
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Visual variant of a grantee avatar.
|
|
3
|
+
*
|
|
4
|
+
* @internal
|
|
5
|
+
*/
|
|
6
|
+
export type GranteeAvatarKind = "user" | "group";
|
|
7
|
+
/**
|
|
8
|
+
* @internal
|
|
9
|
+
*/
|
|
10
|
+
export interface IUiGranteeAvatarProps {
|
|
11
|
+
/** Visual kind — drives which silhouette is rendered. */
|
|
12
|
+
kind: GranteeAvatarKind;
|
|
13
|
+
/**
|
|
14
|
+
* When true, the avatar is hidden from assistive tech. Use when the
|
|
15
|
+
* avatar sits next to a visible name and would only duplicate that name
|
|
16
|
+
* for screen-reader users (e.g. inside `UiGranteeRow`).
|
|
17
|
+
*/
|
|
18
|
+
decorative?: boolean;
|
|
19
|
+
/** Test id forwarded to the root element. */
|
|
20
|
+
dataTestId?: string;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* 32×32 circle avatar used by the OLP share-dialog grantee list. Thin wrapper
|
|
24
|
+
* over `UiAvatar` that picks the right silhouette and i18n
|
|
25
|
+
* accessibility label per grantee kind. Pass `decorative` when
|
|
26
|
+
* the avatar is paired with a visible name in the same row.
|
|
27
|
+
*
|
|
28
|
+
* @internal
|
|
29
|
+
*/
|
|
30
|
+
export declare function UiGranteeAvatar({ kind, decorative, dataTestId }: IUiGranteeAvatarProps): import("react/jsx-runtime").JSX.Element;
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
// (C) 2026 GoodData Corporation
|
|
3
|
+
import { useIntl } from "react-intl";
|
|
4
|
+
import { olpGranteeAvatarMessages } from "../../locales.js";
|
|
5
|
+
import { UiAvatar } from "../UiAvatar/UiAvatar.js";
|
|
6
|
+
const ICON_BY_KIND = {
|
|
7
|
+
user: "user",
|
|
8
|
+
group: "users",
|
|
9
|
+
};
|
|
10
|
+
/**
|
|
11
|
+
* 32×32 circle avatar used by the OLP share-dialog grantee list. Thin wrapper
|
|
12
|
+
* over `UiAvatar` that picks the right silhouette and i18n
|
|
13
|
+
* accessibility label per grantee kind. Pass `decorative` when
|
|
14
|
+
* the avatar is paired with a visible name in the same row.
|
|
15
|
+
*
|
|
16
|
+
* @internal
|
|
17
|
+
*/
|
|
18
|
+
export function UiGranteeAvatar({ kind, decorative, dataTestId }) {
|
|
19
|
+
const intl = useIntl();
|
|
20
|
+
if (decorative) {
|
|
21
|
+
return (_jsx(UiAvatar, { icon: ICON_BY_KIND[kind], accessibilityConfig: { ariaHidden: true }, dataTestId: dataTestId }));
|
|
22
|
+
}
|
|
23
|
+
const ariaLabel = intl.formatMessage(kind === "group" ? olpGranteeAvatarMessages.group : olpGranteeAvatarMessages.user);
|
|
24
|
+
return _jsx(UiAvatar, { icon: ICON_BY_KIND[kind], accessibilityConfig: { ariaLabel }, dataTestId: dataTestId });
|
|
25
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { type ReactNode } from "react";
|
|
2
|
+
import { type GranteeAvatarKind } from "../UiGranteeAvatar/UiGranteeAvatar.js";
|
|
3
|
+
/**
|
|
4
|
+
* @internal
|
|
5
|
+
*/
|
|
6
|
+
export interface IUiGranteeRowProps {
|
|
7
|
+
/** Visual kind — drives the avatar silhouette. */
|
|
8
|
+
kind: GranteeAvatarKind;
|
|
9
|
+
/** Display name shown on the first line. */
|
|
10
|
+
name: string;
|
|
11
|
+
/** Optional email subline shown below the name. */
|
|
12
|
+
email?: string;
|
|
13
|
+
/** When true, an "Owner" tag is rendered between the text block and the controls slot. */
|
|
14
|
+
isOwner?: boolean;
|
|
15
|
+
/** Trailing controls slot — typically the `UiGranteeRowControls` trigger pair. */
|
|
16
|
+
controls?: ReactNode;
|
|
17
|
+
/** Test id forwarded to the root element. */
|
|
18
|
+
dataTestId?: string;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Grantee row used by the OLP share dialog. Renders avatar + name + optional
|
|
22
|
+
* email subline + optional "Owner" tag + trailing controls slot.
|
|
23
|
+
*
|
|
24
|
+
* @internal
|
|
25
|
+
*/
|
|
26
|
+
export declare function UiGranteeRow({ kind, name, email, isOwner, controls, dataTestId }: IUiGranteeRowProps): import("react/jsx-runtime").JSX.Element;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { useIntl } from "react-intl";
|
|
3
|
+
import { olpGranteeRowMessages } from "../../locales.js";
|
|
4
|
+
import { bem } from "../@utils/bem.js";
|
|
5
|
+
import { UiGranteeAvatar } from "../UiGranteeAvatar/UiGranteeAvatar.js";
|
|
6
|
+
import { UiTag } from "../UiTag/UiTag.js";
|
|
7
|
+
const { b, e } = bem("gd-ui-kit-grantee-row");
|
|
8
|
+
/**
|
|
9
|
+
* Grantee row used by the OLP share dialog. Renders avatar + name + optional
|
|
10
|
+
* email subline + optional "Owner" tag + trailing controls slot.
|
|
11
|
+
*
|
|
12
|
+
* @internal
|
|
13
|
+
*/
|
|
14
|
+
export function UiGranteeRow({ kind, name, email, isOwner, controls, dataTestId }) {
|
|
15
|
+
const intl = useIntl();
|
|
16
|
+
return (_jsxs("div", { className: b(), "data-testid": dataTestId, children: [
|
|
17
|
+
_jsx(UiGranteeAvatar, { kind: kind, decorative: true }), _jsxs("div", { className: e("text"), children: [
|
|
18
|
+
_jsx("span", { className: e("name"), title: name, children: name }), email ? (_jsx("span", { className: e("email"), title: email, children: email })) : null] }), isOwner ? (_jsx(UiTag, { label: intl.formatMessage(olpGranteeRowMessages.ownerTag), size: "small", variant: "solid" })) : null, controls] }));
|
|
19
|
+
}
|