@gooddata/sdk-ui-kit 11.51.0-alpha.1 → 11.51.0-alpha.2

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.
Files changed (48) hide show
  1. package/esm/@ui/UiGeneralAccessRadio/UiGeneralAccessRadio.d.ts +3 -2
  2. package/esm/@ui/UiGeneralAccessRadio/UiGeneralAccessRadio.d.ts.map +1 -1
  3. package/esm/@ui/UiGeneralAccessRadio/UiGeneralAccessRadio.js +7 -3
  4. package/esm/@ui/UiGranteeAsyncPicker/UiGranteeAsyncPicker.d.ts +5 -0
  5. package/esm/@ui/UiGranteeAsyncPicker/UiGranteeAsyncPicker.d.ts.map +1 -1
  6. package/esm/@ui/UiGranteeAsyncPicker/UiGranteeAsyncPicker.js +3 -5
  7. package/esm/@ui/UiGranteeRowControls/UiGranteeRowControls.d.ts +10 -16
  8. package/esm/@ui/UiGranteeRowControls/UiGranteeRowControls.d.ts.map +1 -1
  9. package/esm/@ui/UiGranteeRowControls/UiGranteeRowControls.js +19 -32
  10. package/esm/@ui/UiLabelsChecklist/UiLabelsChecklist.d.ts +3 -1
  11. package/esm/@ui/UiLabelsChecklist/UiLabelsChecklist.d.ts.map +1 -1
  12. package/esm/@ui/UiLabelsChecklist/UiLabelsChecklist.js +12 -3
  13. package/esm/@ui/UiObjectShareDialog/UiObjectShareDialogCard.d.ts +9 -3
  14. package/esm/@ui/UiObjectShareDialog/UiObjectShareDialogCard.d.ts.map +1 -1
  15. package/esm/@ui/UiObjectShareDialog/UiObjectShareDialogCard.js +3 -3
  16. package/esm/@ui/UiPermissionMenu/UiPermissionMenu.d.ts +18 -10
  17. package/esm/@ui/UiPermissionMenu/UiPermissionMenu.d.ts.map +1 -1
  18. package/esm/@ui/UiPermissionMenu/UiPermissionMenu.js +45 -13
  19. package/esm/@ui/UiSubmenuHeader/UiSubmenuHeader.d.ts +4 -2
  20. package/esm/@ui/UiSubmenuHeader/UiSubmenuHeader.d.ts.map +1 -1
  21. package/esm/@ui/UiSubmenuHeader/UiSubmenuHeader.js +2 -2
  22. package/esm/ParameterControl/StringParameterControlDropdown.js +2 -2
  23. package/esm/Timezone/TimezoneSelect.d.ts +108 -0
  24. package/esm/Timezone/TimezoneSelect.d.ts.map +1 -0
  25. package/esm/Timezone/TimezoneSelect.js +90 -0
  26. package/esm/Timezone/timezones.d.ts +86 -0
  27. package/esm/Timezone/timezones.d.ts.map +1 -0
  28. package/esm/Timezone/timezones.js +253 -0
  29. package/esm/index.d.ts +3 -2
  30. package/esm/index.d.ts.map +1 -1
  31. package/esm/index.js +3 -2
  32. package/esm/locales.d.ts +9 -6
  33. package/esm/locales.d.ts.map +1 -1
  34. package/esm/locales.js +4 -3
  35. package/esm/sdk-ui-kit.d.ts +238 -61
  36. package/package.json +11 -11
  37. package/src/@ui/UiGranteeRowControls/UiGranteeRowControls.scss +0 -8
  38. package/src/@ui/UiLabelsChecklist/UiLabelsChecklist.scss +2 -2
  39. package/src/@ui/UiPermissionMenu/UiPermissionMenu.scss +5 -0
  40. package/src/@ui/index.scss +0 -1
  41. package/src/Timezone/TimezoneSelect.scss +22 -0
  42. package/styles/css/main.css +17 -12
  43. package/styles/css/main.css.map +1 -1
  44. package/styles/scss/main.scss +1 -0
  45. package/esm/@ui/UiMoreOptionsMenu/UiMoreOptionsMenu.d.ts +0 -28
  46. package/esm/@ui/UiMoreOptionsMenu/UiMoreOptionsMenu.d.ts.map +0 -1
  47. package/esm/@ui/UiMoreOptionsMenu/UiMoreOptionsMenu.js +0 -85
  48. package/src/@ui/UiMoreOptionsMenu/UiMoreOptionsMenu.scss +0 -10
@@ -30,9 +30,10 @@ export interface IUiGeneralAccessRadioProps {
30
30
  /**
31
31
  * Workspace-wide permission level, used to keep the `All workspace members`
32
32
  * description in sync with the level picked in `workspaceControls`
33
- * (`view` → "can view", `share` → "can view and share"). Defaults to `view`.
33
+ * (`VIEW` → "can view", `SHARE` → "can view and share", `EDIT` "can edit").
34
+ * Defaults to `VIEW`.
34
35
  */
35
- workspaceLevel?: "VIEW" | "SHARE";
36
+ workspaceLevel?: "VIEW" | "SHARE" | "EDIT";
36
37
  /** Test id forwarded to the root element. */
37
38
  dataTestId?: string;
38
39
  }
@@ -1 +1 @@
1
- {"version":3,"file":"UiGeneralAccessRadio.d.ts","sourceRoot":"","sources":["../../../src/@ui/UiGeneralAccessRadio/UiGeneralAccessRadio.tsx"],"names":[],"mappings":"AAEA,OAAO,EAAE,KAAK,SAAS,EAAS,MAAM,OAAO,CAAC;AAU9C;;;;GAIG;AACH,MAAM,MAAM,kBAAkB,GAAG,YAAY,GAAG,WAAW,CAAC;AAE5D;;GAEG;AACH,MAAM,WAAW,0BAA0B;IACvC,uBAAuB;IACvB,KAAK,EAAE,kBAAkB,CAAC;IAC1B,oDAAoD;IACpD,QAAQ,EAAE,CAAC,KAAK,EAAE,kBAAkB,KAAK,IAAI,CAAC;IAC9C,0EAAwE;IACxE,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB;;;;OAIG;IACH,wBAAwB,CAAC,EAAE,OAAO,CAAC;IACnC;;;;OAIG;IACH,iBAAiB,CAAC,EAAE,SAAS,CAAC;IAC9B;;;;OAIG;IACH,cAAc,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;IAClC,6CAA6C;IAC7C,UAAU,CAAC,EAAE,MAAM,CAAC;CACvB;AAED;;;;;;GAMG;AACH,wBAAgB,oBAAoB,CAAC,EACjC,KAAK,EACL,QAAQ,EACR,QAAQ,EACR,wBAAwB,EACxB,iBAAiB,EACjB,cAAuB,EACvB,UAAU,EACb,EAAE,0BAA0B,2CAuC5B"}
1
+ {"version":3,"file":"UiGeneralAccessRadio.d.ts","sourceRoot":"","sources":["../../../src/@ui/UiGeneralAccessRadio/UiGeneralAccessRadio.tsx"],"names":[],"mappings":"AAEA,OAAO,EAAE,KAAK,SAAS,EAAS,MAAM,OAAO,CAAC;AAiB9C;;;;GAIG;AACH,MAAM,MAAM,kBAAkB,GAAG,YAAY,GAAG,WAAW,CAAC;AAE5D;;GAEG;AACH,MAAM,WAAW,0BAA0B;IACvC,uBAAuB;IACvB,KAAK,EAAE,kBAAkB,CAAC;IAC1B,oDAAoD;IACpD,QAAQ,EAAE,CAAC,KAAK,EAAE,kBAAkB,KAAK,IAAI,CAAC;IAC9C,0EAAwE;IACxE,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB;;;;OAIG;IACH,wBAAwB,CAAC,EAAE,OAAO,CAAC;IACnC;;;;OAIG;IACH,iBAAiB,CAAC,EAAE,SAAS,CAAC;IAC9B;;;;;OAKG;IACH,cAAc,CAAC,EAAE,MAAM,GAAG,OAAO,GAAG,MAAM,CAAC;IAC3C,6CAA6C;IAC7C,UAAU,CAAC,EAAE,MAAM,CAAC;CACvB;AAED;;;;;;GAMG;AACH,wBAAgB,oBAAoB,CAAC,EACjC,KAAK,EACL,QAAQ,EACR,QAAQ,EACR,wBAAwB,EACxB,iBAAiB,EACjB,cAAuB,EACvB,UAAU,EACb,EAAE,0BAA0B,2CAmC5B"}
@@ -6,6 +6,12 @@ import { olpGeneralAccessMessages } from "../../locales.js";
6
6
  import { bem } from "../@utils/bem.js";
7
7
  import { UiRadioRow } from "../UiRadioRow/UiRadioRow.js";
8
8
  const { b } = bem("gd-ui-kit-general-access-radio");
9
+ // "All workspace members" description for each workspace-wide level.
10
+ const WORKSPACE_DESCRIPTION = {
11
+ VIEW: olpGeneralAccessMessages.workspaceDescription,
12
+ SHARE: olpGeneralAccessMessages.workspaceDescriptionShare,
13
+ EDIT: olpGeneralAccessMessages.workspaceDescriptionEdit,
14
+ };
9
15
  /**
10
16
  * Two-row radio used by the OLP share dialog to choose between restricting
11
17
  * access to the listed grantees and granting access to every workspace
@@ -19,8 +25,6 @@ export function UiGeneralAccessRadio({ value, onChange, disabled, workspaceAcces
19
25
  return (_jsxs("div", { className: b(), "data-testid": dataTestId, role: "radiogroup", "aria-label": intl.formatMessage(olpGeneralAccessMessages.groupLabel), children: [
20
26
  _jsx(UiRadioRow, { name: name, value: "RESTRICTED", checked: value === "RESTRICTED", disabled: disabled || workspaceAccessInherited, title: intl.formatMessage(olpGeneralAccessMessages.restrictedTitle), description: intl.formatMessage(workspaceAccessInherited
21
27
  ? olpGeneralAccessMessages.restrictedDescriptionInherited
22
- : olpGeneralAccessMessages.restrictedDescription), onChange: () => onChange("RESTRICTED") }), _jsx(UiRadioRow, { name: name, value: "WORKSPACE", checked: value === "WORKSPACE", disabled: disabled, title: intl.formatMessage(olpGeneralAccessMessages.workspaceTitle), description: intl.formatMessage(workspaceLevel === "SHARE"
23
- ? olpGeneralAccessMessages.workspaceDescriptionShare
24
- : olpGeneralAccessMessages.workspaceDescription), onChange: () => onChange("WORKSPACE"), trailing: workspaceControls })
28
+ : olpGeneralAccessMessages.restrictedDescription), onChange: () => onChange("RESTRICTED") }), _jsx(UiRadioRow, { name: name, value: "WORKSPACE", checked: value === "WORKSPACE", disabled: disabled, title: intl.formatMessage(olpGeneralAccessMessages.workspaceTitle), description: intl.formatMessage(WORKSPACE_DESCRIPTION[workspaceLevel]), onChange: () => onChange("WORKSPACE"), trailing: workspaceControls })
25
29
  ] }));
26
30
  }
@@ -1,3 +1,4 @@
1
+ import { type ObjRef } from "@gooddata/sdk-model";
1
2
  import { type GranteeAvatarKind } from "../UiGranteeAvatar/UiGranteeAvatar.js";
2
3
  import { type PermissionMenuLevel } from "../UiPermissionMenu/UiPermissionMenu.js";
3
4
  /**
@@ -8,6 +9,10 @@ import { type PermissionMenuLevel } from "../UiPermissionMenu/UiPermissionMenu.j
8
9
  export interface IUiGranteeAsyncOption {
9
10
  /** Stable identifier — used as the React key and as the value passed to `onSelect`. */
