@gooddata/sdk-ui-kit 11.42.0 → 11.43.0-alpha.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (73) hide show
  1. package/esm/@ui/UiGranteeAsyncPicker/UiGranteeAsyncPicker.d.ts.map +1 -1
  2. package/esm/@ui/UiGranteeAsyncPicker/UiGranteeAsyncPicker.js +7 -4
  3. package/esm/@ui/UiGranteeRow/UiGranteeRow.d.ts +3 -1
  4. package/esm/@ui/UiGranteeRow/UiGranteeRow.d.ts.map +1 -1
  5. package/esm/@ui/UiGranteeRow/UiGranteeRow.js +2 -2
  6. package/esm/@ui/UiGranteeRowControls/UiGranteeRowControls.d.ts +15 -15
  7. package/esm/@ui/UiGranteeRowControls/UiGranteeRowControls.d.ts.map +1 -1
  8. package/esm/@ui/UiGranteeRowControls/UiGranteeRowControls.js +20 -18
  9. package/esm/@ui/UiLabelsChecklist/UiLabelsChecklist.d.ts +44 -0
  10. package/esm/@ui/UiLabelsChecklist/UiLabelsChecklist.d.ts.map +1 -0
  11. package/esm/@ui/UiLabelsChecklist/UiLabelsChecklist.js +76 -0
  12. package/esm/@ui/UiMoreOptionsMenu/UiMoreOptionsMenu.d.ts +23 -0
  13. package/esm/@ui/UiMoreOptionsMenu/UiMoreOptionsMenu.d.ts.map +1 -0
  14. package/esm/@ui/UiMoreOptionsMenu/UiMoreOptionsMenu.js +83 -0
  15. package/esm/@ui/UiObjectShareDialog/UiObjectShareDialogCard.d.ts +2 -0
  16. package/esm/@ui/UiObjectShareDialog/UiObjectShareDialogCard.d.ts.map +1 -1
  17. package/esm/@ui/UiObjectShareDialog/UiObjectShareDialogCard.js +1 -1
  18. package/esm/@ui/UiPermissionMenu/UiPermissionMenu.d.ts +4 -15
  19. package/esm/@ui/UiPermissionMenu/UiPermissionMenu.d.ts.map +1 -1
  20. package/esm/@ui/UiPermissionMenu/UiPermissionMenu.js +11 -23
  21. package/esm/@ui/UiPopover/UiPopover.d.ts +10 -1
  22. package/esm/@ui/UiPopover/UiPopover.d.ts.map +1 -1
  23. package/esm/@ui/UiPopover/UiPopover.js +2 -2
  24. package/esm/@ui/UiTag/UiTag.d.ts +1 -0
  25. package/esm/@ui/UiTag/UiTag.d.ts.map +1 -1
  26. package/esm/@ui/UiTag/UiTag.js +10 -4
  27. package/esm/@ui/UiTags/UiTag.d.ts +0 -2
  28. package/esm/@ui/UiTags/UiTag.d.ts.map +1 -1
  29. package/esm/@ui/UiTags/UiTag.js +14 -9
  30. package/esm/@ui/UiTags/UiTags.d.ts.map +1 -1
  31. package/esm/@ui/UiTags/UiTags.js +38 -24
  32. package/esm/@ui/UiTags/interactions.d.ts +4 -9
  33. package/esm/@ui/UiTags/interactions.d.ts.map +1 -1
  34. package/esm/@ui/UiTags/interactions.js +58 -228
  35. package/esm/@ui/UiTooltip/UiTooltip.d.ts +1 -1
  36. package/esm/@ui/UiTooltip/UiTooltip.d.ts.map +1 -1
  37. package/esm/@ui/UiTooltip/UiTooltip.js +17 -9
  38. package/esm/@ui/UiTooltip/types.d.ts +10 -1
  39. package/esm/@ui/UiTooltip/types.d.ts.map +1 -1
  40. package/esm/Button/Button.d.ts.map +1 -1
  41. package/esm/Button/Button.js +2 -2
  42. package/esm/Icon/icons/InsightIcons/Radar.d.ts.map +1 -1
  43. package/esm/Icon/icons/InsightIcons/Radar.js +3 -1
  44. package/esm/List/MenuList.d.ts +2 -1
  45. package/esm/List/MenuList.d.ts.map +1 -1
  46. package/esm/List/MenuList.js +2 -2
  47. package/esm/index.d.ts +2 -1
  48. package/esm/index.d.ts.map +1 -1
  49. package/esm/index.js +2 -1
  50. package/esm/locales.d.ts +11 -4
  51. package/esm/locales.d.ts.map +1 -1
  52. package/esm/locales.js +5 -4
  53. package/esm/sdk-ui-kit.d.ts +101 -84
  54. package/esm/tsdoc-metadata.json +1 -1
  55. package/package.json +11 -11
  56. package/src/@ui/UiGranteeAsyncPicker/UiGranteeAsyncPicker.scss +12 -0
  57. package/src/@ui/UiGranteeRow/UiGranteeRow.scss +5 -0
  58. package/src/@ui/UiGranteeRowControls/UiGranteeRowControls.scss +7 -0
  59. package/src/@ui/{UiLabelsPicker/UiLabelsPicker.scss → UiLabelsChecklist/UiLabelsChecklist.scss} +2 -7
  60. package/src/@ui/UiModalDialog/UiModalDialog.scss +11 -1
  61. package/src/@ui/UiMoreOptionsMenu/UiMoreOptionsMenu.scss +10 -0
  62. package/src/@ui/UiPermissionMenu/UiPermissionMenu.scss +0 -7
  63. package/src/@ui/UiTabs/UiTabs.scss +0 -1
  64. package/src/@ui/UiTag/UiTag.scss +4 -0
  65. package/src/@ui/UiTags/UiTags.scss +5 -1
  66. package/src/@ui/index.scss +2 -1
  67. package/styles/css/main.css +53 -21
  68. package/styles/css/main.css.map +1 -1
  69. package/styles/images/visualization-types/radar-active.svg +10 -6
  70. package/styles/images/visualization-types/radar.svg +16 -5
  71. package/esm/@ui/UiLabelsPicker/UiLabelsPicker.d.ts +0 -64
  72. package/esm/@ui/UiLabelsPicker/UiLabelsPicker.d.ts.map +0 -1
  73. package/esm/@ui/UiLabelsPicker/UiLabelsPicker.js +0 -89
