@gooddata/sdk-ui-kit 11.52.0-alpha.4 → 11.52.0-alpha.5

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 (33) hide show
  1. package/esm/@ui/UiAsyncTable/UiAsyncTable/UiAsyncTableBody.d.ts.map +1 -1
  2. package/esm/@ui/UiAsyncTable/UiAsyncTable/UiAsyncTableBody.js +9 -6
  3. package/esm/@ui/UiAsyncTable/UiAsyncTable/UiAsyncTableRow.d.ts.map +1 -1
  4. package/esm/@ui/UiAsyncTable/UiAsyncTable/UiAsyncTableRow.js +13 -2
  5. package/esm/@ui/UiAsyncTable/UiAsyncTable/asyncTableGridContext.d.ts +4 -0
  6. package/esm/@ui/UiAsyncTable/UiAsyncTable/asyncTableGridContext.d.ts.map +1 -0
  7. package/esm/@ui/UiAsyncTable/UiAsyncTable/asyncTableGridContext.js +12 -0
  8. package/esm/Dialog/StylingEditorDialog/StylingEditorDialog.d.ts +9 -0
  9. package/esm/Dialog/StylingEditorDialog/StylingEditorDialog.d.ts.map +1 -1
  10. package/esm/Dialog/StylingEditorDialog/StylingEditorDialog.js +33 -28
  11. package/esm/Dropdown/DropdownButton.d.ts.map +1 -1
  12. package/esm/Dropdown/DropdownButton.js +5 -0
  13. package/esm/Header/Header.d.ts.map +1 -1
  14. package/esm/Header/Header.js +2 -2
  15. package/esm/Header/HeaderChatButton.d.ts +9 -1
  16. package/esm/Header/HeaderChatButton.d.ts.map +1 -1
  17. package/esm/Header/HeaderChatButton.js +12 -1
  18. package/esm/Header/typings.d.ts +5 -0
  19. package/esm/Header/typings.d.ts.map +1 -1
  20. package/esm/Header/typings.js +1 -1
  21. package/esm/Timezone/TimezoneSelect.d.ts +10 -2
  22. package/esm/Timezone/TimezoneSelect.d.ts.map +1 -1
  23. package/esm/Timezone/TimezoneSelect.js +4 -3
  24. package/esm/index.d.ts +1 -1
  25. package/esm/index.d.ts.map +1 -1
  26. package/esm/index.js +1 -1
  27. package/esm/sdk-ui-kit.d.ts +31 -1
  28. package/package.json +11 -11
  29. package/styles/css/main.css +3 -0
  30. package/styles/css/main.css.map +1 -1
  31. package/styles/css/stylingEditorDialog.css +3 -0
  32. package/styles/css/stylingEditorDialog.css.map +1 -1
  33. package/styles/scss/stylingEditorDialog.scss +4 -0
@@ -1 +1 @@
1
- {"version":3,"file":"UiAsyncTableBody.d.ts","sourceRoot":"","sources":["../../../../src/@ui/UiAsyncTable/UiAsyncTable/UiAsyncTableBody.tsx"],"names":[],"mappings":"AAIA,OAAO,EAAE,KAAK,MAAM,EAAE,MAAM,qBAAqB,CAAC;AAKlD,OAAO,EAAE,KAAK,sBAAsB,EAAE,MAAM,aAAa,CAAC;AAK1D,wBAAgB,gBAAgB,CAAC,CAAC,SAAS;IAAE,EAAE,EAAE,MAAM,CAAA;CAAE,GAAG;IAAE,GAAG,EAAE,MAAM,CAAA;CAAE,EAAE,EACzE,KAAK,EACL,SAAS,EACT,UAAU,EACV,kBAAkB,EAClB,WAAW,EACX,SAAS,EACT,WAAW,EACX,YAAY,EACZ,OAAO,EACP,WAAW,EACX,aAAa,EACb,UAAU,EACV,kBAAkB,EAClB,UAAU,EACb,EAAE,sBAAsB,CAAC,CAAC,CAAC,2CAoD3B"}
1
+ {"version":3,"file":"UiAsyncTableBody.d.ts","sourceRoot":"","sources":["../../../../src/@ui/UiAsyncTable/UiAsyncTable/UiAsyncTableBody.tsx"],"names":[],"mappings":"AAIA,OAAO,EAAE,KAAK,MAAM,EAAE,MAAM,qBAAqB,CAAC;AAKlD,OAAO,EAAE,KAAK,sBAAsB,EAAE,MAAM,aAAa,CAAC;AAM1D,wBAAgB,gBAAgB,CAAC,CAAC,SAAS;IAAE,EAAE,EAAE,MAAM,CAAA;CAAE,GAAG;IAAE,GAAG,EAAE,MAAM,CAAA;CAAE,EAAE,EACzE,KAAK,EACL,SAAS,EACT,UAAU,EACV,kBAAkB,EAClB,WAAW,EACX,SAAS,EACT,WAAW,EACX,YAAY,EACZ,OAAO,EACP,WAAW,EACX,aAAa,EACb,UAAU,EACV,kBAAkB,EAClB,UAAU,EACb,EAAE,sBAAsB,CAAC,CAAC,CAAC,2CAyD3B"}
@@ -4,10 +4,12 @@ import { useCallback, useEffect, useMemo, useRef, useState } from "react";
4
4
  import { isEnterKey } from "../../../utils/events.js";
5
5
  import { makeGridKeyboardNavigation } from "../../@utils/keyboardNavigation.js";
6
6
  import { UiPagedVirtualList } from "../../UiPagedVirtualList/UiPagedVirtualList.js";
7
+ import { AsyncTableGridRefProvider } from "./asyncTableGridContext.js";
7
8
  import { useSkeletonItem } from "./SkeletonItemFactory.js";
8
9
  import { getCellId, getItemKey, getRowId } from "./utils.js";