10
11
  id: string;
12
+ /** Backend ref of the user/group, carried through selection so the consumer can
13
+ * write the grant against the exact ref (preserves Uri-vs-Id; `id` is a lossy
14
+ * serialization). */
15
+ ref: ObjRef;
11
16
  /** Avatar variant. */
12
17
  kind: GranteeAvatarKind;
13
18
  /** Display name shown on the row. */
@@ -1 +1 @@
1
- {"version":3,"file":"UiGranteeAsyncPicker.d.ts","sourceRoot":"","sources":["../../../src/@ui/UiGranteeAsyncPicker/UiGranteeAsyncPicker.tsx"],"names":[],"mappings":"AAeA,OAAO,EAAE,KAAK,iBAAiB,EAAE,MAAM,uCAAuC,CAAC;AAE/E,OAAO,EAAE,KAAK,mBAAmB,EAAoB,MAAM,yCAAyC,CAAC;AAIrG;;;;GAIG;AACH,MAAM,WAAW,qBAAqB;IAClC,yFAAuF;IACvF,EAAE,EAAE,MAAM,CAAC;IACX,sBAAsB;IACtB,IAAI,EAAE,iBAAiB,CAAC;IACxB,qCAAqC;IACrC,IAAI,EAAE,MAAM,CAAC;IACb,2CAA2C;IAC3C,KAAK,CAAC,EAAE,MAAM,CAAC;CAClB;AAED;;;;GAIG;AACH,MAAM,WAAW,gBAAiB,SAAQ,qBAAqB;IAC3D,gGAAgG;IAChG,eAAe,EAAE,mBAAmB,CAAC;CACxC;AAED;;;;;GAKG;AACH,MAAM,WAAW,sBAAsB;IACnC,MAAM,EAAE,qBAAqB,EAAE,CAAC;IAChC,KAAK,EAAE,qBAAqB,EAAE,CAAC;CAClC;AAED;;GAEG;AACH,MAAM,WAAW,0BAA0B;IACvC;;;;;OAKG;IACH,WAAW,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,OAAO,CAAC,sBAAsB,CAAC,CAAC;IACjE;;;;OAIG;IACH,gBAAgB,CAAC,EAAE,aAAa,CAAC,gBAAgB,CAAC,CAAC;IACnD,6DAA6D;IAC7D,QAAQ,EAAE,CAAC,MAAM,EAAE,qBAAqB,KAAK,IAAI,CAAC;IAClD,wEAAwE;IACxE,kBAAkB,CAAC,EAAE,CAAC,OAAO,EAAE,gBAAgB,EAAE,IAAI,EAAE,mBAAmB,KAAK,IAAI,CAAC;IACpF,4EAA4E;IAC5E,QAAQ,CAAC,EAAE,CAAC,OAAO,EAAE,gBAAgB,KAAK,IAAI,CAAC;IAC/C,6CAA6C;IAC7C,UAAU,CAAC,EAAE,MAAM,CAAC;CACvB;AAOD;;;;;;;;GAQG;AACH,wBAAgB,oBAAoB,CAAC,EACjC,WAAW,EACX,gBAAqB,EACrB,QAAQ,EACR,kBAAkB,EAClB,QAAQ,EACR,UAAU,EACb,EAAE,0BAA0B,2CAgH5B"}
1
+ {"version":3,"file":"UiGranteeAsyncPicker.d.ts","sourceRoot":"","sources":["../../../src/@ui/UiGranteeAsyncPicker/UiGranteeAsyncPicker.tsx"],"names":[],"mappings":"AAMA,OAAO,EAAE,KAAK,MAAM,EAAE,MAAM,qBAAqB,CAAC;AAOlD,OAAO,EAAE,KAAK,iBAAiB,EAAE,MAAM,uCAAuC,CAAC;AAE/E,OAAO,EACH,KAAK,mBAAmB,EAG3B,MAAM,yCAAyC,CAAC;AAIjD;;;;GAIG;AACH,MAAM,WAAW,qBAAqB;IAClC,yFAAuF;IACvF,EAAE,EAAE,MAAM,CAAC;IACX;;yBAEqB;IACrB,GAAG,EAAE,MAAM,CAAC;IACZ,sBAAsB;IACtB,IAAI,EAAE,iBAAiB,CAAC;IACxB,qCAAqC;IACrC,IAAI,EAAE,MAAM,CAAC;IACb,2CAA2C;IAC3C,KAAK,CAAC,EAAE,MAAM,CAAC;CAClB;AAED;;;;GAIG;AACH,MAAM,WAAW,gBAAiB,SAAQ,qBAAqB;IAC3D,gGAAgG;IAChG,eAAe,EAAE,mBAAmB,CAAC;CACxC;AAED;;;;;GAKG;AACH,MAAM,WAAW,sBAAsB;IACnC,MAAM,EAAE,qBAAqB,EAAE,CAAC;IAChC,KAAK,EAAE,qBAAqB,EAAE,CAAC;CAClC;AAED;;GAEG;AACH,MAAM,WAAW,0BAA0B;IACvC;;;;;OAKG;IACH,WAAW,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,OAAO,CAAC,sBAAsB,CAAC,CAAC;IACjE;;;;OAIG;IACH,gBAAgB,CAAC,EAAE,aAAa,CAAC,gBAAgB,CAAC,CAAC;IACnD,6DAA6D;IAC7D,QAAQ,EAAE,CAAC,MAAM,EAAE,qBAAqB,KAAK,IAAI,CAAC;IAClD,wEAAwE;IACxE,kBAAkB,CAAC,EAAE,CAAC,OAAO,EAAE,gBAAgB,EAAE,IAAI,EAAE,mBAAmB,KAAK,IAAI,CAAC;IACpF,4EAA4E;IAC5E,QAAQ,CAAC,EAAE,CAAC,OAAO,EAAE,gBAAgB,KAAK,IAAI,CAAC;IAC/C,6CAA6C;IAC7C,UAAU,CAAC,EAAE,MAAM,CAAC;CACvB;AAOD;;;;;;;;GAQG;AACH,wBAAgB,oBAAoB,CAAC,EACjC,WAAW,EACX,gBAAqB,EACrB,QAAQ,EACR,kBAAkB,EAClB,QAAQ,EACR,UAAU,EACb,EAAE,0BAA0B,2CA8G5B"}
@@ -2,12 +2,12 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  // (C) 2026 GoodData Corporation
3
3
  import { useCallback, useMemo } from "react";
4
4
  import { useIntl } from "react-intl";
5
- import { olpAddGranteeDialogMessages, olpPermissionMessages, uiGranteeAsyncPickerMessages, } from "../../locales.js";
5
+ import { olpAddGranteeDialogMessages, uiGranteeAsyncPickerMessages } from "../../locales.js";
6
6
  import { bem } from "../@utils/bem.js";
7
7
  import { UiAutocomplete } from "../UiAutocomplete/UiAutocomplete.js";
8
8
  import { UiButton } from "../UiButton/UiButton.js";
9
9
  import { UiGranteeRow } from "../UiGranteeRow/UiGranteeRow.js";
10
- import { UiPermissionMenu } from "../UiPermissionMenu/UiPermissionMenu.js";
10
+ import { UiPermissionMenu, permissionLevelMessage, } from "../UiPermissionMenu/UiPermissionMenu.js";
11
11
  const { b, e } = bem("gd-ui-kit-grantee-async-picker");
12
12
  /**
13
13
  * Sectioned async grantee picker — specialization of `UiAutocomplete` for the
@@ -22,8 +22,6 @@ export function UiGranteeAsyncPicker({ loadOptions, selectedGrantees = [], onSel
22
22
  const intl = useIntl();
23
23
  const groupsLabel = intl.formatMessage(uiGranteeAsyncPickerMessages.sectionGroups);
24
24
  const usersLabel = intl.formatMessage(uiGranteeAsyncPickerMessages.sectionUsers);
25
- const canViewLabel = intl.formatMessage(olpPermissionMessages.canView);
26
- const canShareLabel = intl.formatMessage(olpPermissionMessages.canViewAndShare);
27
25
  const selectedIds = useMemo(() => selectedGrantees.map((g) => g.id), [selectedGrantees]);
28
26
  const adaptedLoadOptions = useCallback(async (search) => {
29
27
  const { groups, users } = await loadOptions(search);
@@ -66,7 +64,7 @@ export function UiGranteeAsyncPicker({ loadOptions, selectedGrantees = [], onSel
66
64
  ariaLabel: fieldLabel,
67
65
  } })
68
66
  ] }), selectedGrantees.length === 0 ? (_jsx("div", { className: e("empty-state"), children: intl.formatMessage(olpAddGranteeDialogMessages.emptyState) })) : null, selectedGrantees.length > 0 ? (_jsx("ul", { className: e("picked-list"), children: selectedGrantees.map((g) => {
69
- const triggerLabel = g.permissionLevel === "SHARE" ? canShareLabel : canViewLabel;
67
+ const triggerLabel = intl.formatMessage(permissionLevelMessage(g.permissionLevel));
70
68
  return (_jsx("li", { className: e("picked-item"), children: _jsx(UiGranteeRow, { kind: g.kind, name: g.name, email: g.email, controls: _jsx(UiPermissionMenu, { selectedLevel: g.permissionLevel, onPermissionChange: (next) => onPermissionChange?.(g, next), onRemoveAccess: onRemove ? () => onRemove(g) : undefined, anchor: _jsx(UiButton, { label: triggerLabel, variant: "dropdownInline", size: "small", iconAfter: "navigateDown" }) }) }) }, g.id));
71
69
  }) })) : null] }));
72
70
  }
@@ -8,38 +8,32 @@ export interface IUiGranteeRowControlsProps {
8
8
  /** Locked items are always treated as selected. */