@@ -23,7 +23,7 @@ function buildAnchorAriaAttrs(cfg) {
23
23
  /**
24
24
  * @internal
25
25
  */
26
- export function UiPopover({ id, accessibilityConfig = defaultAccessibilityConfig, anchor, anchorAccessibilityConfig, width = "default", title, tabIndex, disabled, content, footer, closeText, closeVisible, initialFocus, returnFocusTo, triggerBy = ["click"], returnFocusAfterClose = true, focusCheckFn = defaultFocusCheckFn, enableFocusTrap = false, onOpen, onClose, }) {
26
+ export function UiPopover({ id, accessibilityConfig = defaultAccessibilityConfig, anchor, anchorAccessibilityConfig, width = "default", title, tabIndex, disabled, content, footer, closeText, closeVisible, initialFocus, returnFocusTo, triggerBy = ["click"], returnFocusAfterClose = true, focusCheckFn = defaultFocusCheckFn, enableFocusTrap = false, isOpen, onOpenChange, onOpen, onClose, }) {
27
27
  const ref = useRef(null);
28
28
  const returnFocus = useMemo(() => {
29
29
  return returnFocusTo ?? ref;
@@ -35,7 +35,7 @@ export function UiPopover({ id, accessibilityConfig = defaultAccessibilityConfig
35
35
  // popovers (e.g. UiPermissionMenu) emit a dangling reference. Caller-supplied
36
36
  // ariaLabel / ariaLabelledBy in accessibilityConfig still takes precedence.
37
37
  const titleLabelledBy = title ? titleId : undefined;
38
- return (_jsx(UiTooltip, { onOpen: onOpen, onClose: onClose, accessibilityConfig: {
38
+ return (_jsx(UiTooltip, { isOpen: isOpen, onOpenChange: onOpenChange, onOpen: onOpen, onClose: onClose, accessibilityConfig: {
39
39
  ariaLabelledBy: titleLabelledBy,
40
40
  ...accessibilityConfig,
41
41
  role: "dialog",
@@ -26,6 +26,7 @@ export type UiTagProps = {
26
26
  onDeleteKeyDown?: (event: KeyboardEvent<HTMLButtonElement>) => void;
27
27
  tabIndex?: number;
28
28
  deleteTabIndex?: number;
29
+ labelAs?: "button" | "span";
29
30
  };
30
31
  /**
31
32
  * @internal
@@ -1 +1 @@
1
- {"version":3,"file":"UiTag.d.ts","sourceRoot":"","sources":["../../../src/@ui/UiTag/UiTag.tsx"],"names":[],"mappings":"AAEA,OAAO,EAAE,KAAK,aAAa,EAAE,KAAK,UAAU,EAAyC,MAAM,OAAO,CAAC;AAEnG,OAAO,EAAE,KAAK,wBAAwB,EAAE,MAAM,gCAAgC,CAAC;AAC/E,OAAO,EAAE,KAAK,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAClD,OAAO,EAAE,KAAK,UAAU,EAAE,MAAM,0BAA0B,CAAC;AAO3D;;GAEG;AACH,MAAM,WAAW,yBAA0B,SAAQ,wBAAwB;IACvE,eAAe,CAAC,EAAE,MAAM,CAAC;CAC5B;AAED;;GAEG;AACH,MAAM,MAAM,UAAU,GAAG;IACrB,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,OAAO,GAAG,UAAU,GAAG,WAAW,CAAC;IAC7C,IAAI,CAAC,EAAE,OAAO,GAAG,OAAO,CAAC;IACzB,UAAU,CAAC,EAAE,QAAQ,CAAC;IACtB,eAAe,CAAC,EAAE,UAAU,CAAC;IAC7B,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,mBAAmB,CAAC,EAAE,yBAAyB,CAAC;IAChD,OAAO,CAAC,EAAE,CAAC,CAAC,EAAE,UAAU,CAAC,iBAAiB,CAAC,KAAK,IAAI,CAAC;IACrD,QAAQ,CAAC,EAAE,CAAC,CAAC,EAAE,UAAU,CAAC,iBAAiB,CAAC,KAAK,IAAI,CAAC;IACtD,eAAe,CAAC,EAAE,CAAC,KAAK,EAAE,aAAa,CAAC,iBAAiB,CAAC,KAAK,IAAI,CAAC;IACpE,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,cAAc,CAAC,EAAE,MAAM,CAAC;CAC3B,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,KAAK,0GA0FhB,CAAC"}
1
+ {"version":3,"file":"UiTag.d.ts","sourceRoot":"","sources":["../../../src/@ui/UiTag/UiTag.tsx"],"names":[],"mappings":"AAEA,OAAO,EAAE,KAAK,aAAa,EAAE,KAAK,UAAU,EAAyC,MAAM,OAAO,CAAC;AAEnG,OAAO,EAAE,KAAK,wBAAwB,EAAE,MAAM,gCAAgC,CAAC;AAC/E,OAAO,EAAE,KAAK,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAClD,OAAO,EAAE,KAAK,UAAU,EAAE,MAAM,0BAA0B,CAAC;AAO3D;;GAEG;AACH,MAAM,WAAW,yBAA0B,SAAQ,wBAAwB;IACvE,eAAe,CAAC,EAAE,MAAM,CAAC;CAC5B;AAED;;GAEG;AACH,MAAM,MAAM,UAAU,GAAG;IACrB,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,OAAO,GAAG,UAAU,GAAG,WAAW,CAAC;IAC7C,IAAI,CAAC,EAAE,OAAO,GAAG,OAAO,CAAC;IACzB,UAAU,CAAC,EAAE,QAAQ,CAAC;IACtB,eAAe,CAAC,EAAE,UAAU,CAAC;IAC7B,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,mBAAmB,CAAC,EAAE,yBAAyB,CAAC;IAChD,OAAO,CAAC,EAAE,CAAC,CAAC,EAAE,UAAU,CAAC,iBAAiB,CAAC,KAAK,IAAI,CAAC;IACrD,QAAQ,CAAC,EAAE,CAAC,CAAC,EAAE,UAAU,CAAC,iBAAiB,CAAC,KAAK,IAAI,CAAC;IACtD,eAAe,CAAC,EAAE,CAAC,KAAK,EAAE,aAAa,CAAC,iBAAiB,CAAC,KAAK,IAAI,CAAC;IACpE,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,OAAO,CAAC,EAAE,QAAQ,GAAG,MAAM,CAAC;CAC/B,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,KAAK,0GA8GhB,CAAC"}
@@ -1,4 +1,4 @@
1
- import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
1
+ import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  // (C) 2025-2026 GoodData Corporation
3
3
  import { forwardRef, useLayoutEffect, useState } from "react";
4
4
  import { bem } from "../@utils/bem.js";
@@ -8,7 +8,7 @@ const { b, e } = bem("gd-ui-kit-tag");
8
8
  /**
9
9
  * @internal
10
10
  */
11
- export const UiTag = forwardRef(function UiTag({ label, size = "small", variant = "solid", iconBefore, iconBeforeColor, tabIndex, deleteTabIndex, accessibilityConfig, isDisabled, isDeletable, dataTestId, onClick, onDelete, onDeleteKeyDown, }, ref) {
11
+ export const UiTag = forwardRef(function UiTag({ label, size = "small", variant = "solid", iconBefore, iconBeforeColor, tabIndex, deleteTabIndex, accessibilityConfig, isDisabled, isDeletable, dataTestId, labelAs, onClick, onDelete, onDeleteKeyDown, }, ref) {
12
12
  const [labelRef, setLabelRef] = useState(null);
13
13
  const [hasTooltip, setHasTooltip] = useState(false);
14
14
  const { ariaLabel, ariaLabelledBy, deleteAriaLabel } = accessibilityConfig ?? {};
@@ -23,7 +23,13 @@ export const UiTag = forwardRef(function UiTag({ label, size = "small", variant
23
23
  const iconSize = size === "small" ? 14 : 16;
24
24
  const defaultIconColor = variant === "decorated" ? "complementary-0" : "complementary-6";
25
25
  const iconColor = iconBeforeColor ?? defaultIconColor;
26
- const button = (_jsxs("button", { ref: ref, tabIndex: tabIndex, "data-testid": dataTestId, className: e("trigger", { isDeletable: isDeletable ?? false, isDisabled: isDisabled ?? false }), disabled: isDisabled, "aria-disabled": isDisabled, "aria-label": ariaLabel, "aria-labelledby": ariaLabelledBy, onClick: onClick, children: [iconBefore ? (_jsx("span", { className: e("icon-before"), children: _jsx(UiIcon, { type: iconBefore, size: iconSize, color: iconColor }) })) : null, _jsx("span", { className: e("label"), ref: setLabelRef, children: label })
26
+ const labelIsButton = labelAs ? labelAs === "button" : onClick !== undefined;
27
+ const labelClassName = e("trigger", {
28
+ isDeletable: isDeletable ?? false,
29
+ isDisabled: isDisabled ?? false,
30
+ });
31
+ const labelInner = (_jsxs(_Fragment, { children: [iconBefore ? (_jsx("span", { className: e("icon-before"), children: _jsx(UiIcon, { type: iconBefore, size: iconSize, color: iconColor }) })) : null, _jsx("span", { className: e("label"), ref: setLabelRef, children: label })
27
32
  ] }));
28
- return (_jsxs("div", { className: b({ size, variant }), children: [hasTooltip ? (_jsx(UiTooltip, { anchor: button, content: _jsx("div", { className: e("tooltip"), children: label }), triggerBy: ["hover"], arrowPlacement: "top" })) : (button), isDeletable && !isDisabled ? (_jsx("button", { tabIndex: deleteTabIndex, "data-testid": dataTestId ? `${dataTestId}-delete-button` : undefined, "aria-label": deleteAriaLabel, className: e("delete"), onClick: onDelete, onKeyDown: onDeleteKeyDown, children: _jsx("span", { className: e("icon-delete"), children: _jsx(UiIcon, { size: 14, type: "cross", color: variant === "decorated" ? "complementary-0" : "complementary-6" }) }) })) : null] }));
33
+ const labelElement = labelIsButton ? (_jsx("button", { ref: ref, tabIndex: tabIndex, "data-testid": dataTestId, className: labelClassName, disabled: isDisabled, "aria-disabled": isDisabled, "aria-label": ariaLabel, "aria-labelledby": ariaLabelledBy, onClick: onClick, children: labelInner })) : (_jsx("span", { className: labelClassName, "aria-label": ariaLabel, "aria-labelledby": ariaLabelledBy, "data-testid": dataTestId, children: labelInner }));
34
+ return (_jsxs("div", { className: b({ size, variant }), children: [hasTooltip ? (_jsx(UiTooltip, { anchor: labelElement, content: _jsx("div", { className: e("tooltip"), children: label }), triggerBy: ["hover"], arrowPlacement: "top" })) : (labelElement), isDeletable && !isDisabled ? (_jsx("button", { tabIndex: deleteTabIndex, "data-testid": dataTestId ? `${dataTestId}-delete-button` : undefined, "aria-label": deleteAriaLabel, className: e("delete"), onClick: onDelete, onKeyDown: onDeleteKeyDown, children: _jsx("span", { className: e("icon-delete"), children: _jsx(UiIcon, { size: 14, type: "cross", color: variant === "decorated" ? "complementary-0" : "complementary-6" }) }) })) : null] }));
29
35
  });
@@ -3,9 +3,7 @@ export interface IUiTagProps {
3
3
  tag: IUiTagDef;
4
4
  isDeletable: boolean;
5
5
  deleteLabel?: string;
6
- isReadOnly?: boolean;
7
6
  isDisabled?: boolean;
8
- isFocused?: boolean;
9
7
  size?: "small" | "large";
10
8
  onDelete?: (tag: IUiTagDef) => void;
11
9
  onClick?: (tag: IUiTagDef) => void;
@@ -1 +1 @@
1
- {"version":3,"file":"UiTag.d.ts","sourceRoot":"","sources":["../../../src/@ui/UiTags/UiTag.tsx"],"names":[],"mappings":"AAOA,OAAO,EAAE,KAAK,SAAS,EAAE,MAAM,YAAY,CAAC;AAI5C,MAAM,WAAW,WAAW;IACxB,GAAG,EAAE,SAAS,CAAC;IACf,WAAW,EAAE,OAAO,CAAC;IACrB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,IAAI,CAAC,EAAE,OAAO,GAAG,OAAO,CAAC;IACzB,QAAQ,CAAC,EAAE,CAAC,GAAG,EAAE,SAAS,KAAK,IAAI,CAAC;IACpC,OAAO,CAAC,EAAE,CAAC,GAAG,EAAE,SAAS,KAAK,IAAI,CAAC;IACnC,QAAQ,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;CAC9B;AAED,eAAO,MAAM,KAAK,2GA+BhB,CAAC"}
1
+ {"version":3,"file":"UiTag.d.ts","sourceRoot":"","sources":["../../../src/@ui/UiTags/UiTag.tsx"],"names":[],"mappings":"AAOA,OAAO,EAAE,KAAK,SAAS,EAAE,MAAM,YAAY,CAAC;AAI5C,MAAM,WAAW,WAAW;IACxB,GAAG,EAAE,SAAS,CAAC;IACf,WAAW,EAAE,OAAO,CAAC;IACrB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,IAAI,CAAC,EAAE,OAAO,GAAG,OAAO,CAAC;IACzB,QAAQ,CAAC,EAAE,CAAC,GAAG,EAAE,SAAS,KAAK,IAAI,CAAC;IACpC,OAAO,CAAC,EAAE,CAAC,GAAG,EAAE,SAAS,KAAK,IAAI,CAAC;IACnC,QAAQ,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;CAC9B;AAED,eAAO,MAAM,KAAK,2GA6ChB,CAAC"}
@@ -4,16 +4,21 @@ import { forwardRef } from "react";
4
4
  import { bem } from "../@utils/bem.js";
5
5
  import { UiTag as UiTagComponent } from "../UiTag/UiTag.js";
6
6
  const { e } = bem("gd-ui-kit-tags");
7
- export const UiTag = forwardRef(function UiTag({ tag, maxWidth, isDeletable, isDisabled, isFocused, size, deleteLabel, onDelete, onClick }, ref) {
7
+ export const UiTag = forwardRef(function UiTag({ tag, maxWidth, isDeletable, isDisabled, size, deleteLabel, onDelete, onClick }, ref) {
8
8
  const canBeDeleted = isDeletable && (tag.isDeletable ?? true);
9
- return (_jsx("div", { className: e("tag", { isFocused: isFocused ?? false }), role: "listitem", style: { maxWidth }, children: _jsx(UiTagComponent, { ref: ref, tabIndex: -1, deleteTabIndex: -1, label: `${tag.label}`, size: size, iconBefore: tag.iconBefore, isDeletable: canBeDeleted, isDisabled: isDisabled, accessibilityConfig: {
9
+ const isClickable = onClick !== undefined;
10
+ return (_jsx("div", { className: e("tag"), style: { maxWidth }, "data-tag-id": tag.id, tabIndex: -1, "aria-label": tag.label, children: _jsx(UiTagComponent, { ref: isClickable ? ref : undefined, labelAs: isClickable ? "button" : "span", label: `${tag.label}`, size: size, iconBefore: tag.iconBefore, isDeletable: canBeDeleted, isDisabled: isDisabled, accessibilityConfig: {
10
11
  ariaLabel: tag.label,
11
12
  deleteAriaLabel: `${deleteLabel ?? "Delete"} ${tag.label}`,
12
- }, onDelete: (e) => {
13
- onDelete?.(tag);
14
- e.stopPropagation();
15
- }, onClick: (e) => {
16
- onClick?.(tag);
17
- e.stopPropagation();
18
- } }) }));
13
+ }, onDelete: canBeDeleted
14
+ ? (e) => {
15
+ onDelete?.(tag);
16
+ e.stopPropagation();
17
+ }
18
+ : undefined, onClick: isClickable
19
+ ? (e) => {
20
+ onClick(tag);
21
+ e.stopPropagation();
22
+ }
23
+ : undefined }) }));
19
24
  });
@@ -1 +1 @@
1
- {"version":3,"file":"UiTags.d.ts","sourceRoot":"","sources":["../../../src/@ui/UiTags/UiTags.tsx"],"names":[],"mappings":"AAqBA,OAAO,EAAkB,KAAK,YAAY,EAAE,MAAM,YAAY,CAAC;AAO/D;;GAEG;AACH,wBAAgB,MAAM,CAAC,EACnB,IAAI,EACJ,UAAU,EACV,QAAoB,EACpB,SAAkB,EAClB,WAAsB,EACtB,UAAoB,EACpB,SAAkB,EAClB,WAAuB,EACvB,SAAuB,EACvB,WAAsB,EACtB,cAA+B,EAC/B,IAAoB,EACpB,IAAc,EACd,aAAoB,EACpB,YAAmB,EACnB,QAAgB,EAChB,UAAqB,EACrB,QAAmB,EACnB,WAAsB,EACtB,mBAAgD,EAChD,eAAe,EAClB,EAAE,YAAY,2CAmUd"}
1
+ {"version":3,"file":"UiTags.d.ts","sourceRoot":"","sources":["../../../src/@ui/UiTags/UiTags.tsx"],"names":[],"mappings":"AAsBA,OAAO,EAAkB,KAAK,YAAY,EAAE,MAAM,YAAY,CAAC;AAO/D;;GAEG;AACH,wBAAgB,MAAM,CAAC,EACnB,IAAI,EACJ,UAAU,EACV,QAAoB,EACpB,SAAkB,EAClB,WAAsB,EACtB,UAAoB,EACpB,SAAkB,EAClB,WAAuB,EACvB,SAAuB,EACvB,WAAsB,EACtB,cAA+B,EAC/B,IAAoB,EACpB,IAAc,EACd,aAAoB,EACpB,YAAmB,EACnB,QAAgB,EAChB,UAAU,EACV,QAAmB,EACnB,WAAsB,EACtB,mBAAgD,EAChD,eAAe,EAClB,EAAE,YAAY,2CAuVd"}
@@ -9,6 +9,7 @@ import { UiComboboxList } from "../UiCombobox/UiComboboxList.js";
9
9
  import { UiComboboxListItem, UiComboboxListItemCreatableLabel, UiComboboxListItemLabel, } from "../UiCombobox/UiComboboxListItem.js";
10
10
  import { UiComboboxPopup } from "../UiCombobox/UiComboboxPopup.js";
11
11
  import { UiPopover } from "../UiPopover/UiPopover.js";
12
+ import { UiTooltip } from "../UiTooltip/UiTooltip.js";
12
13
  import { useResponsiveTags } from "./hooks/useResponsiveTags.js";
13
14
  import { useTagsInteractions } from "./interactions.js";
14
15
  import { UiTag } from "./UiTag.js";
@@ -17,7 +18,7 @@ const defaultAccessibilityConfig = {};
17
18
  /**
18
19
  * @internal
19
20
  */
20
- export function UiTags({ tags, tagOptions, addLabel = "Add tag", nameLabel = "Name", cancelLabel = "Cancel", closeLabel = "Close", saveLabel = "Save", noTagsLabel = "No tags", moreLabel = "More tags", removeLabel = "Remove", creatableLabel = "(Create new)", mode = "single-line", size = "small", canDeleteTags = true, canCreateTag = true, readOnly = false, onTagClick = () => { }, onTagAdd = () => { }, onTagRemove = () => { }, accessibilityConfig = defaultAccessibilityConfig, renderAddButton, }) {
21
+ export function UiTags({ tags, tagOptions, addLabel = "Add tag", nameLabel = "Name", cancelLabel = "Cancel", closeLabel = "Close", saveLabel = "Save", noTagsLabel = "No tags", moreLabel = "More tags", removeLabel = "Remove", creatableLabel = "(Create new)", mode = "single-line", size = "small", canDeleteTags = true, canCreateTag = true, readOnly = false, onTagClick, onTagAdd = () => { }, onTagRemove = () => { }, accessibilityConfig = defaultAccessibilityConfig, renderAddButton, }) {
21
22
  const inputRef = useRef(null);
22
23
  const [popupOpen, setPopupOpen] = useState(false);
23
24
  const popupId = useId();
@@ -27,7 +28,13 @@ export function UiTags({ tags, tagOptions, addLabel = "Add tag", nameLabel = "Na
27
28
  const isAddable = canCreateTag && !readOnly && !hasCustomAddButton;
28
29
  const { rootRef, showedTags, hiddenTags, tagsContainerRef, hiddenTagsContainerRef, tooltipTagsContainerRef, addButtonRef, allContainerRef, tooltipWidth, availableWidth, lastAvailableWidth, setTooltipContainer, } = useResponsiveTags(tags, mode, [canCreateTag, canDeleteTags, readOnly, hasCustomAddButton]);
29
30
  const items = [...showedTags, hiddenTags];
30
- const { handleKeyDown, interactionState, onMoreOpen, onMoreClose, onAddOpen, onAddClose, showedFocusedIndex, hiddenFocusedIndex, tag, setTag, onTagClickHandler, onTagRemoveHandler, onTagAddHandler, } = useTagsInteractions(rootRef, tooltipTagsContainerRef, showedTags, hiddenTags, onTagClick, onTagAdd, onTagRemove);
31
+ const { interactionState, onAddOpen, onAddClose, onMoreOpen, onMoreClose, tag, setTag, onTagClickHandler, onTagRemoveHandler, onTagAddHandler, } = useTagsInteractions(tagsContainerRef, tooltipTagsContainerRef, showedTags, hiddenTags, onTagAdd, onTagRemove, onTagClick);
32
+ const [morePopoverOpen, setMorePopoverOpen] = useState(false);
33
+ const morePopoverId = useId();
34
+ const groupLabelId = useId();
35
+ const hasTagClickHandler = onTagClick !== undefined;
36
+ const groupLabelledBy = accessibilityConfig?.ariaLabelledBy ?? groupLabelId;
37
+ const groupLabelText = accessibilityConfig?.ariaLabel ?? (tags.length === 1 ? "Tags, 1" : `Tags, ${tags.length}`);
31
38
  const comboboxOptions = useMemo(() => {
32
39
  if (!tagOptions) {
33
40
  return [];
@@ -37,36 +44,44 @@ export function UiTags({ tags, tagOptions, addLabel = "Add tag", nameLabel = "Na
37
44
  .filter((tagOption) => !tagIds.has(tagOption.id))
38
45
  .map((tagOption) => ({ id: tagOption.id, label: tagOption.label }));
39
46
  }, [tagOptions, tags]);
40
- return (_jsxs("div", { ref: rootRef, tabIndex: tags.length === 0 ? -1 : 0, onKeyDown: handleKeyDown, className: b({ readOnly, mode }), "aria-label": accessibilityConfig?.ariaLabel, "aria-labelledby": accessibilityConfig?.ariaLabelledBy, "aria-describedby": accessibilityConfig?.ariaDescribedBy, role: accessibilityConfig?.role ?? "list", children: [
41
- _jsx("div", { className: e("shadow-container"), ref: allContainerRef, children: tags.map((tag) => {
47
+ return (_jsxs("div", { ref: rootRef, className: b({ readOnly, mode }), "aria-labelledby": groupLabelledBy, "aria-describedby": accessibilityConfig?.ariaDescribedBy, role: accessibilityConfig?.role ?? "group", children: [accessibilityConfig?.ariaLabelledBy ? null : (_jsx("span", { className: "sr-only", id: groupLabelId, children: groupLabelText })), _jsx("div", { className: e("shadow-container"), ref: allContainerRef, children: tags.map((tag) => {
42
48
  return (_jsx(UiTag, { tag: tag, isDeletable: isDeletable, size: size }, getKey(tag, isDeletable, readOnly)));
43
49
  }) }), _jsxs("div", { className: e("tags-container"), ref: tagsContainerRef, children: [items.map((tag, i) => {
44
50
  if (Array.isArray(tag)) {
45
51
  if (hiddenTags.length === 0) {
46
52
  return null;
47
53
  }
48
- return (_jsx("div", { role: "listitem", className: e("hidden-tags", { isFocused: showedFocusedIndex === i }), onClick: (e) => {
54
+ return (_jsx("div", { className: e("hidden-tags"), onClick: (e) => {
49
55
  e.stopPropagation();
50
56
  e.preventDefault();
51
- }, children: hiddenTags.length > 0 ? (_jsx(UiPopover, { onOpen: onMoreOpen, onClose: onMoreClose, enableFocusTrap: true, initialFocus: tooltipTagsContainerRef, returnFocusTo: rootRef, anchor: _jsx(UiButton, { tabIndex: -1, label: `+${hiddenTags.length}`, size: "small", variant: "tertiary", ref: (ref) => {
57
+ }, children: hiddenTags.length > 0 ? (_jsx(UiPopover, { id: morePopoverId, onOpen: () => {
58
+ setMorePopoverOpen(true);
59
+ onMoreOpen();
60
+ }, onClose: () => {
61
+ setMorePopoverOpen(false);
62
+ onMoreClose();
63
+ }, enableFocusTrap: true, initialFocus: tooltipTagsContainerRef, returnFocusTo: hiddenTagsContainerRef, anchorAccessibilityConfig: {
64
+ ariaHaspopup: "dialog",
65
+ ariaControls: morePopoverId,
66
+ }, anchor: _jsx(UiButton, { label: `+${hiddenTags.length}`, size: "small", variant: "tertiary", accessibilityConfig: {
67
+ ariaLabel: moreLabel,
68
+ ariaExpanded: morePopoverOpen,
69
+ }, ref: (ref) => {
52
70
  hiddenTagsContainerRef.current = ref;
53
- interactionState.current.more = ref;
54
- } }), width: 300, title: moreLabel, content: () => (_jsx("div", { onKeyDown: handleKeyDown, className: e("tags-more-tooltip"), ref: (ref) => {
71
+ } }), width: 300, title: moreLabel, content: () => (_jsx("div", { className: e("tags-more-tooltip"), ref: (ref) => {
55
72
  tooltipTagsContainerRef.current = ref;
56
73
  setTooltipContainer(ref);
57
- }, tabIndex: 0, children: hiddenTags.map((tag, i) => {
58
- return (_jsx(UiTag, { tag: tag, deleteLabel: removeLabel, ref: (ref) => {
59
- interactionState.current.tags[tag.id] = ref;
60
- }, isDeletable: isDeletable, isDisabled: readOnly, isFocused: hiddenFocusedIndex === i, size: size, maxWidth: tooltipWidth, onDelete: onTagRemoveHandler, onClick: onTagClickHandler }, i));
74
+ }, children: hiddenTags.map((tag, i) => {
75
+ return (_jsx(UiTag, { tag: tag, deleteLabel: removeLabel, isDeletable: isDeletable, isDisabled: readOnly, size: size, maxWidth: tooltipWidth, onDelete: onTagRemoveHandler, onClick: hasTagClickHandler
76
+ ? onTagClickHandler
77
+ : undefined }, i));
61
78
  }) })), footer: ({ onClose }) => (_jsx(_Fragment, { children: _jsx(UiButton, { ref: (ref) => {
62
79
  interactionState.current.close = ref;
63
80
  }, label: closeLabel, variant: "secondary", onClick: () => {
64
81
  onClose();
65
82
  } }) })) })) : null }, i));
66
83
  }
67
- return (_jsx(UiTag, { tag: tag, ref: (ref) => {
68
- interactionState.current.tags[tag.id] = ref;
69
- }, isDeletable: isDeletable, isDisabled: readOnly, deleteLabel: removeLabel, isFocused: showedFocusedIndex === i, size: size, onDelete: onTagRemoveHandler, onClick: onTagClickHandler, maxWidth: i === showedTags.length - 1 ? lastAvailableWidth : availableWidth }, getKey(tag, isDeletable, readOnly)));
84
+ return (_jsx(UiTag, { tag: tag, isDeletable: isDeletable, isDisabled: readOnly, deleteLabel: removeLabel, size: size, onDelete: onTagRemoveHandler, onClick: hasTagClickHandler ? onTagClickHandler : undefined, maxWidth: i === showedTags.length - 1 ? lastAvailableWidth : availableWidth }, getKey(tag, isDeletable, readOnly)));
70
85
  }), hasCustomAddButton ? (_jsx("div", { className: e("add-button"), ref: addButtonRef, onClick: (e) => {
71
86
  e.stopPropagation();
72
87
  e.preventDefault();
@@ -82,15 +97,14 @@ export function UiTags({ tags, tagOptions, addLabel = "Add tag", nameLabel = "Na
82
97
  setTag("");
83
98
  onAddClose();
84
99
  setPopupOpen(false);
85
- }, enableFocusTrap: true, anchor: _jsx(UiButton, { label: showedTags.length > 0 ? "" : addLabel, accessibilityConfig: {
86
- ariaHaspopup: true,
87
- ariaControls: popupId,
88
- ariaLabel: showedTags.length > 0 ? addLabel : undefined,
89
- ariaExpanded: popupOpen,
90
- role: "listitem",
91
- }, size: "small", iconBefore: "plus", variant: "tertiary", ref: (ref) => {
92
- interactionState.current.add = ref;
93
- } }), title: addLabel, initialFocus: inputRef, content: ({ onClose }) => (_jsxs(UiCombobox, { options: comboboxOptions, value: tag, onValueChange: setTag, creatable: true, children: [
100
+ }, enableFocusTrap: true, anchor: _jsx(UiTooltip, { content: addLabel, triggerBy: ["hover", "focus"], anchorWrapperStyles: { display: "flex", alignItems: "center" }, anchor: _jsx(UiButton, { label: showedTags.length > 0 ? "" : addLabel, accessibilityConfig: {
101
+ ariaHaspopup: true,
102
+ ariaControls: popupId,
103
+ ariaLabel: addLabel,
104
+ ariaExpanded: popupOpen,
105
+ }, size: "small", iconBefore: "plus", variant: "tertiary", ref: (ref) => {
106
+ interactionState.current.add = ref;
107
+ } }) }), title: addLabel, initialFocus: inputRef, content: ({ onClose }) => (_jsxs(UiCombobox, { options: comboboxOptions, value: tag, onValueChange: setTag, creatable: true, children: [
94
108
  _jsx(UiComboboxInput, { ref: (node) => {
95
109
  inputRef.current = node;
96
110
  interactionState.current.input = node;
@@ -3,27 +3,22 @@ import { type IUiTagDef, type IUiTagsProps } from "./types.js";
3
3
  type InteractionState = {
4
4
  moreOpen: boolean;
5
5
  addOpen: boolean;
6
- tags: Record<string, HTMLButtonElement>;
7
- more: HTMLButtonElement | null;
8
6
  add: HTMLButtonElement | null;
9
7
  close: HTMLButtonElement | null;
10
8
  save: HTMLButtonElement | null;
11
9
  input: HTMLInputElement | null;
12
10
  };
13
- export declare function useTagsInteractions(rootRef: MutableRefObject<HTMLDivElement | null>, hiddenTagsRef: MutableRefObject<HTMLDivElement | null>, showedTags: IUiTagDef[], hiddenTags: IUiTagDef[], onTagClick: IUiTagsProps["onTagClick"], onTagAdd: IUiTagsProps["onTagAdd"], onTagRemove: IUiTagsProps["onTagRemove"]): {
11
+ export declare function useTagsInteractions(tagsContainerRef: MutableRefObject<HTMLDivElement | null>, tooltipTagsContainerRef: MutableRefObject<HTMLDivElement | null>, showedTags: IUiTagDef[], hiddenTags: IUiTagDef[], onTagAdd: IUiTagsProps["onTagAdd"], onTagRemove: IUiTagsProps["onTagRemove"], onTagClick: IUiTagsProps["onTagClick"]): {
14
12
  tag: string;
15
13
  setTag: import("react").Dispatch<import("react").SetStateAction<string>>;
16
14
  onAddOpen: () => void;
17
15
  onAddClose: () => void;
18
16
  onMoreOpen: () => void;
19
17
  onMoreClose: () => void;
20
- handleKeyDown: (event: import("react").KeyboardEvent<Element>) => void;
21
- interactionState: import("react").RefObject<InteractionState>;
22
- showedFocusedIndex: number;
23
- hiddenFocusedIndex: number;
24
18
  onTagAddHandler: () => void;
25
- onTagRemoveHandler: (tag: IUiTagDef) => void;
26
- onTagClickHandler: (tag: IUiTagDef) => void;
19
+ onTagRemoveHandler: (removedTag: IUiTagDef) => void;
20
+ onTagClickHandler: (clickedTag: IUiTagDef) => void;
21
+ interactionState: import("react").RefObject<InteractionState>;
27
22
  };
28
23
  export {};
29
24
  //# sourceMappingURL=interactions.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"interactions.d.ts","sourceRoot":"","sources":["../../../src/@ui/UiTags/interactions.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,KAAK,gBAAgB,EAA0C,MAAM,OAAO,CAAC;AAItF,OAAO,EAAE,KAAK,SAAS,EAAE,KAAK,YAAY,EAAE,MAAM,YAAY,CAAC;AAE/D,KAAK,gBAAgB,GAAG;IACpB,QAAQ,EAAE,OAAO,CAAC;IAClB,OAAO,EAAE,OAAO,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,iBAAiB,CAAC,CAAC;IACxC,IAAI,EAAE,iBAAiB,GAAG,IAAI,CAAC;IAC/B,GAAG,EAAE,iBAAiB,GAAG,IAAI,CAAC;IAC9B,KAAK,EAAE,iBAAiB,GAAG,IAAI,CAAC;IAChC,IAAI,EAAE,iBAAiB,GAAG,IAAI,CAAC;IAC/B,KAAK,EAAE,gBAAgB,GAAG,IAAI,CAAC;CAClC,CAAC;AAEF,wBAAgB,mBAAmB,CAC/B,OAAO,EAAE,gBAAgB,CAAC,cAAc,GAAG,IAAI,CAAC,EAChD,aAAa,EAAE,gBAAgB,CAAC,cAAc,GAAG,IAAI,CAAC,EACtD,UAAU,EAAE,SAAS,EAAE,EACvB,UAAU,EAAE,SAAS,EAAE,EACvB,UAAU,EAAE,YAAY,CAAC,YAAY,CAAC,EACtC,QAAQ,EAAE,YAAY,CAAC,UAAU,CAAC,EAClC,WAAW,EAAE,YAAY,CAAC,aAAa,CAAC;;;;;;;;;;;;;;EA8R3C"}
1
+ {"version":3,"file":"interactions.d.ts","sourceRoot":"","sources":["../../../src/@ui/UiTags/interactions.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,KAAK,gBAAgB,EAAkD,MAAM,OAAO,CAAC;AAI9F,OAAO,EAAE,KAAK,SAAS,EAAE,KAAK,YAAY,EAAE,MAAM,YAAY,CAAC;AAI/D,KAAK,gBAAgB,GAAG;IACpB,QAAQ,EAAE,OAAO,CAAC;IAClB,OAAO,EAAE,OAAO,CAAC;IACjB,GAAG,EAAE,iBAAiB,GAAG,IAAI,CAAC;IAC9B,KAAK,EAAE,iBAAiB,GAAG,IAAI,CAAC;IAChC,IAAI,EAAE,iBAAiB,GAAG,IAAI,CAAC;IAC/B,KAAK,EAAE,gBAAgB,GAAG,IAAI,CAAC;CAClC,CAAC;AAmBF,wBAAgB,mBAAmB,CAC/B,gBAAgB,EAAE,gBAAgB,CAAC,cAAc,GAAG,IAAI,CAAC,EACzD,uBAAuB,EAAE,gBAAgB,CAAC,cAAc,GAAG,IAAI,CAAC,EAChE,UAAU,EAAE,SAAS,EAAE,EACvB,UAAU,EAAE,SAAS,EAAE,EACvB,QAAQ,EAAE,YAAY,CAAC,UAAU,CAAC,EAClC,WAAW,EAAE,YAAY,CAAC,aAAa,CAAC,EACxC,UAAU,EAAE,YAAY,CAAC,YAAY,CAAC;;;;;;;;;;;EAiHzC"}
@@ -1,33 +1,47 @@
1
1
  // (C) 2025-2026 GoodData Corporation
2
- import { useCallback, useMemo, useRef, useState } from "react";
3
- import { makeTabsKeyboardNavigation } from "../@utils/keyboardNavigation.js";
4
- export function useTagsInteractions(rootRef, hiddenTagsRef, showedTags, hiddenTags, onTagClick, onTagAdd, onTagRemove) {
2
+ import { useCallback, useLayoutEffect, useRef, useState } from "react";
3
+ import { programaticFocusManagement } from "../UiFocusManager/utils.js";
4
+ const TAG_SELECTOR = ".gd-ui-kit-tags__tag";
5
+ function getTagElements(container) {
6
+ if (!container) {
7
+ return [];
8
+ }
9
+ return Array.from(container.querySelectorAll(TAG_SELECTOR));
10
+ }
11
+ function findTagIndex(container, tagId) {
12
+ return getTagElements(container).findIndex((element) => element.dataset["tagId"] === tagId);
13
+ }
14
+ export function useTagsInteractions(tagsContainerRef, tooltipTagsContainerRef, showedTags, hiddenTags, onTagAdd, onTagRemove, onTagClick) {
5
15
  const [tag, setTag] = useState("");
6
- const [showedFocusedIndex, setShowedFocusedIndex] = useState(0);
7
- const [hiddenFocusedIndex, setHiddenFocusedIndex] = useState(0);
8
- const rootItems = useMemo(() => {
9
- return [...showedTags, ...(hiddenTags.length > 0 ? [hiddenTags] : [])];
10
- }, [showedTags, hiddenTags]);
16
+ const pendingTagFocus = useRef(null);
11
17
  const interactionState = useRef({
12
18
  moreOpen: false,
13
19
  addOpen: false,
14
- tags: {},
15
- more: null,
16
20
  add: null,
17
21
  close: null,
18
22
  save: null,
19
23
  input: null,
20
24
  });
25
+ const focusTagByIndex = (tagElements, index) => {
26
+ if (tagElements.length === 0) {
27
+ interactionState.current.add?.focus();
28
+ return false;
29
+ }
30
+ const focusIndex = Math.min(Math.max(index, 0), tagElements.length - 1);
31
+ const tagWrapper = tagElements[focusIndex];
32
+ if (!tagWrapper) {
33
+ return false;
34
+ }
35
+ const innerTag = tagWrapper.querySelector(".gd-ui-kit-tag");
36
+ programaticFocusManagement(innerTag ?? tagWrapper);
37
+ return true;
38
+ };
21
39
  const onMoreOpen = useCallback(() => {
22
40
  interactionState.current.moreOpen = true;
23
- setShowedFocusedIndex(rootItems.length - 1);
24
- setHiddenFocusedIndex(0);
25
- }, [rootItems]);
41
+ }, []);
26
42
  const onMoreClose = useCallback(() => {
27
43
  interactionState.current.moreOpen = false;
28
- setShowedFocusedIndex(rootItems.length - 1);
29
- setHiddenFocusedIndex(0);
30
- }, [rootItems]);
44
+ }, []);
31
45
  const onAddOpen = useCallback(() => {
32
46
  interactionState.current.addOpen = true;
33
47
  }, []);
@@ -41,182 +55,37 @@ export function useTagsInteractions(rootRef, hiddenTagsRef, showedTags, hiddenTa
41
55
  onTagAdd?.({ id: tag, label: tag });
42
56
  setTag("");
43
57
  }, [tag, onTagAdd]);
44
- const onTagRemoveHandler = useCallback((tag) => {
45
- const deletedShowedTag = showedTags.findIndex((t) => t === tag);
46
- const deletedHiddenTag = hiddenTags.findIndex((t) => t === tag);
47
- if (deletedShowedTag !== -1) {
48
- setShowedFocusedIndex(Math.min(deletedShowedTag, showedTags.length - 1));
58
+ const onTagRemoveHandler = useCallback((removedTag) => {
59
+ let area = "root";
60
+ let deletedIndex = findTagIndex(tooltipTagsContainerRef.current, removedTag.id);
61
+ if (deletedIndex === -1) {
62
+ deletedIndex = findTagIndex(tagsContainerRef.current, removedTag.id);
49
63
  }
50
- if (deletedHiddenTag !== -1) {
51
- setHiddenFocusedIndex(Math.min(deletedHiddenTag, hiddenTags.length - 1));
64
+ else {
65
+ area = "dialog";
52
66
  }
53
- onTagRemove?.(tag);
54
- }, [hiddenTags, onTagRemove, showedTags]);
55
- const onTagClickHandler = useCallback((tag) => {
56
- const showedTag = showedTags.findIndex((t) => t === tag);
57
- if (showedTag !== -1) {
58
- setShowedFocusedIndex(showedTag);
67
+ if (deletedIndex !== -1) {
68
+ pendingTagFocus.current = { area, deletedIndex };
59
69
  }
60
- const hiddenTag = hiddenTags.findIndex((t) => t === tag);
61
- if (hiddenTag !== -1) {
62
- setHiddenFocusedIndex(hiddenTag);
70
+ onTagRemove?.(removedTag);
71
+ }, [onTagRemove, tagsContainerRef, tooltipTagsContainerRef]);
72
+ const onTagClickHandler = useCallback((clickedTag) => {
73
+ onTagClick?.(clickedTag);
74
+ }, [onTagClick]);
75
+ useLayoutEffect(() => {
76
+ if (!pendingTagFocus.current) {
77
+ return;
63
78
  }
64
- onTagClick?.(tag);
65
- }, [hiddenTags, onTagClick, showedTags]);
66
- const handleKeyDown = useMemo(() => makeTabsKeyboardNavigation({
67
- onFocusPrevious: (event) => {
68
- if (interactionState.current.addOpen) {
69
- return;
70
- }
71
- if (event.target === interactionState.current.add) {
72
- return;
73
- }
74
- if (interactionState.current.moreOpen) {
75
- hiddenTagsRef.current?.focus();
76
- if (hiddenFocusedIndex === 0) {
77
- setHiddenFocusedIndex(hiddenTags.length - 1);
78
- }
79
- else {
80
- setHiddenFocusedIndex(Math.min(hiddenFocusedIndex - 1, hiddenTags.length - 1));
81
- }
82
- }
83
- else {
84
- rootRef.current?.focus();
85
- if (showedFocusedIndex === 0) {
86
- setShowedFocusedIndex(rootItems.length - 1);
87
- }
88
- else {
89
- setShowedFocusedIndex(Math.min(showedFocusedIndex - 1, showedTags.length - 1));
90
- }
91
- }
92
- },
93
- onFocusNext: (event) => {
94
- if (interactionState.current.addOpen) {
95
- return;
96
- }
97
- if (event.target === interactionState.current.add) {
98
- return;
99
- }
100
- if (interactionState.current.moreOpen) {
101
- hiddenTagsRef.current?.focus();
102
- if (hiddenTags.length - 1 <= hiddenFocusedIndex) {
103
- setHiddenFocusedIndex(0);
104
- }
105
- else {
106
- setHiddenFocusedIndex(hiddenFocusedIndex + 1);
107
- }
108
- }
109
- else {
110
- rootRef.current?.focus();
111
- if (rootItems.length - 1 <= showedFocusedIndex) {
112
- setShowedFocusedIndex(0);
113
- }
114
- else {
115
- setShowedFocusedIndex(showedFocusedIndex + 1);
116
- }
117
- }
118
- },
119
- onFocusFirst: (event) => {
120
- if (interactionState.current.addOpen) {
121
- return;
122
- }
123
- if (event.target === interactionState.current.add) {
124
- return;
125
- }
126
- if (interactionState.current.moreOpen) {
127
- hiddenTagsRef.current?.focus();
128
- setHiddenFocusedIndex(0);
129
- }
130
- else {
131
- rootRef.current?.focus();
132
- setShowedFocusedIndex(0);
133
- }
134
- },
135
- onFocusLast: (event) => {
136
- if (interactionState.current.addOpen) {
137
- return;
138
- }
139
- if (event.target === interactionState.current.add) {
140
- return;
141
- }
142
- if (interactionState.current.moreOpen) {
143
- hiddenTagsRef.current?.focus();
144
- setHiddenFocusedIndex(hiddenTags.length - 1);
145
- }
146
- else {
147
- rootRef.current?.focus();
148
- setShowedFocusedIndex(rootItems.length - 1);
149
- }
150
- },
151
- onSelect: (event) => {
152
- const { button, input } = loadActiveElement(interactionState, event.target);
153
- if (button) {
154
- button.click();
155
- event.preventDefault();
156
- event.stopPropagation();
157
- return;
158
- }
159
- // Do not handle any select if add is open
160
- if (input) {
161
- event.stopPropagation();
162
- return;
163
- }
164
- // Tags
165
- if (interactionState.current.moreOpen) {
166
- const item = loadActiveTag(interactionState, hiddenTags, hiddenFocusedIndex, false);
167
- if (item) {
168
- item.click();
169
- event.preventDefault();
170
- event.stopPropagation();
171
- }
172
- }
173
- else {
174
- const item = loadActiveTag(interactionState, showedTags, showedFocusedIndex, true);
175
- if (item) {
176
- item.click();
177
- event.preventDefault();
178
- event.stopPropagation();
179
- }
180
- }
181
- },
182
- onUnhandledKeyDown: (event) => {
183
- //Delete
184
- if (event.key === "Backspace" || event.key === "Delete") {
185
- const { button, input } = loadActiveElement(interactionState, event.target);
186
- if (button || input) {
187
- return;
188
- }
189
- if (interactionState.current.moreOpen) {
190
- const item = loadActiveTag(interactionState, hiddenTags, hiddenFocusedIndex, false);
191
- if (item) {
192
- onTagRemoveHandler(hiddenTags[hiddenFocusedIndex]);
193
- event.preventDefault();
194
- event.stopPropagation();
195
- }
196
- }
197
- else {
198
- const item = loadActiveTag(interactionState, showedTags, showedFocusedIndex, false);
199
- if (item) {
200
- onTagRemoveHandler(showedTags[showedFocusedIndex]);
201
- event.preventDefault();
202
- event.stopPropagation();
203
- }
204
- }
205
- }
206
- },
207
- }, {
208
- shouldPreventDefault: false,
209
- shouldStopPropagation: false,
210
- }), [
211
- hiddenTagsRef,
212
- hiddenFocusedIndex,
213
- hiddenTags,
214
- rootRef,
215
- showedFocusedIndex,
216
- rootItems.length,
217
- showedTags,
218
- onTagRemoveHandler,
219
- ]);
79
+ const { area, deletedIndex } = pendingTagFocus.current;
80
+ pendingTagFocus.current = null;
81
+ const primaryContainer = area === "dialog" ? tooltipTagsContainerRef.current : tagsContainerRef.current;
82
+ const primaryTagElements = getTagElements(primaryContainer);
83
+ if (focusTagByIndex(primaryTagElements, deletedIndex)) {
84
+ return;
85
+ }
86
+ const showedTagElements = getTagElements(tagsContainerRef.current);
87
+ focusTagByIndex(showedTagElements, showedTagElements.length - 1);
88
+ }, [showedTags, hiddenTags, tagsContainerRef, tooltipTagsContainerRef]);
220
89
  return {
221
90
  tag,
222
91
  setTag,
@@ -224,48 +93,9 @@ export function useTagsInteractions(rootRef, hiddenTagsRef, showedTags, hiddenTa
224
93
  onAddClose,
225
94
  onMoreOpen,
226
95
  onMoreClose,
227
- handleKeyDown,
228
- interactionState,
229
- showedFocusedIndex,
230
- hiddenFocusedIndex,
231
96
  onTagAddHandler,
232
97
  onTagRemoveHandler,
233
98
  onTagClickHandler,
99
+ interactionState,
234
100
  };
235
101
  }
236
- function loadActiveTag(interactionState, tags, index, allowMore) {
237
- // More
238
- if (index === tags.length) {
239
- if (!allowMore) {
240
- return null;
241
- }
242
- const more = interactionState.current.more;
243
- if (more) {
244
- return more;
245
- }
246
- return null;
247
- }
248
- // Tag
249
- const tag = tags[index];
250
- const item = interactionState.current.tags[tag?.id];
251
- if (item) {
252
- return item;
253
- }
254
- return null;
255
- }
256
- function loadActiveElement(interactionState, target) {
257
- const buttons = [
258
- interactionState.current.add,
259
- interactionState.current.close,
260
- interactionState.current.save,
261
- ];
262
- const button = buttons.find((b) => b === target);
263
- if (button) {
264
- return { button };
265
- }
266
- // Do not handle any select if add is open
267
- if (target === interactionState.current.input) {
268
- return { input: interactionState.current.input };
269
- }
270
- return {};
271
- }
@@ -2,5 +2,5 @@ import { type IUiTooltipProps } from "./types.js";
2
2
  /**
3
3
  * @internal
4
4
  */
5
- export declare function UiTooltip({ id, anchor, content, behaviour, arrowPlacement, triggerBy, hoverOpenDelay, hoverCloseDelay, showArrow, width, offset: offsetProp, optimalPlacement, accessibilityConfig, variant, disabled, isOpen: isOpenProp, onOpen, onClose, anchorWrapperStyles }: IUiTooltipProps): import("react/jsx-runtime").JSX.Element;
5
+ export declare function UiTooltip({ id, anchor, content, behaviour, arrowPlacement, triggerBy, hoverOpenDelay, hoverCloseDelay, showArrow, width, offset: offsetProp, optimalPlacement, accessibilityConfig, variant, disabled, isOpen: isOpenProp, onOpen, onClose, onOpenChange, anchorWrapperStyles }: IUiTooltipProps): import("react/jsx-runtime").JSX.Element;
6
6
  //# sourceMappingURL=UiTooltip.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"UiTooltip.d.ts","sourceRoot":"","sources":["../../../src/@ui/UiTooltip/UiTooltip.tsx"],"names":[],"mappings":"AA2BA,OAAO,EAAmB,KAAK,eAAe,EAAE,MAAM,YAAY,CAAC;AAWnE;;GAEG;AACH,wBAAgB,SAAS,CAAC,EACtB,EAAE,EACF,MAAM,EACN,OAAO,EACP,SAAqB,EACrB,cAAsB,EACtB,SAAc,EACd,cAA2B,EAC3B,eAA4B,EAC5B,SAAgB,EAChB,KAAK,EACL,MAAM,EAAE,UAAU,EAClB,gBAAwB,EACxB,mBAAmB,EACnB,OAAmB,EACnB,QAAQ,EACR,MAAM,EAAE,UAAU,EAClB,MAAM,EACN,OAAO,EACP,mBAAmB,EACtB,EAAE,eAAe,2CAmLjB"}
1
+ {"version":3,"file":"UiTooltip.d.ts","sourceRoot":"","sources":["../../../src/@ui/UiTooltip/UiTooltip.tsx"],"names":[],"mappings":"AA2BA,OAAO,EAAmB,KAAK,eAAe,EAAE,MAAM,YAAY,CAAC;AAWnE;;GAEG;AACH,wBAAgB,SAAS,CAAC,EACtB,EAAE,EACF,MAAM,EACN,OAAO,EACP,SAAqB,EACrB,cAAsB,EACtB,SAAc,EACd,cAA2B,EAC3B,eAA4B,EAC5B,SAAgB,EAChB,KAAK,EACL,MAAM,EAAE,UAAU,EAClB,gBAAwB,EACxB,mBAAmB,EACnB,OAAmB,EACnB,QAAQ,EACR,MAAM,EAAE,UAAU,EAClB,MAAM,EACN,OAAO,EACP,YAAY,EACZ,mBAAmB,EACtB,EAAE,eAAe,2CA0LjB"}