9
10
  export function UiAsyncTableBody({ items, maxHeight, itemHeight, skeletonItemsCount, hasNextPage, isLoading, onItemClick, loadNextPage, columns, bulkActions, scrollToIndex, isLargeRow, shouldLoadNextPage, renderItem, }) {
10
11
  const SkeletonItem = useSkeletonItem(columns, bulkActions, isLargeRow ?? false);
12
+ const gridRef = useRef(null);
11
13
  const { handleKeyDown, handleFocus, focusedRowIndex, focusedColumnIndex, focusedItemRef } = useAsyncTableBodyKeyboardNavigation(items.length, columns.length, !!bulkActions, scrollToIndex);
12
14
  const activeDescendantId = useMemo(() => {
13
15
  if (focusedRowIndex === undefined || focusedRowIndex < 0 || focusedRowIndex >= items.length) {
@@ -19,12 +21,13 @@ export function UiAsyncTableBody({ items, maxHeight, itemHeight, skeletonItemsCo
19
21
  }
20
22
  return getRowId(itemId);
21
23
  }, [focusedRowIndex, focusedColumnIndex, items]);
22
- return (_jsx(UiPagedVirtualList, { maxHeight: maxHeight, itemHeight: itemHeight, itemsGap: 0, itemPadding: 0, items: items, skeletonItemsCount: skeletonItemsCount, hasNextPage: hasNextPage, isLoading: isLoading, onKeyDownSelect: onItemClick, loadNextPage: loadNextPage, SkeletonItem: SkeletonItem, scrollbarHoverEffect: true, scrollToIndex: scrollToIndex ?? focusedRowIndex, shouldLoadNextPage: shouldLoadNextPage, tabIndex: items.length ? 0 : -1, customKeyboardNavigationHandler: handleKeyDown, onFocus: handleFocus, listboxProps: {
23
- "aria-activedescendant": activeDescendantId,
24
- }, children: (item, focusedIndex) => {
25
- const itemIndex = focusedIndex ?? 0;
26
- return renderItem(item, itemIndex, focusedItemRef, itemIndex === focusedRowIndex, focusedColumnIndex);
27
- } }));
24
+ return (_jsx(AsyncTableGridRefProvider, { value: gridRef, children: _jsx(UiPagedVirtualList, { maxHeight: maxHeight, itemHeight: itemHeight, itemsGap: 0, itemPadding: 0, items: items, skeletonItemsCount: skeletonItemsCount, hasNextPage: hasNextPage, isLoading: isLoading, onKeyDownSelect: onItemClick, loadNextPage: loadNextPage, SkeletonItem: SkeletonItem, scrollbarHoverEffect: true, scrollToIndex: scrollToIndex ?? focusedRowIndex, shouldLoadNextPage: shouldLoadNextPage, tabIndex: items.length ? 0 : -1, customKeyboardNavigationHandler: handleKeyDown, onFocus: handleFocus, listboxProps: {
25
+ "aria-activedescendant": activeDescendantId,
26
+ ref: gridRef,
27
+ }, children: (item, focusedIndex) => {
28
+ const itemIndex = focusedIndex ?? 0;
29
+ return renderItem(item, itemIndex, focusedItemRef, itemIndex === focusedRowIndex, focusedColumnIndex);
30
+ } }) }));
28
31
  }
29
32
  const useAsyncTableBodyKeyboardNavigation = (rowsLength, definedColumnsLength, hasBulkActions, scrollToIndex) => {
30
33
  const [focusedRowIndex, setFocusedRowIndex] = useState(undefined);
@@ -1 +1 @@
1
- {"version":3,"file":"UiAsyncTableRow.d.ts","sourceRoot":"","sources":["../../../../src/@ui/UiAsyncTable/UiAsyncTable/UiAsyncTableRow.tsx"],"names":[],"mappings":"AAIA,OAAO,EAAE,KAAK,MAAM,EAAE,MAAM,qBAAqB,CAAC;AAKlD,OAAO,EAGH,KAAK,qBAAqB,EAE7B,MAAM,aAAa,CAAC;AAOrB,wBAAgB,eAAe,CAAC,CAAC,SAAS;IAAE,EAAE,EAAE,MAAM,CAAA;CAAE,GAAG;IAAE,GAAG,EAAE,MAAM,CAAA;CAAE,EAAE,EACxE,IAAI,EACJ,SAAS,EACT,OAAO,EACP,QAAQ,EACR,OAAO,EACP,UAAU,EACV,WAAW,EACX,OAAO,EACP,SAAS,EACT,kBAAkB,EAClB,iBAAiB,EACjB,mBAAmB,EACtB,EAAE,qBAAqB,CAAC,CAAC,CAAC,2CA4E1B"}
1
+ {"version":3,"file":"UiAsyncTableRow.d.ts","sourceRoot":"","sources":["../../../../src/@ui/UiAsyncTable/UiAsyncTable/UiAsyncTableRow.tsx"],"names":[],"mappings":"AAIA,OAAO,EAAE,KAAK,MAAM,EAAE,MAAM,qBAAqB,CAAC;AAKlD,OAAO,EAGH,KAAK,qBAAqB,EAE7B,MAAM,aAAa,CAAC;AAQrB,wBAAgB,eAAe,CAAC,CAAC,SAAS;IAAE,EAAE,EAAE,MAAM,CAAA;CAAE,GAAG;IAAE,GAAG,EAAE,MAAM,CAAA;CAAE,EAAE,EACxE,IAAI,EACJ,SAAS,EACT,OAAO,EACP,QAAQ,EACR,OAAO,EACP,UAAU,EACV,WAAW,EACX,OAAO,EACP,SAAS,EACT,kBAAkB,EAClB,iBAAiB,EACjB,mBAAmB,EACtB,EAAE,qBAAqB,CAAC,CAAC,CAAC,2CA4E1B"}
@@ -4,6 +4,7 @@ import { useCallback } from "react";
4
4
  import { Dropdown } from "../../../Dropdown/Dropdown.js";
5
5
  import { UiIconButton } from "../../UiIconButton/UiIconButton.js";
6
6
  import { e } from "../asyncTableBem.js";
7
+ import { useAsyncTableGridRef } from "./asyncTableGridContext.js";
7
8
  import { UiAsyncTableCheckbox } from "./UiAsyncTableCheckbox.js";
8
9
  import { UiAsyncTableIconRenderer } from "./UiAsyncTableIconRenderer.js";
9
10
  import { getCellId, getColumnWidth, getItemKey, getRowId, getRowLabelId } from "./utils.js";
@@ -43,6 +44,16 @@ export function UiAsyncTableRow({ item, itemIndex, columns, onSelect, onClick, i
43
44
  })] }));
44
45
  }
45
46
  const useRenderCellContent = ({ isLarge, }) => {
47
+ const gridRef = useAsyncTableGridRef();
48
+ // Put focus back on the grid before the menu closes. Callers routinely close the menu and open a
49
+ // dialog in the same tick (flushSync(closeDropdown) then setState); that dialog captures whatever is
50
+ // focused as its own return target, and the dropdown's restore is deferred to a microtask, so it would
51
+ // land after the snapshot was taken and the dialog would return focus to <body> - i.e. the page top.
52
+ // Restoring here keeps it synchronous, and the deferred restore then correctly sees nothing to do.
53
+ const closeMenuAndRestoreFocus = useCallback((closeDropdown) => {
54
+ gridRef?.current?.focus();
55
+ closeDropdown();
56
+ }, [gridRef]);
46
57
  const renderRoleIconWithWrapper = useCallback((renderRoleIcon, item) => {
47
58
  return (_jsx(UiAsyncTableIconRenderer, { renderIcon: renderRoleIcon, className: e("role-icon"), item: item }));
48
59
  }, []);
@@ -64,8 +75,8 @@ const useRenderCellContent = ({ isLarge, }) => {
64
75
  ariaExpanded: isOpen,
65
76
  ariaLabel: label,
66
77
  }, ref: isCellFocused ? focusedElementRef : undefined }));