9
9
  labels: ReadonlyArray<IUiLabelsChecklistItem>;
10
10
  selectedLabelIds: ReadonlyArray<string>;
11
- /** The level to display. `EDIT` renders read-only; VIEW/SHARE are selectable. */
11
+ /** The grantee's current permission level anchors the permission menu. */
12
12
  permissionLevel: AccessGranularPermission;
13
13
  /**
14
- * Set only when the grantee inherits a higher permission than `permissionLevel`
15
- * (e.g. from a group); drives the warning badge. Undefined when not elevated.
14
+ * CONTRACT: set only when the grantee inherits a higher permission than
15
+ * `permissionLevel` (e.g. via a group) the control renders the warning badge
16
+ * whenever this is set and does not re-check the ordering. Undefined when the
17
+ * assigned level already is the effective one.
16
18
  */
17
19
  effectivePermission?: AccessGranularPermission;
18
- /**
19
- * Merge every action into the permission dropdown: the labels drill-in and
20
- * Remove access render inside {@link UiPermissionMenu} (no "⋯" menu), and
21
- * the level dropdown is offered even for an EDIT row. Used for the signed-in
22
- * user's own row when they manage their own access.
23
- */
24
- mergedControls?: boolean;
25
20
  /** Levels rendered disabled in the permission menu — see {@link UiPermissionMenu}. */
26
21
  disabledLevels?: ReadonlyArray<PermissionMenuLevel>;
27
22
  /** Tooltip shown on disabled level rows in place of the level's info text. */
28
23
  disabledTooltip?: string;
29
24
  onLabelsChange: (selectedIds: string[]) => void;
30
- /** Fires only for selectable rows (VIEW/SHARE); EDIT rows have no level control. */
31
25
  onPermissionChange: (level: PermissionMenuLevel) => void;
32
26
  onRemoveAccess?: () => void;
33
- /** Disables both triggers, e.g. while the row's change is saving. */
27
+ /** Disables the permission trigger, e.g. while the row's change is saving. */
34
28
  isDisabled?: boolean;
35
29
  dataTestId?: string;
36
30
  }
37
31
  /**
38
- * Per-row controls in the OLP share dialog: a permission trigger
39
- * ({@link UiPermissionMenu}) plus a "⋯" menu ({@link UiMoreOptionsMenu}) for
40
- * labels access, with an optional inherited-permission warning badge.
32
+ * Per-row controls in the OLP share dialog: the permission dropdown
33
+ * ({@link UiPermissionMenu}) hosting the level choice, the labels drill-in and
34
+ * Remove access, with an optional inherited-permission warning badge.
41
35
  *
42
36
  * @internal
43
37
  */
44
- export declare function UiGranteeRowControls({ labels, selectedLabelIds, permissionLevel, effectivePermission, mergedControls, disabledLevels, disabledTooltip, onLabelsChange, onPermissionChange, onRemoveAccess, isDisabled, dataTestId }: IUiGranteeRowControlsProps): import("react/jsx-runtime").JSX.Element;
38
+ export declare function UiGranteeRowControls({ labels, selectedLabelIds, permissionLevel, effectivePermission, disabledLevels, disabledTooltip, onLabelsChange, onPermissionChange, onRemoveAccess, isDisabled, dataTestId }: IUiGranteeRowControlsProps): import("react/jsx-runtime").JSX.Element;
45
39
  //# sourceMappingURL=UiGranteeRowControls.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"UiGranteeRowControls.d.ts","sourceRoot":"","sources":["../../../src/@ui/UiGranteeRowControls/UiGranteeRowControls.tsx"],"names":[],"mappings":"AAIA,OAAO,EAAE,KAAK,wBAAwB,EAAE,MAAM,qBAAqB,CAAC;AAMpE,OAAO,EAAE,KAAK,sBAAsB,EAAE,MAAM,2CAA2C,CAAC;AAExF,OAAO,EAAE,KAAK,mBAAmB,EAAoB,MAAM,yCAAyC,CAAC;AAKrG;;GAEG;AACH,MAAM,WAAW,0BAA0B;IACvC,mDAAmD;IACnD,MAAM,EAAE,aAAa,CAAC,sBAAsB,CAAC,CAAC;IAC9C,gBAAgB,EAAE,aAAa,CAAC,MAAM,CAAC,CAAC;IACxC,iFAAiF;IACjF,eAAe,EAAE,wBAAwB,CAAC;IAC1C;;;OAGG;IACH,mBAAmB,CAAC,EAAE,wBAAwB,CAAC;IAC/C;;;;;OAKG;IACH,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,wFAAsF;IACtF,cAAc,CAAC,EAAE,aAAa,CAAC,mBAAmB,CAAC,CAAC;IACpD,8EAA8E;IAC9E,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,cAAc,EAAE,CAAC,WAAW,EAAE,MAAM,EAAE,KAAK,IAAI,CAAC;IAChD,oFAAoF;IACpF,kBAAkB,EAAE,CAAC,KAAK,EAAE,mBAAmB,KAAK,IAAI,CAAC;IACzD,cAAc,CAAC,EAAE,MAAM,IAAI,CAAC;IAC5B,qEAAqE;IACrE,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,UAAU,CAAC,EAAE,MAAM,CAAC;CACvB;AAED;;;;;;GAMG;AACH,wBAAgB,oBAAoB,CAAC,EACjC,MAAM,EACN,gBAAgB,EAChB,eAAe,EACf,mBAAmB,EACnB,cAAc,EACd,cAAc,EACd,eAAe,EACf,cAAc,EACd,kBAAkB,EAClB,cAAc,EACd,UAAU,EACV,UAAU,EACb,EAAE,0BAA0B,2CA4F5B"}
1
+ {"version":3,"file":"UiGranteeRowControls.d.ts","sourceRoot":"","sources":["../../../src/@ui/UiGranteeRowControls/UiGranteeRowControls.tsx"],"names":[],"mappings":"AAIA,OAAO,EAAE,KAAK,wBAAwB,EAAE,MAAM,qBAAqB,CAAC;AAMpE,OAAO,EAAE,KAAK,sBAAsB,EAAE,MAAM,2CAA2C,CAAC;AACxF,OAAO,EACH,KAAK,mBAAmB,EAG3B,MAAM,yCAAyC,CAAC;AAYjD;;GAEG;AACH,MAAM,WAAW,0BAA0B;IACvC,mDAAmD;IACnD,MAAM,EAAE,aAAa,CAAC,sBAAsB,CAAC,CAAC;IAC9C,gBAAgB,EAAE,aAAa,CAAC,MAAM,CAAC,CAAC;IACxC,8EAA4E;IAC5E,eAAe,EAAE,wBAAwB,CAAC;IAC1C;;;;;OAKG;IACH,mBAAmB,CAAC,EAAE,wBAAwB,CAAC;IAC/C,wFAAsF;IACtF,cAAc,CAAC,EAAE,aAAa,CAAC,mBAAmB,CAAC,CAAC;IACpD,8EAA8E;IAC9E,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,cAAc,EAAE,CAAC,WAAW,EAAE,MAAM,EAAE,KAAK,IAAI,CAAC;IAChD,kBAAkB,EAAE,CAAC,KAAK,EAAE,mBAAmB,KAAK,IAAI,CAAC;IACzD,cAAc,CAAC,EAAE,MAAM,IAAI,CAAC;IAC5B,8EAA8E;IAC9E,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,UAAU,CAAC,EAAE,MAAM,CAAC;CACvB;AAED;;;;;;GAMG;AACH,wBAAgB,oBAAoB,CAAC,EACjC,MAAM,EACN,gBAAgB,EAChB,eAAe,EACf,mBAAmB,EACnB,cAAc,EACd,eAAe,EACf,cAAc,EACd,kBAAkB,EAClB,cAAc,EACd,UAAU,EACV,UAAU,EACb,EAAE,0BAA0B,2CAuD5B"}
@@ -5,45 +5,32 @@ import { olpPermissionMessages } from "../../locales.js";
5
5
  import { bem } from "../@utils/bem.js";
6
6
  import { UiButton } from "../UiButton/UiButton.js";
7
7
  import { UiIcon } from "../UiIcon/UiIcon.js";
8
- import { UiMoreOptionsMenu } from "../UiMoreOptionsMenu/UiMoreOptionsMenu.js";
9
- import { UiPermissionMenu } from "../UiPermissionMenu/UiPermissionMenu.js";
8
+ import { UiPermissionMenu, permissionLevelMessage, } from "../UiPermissionMenu/UiPermissionMenu.js";
10
9
  import { UiTooltip } from "../UiTooltip/UiTooltip.js";
11
10
  const { b, e } = bem("gd-ui-kit-grantee-row-controls");
11
+ // The warning badge names an inherited EDIT or SHARE. VIEW can never be the
12
+ // higher level and has no entry — an absent entry means "no badge".
13
+ const EFFECTIVE_PERMISSION_TOOLTIP = {
14
+ EDIT: olpPermissionMessages.effectivePermissionTooltipEdit,
15
+ SHARE: olpPermissionMessages.effectivePermissionTooltipShare,
16
+ };
12
17
  /**
13
- * Per-row controls in the OLP share dialog: a permission trigger
14
- * ({@link UiPermissionMenu}) plus a "⋯" menu ({@link UiMoreOptionsMenu}) for
15
- * labels access, with an optional inherited-permission warning badge.
18
+ * Per-row controls in the OLP share dialog: the permission dropdown
19
+ * ({@link UiPermissionMenu}) hosting the level choice, the labels drill-in and
20
+ * Remove access, with an optional inherited-permission warning badge.
16
21
  *
17
22
  * @internal
18
23
  */
19
- export function UiGranteeRowControls({ labels, selectedLabelIds, permissionLevel, effectivePermission, mergedControls, disabledLevels, disabledTooltip, onLabelsChange, onPermissionChange, onRemoveAccess, isDisabled, dataTestId, }) {
24
+ export function UiGranteeRowControls({ labels, selectedLabelIds, permissionLevel, effectivePermission, disabledLevels, disabledTooltip, onLabelsChange, onPermissionChange, onRemoveAccess, isDisabled, dataTestId, }) {
20
25
  const intl = useIntl();
21
26
  const hasLabels = labels.length > 0;
22
- // EDIT is display-only: the dialog can't assign or change it, and offering the
23
- // VIEW/SHARE menu on an EDIT row would silently downgrade the grant on pick.
24
- // So an EDIT row shows a static, non-interactive "Can edit" label instead of
25
- // the permission dropdown except in merged mode, where the user manages
26
- // their own access and downgrading is exactly the offered action.
27
- const isReadOnlyLevel = permissionLevel === "EDIT" && !mergedControls;
28
- // EDIT is not selectable — a merged EDIT row anchors on "Can edit" with no
29
- // radio checked, offering only the (lower) selectable levels.
30
- const selectedLevel = permissionLevel === "EDIT" ? undefined : permissionLevel;
31
- const permissionTriggerText = intl.formatMessage(permissionLevel === "EDIT"
32
- ? olpPermissionMessages.canEdit
33
- : permissionLevel === "SHARE"
34
- ? olpPermissionMessages.canViewAndShare
35
- : olpPermissionMessages.canView);
36
- // A read-only level has no permission dropdown to host Remove access, so that
37
- // action moves into the ⋯ menu for those rows (dropdown rows keep it in the menu).
38
- const removeInMoreOptions = isReadOnlyLevel ? onRemoveAccess : undefined;
39
- // Nothing to put in the ⋯ menu → drop it. Merged mode hosts everything in
40
- // the permission dropdown, so the ⋯ menu never renders there.
41
- const hasMoreOptions = !mergedControls && (hasLabels || !!removeInMoreOptions);
42
- // Guard on permissionLevel too, so the badge can't show when the assigned
43
- // level already matches the inherited one.
44
- const isInheritedHigherPermission = permissionLevel === "VIEW" && effectivePermission === "SHARE";
45
- const effectiveTooltip = isInheritedHigherPermission
46
- ? intl.formatMessage(olpPermissionMessages.effectivePermissionTooltipShare)
27
+ // The caller sets `effectivePermission` only when it outranks the assigned level
28
+ // (the ext side owns that comparison) render the badge whenever it is set and
29
+ // has tooltip copy, without re-deriving the level ordering here.
30
+ const inheritedTooltipMessage = effectivePermission === undefined ? undefined : EFFECTIVE_PERMISSION_TOOLTIP[effectivePermission];
31
+ const effectiveTooltip = inheritedTooltipMessage
32
+ ? intl.formatMessage(inheritedTooltipMessage)
47
33
  : undefined;
48
- return (_jsxs("div", { className: b(), "data-testid": dataTestId, children: [effectiveTooltip ? (_jsx(UiTooltip, { triggerBy: ["hover", "focus"], content: effectiveTooltip, anchor: _jsx("span", { className: e("effective-warning"), role: "img", "aria-label": intl.formatMessage(olpPermissionMessages.effectivePermissionAriaLabel), tabIndex: 0, children: _jsx(UiIcon, { type: "warning", size: 16, color: "warning" }) }) })) : null, isReadOnlyLevel ? (_jsx("span", { className: e("readonly-permission"), children: permissionTriggerText })) : (_jsx(UiPermissionMenu, { anchor: _jsx(UiButton, { label: permissionTriggerText, size: "small", variant: "dropdownInline", iconAfter: "navigateDown", isDisabled: isDisabled }), selectedLevel: selectedLevel, onPermissionChange: onPermissionChange, disabledLevels: disabledLevels, disabledTooltip: disabledTooltip, labels: mergedControls && hasLabels ? labels : undefined, selectedLabelIds: mergedControls ? selectedLabelIds : undefined, onLabelsChange: mergedControls ? onLabelsChange : undefined, onRemoveAccess: onRemoveAccess })), hasMoreOptions ? (_jsx(UiMoreOptionsMenu, { labels: hasLabels ? labels : undefined, selectedLabelIds: selectedLabelIds, onLabelsChange: onLabelsChange, onRemoveAccess: removeInMoreOptions, isDisabled: isDisabled })) : null] }));
34
+ return (_jsxs("div", { className: b(), "data-testid": dataTestId, children: [effectiveTooltip ? (_jsx(UiTooltip, { triggerBy: ["hover", "focus"], content: effectiveTooltip, anchor: _jsx("span", { className: e("effective-warning"), role: "img", "aria-label": intl.formatMessage(olpPermissionMessages.effectivePermissionAriaLabel), tabIndex: 0, children: _jsx(UiIcon, { type: "warning", size: 16, color: "warning" }) }) })) : null, _jsx(UiPermissionMenu, { anchor: _jsx(UiButton, { label: intl.formatMessage(permissionLevelMessage(permissionLevel)), size: "small", variant: "dropdownInline", iconAfter: "navigateDown", isDisabled: isDisabled }), selectedLevel: permissionLevel, onPermissionChange: onPermissionChange, disabledLevels: disabledLevels, disabledTooltip: disabledTooltip, labels: hasLabels ? labels : undefined, selectedLabelIds: selectedLabelIds, onLabelsChange: onLabelsChange, onRemoveAccess: onRemoveAccess })
35
+ ] }));
49
36
  }
@@ -31,6 +31,8 @@ export interface IUiLabelsChecklistProps {
31
31
  onBack: () => void;
32
32
  /** Dismisses the menu; Cancel and (post-commit) Apply both call it. */
33
33
  onClose: () => void;
34
+ /** Focus the Back button on mount — e.g. when opened as a drill-in so keyboard focus follows. */
35
+ autoFocus?: boolean;
34
36
  dataTestId?: string;
35
37
  }
36
38
  /**
@@ -40,5 +42,5 @@ export interface IUiLabelsChecklistProps {
40
42
  *
41
43
  * @internal
42
44
  */
43
- export declare function UiLabelsChecklist({ items, defaultSelectedIds, onApply, onBack, onClose, dataTestId }: IUiLabelsChecklistProps): import("react/jsx-runtime").JSX.Element;
45
+ export declare function UiLabelsChecklist({ items, defaultSelectedIds, onApply, onBack, onClose, autoFocus, dataTestId }: IUiLabelsChecklistProps): import("react/jsx-runtime").JSX.Element;
44
46
  //# sourceMappingURL=UiLabelsChecklist.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"UiLabelsChecklist.d.ts","sourceRoot":"","sources":["../../../src/@ui/UiLabelsChecklist/UiLabelsChecklist.tsx"],"names":[],"mappings":"AAUA,OAAO,EAAE,KAAK,YAAY,EAAE,MAAM,6BAA6B,CAAC;AAKhE;;;;GAIG;AACH,MAAM,WAAW,sBAAsB;IACnC,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,YAAY,CAAC;IACpB,uFAAuF;IACvF,MAAM,CAAC,EAAE,OAAO,CAAC;CACpB;AAED;;;;;GAKG;AACH,eAAO,MAAM,4BAA4B,2EAG0B,CAAC;AAEpE;;GAEG;AACH,MAAM,WAAW,uBAAuB;IACpC,KAAK,EAAE,aAAa,CAAC,sBAAsB,CAAC,CAAC;IAC7C,2DAA2D;IAC3D,kBAAkB,EAAE,aAAa,CAAC,MAAM,CAAC,CAAC;IAC1C,yFAAyF;IACzF,OAAO,EAAE,CAAC,WAAW,EAAE,MAAM,EAAE,KAAK,IAAI,CAAC;IACzC,iDAA+C;IAC/C,MAAM,EAAE,MAAM,IAAI,CAAC;IACnB,uEAAuE;IACvE,OAAO,EAAE,MAAM,IAAI,CAAC;IACpB,UAAU,CAAC,EAAE,MAAM,CAAC;CACvB;AAED;;;;;;GAMG;AACH,wBAAgB,iBAAiB,CAAC,EAC9B,KAAK,EACL,kBAAkB,EAClB,OAAO,EACP,MAAM,EACN,OAAO,EACP,UAAU,EACb,EAAE,uBAAuB,2CAoFzB"}
1
+ {"version":3,"file":"UiLabelsChecklist.d.ts","sourceRoot":"","sources":["../../../src/@ui/UiLabelsChecklist/UiLabelsChecklist.tsx"],"names":[],"mappings":"AAUA,OAAO,EAAE,KAAK,YAAY,EAAE,MAAM,6BAA6B,CAAC;AAKhE;;;;GAIG;AACH,MAAM,WAAW,sBAAsB;IACnC,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,YAAY,CAAC;IACpB,uFAAuF;IACvF,MAAM,CAAC,EAAE,OAAO,CAAC;CACpB;AAED;;;;;GAKG;AACH,eAAO,MAAM,4BAA4B,2EAG0B,CAAC;AAEpE;;GAEG;AACH,MAAM,WAAW,uBAAuB;IACpC,KAAK,EAAE,aAAa,CAAC,sBAAsB,CAAC,CAAC;IAC7C,2DAA2D;IAC3D,kBAAkB,EAAE,aAAa,CAAC,MAAM,CAAC,CAAC;IAC1C,yFAAyF;IACzF,OAAO,EAAE,CAAC,WAAW,EAAE,MAAM,EAAE,KAAK,IAAI,CAAC;IACzC,iDAA+C;IAC/C,MAAM,EAAE,MAAM,IAAI,CAAC;IACnB,uEAAuE;IACvE,OAAO,EAAE,MAAM,IAAI,CAAC;IACpB,mGAAiG;IACjG,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,UAAU,CAAC,EAAE,MAAM,CAAC;CACvB;AAED;;;;;;GAMG;AACH,wBAAgB,iBAAiB,CAAC,EAC9B,KAAK,EACL,kBAAkB,EAClB,OAAO,EACP,MAAM,EACN,OAAO,EACP,SAAS,EACT,UAAU,EACb,EAAE,uBAAuB,2CAiGzB"}
@@ -1,6 +1,6 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  // (C) 2026 GoodData Corporation
3
- import { useId, useState } from "react";
3
+ import { useCallback, useId, useState } from "react";
4
4
  import { useIntl } from "react-intl";
5
5
  import { commonDialogMessages, olpLabelMessages } from "../../locales.js";
6
6
  import { bem } from "../@utils/bem.js";
@@ -22,9 +22,18 @@ export const isLabelsChecklistItemChecked = (item, selectedIds) => item.locked =
22
22
  *
23
23
  * @internal
24
24
  */
25
- export function UiLabelsChecklist({ items, defaultSelectedIds, onApply, onBack, onClose, dataTestId, }) {
25
+ export function UiLabelsChecklist({ items, defaultSelectedIds, onApply, onBack, onClose, autoFocus, dataTestId, }) {
26
26
  const intl = useIntl();
27
27
  const groupId = useId();
28
+ // When opened as a drill-in, focus the Back button as it mounts so the view
29
+ // swap hands keyboard focus to a named control instead of dropping it to
30
+ // <body>. A callback ref focuses on attach — no effect, and it can't race the
31
+ // node's mount the way a ref read in an effect could.
32
+ const focusOnAttach = useCallback((node) => {
33
+ if (autoFocus) {
34
+ node?.focus();
35
+ }
36
+ }, [autoFocus]);
28
37
  // Staged toggles only; locked ids are folded in by the predicate, not stored here.
29
38
  const [selected, setSelected] = useState(() => [...defaultSelectedIds]);
30
39
  const toggle = (id, next) => {
@@ -51,7 +60,7 @@ export function UiLabelsChecklist({ items, defaultSelectedIds, onApply, onBack,
51
60
  return intl.formatMessage(kind === "primary" ? olpLabelMessages.suffixPrimary : olpLabelMessages.suffixDefault);
52
61
  };
53
62
  return (_jsxs("div", { className: b(), "data-testid": dataTestId, children: [
54
- _jsx(UiSubmenuHeader, { title: intl.formatMessage(olpLabelMessages.popoverTitle), backAriaLabel: intl.formatMessage(olpLabelMessages.backAriaLabel), height: "medium", onBack: onBack }), _jsx("div", { id: groupId, className: e("items"), role: "group", "aria-label": intl.formatMessage(olpLabelMessages.popoverTitle), onKeyDown: handleKeyDown, children: items.map((item) => (_jsx(UiLabelChecklistRow, { label: item.label, kind: item.kind, suffix: suffixFor(item.kind), checked: isLabelsChecklistItemChecked(item, selected), disabled: item.locked, onChange: (next) => toggle(item.id, next) }, item.id))) }), _jsxs("div", { className: e("actions"), children: [
63
+ _jsx(UiSubmenuHeader, { backButtonRef: focusOnAttach, title: intl.formatMessage(olpLabelMessages.popoverTitle), backAriaLabel: intl.formatMessage(olpLabelMessages.backAriaLabel), height: "medium", onBack: onBack }), _jsx("div", { id: groupId, className: e("items"), role: "group", "aria-label": intl.formatMessage(olpLabelMessages.popoverTitle), onKeyDown: handleKeyDown, children: items.map((item) => (_jsx(UiLabelChecklistRow, { label: item.label, kind: item.kind, suffix: suffixFor(item.kind), checked: isLabelsChecklistItemChecked(item, selected), disabled: item.locked, onChange: (next) => toggle(item.id, next) }, item.id))) }), _jsxs("div", { className: e("actions"), children: [
55
64
  _jsx(UiButton, { variant: "secondary", size: "small", label: intl.formatMessage(commonDialogMessages.cancel), onClick: onClose }), _jsx(UiButton, { variant: "primary", size: "small", label: intl.formatMessage(commonDialogMessages.apply), onClick: handleApply, isDisabled: !isDirty })
56
65
  ] })
57
66
  ] }));
@@ -35,6 +35,12 @@ export interface IUiObjectShareDialogCardProps {
35
35
  onClose: () => void;
36
36
  /** Grantee rows shown inside the SHARED WITH section, in render order. */
37
37
  grantees: IUiObjectShareDialogGrantee[];
38
+ /**
39
+ * When true, skeleton rows stand in for the grantee list and the
40
+ * general-access radio — set it while the access list is loading, so the
41
+ * placeholders (empty list, Restricted) aren't mistaken for a real policy.
42
+ */
43
+ isLoading?: boolean;
38
44
  /** Fires when the user clicks the + Add link in the SHARED WITH heading. */
39
45
  onAddClick: () => void;
40
46
  /** Disables the + Add action — e.g. while the object's labels are still loading. */
@@ -58,9 +64,9 @@ export interface IUiObjectShareDialogCardProps {
58
64
  workspaceControls?: ReactNode;
59
65
  /**
60
66
  * Workspace-wide permission level, so the "All workspace members" description
61
- * matches the level picked in `workspaceControls`. Defaults to `view`.
67
+ * matches the level picked in `workspaceControls`. Defaults to `VIEW`.
62
68
  */
63
- workspaceLevel?: "VIEW" | "SHARE";
69
+ workspaceLevel?: "VIEW" | "SHARE" | "EDIT";
64
70
  /**
65
71
  * Optional error notice. When set, it replaces the grantee list and
66
72
  * general-access sections (which can't reflect a real policy on a failed
@@ -79,5 +85,5 @@ export interface IUiObjectShareDialogCardProps {
79
85
  *
80
86
  * @internal
81
87
  */
82
- export declare function UiObjectShareDialogCard({ objectTitle, onClose, grantees, onAddClick, isAddDisabled, generalAccess, onGeneralAccessChange, isGeneralAccessDisabled, workspaceAccessInherited, workspaceControls, workspaceLevel, error, dataTestId }: IUiObjectShareDialogCardProps): import("react/jsx-runtime").JSX.Element;
88
+ export declare function UiObjectShareDialogCard({ objectTitle, onClose, grantees, isLoading, onAddClick, isAddDisabled, generalAccess, onGeneralAccessChange, isGeneralAccessDisabled, workspaceAccessInherited, workspaceControls, workspaceLevel, error, dataTestId }: IUiObjectShareDialogCardProps): import("react/jsx-runtime").JSX.Element;
83
89
  //# sourceMappingURL=UiObjectShareDialogCard.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"UiObjectShareDialogCard.d.ts","sourceRoot":"","sources":["../../../src/@ui/UiObjectShareDialog/UiObjectShareDialogCard.tsx"],"names":[],"mappings":"AAEA,OAAO,EAAE,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AAOvC,OAAO,EACH,KAAK,kBAAkB,EAE1B,MAAM,iDAAiD,CAAC;AACzD,OAAO,EAAE,KAAK,iBAAiB,EAAE,MAAM,uCAAuC,CAAC;AAQ/E;;;;;;GAMG;AACH,MAAM,WAAW,2BAA2B;IACxC,+DAA6D;IAC7D,EAAE,EAAE,MAAM,CAAC;IACX,sBAAsB;IACtB,IAAI,EAAE,iBAAiB,CAAC;IACxB,oBAAoB;IACpB,IAAI,EAAE,MAAM,CAAC;IACb,8BAA8B;IAC9B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,wEAAwE;IACxE,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB;;;OAGG;IACH,QAAQ,CAAC,EAAE,SAAS,CAAC;CACxB;AAED;;GAEG;AACH,MAAM,WAAW,6BAA6B;IAC1C,6EAA2E;IAC3E,WAAW,EAAE,MAAM,CAAC;IACpB,iFAAiF;IACjF,OAAO,EAAE,MAAM,IAAI,CAAC;IAEpB,0EAA0E;IAC1E,QAAQ,EAAE,2BAA2B,EAAE,CAAC;IACxC,4EAA4E;IAC5E,UAAU,EAAE,MAAM,IAAI,CAAC;IACvB,sFAAoF;IACpF,aAAa,CAAC,EAAE,OAAO,CAAC;IAExB,sCAAsC;IACtC,aAAa,EAAE,kBAAkB,CAAC;IAClC,mEAAmE;IACnE,qBAAqB,EAAE,CAAC,KAAK,EAAE,kBAAkB,KAAK,IAAI,CAAC;IAC3D,yFAAuF;IACvF,uBAAuB,CAAC,EAAE,OAAO,CAAC;IAClC;;;OAGG;IACH,wBAAwB,CAAC,EAAE,OAAO,CAAC;IACnC;;;;OAIG;IACH,iBAAiB,CAAC,EAAE,SAAS,CAAC;IAC9B;;;OAGG;IACH,cAAc,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;IAElC;;;;;OAKG;IACH,KAAK,CAAC,EAAE,SAAS,CAAC;IAElB,6CAA6C;IAC7C,UAAU,CAAC,EAAE,MAAM,CAAC;CACvB;AAED;;;;;;;GAOG;AACH,wBAAgB,uBAAuB,CAAC,EACpC,WAAW,EACX,OAAO,EACP,QAAQ,EACR,UAAU,EACV,aAAa,EACb,aAAa,EACb,qBAAqB,EACrB,uBAAuB,EACvB,wBAAwB,EACxB,iBAAiB,EACjB,cAAc,EACd,KAAK,EACL,UAAU,EACb,EAAE,6BAA6B,2CA+D/B"}
1
+ {"version":3,"file":"UiObjectShareDialogCard.d.ts","sourceRoot":"","sources":["../../../src/@ui/UiObjectShareDialog/UiObjectShareDialogCard.tsx"],"names":[],"mappings":"AAEA,OAAO,EAAE,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AAOvC,OAAO,EACH,KAAK,kBAAkB,EAE1B,MAAM,iDAAiD,CAAC;AACzD,OAAO,EAAE,KAAK,iBAAiB,EAAE,MAAM,uCAAuC,CAAC;AAS/E;;;;;;GAMG;AACH,MAAM,WAAW,2BAA2B;IACxC,+DAA6D;IAC7D,EAAE,EAAE,MAAM,CAAC;IACX,sBAAsB;IACtB,IAAI,EAAE,iBAAiB,CAAC;IACxB,oBAAoB;IACpB,IAAI,EAAE,MAAM,CAAC;IACb,8BAA8B;IAC9B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,wEAAwE;IACxE,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB;;;OAGG;IACH,QAAQ,CAAC,EAAE,SAAS,CAAC;CACxB;AAED;;GAEG;AACH,MAAM,WAAW,6BAA6B;IAC1C,6EAA2E;IAC3E,WAAW,EAAE,MAAM,CAAC;IACpB,iFAAiF;IACjF,OAAO,EAAE,MAAM,IAAI,CAAC;IAEpB,0EAA0E;IAC1E,QAAQ,EAAE,2BAA2B,EAAE,CAAC;IACxC;;;;OAIG;IACH,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,4EAA4E;IAC5E,UAAU,EAAE,MAAM,IAAI,CAAC;IACvB,sFAAoF;IACpF,aAAa,CAAC,EAAE,OAAO,CAAC;IAExB,sCAAsC;IACtC,aAAa,EAAE,kBAAkB,CAAC;IAClC,mEAAmE;IACnE,qBAAqB,EAAE,CAAC,KAAK,EAAE,kBAAkB,KAAK,IAAI,CAAC;IAC3D,yFAAuF;IACvF,uBAAuB,CAAC,EAAE,OAAO,CAAC;IAClC;;;OAGG;IACH,wBAAwB,CAAC,EAAE,OAAO,CAAC;IACnC;;;;OAIG;IACH,iBAAiB,CAAC,EAAE,SAAS,CAAC;IAC9B;;;OAGG;IACH,cAAc,CAAC,EAAE,MAAM,GAAG,OAAO,GAAG,MAAM,CAAC;IAE3C;;;;;OAKG;IACH,KAAK,CAAC,EAAE,SAAS,CAAC;IAElB,6CAA6C;IAC7C,UAAU,CAAC,EAAE,MAAM,CAAC;CACvB;AAED;;;;;;;GAOG;AACH,wBAAgB,uBAAuB,CAAC,EACpC,WAAW,EACX,OAAO,EACP,QAAQ,EACR,SAAS,EACT,UAAU,EACV,aAAa,EACb,aAAa,EACb,qBAAqB,EACrB,uBAAuB,EACvB,wBAAwB,EACxB,iBAAiB,EACjB,cAAc,EACd,KAAK,EACL,UAAU,EACb,EAAE,6BAA6B,2CAuE/B"}
@@ -8,6 +8,7 @@ import { UiGranteeRow } from "../UiGranteeRow/UiGranteeRow.js";
8
8
  import { UiDialogFooter } from "../UiModalDialog/UiDialogFooter.js";
9
9
  import { UiDialogHeader } from "../UiModalDialog/UiDialogHeader.js";
10
10
  import { UiSectionHeading } from "../UiSectionHeading/UiSectionHeading.js";
11
+ import { UiSkeleton } from "../UiSkeleton/UiSkeleton.js";
11
12
  const { b, e } = bem("gd-ui-kit-object-share-dialog");
12
13
  /**
13
14
  * Object share dialog card — header, grantee list, general-access radio,
@@ -17,12 +18,11 @@ const { b, e } = bem("gd-ui-kit-object-share-dialog");
17
18
  *
18
19
  * @internal
19
20
  */
20
- export function UiObjectShareDialogCard({ objectTitle, onClose, grantees, onAddClick, isAddDisabled, generalAccess, onGeneralAccessChange, isGeneralAccessDisabled, workspaceAccessInherited, workspaceControls, workspaceLevel, error, dataTestId, }) {
21
+ export function UiObjectShareDialogCard({ objectTitle, onClose, grantees, isLoading, onAddClick, isAddDisabled, generalAccess, onGeneralAccessChange, isGeneralAccessDisabled, workspaceAccessInherited, workspaceControls, workspaceLevel, error, dataTestId, }) {
21
22
  const intl = useIntl();
22
23
  const dialogTitle = intl.formatMessage(olpObjectShareDialogMessages.title, { title: objectTitle });
23
24
  return (_jsxs("div", { className: b(), "data-testid": dataTestId, children: [
24
25
  _jsx(UiDialogHeader, { title: dialogTitle, onClose: onClose }), error ? (_jsx("div", { className: e("error"), role: "alert", children: error })) : (_jsxs(_Fragment, { children: [
25
- _jsx(UiSectionHeading, { label: intl.formatMessage(olpObjectShareDialogMessages.sharedWith), action: _jsx(UiButton, { label: intl.formatMessage(olpObjectShareDialogMessages.add), variant: "popout", size: "small", iconBefore: "plus", isDisabled: isAddDisabled, onClick: onAddClick }) }), _jsx("div", { className: e("grantees"), children: grantees.map((grantee) => (_jsx(UiGranteeRow, { kind: grantee.kind, name: grantee.name, email: grantee.email, isPending: grantee.isPending, controls: grantee.controls }, grantee.id))) }), _jsx(UiSectionHeading, { label: intl.formatMessage(olpObjectShareDialogMessages.generalAccess) }), _jsx(UiGeneralAccessRadio, { value: generalAccess, onChange: onGeneralAccessChange, disabled: isGeneralAccessDisabled, workspaceAccessInherited: workspaceAccessInherited, workspaceControls: workspaceControls, workspaceLevel: workspaceLevel })
26
- ] })), _jsx(UiDialogFooter, { divider: true, children: _jsx(UiButton, { label: intl.formatMessage(commonDialogMessages.close), variant: "secondary", size: "medium", onClick: onClose }) })
26
+ _jsx(UiSectionHeading, { label: intl.formatMessage(olpObjectShareDialogMessages.sharedWith), action: _jsx(UiButton, { label: intl.formatMessage(olpObjectShareDialogMessages.add), variant: "popout", size: "small", iconBefore: "plus", isDisabled: isAddDisabled, onClick: onAddClick }) }), _jsx("div", { className: e("grantees"), children: isLoading ? (_jsx(UiSkeleton, { itemsCount: 2, itemHeight: 40, itemsGap: 10 })) : (grantees.map((grantee) => (_jsx(UiGranteeRow, { kind: grantee.kind, name: grantee.name, email: grantee.email, isPending: grantee.isPending, controls: grantee.controls }, grantee.id)))) }), _jsx(UiSectionHeading, { label: intl.formatMessage(olpObjectShareDialogMessages.generalAccess) }), isLoading ? (_jsx(UiSkeleton, { itemsCount: 2, itemHeight: 40, itemsGap: 10 })) : (_jsx(UiGeneralAccessRadio, { value: generalAccess, onChange: onGeneralAccessChange, disabled: isGeneralAccessDisabled, workspaceAccessInherited: workspaceAccessInherited, workspaceControls: workspaceControls, workspaceLevel: workspaceLevel }))] })), _jsx(UiDialogFooter, { divider: true, children: _jsx(UiButton, { label: intl.formatMessage(commonDialogMessages.close), variant: "secondary", size: "medium", onClick: onClose }) })
27
27
  ] }));
28
28
  }
@@ -1,13 +1,21 @@
1
1
  import { type ReactElement } from "react";
2
+ import { type MessageDescriptor } from "react-intl";
2
3
  import { type IUiLabelsChecklistItem } from "../UiLabelsChecklist/UiLabelsChecklist.js";
3
4
  /**
4
- * Selectable permission level. The menu and the add-grantee picker only ever
5
- * assign VIEW or SHARE EDIT is shown as a read-only row (via the model's
6
- * `AccessGranularPermission`) and is never selectable from the UI.
5
+ * Selectable permission level, mirroring the model's `AccessGranularPermission`:
6
+ * EDIT ("Can edit & share"), SHARE ("Can view & share") and VIEW ("Can view")
7
+ * are all assignable from the menu.
7
8
  *
8
9
  * @internal
9
10
  */
10
- export type PermissionMenuLevel = "VIEW" | "SHARE";
11
+ export type PermissionMenuLevel = "VIEW" | "SHARE" | "EDIT";
12
+ /**
13
+ * Message descriptor of a permission level's display label ("Can edit & share" /
14
+ * "Can view & share" / "Can view") — for triggers anchoring {@link UiPermissionMenu}.
15
+ *
16
+ * @internal
17
+ */
18
+ export declare function permissionLevelMessage(level: PermissionMenuLevel): MessageDescriptor;
11
19
  /**
12
20
  * @internal
13
21
  */
@@ -20,7 +28,7 @@ export interface IUiPermissionMenuProps {
20
28
  onPermissionChange: (level: PermissionMenuLevel) => void;
21
29
  /**
22
30
  * Levels rendered disabled (`aria-disabled`, click blocked) — e.g. levels
23
- * above the caller's own when they manage their own access.
31
+ * the signed-in user may not pick because they exceed their own.
24
32
  */
25
33
  disabledLevels?: ReadonlyArray<PermissionMenuLevel>;
26
34
  /** Tooltip shown on disabled level rows in place of the level's info text. */
@@ -40,11 +48,11 @@ export interface IUiPermissionMenuProps {
40
48
  dataTestId?: string;
41
49
  }
42
50
  /**
43
- * Per-grantee permission popover. Renders a fixed set of rows — two
44
- * permission levels (Can view & share / Can view), an optional divider,
45
- * an optional labels drill-in and an optional Remove access action row.
46
- * Each level row carries an `infoCircle` tooltip; disabled level rows
47
- * (`disabledLevels`) swap it for `disabledTooltip`.
51
+ * Per-grantee permission popover. Renders a fixed set of rows — three
52
+ * permission levels (Can edit & share / Can view & share / Can view), an
53
+ * optional divider, an optional labels drill-in and an optional Remove access
54
+ * action row. Each level row carries an `infoCircle` tooltip; disabled level
55
+ * rows (`disabledLevels`) swap it for `disabledTooltip`.
48
56
  *
49
57
  * @internal
50
58
  */
@@ -1 +1 @@
1
- {"version":3,"file":"UiPermissionMenu.d.ts","sourceRoot":"","sources":["../../../src/@ui/UiPermissionMenu/UiPermissionMenu.tsx"],"names":[],"mappings":"AAEA,OAAO,EAAsB,KAAK,YAAY,EAAoB,MAAM,OAAO,CAAC;AAShF,OAAO,EAAE,KAAK,sBAAsB,EAAqB,MAAM,2CAA2C,CAAC;AAM3G;;;;;;GAMG;AACH,MAAM,MAAM,mBAAmB,GAAG,MAAM,GAAG,OAAO,CAAC;AAEnD;;GAEG;AACH,MAAM,WAAW,sBAAsB;IACnC,4CAA4C;IAC5C,MAAM,EAAE,YAAY,CAAC;IACrB,qEAAmE;IACnE,aAAa,CAAC,EAAE,mBAAmB,CAAC;IACpC,oDAAoD;IACpD,kBAAkB,EAAE,CAAC,KAAK,EAAE,mBAAmB,KAAK,IAAI,CAAC;IACzD;;;OAGG;IACH,cAAc,CAAC,EAAE,aAAa,CAAC,mBAAmB,CAAC,CAAC;IACpD,8EAA8E;IAC9E,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB;;;OAGG;IACH,MAAM,CAAC,EAAE,aAAa,CAAC,sBAAsB,CAAC,CAAC;IAC/C,mDAAmD;IACnD,gBAAgB,CAAC,EAAE,aAAa,CAAC,MAAM,CAAC,CAAC;IACzC,uEAAuE;IACvE,cAAc,CAAC,EAAE,CAAC,WAAW,EAAE,MAAM,EAAE,KAAK,IAAI,CAAC;IACjD,+CAA+C;IAC/C,cAAc,CAAC,EAAE,MAAM,IAAI,CAAC;IAC5B,0CAA0C;IAC1C,UAAU,CAAC,EAAE,MAAM,CAAC;CACvB;AAsBD;;;;;;;;GAQG;AACH,wBAAgB,gBAAgB,CAAC,EAC7B,MAAM,EACN,aAAa,EACb,kBAAkB,EAClB,cAAc,EACd,eAAe,EACf,MAAM,EACN,gBAAgB,EAChB,cAAc,EACd,cAAc,EACd,UAAU,EACb,EAAE,sBAAsB,2CAuBxB"}
1
+ {"version":3,"file":"UiPermissionMenu.d.ts","sourceRoot":"","sources":["../../../src/@ui/UiPermissionMenu/UiPermissionMenu.tsx"],"names":[],"mappings":"AAEA,OAAO,EAAsB,KAAK,YAAY,EAAiC,MAAM,OAAO,CAAC;AAE7F,OAAO,EAAE,KAAK,iBAAiB,EAAW,MAAM,YAAY,CAAC;AAO7D,OAAO,EAAE,KAAK,sBAAsB,EAAqB,MAAM,2CAA2C,CAAC;AAM3G;;;;;;GAMG;AACH,MAAM,MAAM,mBAAmB,GAAG,MAAM,GAAG,OAAO,GAAG,MAAM,CAAC;AAQ5D;;;;;GAKG;AACH,wBAAgB,sBAAsB,CAAC,KAAK,EAAE,mBAAmB,GAAG,iBAAiB,CAEpF;AAED;;GAEG;AACH,MAAM,WAAW,sBAAsB;IACnC,4CAA4C;IAC5C,MAAM,EAAE,YAAY,CAAC;IACrB,qEAAmE;IACnE,aAAa,CAAC,EAAE,mBAAmB,CAAC;IACpC,oDAAoD;IACpD,kBAAkB,EAAE,CAAC,KAAK,EAAE,mBAAmB,KAAK,IAAI,CAAC;IACzD;;;OAGG;IACH,cAAc,CAAC,EAAE,aAAa,CAAC,mBAAmB,CAAC,CAAC;IACpD,8EAA8E;IAC9E,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB;;;OAGG;IACH,MAAM,CAAC,EAAE,aAAa,CAAC,sBAAsB,CAAC,CAAC;IAC/C,mDAAmD;IACnD,gBAAgB,CAAC,EAAE,aAAa,CAAC,MAAM,CAAC,CAAC;IACzC,uEAAuE;IACvE,cAAc,CAAC,EAAE,CAAC,WAAW,EAAE,MAAM,EAAE,KAAK,IAAI,CAAC;IACjD,+CAA+C;IAC/C,cAAc,CAAC,EAAE,MAAM,IAAI,CAAC;IAC5B,0CAA0C;IAC1C,UAAU,CAAC,EAAE,MAAM,CAAC;CACvB;AAsBD;;;;;;;;GAQG;AACH,wBAAgB,gBAAgB,CAAC,EAC7B,MAAM,EACN,aAAa,EACb,kBAAkB,EAClB,cAAc,EACd,eAAe,EACf,MAAM,EACN,gBAAgB,EAChB,cAAc,EACd,cAAc,EACd,UAAU,EACb,EAAE,sBAAsB,2CAuBxB"}
@@ -1,6 +1,6 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  // (C) 2026 GoodData Corporation
3
- import { useRef, useState } from "react";
3
+ import { useCallback, useRef, useState } from "react";
4
4
  import { useIntl } from "react-intl";
5
5
  import { olpPermissionMessages } from "../../locales.js";
6
6
  import { bem } from "../@utils/bem.js";
@@ -10,12 +10,26 @@ import { UiLabelsChecklist } from "../UiLabelsChecklist/UiLabelsChecklist.js";
10
10
  import { UiPopover } from "../UiPopover/UiPopover.js";
11
11
  import { UiTooltip } from "../UiTooltip/UiTooltip.js";
12
12
  const { b, e } = bem("gd-ui-kit-permission-menu");
13
+ const PERMISSION_LEVEL_MESSAGE = {
14
+ EDIT: olpPermissionMessages.canEditAndShare,
15
+ SHARE: olpPermissionMessages.canViewAndShare,
16
+ VIEW: olpPermissionMessages.canView,
17
+ };
13
18
  /**
14
- * Per-grantee permission popover. Renders a fixed set of rows — two
15
- * permission levels (Can view & share / Can view), an optional divider,
16
- * an optional labels drill-in and an optional Remove access action row.
17
- * Each level row carries an `infoCircle` tooltip; disabled level rows
18
- * (`disabledLevels`) swap it for `disabledTooltip`.
19
+ * Message descriptor of a permission level's display label ("Can edit & share" /
20
+ * "Can view & share" / "Can view") for triggers anchoring {@link UiPermissionMenu}.
21
+ *
22
+ * @internal
23
+ */
24
+ export function permissionLevelMessage(level) {
25
+ return PERMISSION_LEVEL_MESSAGE[level];
26
+ }
27
+ /**
28
+ * Per-grantee permission popover. Renders a fixed set of rows — three
29
+ * permission levels (Can edit & share / Can view & share / Can view), an
30
+ * optional divider, an optional labels drill-in and an optional Remove access
31
+ * action row. Each level row carries an `infoCircle` tooltip; disabled level
32
+ * rows (`disabledLevels`) swap it for `disabledTooltip`.
19
33
  *
20
34
  * @internal
21
35
  */
@@ -26,8 +40,15 @@ export function UiPermissionMenu({ anchor, selectedLevel, onPermissionChange, di
26
40
  function MenuBody({ selectedLevel, onPermissionChange, disabledLevels, disabledTooltip, labels, selectedLabelIds, onLabelsChange, onRemoveAccess, onClose, dataTestId, }) {
27
41
  const intl = useIntl();
28
42
  // Drill-in state — swaps the row list for the labels checklist. Local to the
29
- // popover content, so it resets every time the menu opens.
30
- const [view, setView] = useState("menu");
43
+ // popover content, so it resets every time the menu opens. `origin` is what
44
+ // triggered the current view so the newly-mounted view knows whether to grab
45
+ // focus: a drill-in/return swaps the focused element out of the DOM (focus
46
+ // would otherwise fall to <body>), while the initial open leaves focus to the
47
+ // popover. See `focusOnMount`.
48
+ const [{ view, origin }, setView] = useState({
49
+ view: "menu",
50
+ origin: "open",
51
+ });
31
52
  const choose = (next) => () => {
32
53
  next();
33
54
  onClose();
@@ -46,6 +67,7 @@ function MenuBody({ selectedLevel, onPermissionChange, disabledLevels, disabledT
46
67
  };
47
68
  };
48
69
  const levelItems = [
70
+ levelItem("EDIT", intl.formatMessage(olpPermissionMessages.canEditAndShare), intl.formatMessage(olpPermissionMessages.canEditAndShareTooltip)),
49
71
  levelItem("SHARE", intl.formatMessage(olpPermissionMessages.canViewAndShare), intl.formatMessage(olpPermissionMessages.canViewAndShareTooltip)),
50
72
  levelItem("VIEW", intl.formatMessage(olpPermissionMessages.canView), intl.formatMessage(olpPermissionMessages.canViewTooltip)),
51
73
  ];
@@ -57,7 +79,7 @@ function MenuBody({ selectedLevel, onPermissionChange, disabledLevels, disabledT
57
79
  icon: "ldmLabel",
58
80
  iconRight: "navigateRight",
59
81
  // Drill in — the checklist owns Back/Cancel/Apply and closes the menu itself.
60
- onClick: () => setView("labels"),
82
+ onClick: () => setView({ view: "labels", origin: "nav" }),
61
83
  });
62
84
  }
63
85
  if (onRemoveAccess) {
@@ -98,20 +120,30 @@ function MenuBody({ selectedLevel, onPermissionChange, disabledLevels, disabledT
98
120
  focusable[nextIndex]?.focus();
99
121
  };
100
122
  if (view === "labels") {
101
- return (_jsx("div", { className: b(), "data-testid": dataTestId, children: _jsx(UiLabelsChecklist, { items: labels ?? [], defaultSelectedIds: selectedLabelIds ?? [], onApply: (ids) => onLabelsChange?.(ids), onBack: () => setView("menu"), onClose: onClose, dataTestId: dataTestId }) }));
123
+ return (_jsx("div", { className: b(), "data-testid": dataTestId, children: _jsx(UiLabelsChecklist, { items: labels ?? [], defaultSelectedIds: selectedLabelIds ?? [], onApply: (ids) => onLabelsChange?.(ids), onBack: () => setView({ view: "menu", origin: "nav" }), onClose: onClose, autoFocus: origin === "nav", dataTestId: dataTestId }) }));
102
124
  }
103
- return (_jsx("div", { className: b(), "data-testid": dataTestId, children: _jsxs("div", { ref: menuRef, className: e("items"), role: "menu", "aria-orientation": "vertical", "aria-label": intl.formatMessage(olpPermissionMessages.menuLabel), onKeyDown: handleKeyDown, children: [levelItems.map((item) => (_jsx(PermissionMenuItem, { item: item, selectedLevel: selectedLevel }, item.key))), actionItems.length > 0 ? _jsx("div", { className: e("divider"), role: "separator" }) : null, actionItems.map((item) => (_jsx(PermissionMenuItem, { item: item, selectedLevel: selectedLevel }, item.key)))] }) }));
125
+ return (_jsx("div", { className: b(), "data-testid": dataTestId, children: _jsxs("div", { ref: menuRef, className: e("items"), role: "menu", "aria-orientation": "vertical", "aria-label": intl.formatMessage(olpPermissionMessages.menuLabel), onKeyDown: handleKeyDown, children: [levelItems.map((item) => (_jsx(PermissionMenuItem, { item: item, selectedLevel: selectedLevel }, item.key))), actionItems.length > 0 ? _jsx("div", { className: e("divider"), role: "separator" }) : null, actionItems.map((item) => (_jsx(PermissionMenuItem, { item: item, selectedLevel: selectedLevel,
126
+ // Returning from the checklist restores focus to the row that opened it.
127
+ autoFocus: item.key === "labels" && origin === "nav" }, item.key)))] }) }));
104
128
  }
105
- function PermissionMenuItem({ item, selectedLevel }) {
129
+ function PermissionMenuItem({ item, selectedLevel, autoFocus }) {
106
130
  const intl = useIntl();
107
131
  // Tooltip anchor must live OUTSIDE the menu-item button so we don't nest an
108
132
  // interactive element inside a button (invalid HTML, breaks focus). The row
109
133
  // wrapper provides the flex layout; the button covers the label; the
110
134
  // tooltip sits next to the button.
135
+ //
136
+ // When this row opens as the drill-in return target, focus it as it mounts via
137
+ // a callback ref — no effect, and it can't race the button's mount.
138
+ const focusOnAttach = useCallback((node) => {
139
+ if (autoFocus) {
140
+ node?.focus();
141
+ }
142
+ }, [autoFocus]);
111
143
  const isRadio = !!item.radioValue;
112
144
  const isChecked = isRadio && item.radioValue === selectedLevel;
113
145
  return (_jsxs("div", { className: e("item-row"), children: [
114
- _jsxs("button", { type: "button", role: isRadio ? "menuitemradio" : "menuitem", "aria-checked": isRadio ? isChecked : undefined, "aria-disabled": item.disabled ? true : undefined, className: e("item", { disabled: Boolean(item.disabled) }), onClick: item.onClick, children: [item.icon ? _jsx(UiIcon, { type: item.icon, size: 16, color: "complementary-7" }) : null, _jsx("span", { className: e("item-label"), children: item.label }), item.iconRight ? _jsx(UiIcon, { type: item.iconRight, size: 14, color: "complementary-7" }) : null] }), item.tooltip ? (_jsx(UiTooltip, { triggerBy: ["hover", "focus"], content: item.tooltip, anchor: _jsx(UiIconButton, { icon: "infoCircle", variant: "tertiary", size: "small", accessibilityConfig: {
146
+ _jsxs("button", { type: "button", ref: focusOnAttach, role: isRadio ? "menuitemradio" : "menuitem", "aria-checked": isRadio ? isChecked : undefined, "aria-disabled": item.disabled ? true : undefined, className: e("item", { disabled: Boolean(item.disabled) }), onClick: item.onClick, children: [item.icon ? _jsx(UiIcon, { type: item.icon, size: 16, color: "complementary-7" }) : null, _jsx("span", { className: e("item-label"), children: item.label }), item.iconRight ? _jsx(UiIcon, { type: item.iconRight, size: 14, color: "complementary-7" }) : null] }), item.tooltip ? (_jsx(UiTooltip, { triggerBy: ["hover", "focus"], content: item.tooltip, anchor: _jsx(UiIconButton, { icon: "infoCircle", variant: "tertiary", size: "small", accessibilityConfig: {
115
147
  ariaLabel: intl.formatMessage(olpPermissionMessages.moreInfoAriaLabel, {
116
148
  label: item.label,
117
149
  }),
@@ -1,4 +1,4 @@
1
- import { type MouseEvent } from "react";
1
+ import { type MouseEvent, type Ref } from "react";
2
2
  import { type SizeLarge, type SizeMedium } from "../@types/size.js";
3
3
  /**
4
4
  * @internal
@@ -8,6 +8,8 @@ export interface IUiSubmenuHeaderProps {
8
8
  tooltipText?: string;
9
9
  onBack?: (e: MouseEvent<HTMLButtonElement>) => void;
10
10
  onClose?: (e: MouseEvent<HTMLButtonElement>) => void;
11
+ /** Ref to the back button, e.g. to focus it when the submenu opens. */
12
+ backButtonRef?: Ref<HTMLButtonElement>;
11
13
  backAriaLabel?: string;
12
14
  closeAriaLabel?: string;
13
15
  useShortenedTitle?: boolean;
@@ -21,5 +23,5 @@ export interface IUiSubmenuHeaderProps {
21
23
  * Title can render as Typography h3 or ShortenedText h3.
22
24
  * @internal
23
25
  */
24
- export declare function UiSubmenuHeader({ title, tooltipText, onBack, onClose, backAriaLabel, closeAriaLabel, useShortenedTitle, textColor, backgroundColor, height, titleId }: IUiSubmenuHeaderProps): import("react/jsx-runtime").JSX.Element;
26
+ export declare function UiSubmenuHeader({ title, tooltipText, onBack, onClose, backButtonRef, backAriaLabel, closeAriaLabel, useShortenedTitle, textColor, backgroundColor, height, titleId }: IUiSubmenuHeaderProps): import("react/jsx-runtime").JSX.Element;
25
27
  //# sourceMappingURL=UiSubmenuHeader.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"UiSubmenuHeader.d.ts","sourceRoot":"","sources":["../../../src/@ui/UiSubmenuHeader/UiSubmenuHeader.tsx"],"names":[],"mappings":"AAEA,OAAO,EAAE,KAAK,UAAU,EAAE,MAAM,OAAO,CAAC;AAOxC,OAAO,EAAE,KAAK,SAAS,EAAE,KAAK,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAIpE;;GAEG;AACH,MAAM,WAAW,qBAAqB;IAClC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,MAAM,CAAC,EAAE,CAAC,CAAC,EAAE,UAAU,CAAC,iBAAiB,CAAC,KAAK,IAAI,CAAC;IACpD,OAAO,CAAC,EAAE,CAAC,CAAC,EAAE,UAAU,CAAC,iBAAiB,CAAC,KAAK,IAAI,CAAC;IACrD,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAC5B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,MAAM,CAAC,EAAE,UAAU,GAAG,SAAS,CAAC;IAChC,OAAO,CAAC,EAAE,MAAM,CAAC;CACpB;AAED;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,EAC5B,KAAU,EACV,WAAW,EACX,MAAM,EACN,OAAO,EACP,aAAa,EACb,cAAc,EACd,iBAAiB,EACjB,SAAS,EACT,eAAe,EACf,MAAiB,EACjB,OAAO,EACV,EAAE,qBAAqB,2CAiFvB"}
1
+ {"version":3,"file":"UiSubmenuHeader.d.ts","sourceRoot":"","sources":["../../../src/@ui/UiSubmenuHeader/UiSubmenuHeader.tsx"],"names":[],"mappings":"AAEA,OAAO,EAAE,KAAK,UAAU,EAAE,KAAK,GAAG,EAAE,MAAM,OAAO,CAAC;AAOlD,OAAO,EAAE,KAAK,SAAS,EAAE,KAAK,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAIpE;;GAEG;AACH,MAAM,WAAW,qBAAqB;IAClC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,MAAM,CAAC,EAAE,CAAC,CAAC,EAAE,UAAU,CAAC,iBAAiB,CAAC,KAAK,IAAI,CAAC;IACpD,OAAO,CAAC,EAAE,CAAC,CAAC,EAAE,UAAU,CAAC,iBAAiB,CAAC,KAAK,IAAI,CAAC;IACrD,uEAAuE;IACvE,aAAa,CAAC,EAAE,GAAG,CAAC,iBAAiB,CAAC,CAAC;IACvC,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAC5B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,MAAM,CAAC,EAAE,UAAU,GAAG,SAAS,CAAC;IAChC,OAAO,CAAC,EAAE,MAAM,CAAC;CACpB;AAED;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,EAC5B,KAAU,EACV,WAAW,EACX,MAAM,EACN,OAAO,EACP,aAAa,EACb,aAAa,EACb,cAAc,EACd,iBAAiB,EACjB,SAAS,EACT,eAAe,EACf,MAAiB,EACjB,OAAO,EACV,EAAE,qBAAqB,2CAkFvB"}
@@ -10,12 +10,12 @@ import { UiTooltip } from "../UiTooltip/UiTooltip.js";
10
10
  * Title can render as Typography h3 or ShortenedText h3.
11
11
  * @internal
12
12
  */
13
- export function UiSubmenuHeader({ title = "", tooltipText, onBack, onClose, backAriaLabel, closeAriaLabel, useShortenedTitle, textColor, backgroundColor, height = "medium", titleId, }) {
13
+ export function UiSubmenuHeader({ title = "", tooltipText, onBack, onClose, backButtonRef, backAriaLabel, closeAriaLabel, useShortenedTitle, textColor, backgroundColor, height = "medium", titleId, }) {
14
14
  const heightClass = cx({
15
15
  "gd-ui-kit-submenu-header--large": height === "large",
16
16
  "gd-ui-kit-submenu-header--medium": height === "medium",
17
17
  });
18
18
  const backButtonSize = "small";
19
19
  const closeButtonSize = "small";
20
- return (_jsxs("div", { className: cx("gd-ui-kit-submenu-header", heightClass), style: { backgroundColor: backgroundColor, color: textColor }, children: [onBack ? (_jsx(UiIconButton, { icon: "navigateLeft", variant: "bare", size: backButtonSize, onClick: onBack, label: backAriaLabel, dataId: "s-submenu-header-back-button", dataTestId: "s-submenu-header-back-button" })) : null, _jsxs("div", { className: cx("gd-ui-kit-submenu-header__title"), "data-testid": "drill-filters-section", children: [useShortenedTitle ? (_jsx(ShortenedText, { tagName: "h3", className: cx("gd-ui-kit-submenu-header__title-text"), id: titleId, children: title })) : (_jsx(Typography, { tagName: "h3", className: cx("gd-ui-kit-submenu-header__title-text"), id: titleId, children: title })), tooltipText ? (_jsx(UiTooltip, { triggerBy: ["hover", "focus"], arrowPlacement: "left", optimalPlacement: true, content: _jsx("div", { className: "gd-ui-kit-submenu-header__title-tooltip-content", children: tooltipText }), anchor: _jsx(QuestionMark, { className: "gd-ui-kit-submenu-header__title-tooltip-icon", width: 14, height: 14, color: "var(--gd-palette-complementary-6)" }), offset: 10, anchorWrapperStyles: { lineHeight: 0, width: "fit-content" } })) : null] }), onClose ? (_jsx(UiIconButton, { size: closeButtonSize, variant: "bare", icon: "close", label: closeAriaLabel, onClick: onClose, dataId: "s-submenu-header-close-button", dataTestId: "s-submenu-header-close-button" })) : null] }));
20
+ return (_jsxs("div", { className: cx("gd-ui-kit-submenu-header", heightClass), style: { backgroundColor: backgroundColor, color: textColor }, children: [onBack ? (_jsx(UiIconButton, { ref: backButtonRef, icon: "navigateLeft", variant: "bare", size: backButtonSize, onClick: onBack, label: backAriaLabel, dataId: "s-submenu-header-back-button", dataTestId: "s-submenu-header-back-button" })) : null, _jsxs("div", { className: cx("gd-ui-kit-submenu-header__title"), "data-testid": "drill-filters-section", children: [useShortenedTitle ? (_jsx(ShortenedText, { tagName: "h3", className: cx("gd-ui-kit-submenu-header__title-text"), id: titleId, children: title })) : (_jsx(Typography, { tagName: "h3", className: cx("gd-ui-kit-submenu-header__title-text"), id: titleId, children: title })), tooltipText ? (_jsx(UiTooltip, { triggerBy: ["hover", "focus"], arrowPlacement: "left", optimalPlacement: true, content: _jsx("div", { className: "gd-ui-kit-submenu-header__title-tooltip-content", children: tooltipText }), anchor: _jsx(QuestionMark, { className: "gd-ui-kit-submenu-header__title-tooltip-icon", width: 14, height: 14, color: "var(--gd-palette-complementary-6)" }), offset: 10, anchorWrapperStyles: { lineHeight: 0, width: "fit-content" } })) : null] }), onClose ? (_jsx(UiIconButton, { size: closeButtonSize, variant: "bare", icon: "close", label: closeAriaLabel, onClick: onClose, dataId: "s-submenu-header-close-button", dataTestId: "s-submenu-header-close-button" })) : null] }));
21
21
  }