67
- }, alignPoints: [{ align: "br tr" }, { align: "tr br" }], renderBody: ({ closeDropdown }) => renderMenu(item, closeDropdown) }));
68
- }, [isLarge]);
78
+ }, alignPoints: [{ align: "br tr" }, { align: "tr br" }], renderBody: ({ closeDropdown }) => renderMenu(item, () => closeMenuAndRestoreFocus(closeDropdown)) }));
79
+ }, [isLarge, closeMenuAndRestoreFocus]);
69
80
  const renderTextContent = useCallback((item, key, labelId, getTextContent, getMultiLineTextContent, renderSuffixIcon) => {
70
81
  if (getMultiLineTextContent) {
71
82
  return getMultiLineTextContent(item).map((line, index) => {
@@ -0,0 +1,4 @@
1
+ import { type RefObject } from "react";
2
+ export declare const AsyncTableGridRefProvider: import("react").Provider<RefObject<HTMLElement | null> | null>;
3
+ export declare const useAsyncTableGridRef: () => RefObject<HTMLElement | null> | null;
4
+ //# sourceMappingURL=asyncTableGridContext.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"asyncTableGridContext.d.ts","sourceRoot":"","sources":["../../../../src/@ui/UiAsyncTable/UiAsyncTable/asyncTableGridContext.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,KAAK,SAAS,EAA6B,MAAM,OAAO,CAAC;AAWlE,eAAO,MAAM,yBAAyB,gEAAoC,CAAC;AAE3E,eAAO,MAAM,oBAAoB,4CAA6C,CAAC"}
@@ -0,0 +1,12 @@
1
+ // (C) 2026 GoodData Corporation
2
+ import { createContext, useContext } from "react";
3
+ /**
4
+ * Ref to the grid element that holds the table's real DOM focus.
5
+ *
6
+ * The table is a composite widget: the grid is its single tab stop and the active row/cell is tracked
7
+ * virtually via aria-activedescendant (row controls are kept out of the tab order). Layers opened from a
8
+ * row therefore return focus here rather than to the control that opened them.
9
+ */
10
+ const AsyncTableGridRefContext = createContext(null);
11
+ export const AsyncTableGridRefProvider = AsyncTableGridRefContext.Provider;
12
+ export const useAsyncTableGridRef = () => useContext(AsyncTableGridRefContext);
@@ -34,6 +34,15 @@ export interface IStylingEditorDialogProps<T extends StylingPickerItemContent> e
34
34
  * submission and display it, or undefined when the content is valid.
35
35
  */
36
36
  validateDefinition?: (content: T) => string | undefined;
37
+ /**
38
+ * Optional non-blocking check of the parsed definition content.
39
+ *
40
+ * @remarks
41
+ * Called only when the definition is valid JSON. Return a localized message to display it as a
42
+ * warning, or undefined when there is nothing to report. Unlike {@link IStylingEditorDialogProps.validateDefinition}
43
+ * this never prevents submission — use it for content that applies but degrades the result.
44
+ */
45
+ validateDefinitionWarning?: (content: T) => string | undefined;
37
46
  }
38
47
  /**
39
48
  * @internal
@@ -1 +1 @@
1
- {"version":3,"file":"StylingEditorDialog.d.ts","sourceRoot":"","sources":["../../../src/Dialog/StylingEditorDialog/StylingEditorDialog.tsx"],"names":[],"mappings":"AAOA,OAAO,EAAE,KAAK,aAAa,EAAE,KAAK,MAAM,EAAE,KAAK,MAAM,EAAE,MAAM,qBAAqB,CAAC;AAOnF,OAAO,EAAE,KAAK,gBAAgB,EAAE,MAAM,eAAe,CAAC;AAGtD,OAAO,EAEH,KAAK,+BAA+B,EACvC,MAAM,gCAAgC,CAAC;AAGxC;;GAEG;AACH,MAAM,MAAM,wBAAwB,GAAG,MAAM,GAAG,aAAa,CAAC;AAE9D;;GAEG;AACH,MAAM,WAAW,kBAAkB,CAAC,CAAC,SAAS,wBAAwB;IAClE,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,CAAC,CAAC;CACd;AAED;;GAEG;AACH,MAAM,WAAW,yBAAyB,CAAC,CAAC,SAAS,wBAAwB,CACzE,SAAQ,+BAA+B,EAAE,IAAI,CAAC,gBAAgB,EAAE,SAAS,GAAG,WAAW,CAAC;IACxF,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,WAAW,CAAC,EAAE,kBAAkB,CAAC,CAAC,CAAC,CAAC;IACpC,QAAQ,CAAC,EAAE,kBAAkB,CAAC,CAAC,CAAC,EAAE,CAAC;IACnC,qBAAqB,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,KAAK,MAAM,EAAE,CAAC;IACjD,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,KAAK,IAAI,CAAC;IACpD,mBAAmB,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;IAC5C,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB;;;;;;OAMG;IACH,kBAAkB,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,KAAK,MAAM,GAAG,SAAS,CAAC;CAC3D;AAED;;GAEG;AACH,wBAAgB,mBAAmB,CAAC,CAAC,SAAS,wBAAwB,EAAE,KAAK,EAAE,yBAAyB,CAAC,CAAC,CAAC,2CAM1G"}
1
+ {"version":3,"file":"StylingEditorDialog.d.ts","sourceRoot":"","sources":["../../../src/Dialog/StylingEditorDialog/StylingEditorDialog.tsx"],"names":[],"mappings":"AAOA,OAAO,EAAE,KAAK,aAAa,EAAE,KAAK,MAAM,EAAE,KAAK,MAAM,EAAE,MAAM,qBAAqB,CAAC;AAQnF,OAAO,EAAE,KAAK,gBAAgB,EAAE,MAAM,eAAe,CAAC;AAGtD,OAAO,EAEH,KAAK,+BAA+B,EACvC,MAAM,gCAAgC,CAAC;AAGxC;;GAEG;AACH,MAAM,MAAM,wBAAwB,GAAG,MAAM,GAAG,aAAa,CAAC;AAE9D;;GAEG;AACH,MAAM,WAAW,kBAAkB,CAAC,CAAC,SAAS,wBAAwB;IAClE,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,CAAC,CAAC;CACd;AAED;;GAEG;AACH,MAAM,WAAW,yBAAyB,CAAC,CAAC,SAAS,wBAAwB,CACzE,SAAQ,+BAA+B,EAAE,IAAI,CAAC,gBAAgB,EAAE,SAAS,GAAG,WAAW,CAAC;IACxF,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,WAAW,CAAC,EAAE,kBAAkB,CAAC,CAAC,CAAC,CAAC;IACpC,QAAQ,CAAC,EAAE,kBAAkB,CAAC,CAAC,CAAC,EAAE,CAAC;IACnC,qBAAqB,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,KAAK,MAAM,EAAE,CAAC;IACjD,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,KAAK,IAAI,CAAC;IACpD,mBAAmB,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;IAC5C,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB;;;;;;OAMG;IACH,kBAAkB,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,KAAK,MAAM,GAAG,SAAS,CAAC;IACxD;;;;;;;OAOG;IACH,yBAAyB,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,KAAK,MAAM,GAAG,SAAS,CAAC;CAClE;AAED;;GAEG;AACH,wBAAgB,mBAAmB,CAAC,CAAC,SAAS,wBAAwB,EAAE,KAAK,EAAE,yBAAyB,CAAC,CAAC,CAAC,2CAM1G"}
@@ -1,10 +1,11 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  // (C) 2022-2026 GoodData Corporation
3
- import { useMemo, useState } from "react";
3
+ import { useCallback, useMemo, useState } from "react";
4
4
  import cx from "classnames";
5
5
  import { useIntl } from "react-intl";
6
6
  import { IntlWrapper } from "@gooddata/sdk-ui";
7
7
  import { Button } from "../../Button/Button.js";
8
+ import { Message } from "../../Messages/Message.js";
8
9
  import { Typography } from "../../Typography/Typography.js";
9
10
  import { useId } from "../../utils/useId.js";
10
11
  import { Dialog } from "../Dialog.js";
@@ -17,49 +18,48 @@ import { StylingExample } from "./StylingExample.js";
17
18
  export function StylingEditorDialog(props) {
18
19
  return (_jsx(IntlWrapper, { locale: props.locale, children: _jsx(StylingEditorDialogCore, { ...props }) }));
19
20
  }
20
- function StylingEditorDialogCore({ title, tooltip, link, stylingItem, examples, exampleToColorPreview, onClose, onSubmit, onCancel, disableSubmit, showProgressIndicator, showBackButton, onHelpClick, onExit = () => { }, className, onInvalidDefinition = () => { }, validateDefinition, }) {
21
+ function StylingEditorDialogCore({ title, tooltip, link, stylingItem, examples, exampleToColorPreview, onClose, onSubmit, onCancel, disableSubmit, showProgressIndicator, showBackButton, onHelpClick, onExit = () => { }, className, onInvalidDefinition = () => { }, validateDefinition, validateDefinitionWarning, }) {
21
22
  const intl = useIntl();
22
23
  const providedExamples = !!examples && examples.length !== 0 && !!exampleToColorPreview;
23
24
  const initialNameField = stylingItem?.name ?? "";
24
25
  const initialDefinitionField = stylingItem?.content ? JSON.stringify(stylingItem?.content, null, 4) : "";
25
26
  const [nameField, setNameField] = useState(initialNameField);
26
27
  const [definitionField, setDefinitionField] = useState(initialDefinitionField);
27
- const fieldsChanged = useMemo(() => {
28
+ const parsedDefinition = useMemo(() => {
28
29
  try {
29
- const parsedDefinition = JSON.parse(definitionField);
30
- const formattedDefinition = JSON.stringify(parsedDefinition, null, 4);
31
- return nameField !== initialNameField || formattedDefinition !== initialDefinitionField;
30
+ return { ok: true, content: JSON.parse(definitionField) };
32
31
  }
33
32
  catch {
33
+ return { ok: false };
34
+ }
35
+ }, [definitionField]);
36
+ const fieldsChanged = useMemo(() => {
37
+ if (!parsedDefinition.ok) {
34
38
  // initial state of the fields is presumed to be valid,
35
39
  // so if JSON throws error, definition was changed
36
40
  return true;
37
41
  }
38
- }, [nameField, initialNameField, definitionField, initialDefinitionField]);
42
+ const formattedDefinition = JSON.stringify(parsedDefinition.content, null, 4);
43
+ return nameField !== initialNameField || formattedDefinition !== initialDefinitionField;
44
+ }, [parsedDefinition, nameField, initialNameField, initialDefinitionField]);
39
45
  const validName = useMemo(() => nameField !== "", [nameField]);
40
- const validDefinition = useMemo(() => {
41
- try {
42
- JSON.parse(definitionField);
43
- return true;
44
- }
45
- catch {
46
- return false;
47
- }
48
- }, [definitionField]);
49
- // Content-level validation (e.g. theme color values) runs only on well-formed JSON.
50
- const definitionContentError = useMemo(() => {
51
- if (!validateDefinition || !validDefinition) {
46
+ const validDefinition = parsedDefinition.ok;
47
+ // A callback that throws must not crash the dialog, so it degrades to "nothing to report" and
48
+ // the user can keep working.
49
+ const runContentCheck = useCallback((check, name) => {
50
+ if (!check || !parsedDefinition.ok) {
52
51
  return undefined;
53
52
  }
54
53
  try {
55
- return validateDefinition(JSON.parse(definitionField));
54
+ return check(parsedDefinition.content);
56
55
  }
57
56
  catch (error) {
58
- // a buggy validator must not crash the dialog; degrade gracefully and let the user proceed
59
- console.error("StylingEditorDialog: the provided validateDefinition callback threw.", error);
57
+ console.error(`StylingEditorDialog: the provided ${name} callback threw.`, error);
60
58
  return undefined;
61
59
  }
62
- }, [validateDefinition, validDefinition, definitionField]);
60
+ }, [parsedDefinition]);
61
+ const definitionContentError = useMemo(() => runContentCheck(validateDefinition, "validateDefinition"), [runContentCheck, validateDefinition]);
62
+ const definitionContentWarning = useMemo(() => runContentCheck(validateDefinitionWarning, "validateDefinitionWarning"), [runContentCheck, validateDefinitionWarning]);
63
63
  const validFields = useMemo(() => validName && validDefinition && !definitionContentError, [validName, validDefinition, definitionContentError]);
64
64
  const isSubmitDisabled = useMemo(() => !validFields || !fieldsChanged || disableSubmit, [validFields, fieldsChanged, disableSubmit]);
65
65
  const emptyDefinition = useMemo(() => definitionField === "", [definitionField]);
@@ -89,10 +89,10 @@ function StylingEditorDialogCore({ title, tooltip, link, stylingItem, examples,
89
89
  stylingItem?.ref,
90
90
  intl,
91
91
  ]);
92
- const getFinalStylingItem = (original, definition, name) => {
92
+ const getFinalStylingItem = (original, content, name) => {
93
93
  return {
94
94
  ...(original || {}),
95
- content: JSON.parse(definition),
95
+ content,
96
96
  name,
97
97
  };
98
98
  };
@@ -111,13 +111,18 @@ function StylingEditorDialogCore({ title, tooltip, link, stylingItem, examples,
111
111
  _jsxs("form", { className: "gd-styling-editor-dialog-content-form", onSubmit: (e) => e.preventDefault(), children: [
112
112
  _jsxs("label", { className: "gd-styling-editor-dialog-content-form-input", children: [intl.formatMessage({ id: "stylingEditor.dialog.name" }), _jsx("input", { "aria-label": "Styling item name", className: "gd-input-field s-input-field", type: "text", value: nameField, onChange: (e) => setNameField(e.target.value) })
113
113
  ] }), _jsxs("label", { className: "gd-styling-editor-dialog-content-form-textarea", children: [intl.formatMessage({ id: "stylingEditor.dialog.definition" }), _jsx("textarea", { "aria-label": "Styling item definition", className: "gd-input-field s-textarea-field", wrap: "off", value: definitionField, onChange: (e) => setDefinitionField(e.target.value) })
114
- ] })
115
- ] }), providedExamples ? (_jsxs("div", { className: cx("gd-styling-editor-dialog-content-examples", "s-gd-styling-editor-dialog-content-examples"), children: [
114
+ ] }), definitionContentWarning && !definitionContentError ? (_jsx(Message, { type: "warning", className: "gd-styling-editor-dialog-content-form-warning s-styling-editor-warning", children: definitionContentWarning })) : null] }), providedExamples ? (_jsxs("div", { className: cx("gd-styling-editor-dialog-content-examples", "s-gd-styling-editor-dialog-content-examples"), children: [
116
115
  _jsx(BubbleHeaderSeparator, { title: intl.formatMessage({ id: "stylingEditor.dialog.examples" }), message: tooltip }), _jsx("div", { className: "gd-styling-editor-dialog-content-examples-list", children: examples.map((example, index) => (_jsx(StylingExample, { name: example.name ?? "", colors: exampleToColorPreview(example.content), onClick: () => {
117
116
  setNameField(example.name ?? "");
118
117
  setDefinitionField(JSON.stringify(example.content, null, 4));
119
118
  } }, index))) })
120
- ] })) : null] }), _jsx(StylingEditorDialogFooter, { disableSubmit: isSubmitDisabled, showProgressIndicator: showProgressIndicator, link: link, errorMessage: errorMessage, onSubmit: () => onSubmit?.(getFinalStylingItem(stylingItem, definitionField, nameField)), onCancel: () => {
119
+ ] })) : null] }), _jsx(StylingEditorDialogFooter, { disableSubmit: isSubmitDisabled, showProgressIndicator: showProgressIndicator, link: link, errorMessage: errorMessage, onSubmit: () => {
120
+ // Submission is disabled while the definition does not parse, so this only
121
+ // narrows the type rather than guarding a reachable state.
122
+ if (parsedDefinition.ok) {
123
+ onSubmit?.(getFinalStylingItem(stylingItem, parsedDefinition.content, nameField));
124
+ }
125
+ }, onCancel: () => {
121
126
  onExit?.(nameField, definitionField);
122
127
  onCancel?.();
123
128
  }, onHelpClick: onHelpClick })
@@ -1 +1 @@
1
- {"version":3,"file":"DropdownButton.d.ts","sourceRoot":"","sources":["../../src/Dropdown/DropdownButton.tsx"],"names":[],"mappings":"AAEA,OAAO,EAAE,KAAK,cAAc,EAAE,KAAK,UAAU,EAAE,KAAK,SAAS,EAAE,KAAK,GAAG,EAAE,MAAM,OAAO,CAAC;AAMvF,OAAO,EAAE,KAAK,wBAAwB,EAAE,MAAM,6BAA6B,CAAC;AAE5E;;GAEG;AACH,MAAM,WAAW,oBAAoB;IACjC,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,mBAAmB,CAAC,EAAE,wBAAwB,GAAG;QAAE,SAAS,CAAC,EAAE,cAAc,CAAC,eAAe,CAAC,CAAA;KAAE,CAAC;IAEjG,KAAK,CAAC,EAAE,SAAS,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC3B,QAAQ,CAAC,EAAE,OAAO,CAAC;IAEnB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,WAAW,CAAC,EAAE,OAAO,CAAC;IAEtB,OAAO,CAAC,EAAE,CAAC,CAAC,EAAE,UAAU,KAAK,IAAI,CAAC;IAElC,QAAQ,CAAC,EAAE,SAAS,CAAC;IACrB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,SAAS,CAAC,EAAE,GAAG,CAAC,WAAW,CAAC,CAAC;CAChC;AAED;;GAEG;AACH,wBAAgB,cAAc,CAAC,EAC3B,EAAE,EACF,SAAS,EACT,mBAAmB,EAEnB,KAAK,EACL,KAAa,EACb,QAAQ,EAER,MAAM,EACN,OAAc,EACd,QAAQ,EACR,WAAmB,EACnB,OAAO,EACP,QAAQ,EACR,UAAU,EACV,SAAS,EACZ,EAAE,oBAAoB,2CAuDtB"}
1
+ {"version":3,"file":"DropdownButton.d.ts","sourceRoot":"","sources":["../../src/Dropdown/DropdownButton.tsx"],"names":[],"mappings":"AAEA,OAAO,EAAE,KAAK,cAAc,EAAE,KAAK,UAAU,EAAE,KAAK,SAAS,EAAE,KAAK,GAAG,EAAE,MAAM,OAAO,CAAC;AAMvF,OAAO,EAAE,KAAK,wBAAwB,EAAE,MAAM,6BAA6B,CAAC;AAE5E;;GAEG;AACH,MAAM,WAAW,oBAAoB;IACjC,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,mBAAmB,CAAC,EAAE,wBAAwB,GAAG;QAAE,SAAS,CAAC,EAAE,cAAc,CAAC,eAAe,CAAC,CAAA;KAAE,CAAC;IAEjG,KAAK,CAAC,EAAE,SAAS,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC3B,QAAQ,CAAC,EAAE,OAAO,CAAC;IAEnB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,WAAW,CAAC,EAAE,OAAO,CAAC;IAEtB,OAAO,CAAC,EAAE,CAAC,CAAC,EAAE,UAAU,KAAK,IAAI,CAAC;IAElC,QAAQ,CAAC,EAAE,SAAS,CAAC;IACrB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,SAAS,CAAC,EAAE,GAAG,CAAC,WAAW,CAAC,CAAC;CAChC;AAED;;GAEG;AACH,wBAAgB,cAAc,CAAC,EAC3B,EAAE,EACF,SAAS,EACT,mBAAmB,EAEnB,KAAK,EACL,KAAa,EACb,QAAQ,EAER,MAAM,EACN,OAAc,EACd,QAAQ,EACR,WAAmB,EACnB,OAAO,EACP,QAAQ,EACR,UAAU,EACV,SAAS,EACZ,EAAE,oBAAoB,2CA4DtB"}
@@ -29,6 +29,11 @@ export function DropdownButton({ id, className, accessibilityConfig, value, titl
29
29
  ariaLabel,
30
30
  ariaLabelledBy,
31
31
  ariaDescribedBy,
32
+ // Without a dropdownId the popup id is unknown, but the trigger is still a combobox,
33
+ // so it has to expose its expanded state - callers commonly pass only isOpen - along
34
+ // with any explicitly controlled id.
35
+ ariaExpanded: effectiveAriaExpanded,
36
+ ariaControls,
32
37
  role: role ?? "combobox",
33
38
  });
34
39
  return (_jsx(Button, { id: id, accessibilityConfig: buttonAccessibilityConfig, title: title && typeof title === "string" ? title : undefined, className: buttonClasses, value: value, iconLeft: iconLeft, iconRight: isOpen ? "gd-icon-navigateup" : "gd-icon-navigatedown", disabled: disabled, onClick: onClick, ref: buttonRef, children: children }));
@@ -1 +1 @@
1
- {"version":3,"file":"Header.d.ts","sourceRoot":"","sources":["../../src/Header/Header.tsx"],"names":[],"mappings":"AA2BA,OAAO,EAAE,KAAK,eAAe,EAA8C,MAAM,cAAc,CAAC;AAyBhG;;GAEG;AACH,eAAO,MAAM,SAAS,kGAokBpB,CAAC"}
1
+ {"version":3,"file":"Header.d.ts","sourceRoot":"","sources":["../../src/Header/Header.tsx"],"names":[],"mappings":"AA2BA,OAAO,EAAE,KAAK,eAAe,EAA8C,MAAM,cAAc,CAAC;AAyBhG;;GAEG;AACH,eAAO,MAAM,SAAS,kGAskBpB,CAAC"}
@@ -42,7 +42,7 @@ const HEADER_HELP_MENU_ITEM_ID = defineMessage({ id: "gs.header.help" }).id;
42
42
  /**
43
43
  * @internal
44
44
  */
45
- export const AppHeader = withTheme(function AppHeader({ logoHref = "/", accountMenuItems = [], helpMenuItems = [], menuItemsGroups = [], search, notificationsPanel, workspacePicker, isAccessibilityCompliant, logoUrl, logoTitle, organizationName, className, activeColor, headerColor, headerTextColor, documentationUrl, expiredDate, showUpsellButton, onUpsellButtonClick, badges, showStaticHelpMenu, userName, theme, helpMenuDropdownAlignPoints: helpDropdownAlign, disableHelpDropdown, onHelpClick, helpRedirectUrl, showChatItem, onChatItemClick, onLogoClick, onMenuItemClick, }) {
45
+ export const AppHeader = withTheme(function AppHeader({ logoHref = "/", accountMenuItems = [], helpMenuItems = [], menuItemsGroups = [], search, notificationsPanel, workspacePicker, isAccessibilityCompliant, logoUrl, logoTitle, organizationName, className, activeColor, headerColor, headerTextColor, documentationUrl, expiredDate, showUpsellButton, onUpsellButtonClick, badges, showStaticHelpMenu, userName, theme, helpMenuDropdownAlignPoints: helpDropdownAlign, disableHelpDropdown, onHelpClick, helpRedirectUrl, showChatItem, isChatOpen, onChatItemClick, onLogoClick, onMenuItemClick, }) {
46
46
  const intl = useIntl();
47
47
  const [state, setState] = useState({
48
48
  childrenWidth: 0,
@@ -345,7 +345,7 @@ export const AppHeader = withTheme(function AppHeader({ logoHref = "/", accountM
345
345
  };
346
346
  const renderStandardNav = () => {
347
347
  return (_jsxs("div", { className: "gd-header-stretch gd-header-menu-wrapper", children: [
348
- _jsx(HeaderMenu, { onMenuItemClick: onMenuItemClick, sections: menuItemsGroups, className: "gd-header-menu-horizontal" }), renderTrialItems(), showChatItem ? (_jsx(HeaderChatButton, { title: intl.formatMessage(messages.aiChat), onClick: onChatItemClick ?? (() => { }) })) : null, notificationsPanel
348
+ _jsx(HeaderMenu, { onMenuItemClick: onMenuItemClick, sections: menuItemsGroups, className: "gd-header-menu-horizontal" }), renderTrialItems(), showChatItem ? (_jsx(HeaderChatButton, { title: intl.formatMessage(messages.aiChat), isOpen: isChatOpen, onClick: onChatItemClick ?? (() => { }) })) : null, notificationsPanel
349
349
  ? notificationsPanel({
350
350
  isMobile: false,
351
351
  closeNotificationsOverlay: closeNotificationsMenu,
@@ -1,12 +1,20 @@
1
1
  import { type MouseEvent } from "react";
2
2
  type HeaderChatButtonProps = {
3
3
  title?: string;
4
+ isOpen?: boolean;
4
5
  onClick: (e: MouseEvent) => void;
5
6
  };
6
7
  /**
7
8
  * @internal
8
9
  */
9
10
  export declare const HEADER_CHAT_BUTTON_ID = "gd-header-chat-button";
10
- export declare function HeaderChatButton({ title, onClick }: HeaderChatButtonProps): import("react/jsx-runtime").JSX.Element;
11
+ /**
12
+ * Id of the assistant panel this button opens. Set on the chat dialog so the button can reference it
13
+ * through aria-controls.
14
+ *
15
+ * @internal
16
+ */
17
+ export declare const HEADER_CHAT_PANEL_ID = "gd-header-chat-panel";
18
+ export declare function HeaderChatButton({ title, isOpen, onClick }: HeaderChatButtonProps): import("react/jsx-runtime").JSX.Element;
11
19
  export {};
12
20
  //# sourceMappingURL=HeaderChatButton.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"HeaderChatButton.d.ts","sourceRoot":"","sources":["../../src/Header/HeaderChatButton.tsx"],"names":[],"mappings":"AAEA,OAAO,EAAE,KAAK,UAAU,EAAE,MAAM,OAAO,CAAC;AAOxC,KAAK,qBAAqB,GAAG;IACzB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,CAAC,CAAC,EAAE,UAAU,KAAK,IAAI,CAAC;CACpC,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,qBAAqB,0BAA0B,CAAC;AAE7D,wBAAgB,gBAAgB,CAAC,EAAE,KAAK,EAAE,OAAO,EAAE,EAAE,qBAAqB,2CAgBzE"}
1
+ {"version":3,"file":"HeaderChatButton.d.ts","sourceRoot":"","sources":["../../src/Header/HeaderChatButton.tsx"],"names":[],"mappings":"AAEA,OAAO,EAAE,KAAK,UAAU,EAAE,MAAM,OAAO,CAAC;AAOxC,KAAK,qBAAqB,GAAG;IACzB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,OAAO,EAAE,CAAC,CAAC,EAAE,UAAU,KAAK,IAAI,CAAC;CACpC,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,qBAAqB,0BAA0B,CAAC;AAE7D;;;;;GAKG;AACH,eAAO,MAAM,oBAAoB,yBAAyB,CAAC;AAE3D,wBAAgB,gBAAgB,CAAC,EAAE,KAAK,EAAE,MAAc,EAAE,OAAO,EAAE,EAAE,qBAAqB,2CAoBzF"}
@@ -6,10 +6,21 @@ import { Button } from "../Button/Button.js";
6
6
  * @internal
7
7
  */
8
8
  export const HEADER_CHAT_BUTTON_ID = "gd-header-chat-button";
9
- export function HeaderChatButton({ title, onClick }) {
9
+ /**
10
+ * Id of the assistant panel this button opens. Set on the chat dialog so the button can reference it
11
+ * through aria-controls.
12
+ *
13
+ * @internal
14
+ */
15
+ export const HEADER_CHAT_PANEL_ID = "gd-header-chat-panel";
16
+ export function HeaderChatButton({ title, isOpen = false, onClick }) {
10
17
  const classNames = cx("gd-header-measure", "gd-header-button", "gd-header-chat");
11
18
  // The text is not l18n-ed because it is not final
12
19
  return (_jsx(Button, { id: HEADER_CHAT_BUTTON_ID, title: title, className: classNames, onClick: onClick, accessibilityConfig: {
13
20
  ariaLabel: title,
21
+ ariaHaspopup: "dialog",
22
+ ariaExpanded: isOpen,
23
+ // The panel is mounted only while open, so reference it only then.
24
+ ariaControls: isOpen ? HEADER_CHAT_PANEL_ID : undefined,
14
25
  }, children: _jsx(UiIcon, { type: "genai", size: 16 }) }));
15
26
  }
@@ -53,6 +53,11 @@ export interface IAppHeaderProps {
53
53
  closeNotificationsOverlay: () => void;
54
54
  }) => ReactNode;
55
55
  showChatItem?: boolean;
56
+ /**
57
+ * Whether the assistant panel opened by the chat button is currently open. Keeps the button's
58
+ * aria-expanded and aria-controls in sync with the panel.
59
+ */
60
+ isChatOpen?: boolean;
56
61
  onChatItemClick?: (e: MouseEvent) => void;
57
62
  }
58
63
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"typings.d.ts","sourceRoot":"","sources":["../../src/Header/typings.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"typings.d.ts","sourceRoot":"","sources":["../../src/Header/typings.ts"],"names":[],"mappings":"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"}
@@ -1,2 +1,2 @@
1
- // (C) 2021-2025 GoodData Corporation
1
+ // (C) 2021-2026 GoodData Corporation
2
2
  export {};
@@ -17,6 +17,10 @@ export interface ITimezoneSelectSpecialItem {
17
17
  * Display label of the item.
18
18
  */
19
19
  label: string;
20
+ /**
21
+ * Tooltip of the item.
22
+ */
23
+ tooltip?: string;
20
24
  }
21
25
  /**
22
26
  * Render props passed to a custom trigger renderer of {@link TimezoneSelect}.
@@ -83,6 +87,10 @@ export interface ITimezoneSelectProps {
83
87
  * Optional content rendered above the search input (e.g. a dialog-like header).
84
88
  */
85
89
  header?: ReactNode;
90
+ /**
91
+ * Whether to show tooltip for list items. Default is false.
92
+ */
93
+ showTooltip?: boolean;
86
94
  /**
87
95
  * Custom renderer of the dropdown trigger. When not provided, a standard dropdown
88
96
  * button showing the current selection is rendered.
@@ -95,7 +103,7 @@ export interface ITimezoneSelectProps {
95
103
  renderButton?: (props: ITimezoneSelectButtonRenderProps) => ReactNode;
96
104
  }
97
105
  type TimezoneListItemData = string | undefined;
98
- export declare function buildListboxItems(specialItems: ITimezoneSelectSpecialItem[], searchString: string): IUiListboxItem<TimezoneListItemData>[];
106
+ export declare function buildListboxItems(specialItems: ITimezoneSelectSpecialItem[], searchString: string, showTooltip: boolean): IUiListboxItem<TimezoneListItemData>[];
99
107
  export declare function getSelectedItemId(value: string | undefined, specialItems: ITimezoneSelectSpecialItem[]): string | undefined;
100
108
  /**
101
109
  * Searchable dropdown for picking a timezone from the curated list, with optional special
@@ -103,6 +111,6 @@ export declare function getSelectedItemId(value: string | undefined, specialItem
103
111
  *
104
112
  * @internal
105
113
  */
106
- export declare function TimezoneSelect({ value, onChange, specialItems, placeholder, searchPlaceholder, ariaLabel, noMatchLabel, isDisabled, header, renderButton }: ITimezoneSelectProps): ReactElement;
114
+ export declare function TimezoneSelect({ value, onChange, specialItems, placeholder, searchPlaceholder, ariaLabel, noMatchLabel, isDisabled, header, showTooltip, renderButton }: ITimezoneSelectProps): ReactElement;
107
115
  export {};
108
116
  //# sourceMappingURL=TimezoneSelect.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"TimezoneSelect.d.ts","sourceRoot":"","sources":["../../src/Timezone/TimezoneSelect.tsx"],"names":[],"mappings":"AAEA,OAAO,EAAE,KAAK,YAAY,EAAE,KAAK,SAAS,EAAqB,MAAM,OAAO,CAAC;AAE7E,OAAO,EAAkC,KAAK,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAEhG,OAAO,EAAY,KAAK,0BAA0B,EAAE,MAAM,yBAAyB,CAAC;AAapF;;;;;GAKG;AACH,MAAM,WAAW,0BAA0B;IACvC;;;OAGG;IACH,EAAE,EAAE,MAAM,GAAG,SAAS,CAAC;IAEvB;;OAEG;IACH,KAAK,EAAE,MAAM,CAAC;CACjB;AAED;;;;;;;;GAQG;AACH,MAAM,WAAW,gCAAiC,SAAQ,0BAA0B;IAChF;;;;OAIG;IACH,WAAW,EAAE,MAAM,CAAC;IAEpB;;OAEG;IACH,KAAK,EAAE,MAAM,GAAG,SAAS,CAAC;IAE1B;;OAEG;IACH,UAAU,CAAC,EAAE,OAAO,CAAC;CACxB;AAED;;;;;GAKG;AACH,MAAM,WAAW,oBAAoB;IACjC;;OAEG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;IAEf;;OAEG;IACH,QAAQ,EAAE,CAAC,EAAE,EAAE,MAAM,GAAG,SAAS,KAAK,IAAI,CAAC;IAE3C;;OAEG;IACH,YAAY,CAAC,EAAE,0BAA0B,EAAE,CAAC;IAE5C;;OAEG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IAErB;;OAEG;IACH,iBAAiB,EAAE,MAAM,CAAC;IAE1B;;OAEG;IACH,SAAS,EAAE,MAAM,CAAC;IAElB;;OAEG;IACH,YAAY,EAAE,MAAM,CAAC;IAErB,UAAU,CAAC,EAAE,OAAO,CAAC;IAErB;;OAEG;IACH,MAAM,CAAC,EAAE,SAAS,CAAC;IAEnB;;;;;;;;OAQG;IACH,YAAY,CAAC,EAAE,CAAC,KAAK,EAAE,gCAAgC,KAAK,SAAS,CAAC;CACzE;AAED,KAAK,oBAAoB,GAAG,MAAM,GAAG,SAAS,CAAC;AAM/C,wBAAgB,iBAAiB,CAC7B,YAAY,EAAE,0BAA0B,EAAE,EAC1C,YAAY,EAAE,MAAM,GACrB,cAAc,CAAC,oBAAoB,CAAC,EAAE,CAoCxC;AAGD,wBAAgB,iBAAiB,CAC7B,KAAK,EAAE,MAAM,GAAG,SAAS,EACzB,YAAY,EAAE,0BAA0B,EAAE,GAC3C,MAAM,GAAG,SAAS,CAMpB;AAED;;;;;GAKG;AACH,wBAAgB,cAAc,CAAC,EAC3B,KAAK,EACL,QAAQ,EACR,YAAiB,EACjB,WAAgB,EAChB,iBAAiB,EACjB,SAAS,EACT,YAAY,EACZ,UAAU,EACV,MAAM,EACN,YAAY,EACf,EAAE,oBAAoB,GAAG,YAAY,CA8FrC"}
1
+ {"version":3,"file":"TimezoneSelect.d.ts","sourceRoot":"","sources":["../../src/Timezone/TimezoneSelect.tsx"],"names":[],"mappings":"AAEA,OAAO,EAAE,KAAK,YAAY,EAAE,KAAK,SAAS,EAAqB,MAAM,OAAO,CAAC;AAE7E,OAAO,EAAkC,KAAK,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAEhG,OAAO,EAAY,KAAK,0BAA0B,EAAE,MAAM,yBAAyB,CAAC;AAapF;;;;;GAKG;AACH,MAAM,WAAW,0BAA0B;IACvC;;;OAGG;IACH,EAAE,EAAE,MAAM,GAAG,SAAS,CAAC;IAEvB;;OAEG;IACH,KAAK,EAAE,MAAM,CAAC;IAEd;;OAEG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;CACpB;AAED;;;;;;;;GAQG;AACH,MAAM,WAAW,gCAAiC,SAAQ,0BAA0B;IAChF;;;;OAIG;IACH,WAAW,EAAE,MAAM,CAAC;IAEpB;;OAEG;IACH,KAAK,EAAE,MAAM,GAAG,SAAS,CAAC;IAE1B;;OAEG;IACH,UAAU,CAAC,EAAE,OAAO,CAAC;CACxB;AAED;;;;;GAKG;AACH,MAAM,WAAW,oBAAoB;IACjC;;OAEG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;IAEf;;OAEG;IACH,QAAQ,EAAE,CAAC,EAAE,EAAE,MAAM,GAAG,SAAS,KAAK,IAAI,CAAC;IAE3C;;OAEG;IACH,YAAY,CAAC,EAAE,0BAA0B,EAAE,CAAC;IAE5C;;OAEG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IAErB;;OAEG;IACH,iBAAiB,EAAE,MAAM,CAAC;IAE1B;;OAEG;IACH,SAAS,EAAE,MAAM,CAAC;IAElB;;OAEG;IACH,YAAY,EAAE,MAAM,CAAC;IAErB,UAAU,CAAC,EAAE,OAAO,CAAC;IAErB;;OAEG;IACH,MAAM,CAAC,EAAE,SAAS,CAAC;IAEnB;;OAEG;IACH,WAAW,CAAC,EAAE,OAAO,CAAC;IAEtB;;;;;;;;OAQG;IACH,YAAY,CAAC,EAAE,CAAC,KAAK,EAAE,gCAAgC,KAAK,SAAS,CAAC;CACzE;AAED,KAAK,oBAAoB,GAAG,MAAM,GAAG,SAAS,CAAC;AAM/C,wBAAgB,iBAAiB,CAC7B,YAAY,EAAE,0BAA0B,EAAE,EAC1C,YAAY,EAAE,MAAM,EACpB,WAAW,EAAE,OAAO,GACrB,cAAc,CAAC,oBAAoB,CAAC,EAAE,CAqCxC;AAGD,wBAAgB,iBAAiB,CAC7B,KAAK,EAAE,MAAM,GAAG,SAAS,EACzB,YAAY,EAAE,0BAA0B,EAAE,GAC3C,MAAM,GAAG,SAAS,CAMpB;AAED;;;;;GAKG;AACH,wBAAgB,cAAc,CAAC,EAC3B,KAAK,EACL,QAAQ,EACR,YAAiB,EACjB,WAAgB,EAChB,iBAAiB,EACjB,SAAS,EACT,YAAY,EACZ,UAAU,EACV,MAAM,EACN,WAAmB,EACnB,YAAY,EACf,EAAE,oBAAoB,GAAG,YAAY,CAiGrC"}
@@ -14,7 +14,7 @@ const LIST_MAX_HEIGHT = 280;
14
14
  // special items may carry an undefined id, so listbox entries need a synthetic unique id
15
15
  const SPECIAL_ITEM_ID_PREFIX = "special-item-";
16
16
  // exported for tests
17
- export function buildListboxItems(specialItems, searchString) {
17
+ export function buildListboxItems(specialItems, searchString, showTooltip) {
18
18
  const search = searchString.trim().toLowerCase();
19
19
  const specialListItems = specialItems
20
20
  // keep the pre-filter index — getSelectedItemId derives the selected id from the
@@ -25,6 +25,7 @@ export function buildListboxItems(specialItems, searchString) {
25
25
  type: "interactive",
26
26
  id: `${SPECIAL_ITEM_ID_PREFIX}${index}`,
27
27
  stringTitle: item.label,
28
+ tooltip: showTooltip ? item.tooltip : undefined,
28
29
  data: item.id,
29
30
  }));
30
31
  const timezoneListItems = getTimezones()
@@ -62,7 +63,7 @@ export function getSelectedItemId(value, specialItems) {
62
63
  *
63
64
  * @internal
64
65
  */
65
- export function TimezoneSelect({ value, onChange, specialItems = [], placeholder = "", searchPlaceholder, ariaLabel, noMatchLabel, isDisabled, header, renderButton, }) {
66
+ export function TimezoneSelect({ value, onChange, specialItems = [], placeholder = "", searchPlaceholder, ariaLabel, noMatchLabel, isDisabled, header, showTooltip = false, renderButton, }) {
66
67
  const [searchString, setSearchString] = useState("");
67
68
  const selectedSpecialItem = specialItems.find((item) => item.id === value);
68
69
  const buttonLabel = selectedSpecialItem
@@ -70,7 +71,7 @@ export function TimezoneSelect({ value, onChange, specialItems = [], placeholder
70
71
  : value === undefined
71
72
  ? placeholder
72
73
  : getTimezoneDisplayLabel(value);
73
- const items = useMemo(() => buildListboxItems(specialItems, searchString), [specialItems, searchString]);
74
+ const items = useMemo(() => buildListboxItems(specialItems, searchString, showTooltip), [specialItems, searchString, showTooltip]);
74
75
  const hasNoMatchingData = items.length === 0;
75
76
  return (_jsx(Dropdown, { closeOnParentScroll: true, closeOnOutsideClick: true, alignPoints: DROPDOWN_ALIGN_POINTS, className: "gd-timezone-select s-timezone-select", onOpenStateChanged: (isOpen) => {
76
77
  if (!isOpen) {
package/esm/index.d.ts CHANGED
@@ -89,7 +89,7 @@ export { HEADER_ITEM_ID_DASHBOARDS, HEADER_ITEM_ID_REPORTS, HEADER_ITEM_ID_KPIS_
89
89
  export { activateHeaderMenuItems } from "./Header/activateHeaderMenuItems.js";
90
90
  export type { IHeaderMenuItem, IAppHeaderProps, IAppHeaderState, IHeaderAccountProps, IHeaderAccountState, IHeaderMenuProps, IHeaderUpsellButtonProps, TUTMContent, } from "./Header/typings.js";
91
91
  export { type HeaderSearchContext, HeaderSearchProvider, useHeaderSearch, } from "./Header/headerSearchContext.js";
92
- export { HEADER_CHAT_BUTTON_ID } from "./Header/HeaderChatButton.js";
92
+ export { HEADER_CHAT_BUTTON_ID, HEADER_CHAT_PANEL_ID } from "./Header/HeaderChatButton.js";
93
93
  export type { MessageType, FormatMessageParams, IMessageDefinition, IMessage, IMessageProps, } from "./Messages/typings.js";
94
94
  export { Message } from "./Messages/Message.js";
95
95
  export { useToastMessage, type IUseToastMessageType, type AddMessageType, type MessageParameters, } from "./Messages/toasts/useToastMessage.js";