@gooddata/sdk-ui-filters 11.39.0-alpha.3 → 11.39.0

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 (29) hide show
  1. package/esm/FilterGroup/FilterGroup.js +1 -1
  2. package/esm/MeasureValueFilter/Dropdown.d.ts +3 -0
  3. package/esm/MeasureValueFilter/Dropdown.js +12 -4
  4. package/esm/MeasureValueFilter/DropdownBody.d.ts +1 -0
  5. package/esm/MeasureValueFilter/DropdownBody.js +18 -9
  6. package/esm/MeasureValueFilter/MeasureValueFilter.js +17 -2
  7. package/esm/MeasureValueFilter/MeasureValueFilterDropdown.d.ts +11 -0
  8. package/esm/MeasureValueFilter/MeasureValueFilterDropdown.js +2 -2
  9. package/esm/MeasureValueFilter/OperatorDropdown.d.ts +1 -0
  10. package/esm/MeasureValueFilter/OperatorDropdown.js +1 -1
  11. package/esm/MeasureValueFilter/OperatorDropdownBody.d.ts +1 -0
  12. package/esm/MeasureValueFilter/OperatorDropdownBody.js +47 -7
  13. package/esm/MeasureValueFilter/OperatorDropdownItem.d.ts +1 -0
  14. package/esm/MeasureValueFilter/OperatorDropdownItem.js +2 -3
  15. package/esm/MeasureValueFilter/TreatNullValuesAsZeroCheckbox.d.ts +2 -1
  16. package/esm/MeasureValueFilter/TreatNullValuesAsZeroCheckbox.js +3 -4
  17. package/esm/MeasureValueFilter/typings.d.ts +12 -0
  18. package/esm/internal.d.ts +2 -0
  19. package/esm/internal.js +1 -0
  20. package/esm/sdk-ui-filters.d.ts +22 -0
  21. package/package.json +12 -12
  22. package/styles/css/filterGroup.css +1 -0
  23. package/styles/css/filterGroup.css.map +1 -1
  24. package/styles/css/main.css +192 -0
  25. package/styles/css/main.css.map +1 -1
  26. package/styles/css/measureValueFilter.css +191 -0
  27. package/styles/css/measureValueFilter.css.map +1 -1
  28. package/styles/scss/filterGroup.scss +1 -0
  29. package/styles/scss/measureValueFilter.scss +245 -0
@@ -203,7 +203,7 @@ export function FilterGroup(props) {
203
203
  ariaLabel: groupAriaLabel,
204
204
  }, renderItem: renderItem, onKeyDownSelect: handleItemKeyboardAction, closeDropdown: closeDropdown, isMobile: isMobile }) })), [filters, renderItem, handleKeyDown, handleKeyDownCapture, handleItemKeyboardAction, groupAriaLabel]);
205
205
  const isMobile = useMediaQuery("mobileDevice");
206
- const renderButton = useCallback(({ toggleDropdown, isOpen, buttonRef, dropdownId }) => (_jsx("div", { className: cx({ "gd-is-mobile": isMobile && isOpen }), children: _jsx(AttributeFilterDropdownButton, { title: title, subtitle: subtitle, isLoaded: !isAnyFilterError, isOpen: isOpen, selectedItemsCount: selectedItemsCount, totalItemsCount: totalItemsCount, showSelectionCount: selectedItemsCount !== undefined || totalItemsCount !== undefined, icon: _jsx(UiIcon, { type: "folder", size: 12, color: "currentColor" }), dropdownId: dropdownId, buttonRef: buttonRef, onClick: toggleDropdown, isError: isAnyFilterError, ariaLabel: groupAriaLabelWithState }) })), [
206
+ const renderButton = useCallback(({ toggleDropdown, isOpen, buttonRef, dropdownId }) => (_jsx("div", { className: cx({ "gd-is-mobile": isMobile && isOpen }), children: _jsx(AttributeFilterDropdownButton, { title: title, subtitle: subtitle, isLoaded: !isAnyFilterError, isOpen: isOpen, selectedItemsCount: selectedItemsCount, totalItemsCount: totalItemsCount, showSelectionCount: selectedItemsCount !== undefined || totalItemsCount !== undefined, icon: _jsx(UiIcon, { type: "folderSmall", size: 12, color: "complementary-6" }), dropdownId: dropdownId, buttonRef: buttonRef, onClick: toggleDropdown, isError: isAnyFilterError, ariaLabel: groupAriaLabelWithState }) })), [
207
207
  title,
208
208
  subtitle,
209
209
  isAnyFilterError,
@@ -1,3 +1,4 @@
1
+ import { type ReactNode } from "react";
1
2
  import { type IMeasureMetadataObject, type MeasureValueFilterCondition, type ObjRefInScope } from "@gooddata/sdk-model";
2
3
  import { type ISeparators } from "@gooddata/sdk-ui";
3
4
  import { type IAlignPoint } from "@gooddata/sdk-ui-kit";
@@ -35,6 +36,8 @@ interface IDropdownProps extends IMeasureValueFilterCustomComponentProps {
35
36
  loadMetricDetails?: () => Promise<IMeasureMetadataObject | undefined>;
36
37
  isHeaderEnabled?: boolean;
37
38
  alignPoints?: IAlignPoint[];
39
+ fullscreenOnMobile?: boolean;
40
+ mobileHeader?: ReactNode;
38
41
  }
39
42
  export declare function Dropdown(props: IDropdownProps): import("react/jsx-runtime").JSX.Element;
40
43
  export {};
@@ -1,8 +1,8 @@
1
- import { jsx as _jsx } from "react/jsx-runtime";
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  // (C) 2019-2026 GoodData Corporation
3
3
  import { memo, useCallback } from "react";
4
4
  import { IntlWrapper } from "@gooddata/sdk-ui";
5
- import { Overlay, UiFocusManager } from "@gooddata/sdk-ui-kit";
5
+ import { FullScreenOverlay, Overlay, UiFocusManager, useMediaQuery, } from "@gooddata/sdk-ui-kit";
6
6
  import { DropdownBody } from "./DropdownBody.js";
7
7
  const alignPoints = ["bl tl", "tl bl", "br tr", "tr br"];
8
8
  /*
@@ -11,13 +11,21 @@ const alignPoints = ["bl tl", "tl bl", "br tr", "tr br"];
11
11
  * thin layer on top of goodstrap (?)
12
12
  */
13
13
  const DROPDOWN_ALIGNMENTS = alignPoints.map((align) => ({ align, offset: { x: 1, y: 0 } }));
14
+ const MOBILE_DROPDOWN_ALIGN_POINTS = [{ align: "tl tl" }];
14
15
  const DropdownWithIntl = memo(function DropdownWithIntl(props) {
15
- const { operator = "ALL", usePercentage, warningMessage, locale, onCancel, anchorEl, separators, format, useShortFormat, measureTitle, displayTreatNullAsZeroOption = false, treatNullAsZeroValue = false, enableOperatorSelection, onApply: onApplyProp, onChange: onChangeProp, withoutApply, BodyComponent, DropdownActionsComponent, dimensionality, insightDimensionality, isDimensionalityEnabled, isFilterSummaryEnabled = true, catalogDimensionality, loadCatalogDimensionality, onDimensionalityChange, isLoadingCatalogDimensionality, conditions = [], enableMultipleConditions = false, enableRankingWithMvf, applyOnResult, loadMetricDetails, isHeaderEnabled, alignPoints, } = props;
16
+ const { operator = "ALL", usePercentage, warningMessage, locale, onCancel, anchorEl, separators, format, useShortFormat, measureTitle, displayTreatNullAsZeroOption = false, treatNullAsZeroValue = false, enableOperatorSelection, onApply: onApplyProp, onChange: onChangeProp, withoutApply, BodyComponent, DropdownActionsComponent, dimensionality, insightDimensionality, isDimensionalityEnabled, isFilterSummaryEnabled = true, catalogDimensionality, loadCatalogDimensionality, onDimensionalityChange, isLoadingCatalogDimensionality, conditions = [], enableMultipleConditions = false, enableRankingWithMvf, applyOnResult, loadMetricDetails, isHeaderEnabled, alignPoints, fullscreenOnMobile, mobileHeader, } = props;
17
+ const isMobile = useMediaQuery("mobileDevice");
18
+ const useFullScreen = !!fullscreenOnMobile && isMobile;
16
19
  const onApply = useCallback((conditions, newDimensionality, applyOnResult) => {
17
20
  onApplyProp(conditions, newDimensionality, applyOnResult);
18
21
  }, [onApplyProp]);
19
22
  const selectedOperator = operator === null ? "ALL" : operator;
20
- return (_jsx(Overlay, { alignTo: anchorEl, alignPoints: alignPoints ?? DROPDOWN_ALIGNMENTS, closeOnOutsideClick: true, closeOnParentScroll: true, closeOnMouseDrag: true, onClose: onCancel, children: _jsx(UiFocusManager, { enableFocusTrap: true, enableAutofocus: true, enableReturnFocusOnUnmount: true, children: _jsx(DropdownBody, { operator: selectedOperator, conditions: conditions, enableMultipleConditions: enableMultipleConditions, usePercentage: usePercentage, warningMessage: warningMessage, locale: locale, onChange: onChangeProp, withoutApply: withoutApply, BodyComponent: BodyComponent, DropdownActionsComponent: DropdownActionsComponent, onCancel: onCancel, onApply: onApply, separators: separators, format: format, useShortFormat: useShortFormat, measureTitle: measureTitle, displayTreatNullAsZeroOption: displayTreatNullAsZeroOption, treatNullAsZeroValue: treatNullAsZeroValue, enableOperatorSelection: enableOperatorSelection, dimensionality: dimensionality, insightDimensionality: insightDimensionality, isDimensionalityEnabled: isDimensionalityEnabled, isFilterSummaryEnabled: isFilterSummaryEnabled, catalogDimensionality: catalogDimensionality, loadCatalogDimensionality: loadCatalogDimensionality, onDimensionalityChange: onDimensionalityChange, isLoadingCatalogDimensionality: isLoadingCatalogDimensionality, enableRankingWithMvf: enableRankingWithMvf, applyOnResult: applyOnResult, loadMetricDetails: loadMetricDetails, isHeaderEnabled: isHeaderEnabled }) }) }));
23
+ const body = (_jsx(UiFocusManager, { enableFocusTrap: true, enableAutofocus: true, enableReturnFocusOnUnmount: true, children: _jsx(DropdownBody, { operator: selectedOperator, conditions: conditions, enableMultipleConditions: enableMultipleConditions, usePercentage: usePercentage, warningMessage: warningMessage, locale: locale, onChange: onChangeProp, withoutApply: withoutApply, BodyComponent: BodyComponent, DropdownActionsComponent: DropdownActionsComponent, onCancel: onCancel, onApply: onApply, separators: separators, format: format, useShortFormat: useShortFormat, measureTitle: measureTitle, displayTreatNullAsZeroOption: displayTreatNullAsZeroOption, treatNullAsZeroValue: treatNullAsZeroValue, enableOperatorSelection: enableOperatorSelection, dimensionality: dimensionality, insightDimensionality: insightDimensionality, isDimensionalityEnabled: isDimensionalityEnabled, isFilterSummaryEnabled: isFilterSummaryEnabled, catalogDimensionality: catalogDimensionality, loadCatalogDimensionality: loadCatalogDimensionality, onDimensionalityChange: onDimensionalityChange, isLoadingCatalogDimensionality: isLoadingCatalogDimensionality, enableRankingWithMvf: enableRankingWithMvf, applyOnResult: applyOnResult, loadMetricDetails: loadMetricDetails, isHeaderEnabled: isHeaderEnabled, isMobile: useFullScreen }) }));
24
+ if (useFullScreen) {
25
+ return (_jsx(FullScreenOverlay, { alignTo: "body", alignPoints: MOBILE_DROPDOWN_ALIGN_POINTS, onClose: onCancel, children: _jsxs("div", { className: "gd-mobile-dropdown-overlay overlay gd-flex-row-container gd-mvf-mobile-dropdown", children: [mobileHeader ? (_jsx("div", { className: "gd-mobile-dropdown-header gd-flex-item gd-mvf-mobile-dropdown-header gd-is-mobile", children: mobileHeader })) : null, _jsx("div", { className: "gd-mobile-dropdown-content gd-flex-item-stretch gd-flex-row-container gd-mvf-mobile-dropdown-content", children: body })
26
+ ] }) }));
27
+ }
28
+ return (_jsx(Overlay, { alignTo: anchorEl, alignPoints: alignPoints ?? DROPDOWN_ALIGNMENTS, closeOnOutsideClick: true, closeOnParentScroll: true, closeOnMouseDrag: true, onClose: onCancel, children: body }));
21
29
  });
22
30
  export function Dropdown(props) {
23
31
  return (_jsx(IntlWrapper, { locale: props.locale, children: _jsx(DropdownWithIntl, { ...props }) }));
@@ -33,6 +33,7 @@ interface IDropdownBodyProps extends IMeasureValueFilterCustomComponentProps {
33
33
  isLoadingCatalogDimensionality?: boolean;
34
34
  loadMetricDetails?: () => Promise<IMeasureMetadataObject | undefined>;
35
35
  isHeaderEnabled?: boolean;
36
+ isMobile?: boolean;
36
37
  }
37
38
  export declare const DropdownBodyWithIntl: import("react").NamedExoticComponent<IDropdownBodyProps>;
38
39
  export declare const DropdownBody: import("react").NamedExoticComponent<IDropdownBodyProps>;
@@ -18,6 +18,19 @@ import { TreatNullValuesAsZeroCheckbox } from "./TreatNullValuesAsZeroCheckbox.j
18
18
  import { WarningMessageComponent } from "./WarningMessage.js";
19
19
  const DefaultValuePrecision = 6;
20
20
  const ALIGN_POINTS = [{ align: "cr cl" }];
21
+ /**
22
+ * Plus / cross button next to a condition row. On mobile, skip the hover tooltip wrapper —
23
+ * tooltips aren't usable on touch and the Bubble's internal Overlay caused a re-positioning
24
+ * feedback loop when a new condition row was inserted into the fullscreen overlay.
25
+ */
26
+ function ConditionActionButton({ icon, isMobile, isDisabled, isDestructive, onClick, dataTestId, label, tooltip, }) {
27
+ const button = (_jsx(UiIconButton, { icon: icon, size: isMobile ? "medium" : "small", variant: "tertiary", isDisabled: isDisabled, isDesctructive: isDestructive, onClick: onClick, dataTestId: dataTestId, label: label }));
28
+ if (isMobile) {
29
+ return button;
30
+ }
31
+ return (_jsxs(BubbleHoverTrigger, { children: [button, _jsx(Bubble, { alignPoints: ALIGN_POINTS, children: tooltip })
32
+ ] }));
33
+ }
21
34
  const toFormCondition = (condition) => {
22
35
  if (isComparisonCondition(condition)) {
23
36
  return {
@@ -539,21 +552,17 @@ export const DropdownBodyWithIntl = memo(function DropdownBodyWithIntl(props) {
539
552
  isCommitPending.current = true;
540
553
  setApplyOnResult(event.target.checked);
541
554
  }, [setApplyOnResult]);
542
- return (_jsxs("div", { className: `${MEASURE_VALUE_FILTER_DROPDOWN_BODY_CLASS} gd-dialog gd-dropdown overlay s-mvf-dropdown-body`, "data-testid": "mvf-dropdown-body", children: [props.isHeaderEnabled && props.measureTitle ? (_jsx(MeasureValueFilterDropdownHeader, { title: props.measureTitle, loadMetricDetails: props.loadMetricDetails })) : null, _jsx("div", { className: "gd-mvf-dropdown-content", children: BodyComponent ? (_jsx(BodyComponent, { onApplyButtonClick: onApply, onCancelButtonClick: onCancel ?? (() => undefined) })) : (_jsxs(_Fragment, { children: [warningMessage ? (_jsx("div", { className: "gd-mvf-dropdown-section", children: _jsx(WarningMessageComponent, { warningMessage: warningMessage }) })) : null, _jsxs("div", { className: "gd-mvf-conditions-scroll-container", children: [(enableMultipleConditions ? state.conditions : state.conditions.slice(0, 1)).map((c, idx) => (_jsxs("div", { className: cx("gd-mvf-dropdown-section", "gd-mvf-condition-section", {
555
+ return (_jsxs("div", { className: cx(MEASURE_VALUE_FILTER_DROPDOWN_BODY_CLASS, "gd-dialog gd-dropdown overlay s-mvf-dropdown-body", { "gd-is-mobile": props.isMobile }), "data-testid": "mvf-dropdown-body", children: [props.isHeaderEnabled && props.measureTitle && !props.isMobile ? (_jsx(MeasureValueFilterDropdownHeader, { title: props.measureTitle, loadMetricDetails: props.loadMetricDetails })) : null, _jsx("div", { className: "gd-mvf-dropdown-content", children: BodyComponent ? (_jsx(BodyComponent, { onApplyButtonClick: onApply, onCancelButtonClick: onCancel ?? (() => undefined) })) : (_jsxs(_Fragment, { children: [warningMessage ? (_jsx("div", { className: "gd-mvf-dropdown-section", children: _jsx(WarningMessageComponent, { warningMessage: warningMessage }) })) : null, _jsxs("div", { className: "gd-mvf-conditions-scroll-container", children: [(enableMultipleConditions ? state.conditions : state.conditions.slice(0, 1)).map((c, idx) => (_jsxs("div", { className: cx("gd-mvf-dropdown-section", "gd-mvf-condition-section", {
543
556
  "gd-mvf-condition-section--multi": enableMultipleConditions,
544
557
  }), children: [
545
558
  _jsxs("div", { className: "gd-mvf-condition-header", "data-testid": `mvf-condition-${idx}`, children: [
546
- _jsx("div", { className: "gd-mvf-condition-operator", children: _jsx(OperatorDropdown, { onSelect: (op) => handleOperatorSelection(idx, op), operator: c.operator, isDisabled: !enableOperatorSelection, isAllOperatorDisabled: isAllOperatorDisabled }) }), enableMultipleConditions ? (_jsx("div", { className: "gd-mvf-condition-action", children: idx === 0 ? (_jsxs(BubbleHoverTrigger, { children: [
547
- _jsx(UiIconButton, { icon: "plus", size: "small", variant: "tertiary", isDisabled: isAddConditionDisabled, onClick: handleAddCondition, dataTestId: "mvf-add-condition", label: addConditionTooltip }), _jsx(Bubble, { alignPoints: ALIGN_POINTS, children: isAddConditionDisabled
548
- ? addConditionDisabledTooltip
549
- : addConditionTooltip })
550
- ] })) : (_jsxs(BubbleHoverTrigger, { children: [
551
- _jsx(UiIconButton, { icon: "cross", size: "small", variant: "tertiary", isDesctructive: true, onClick: () => handleRemoveCondition(idx), dataTestId: `mvf-remove-condition-${idx}`, label: removeConditionTooltip }), _jsx(Bubble, { alignPoints: ALIGN_POINTS, children: removeConditionTooltip })
552
- ] })) })) : null] }), c.operator === "ALL" ? null : (_jsxs("div", { className: "gd-mvf-condition-inputs", children: [
559
+ _jsx("div", { className: "gd-mvf-condition-operator", children: _jsx(OperatorDropdown, { onSelect: (op) => handleOperatorSelection(idx, op), operator: c.operator, isDisabled: !enableOperatorSelection, isAllOperatorDisabled: isAllOperatorDisabled, isMobile: props.isMobile }) }), enableMultipleConditions ? (_jsx("div", { className: "gd-mvf-condition-action", children: idx === 0 ? (_jsx(ConditionActionButton, { icon: "plus", isMobile: props.isMobile, isDisabled: isAddConditionDisabled, onClick: handleAddCondition, dataTestId: "mvf-add-condition", label: addConditionTooltip, tooltip: isAddConditionDisabled
560
+ ? addConditionDisabledTooltip
561
+ : addConditionTooltip })) : (_jsx(ConditionActionButton, { icon: "cross", isMobile: props.isMobile, isDestructive: true, onClick: () => handleRemoveCondition(idx), dataTestId: `mvf-remove-condition-${idx}`, label: removeConditionTooltip, tooltip: removeConditionTooltip })) })) : null] }), c.operator === "ALL" ? null : (_jsxs("div", { className: "gd-mvf-condition-inputs", children: [
553
562
  _jsx(ConditionInputSection, { index: idx, condition: c, usePercentage: props.usePercentage ?? false, baseDisableAutofocus: props.disableAutofocus, separators: props.separators, onValueChange: handleValueChange, onFromChange: handleFromChange, onToChange: handleToChange, onValueBlur: handleValueBlur, onFromBlur: handleFromBlur, onToBlur: handleToBlur, onApply: onApply }), idx ===
554
563
  (enableMultipleConditions
555
564
  ? state.conditions.length - 1
556
- : 0) && shouldShowTreatNullAsZeroCheckbox ? (_jsx(TreatNullValuesAsZeroCheckbox, { onChange: handleTreatNullAsZeroClicked, checked: enabledTreatNullValuesAsZero, intl: intl })) : null, idx ===
565
+ : 0) && shouldShowTreatNullAsZeroCheckbox ? (_jsx(TreatNullValuesAsZeroCheckbox, { onChange: handleTreatNullAsZeroClicked, checked: enabledTreatNullValuesAsZero, isMobile: props.isMobile, intl: intl })) : null, idx ===
557
566
  (enableMultipleConditions
558
567
  ? state.conditions.length - 1
559
568
  : 0) && enableRankingWithMvf ? (_jsxs("label", { className: "input-checkbox-label gd-mvf-apply-on-result-checkbox", "data-testid": "mvf-apply-on-result", children: [
@@ -1,15 +1,18 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  // (C) 2020-2026 GoodData Corporation
3
3
  import { Fragment, memo, useCallback, useEffect, useRef, useState } from "react";
4
+ import { useMediaQuery } from "@gooddata/sdk-ui-kit";
4
5
  import { DropdownButton } from "./MeasureValueFilterButton.js";
5
6
  import { MeasureValueFilterDropdown } from "./MeasureValueFilterDropdown.js";
6
7
  /**
7
8
  * @beta
8
9
  */
9
- export const MeasureValueFilter = memo(function MeasureValueFilter({ onCancel = () => { }, filter, measureIdentifier, buttonTitle, buttonSubtitle, buttonTitleExtension, buttonDisabled, measureTitle, usePercentage, warningMessage, locale, separators, format, useShortFormat, displayTreatNullAsZeroOption, treatNullAsZeroDefaultValue, enableOperatorSelection, dimensionality, insightDimensionality, isDimensionalityEnabled, isFilterSummaryEnabled, catalogDimensionality, loadCatalogDimensionality, onDimensionalityChange, isLoadingCatalogDimensionality, withoutApply, BodyComponent, DropdownActionsComponent, enableMultipleConditions = false, enableRankingWithMvf, onApply, DropdownButtonComponent = DropdownButton, autoOpen, loadMetricDetails, isHeaderEnabled, onChange, alignPoints, }) {
10
+ export const MeasureValueFilter = memo(function MeasureValueFilter({ onCancel = () => { }, filter, measureIdentifier, buttonTitle, buttonSubtitle, buttonTitleExtension, buttonDisabled, measureTitle, usePercentage, warningMessage, locale, separators, format, useShortFormat, displayTreatNullAsZeroOption, treatNullAsZeroDefaultValue, enableOperatorSelection, dimensionality, insightDimensionality, isDimensionalityEnabled, isFilterSummaryEnabled, catalogDimensionality, loadCatalogDimensionality, onDimensionalityChange, isLoadingCatalogDimensionality, withoutApply, BodyComponent, DropdownActionsComponent, enableMultipleConditions = false, enableRankingWithMvf, onApply, DropdownButtonComponent = DropdownButton, autoOpen, loadMetricDetails, isHeaderEnabled, onChange, alignPoints, fullscreenOnMobile, }) {
10
11
  const [displayDropdown, setDisplayDropdown] = useState(false);
11
12
  const buttonRef = useRef(null);
12
13
  const autoOpenedRef = useRef(false);
14
+ const isMobile = useMediaQuery("mobileDevice");
15
+ const useFullScreen = !!fullscreenOnMobile && isMobile;
13
16
  useEffect(() => {
14
17
  if (autoOpen && !autoOpenedRef.current) {
15
18
  autoOpenedRef.current = true;
@@ -30,6 +33,18 @@ export const MeasureValueFilter = memo(function MeasureValueFilter({ onCancel =
30
33
  const toggleDropdown = useCallback(() => {
31
34
  setDisplayDropdown((state) => !state);
32
35
  }, []);
36
+ const renderDropdownButton = useCallback((onClickHandler) => (_jsx(DropdownButtonComponent, { onClick: onClickHandler, isActive: displayDropdown, buttonTitle: buttonTitle, buttonSubtitle: buttonSubtitle, buttonTitleExtension: buttonTitleExtension, disabled: buttonDisabled })), [
37
+ DropdownButtonComponent,
38
+ buttonDisabled,
39
+ buttonSubtitle,
40
+ buttonTitle,
41
+ buttonTitleExtension,
42
+ displayDropdown,
43
+ ]);
33
44
  return (_jsxs(Fragment, { children: [
34
- _jsx("div", { ref: buttonRef, children: _jsx(DropdownButtonComponent, { onClick: toggleDropdown, isActive: displayDropdown, buttonTitle: buttonTitle, buttonSubtitle: buttonSubtitle, buttonTitleExtension: buttonTitleExtension, disabled: buttonDisabled }) }), displayDropdown ? (_jsx(MeasureValueFilterDropdown, { onApply: handleApply, onChange: onChange, withoutApply: withoutApply, BodyComponent: BodyComponent, DropdownActionsComponent: DropdownActionsComponent, onCancel: handleCancel, filter: filter, measureIdentifier: measureIdentifier, measureTitle: measureTitle, usePercentage: usePercentage, warningMessage: warningMessage, locale: locale, separators: separators, format: format, useShortFormat: useShortFormat, displayTreatNullAsZeroOption: displayTreatNullAsZeroOption, treatNullAsZeroDefaultValue: treatNullAsZeroDefaultValue, enableOperatorSelection: enableOperatorSelection, dimensionality: dimensionality, insightDimensionality: insightDimensionality, isDimensionalityEnabled: isDimensionalityEnabled, isFilterSummaryEnabled: isFilterSummaryEnabled, catalogDimensionality: catalogDimensionality, loadCatalogDimensionality: loadCatalogDimensionality, onDimensionalityChange: onDimensionalityChange, isLoadingCatalogDimensionality: isLoadingCatalogDimensionality, enableMultipleConditions: enableMultipleConditions, enableRankingWithMvf: enableRankingWithMvf, anchorEl: buttonRef.current ?? undefined, loadMetricDetails: loadMetricDetails, isHeaderEnabled: isHeaderEnabled, alignPoints: alignPoints })) : null] }));
45
+ _jsx("div", { ref: buttonRef, children: renderDropdownButton(toggleDropdown) }), displayDropdown ? (_jsx(MeasureValueFilterDropdown, { onApply: handleApply, onChange: onChange, withoutApply: withoutApply, BodyComponent: BodyComponent, DropdownActionsComponent: DropdownActionsComponent, onCancel: handleCancel, filter: filter, measureIdentifier: measureIdentifier, measureTitle: measureTitle, usePercentage: usePercentage, warningMessage: warningMessage, locale: locale, separators: separators, format: format, useShortFormat: useShortFormat, displayTreatNullAsZeroOption: displayTreatNullAsZeroOption, treatNullAsZeroDefaultValue: treatNullAsZeroDefaultValue, enableOperatorSelection: enableOperatorSelection, dimensionality: dimensionality, insightDimensionality: insightDimensionality, isDimensionalityEnabled: isDimensionalityEnabled, isFilterSummaryEnabled: isFilterSummaryEnabled, catalogDimensionality: catalogDimensionality, loadCatalogDimensionality: loadCatalogDimensionality, onDimensionalityChange: onDimensionalityChange, isLoadingCatalogDimensionality: isLoadingCatalogDimensionality, enableMultipleConditions: enableMultipleConditions, enableRankingWithMvf: enableRankingWithMvf, anchorEl: buttonRef.current ?? undefined, loadMetricDetails: loadMetricDetails, isHeaderEnabled: isHeaderEnabled, alignPoints: alignPoints, fullscreenOnMobile: fullscreenOnMobile,
46
+ // Mobile header is the same visual button but dismisses via handleCancel
47
+ // so host onCancel cleanup (e.g. closing the configuration panel,
48
+ // clearing autoOpen) runs — toggleDropdown would skip that path.
49
+ mobileHeader: useFullScreen ? renderDropdownButton(handleCancel) : undefined })) : null] }));
35
50
  });
@@ -1,3 +1,4 @@
1
+ import { type ReactNode } from "react";
1
2
  import { type IMeasureValueFilterCommonProps } from "./typings.js";
2
3
  /**
3
4
  * @beta
@@ -5,6 +6,16 @@ import { type IMeasureValueFilterCommonProps } from "./typings.js";
5
6
  export interface IMeasureValueFilterDropdownProps extends IMeasureValueFilterCommonProps {
6
7
  onCancel: () => void;
7
8
  anchorEl?: HTMLElement | string;
9
+ /**
10
+ * Element rendered at the top of the dropdown overlay when displayed in fullscreen mobile mode.
11
+ *
12
+ * @remarks
13
+ * Typically the host's dropdown button — composed by the parent {@link MeasureValueFilter}
14
+ * so the trigger appears as the overlay header on small viewports.
15
+ *
16
+ * @internal
17
+ */
18
+ mobileHeader?: ReactNode;
8
19
  }
9
20
  /**
10
21
  * @beta
@@ -21,7 +21,7 @@ const getTreatNullAsZeroValue = (filter, treatNullAsZeroDefaultValue, enableMult
21
21
  /**
22
22
  * @beta
23
23
  */
24
- export const MeasureValueFilterDropdown = memo(function MeasureValueFilterDropdown({ filter, onCancel, onApply, onChange, withoutApply, BodyComponent, DropdownActionsComponent, measureIdentifier, measureTitle, usePercentage, warningMessage, locale, anchorEl, separators, format, useShortFormat, displayTreatNullAsZeroOption = false, treatNullAsZeroDefaultValue = false, enableOperatorSelection = true, dimensionality, insightDimensionality, isDimensionalityEnabled, isFilterSummaryEnabled, catalogDimensionality, loadCatalogDimensionality, onDimensionalityChange, isLoadingCatalogDimensionality, enableMultipleConditions = false, enableRankingWithMvf, loadMetricDetails, isHeaderEnabled, alignPoints, }) {
24
+ export const MeasureValueFilterDropdown = memo(function MeasureValueFilterDropdown({ filter, onCancel, onApply, onChange, withoutApply, BodyComponent, DropdownActionsComponent, measureIdentifier, measureTitle, usePercentage, warningMessage, locale, anchorEl, separators, format, useShortFormat, displayTreatNullAsZeroOption = false, treatNullAsZeroDefaultValue = false, enableOperatorSelection = true, dimensionality, insightDimensionality, isDimensionalityEnabled, isFilterSummaryEnabled, catalogDimensionality, loadCatalogDimensionality, onDimensionalityChange, isLoadingCatalogDimensionality, enableMultipleConditions = false, enableRankingWithMvf, loadMetricDetails, isHeaderEnabled, alignPoints, fullscreenOnMobile, mobileHeader, }) {
25
25
  const applyOnResult = filter?.measureValueFilter.applyOnResult;
26
26
  const buildFilter = useCallback((conditions, newDimensionality, applyOnResult) => {
27
27
  const effectiveConditions = enableMultipleConditions ? conditions : conditions?.slice(0, 1);
@@ -79,5 +79,5 @@ export const MeasureValueFilterDropdown = memo(function MeasureValueFilterDropdo
79
79
  const handleChange = useCallback((conditions, newDimensionality, applyOnResult) => {
80
80
  onChange?.(buildFilter(conditions, newDimensionality, applyOnResult));
81
81
  }, [onChange, buildFilter]);
82
- return (_jsx(Dropdown, { onApply: handleApply, onChange: onChange ? handleChange : undefined, withoutApply: withoutApply, BodyComponent: BodyComponent, DropdownActionsComponent: DropdownActionsComponent, onCancel: onCancel, operator: (filter && measureValueFilterOperator(filter)) || null, conditions: getConditionsFromFilter(filter, enableMultipleConditions), usePercentage: usePercentage, warningMessage: warningMessage, locale: locale, anchorEl: anchorEl, separators: separators, format: format, useShortFormat: useShortFormat, measureTitle: measureTitle, displayTreatNullAsZeroOption: displayTreatNullAsZeroOption, treatNullAsZeroValue: getTreatNullAsZeroValue(filter, treatNullAsZeroDefaultValue, enableMultipleConditions), enableOperatorSelection: enableOperatorSelection, dimensionality: dimensionality, insightDimensionality: insightDimensionality, isDimensionalityEnabled: isDimensionalityEnabled, isFilterSummaryEnabled: isFilterSummaryEnabled, catalogDimensionality: catalogDimensionality, loadCatalogDimensionality: loadCatalogDimensionality, onDimensionalityChange: onDimensionalityChange, isLoadingCatalogDimensionality: isLoadingCatalogDimensionality, enableMultipleConditions: enableMultipleConditions, enableRankingWithMvf: enableRankingWithMvf, applyOnResult: applyOnResult, loadMetricDetails: loadMetricDetails, isHeaderEnabled: isHeaderEnabled, alignPoints: alignPoints }));
82
+ return (_jsx(Dropdown, { onApply: handleApply, onChange: onChange ? handleChange : undefined, withoutApply: withoutApply, BodyComponent: BodyComponent, DropdownActionsComponent: DropdownActionsComponent, onCancel: onCancel, operator: (filter && measureValueFilterOperator(filter)) || null, conditions: getConditionsFromFilter(filter, enableMultipleConditions), usePercentage: usePercentage, warningMessage: warningMessage, locale: locale, anchorEl: anchorEl, separators: separators, format: format, useShortFormat: useShortFormat, measureTitle: measureTitle, displayTreatNullAsZeroOption: displayTreatNullAsZeroOption, treatNullAsZeroValue: getTreatNullAsZeroValue(filter, treatNullAsZeroDefaultValue, enableMultipleConditions), enableOperatorSelection: enableOperatorSelection, dimensionality: dimensionality, insightDimensionality: insightDimensionality, isDimensionalityEnabled: isDimensionalityEnabled, isFilterSummaryEnabled: isFilterSummaryEnabled, catalogDimensionality: catalogDimensionality, loadCatalogDimensionality: loadCatalogDimensionality, onDimensionalityChange: onDimensionalityChange, isLoadingCatalogDimensionality: isLoadingCatalogDimensionality, enableMultipleConditions: enableMultipleConditions, enableRankingWithMvf: enableRankingWithMvf, applyOnResult: applyOnResult, loadMetricDetails: loadMetricDetails, isHeaderEnabled: isHeaderEnabled, alignPoints: alignPoints, fullscreenOnMobile: fullscreenOnMobile, mobileHeader: mobileHeader }));
83
83
  });
@@ -4,6 +4,7 @@ interface IOperatorDropdownProps {
4
4
  operator: MeasureValueFilterOperator;
5
5
  isDisabled?: boolean;
6
6
  isAllOperatorDisabled?: boolean;
7
+ isMobile?: boolean;
7
8
  }
8
9
  export declare const OperatorDropdown: import("react").NamedExoticComponent<IOperatorDropdownProps>;
9
10
  export {};
@@ -32,5 +32,5 @@ export const OperatorDropdown = memo(function OperatorDropdown(props) {
32
32
  const handleOperatorDropdownButtonClick = () => setOpened((state) => !state);
33
33
  return (_jsxs(_Fragment, { children: [
34
34
  _jsxs("div", { className: "gd-mvf-operator-dropdown", "data-testid": "mvf-operator-section", children: [
35
- _jsx("div", { className: "gd-mvf-operator-dropdown-label", children: intl.formatMessage({ id: "mvf.condition" }) }), renderDropdownButton()] }), opened ? (_jsx(OperatorDropdownBody, { alignTo: ".gd-mvf-operator-dropdown-button", onSelect: handleOperatorSelected, selectedOperator: props.operator, onClose: closeOperatorDropdown, isAllOperatorDisabled: props.isAllOperatorDisabled })) : null] }));
35
+ _jsx("div", { className: "gd-mvf-operator-dropdown-label", children: intl.formatMessage({ id: "mvf.condition" }) }), renderDropdownButton()] }), opened ? (_jsx(OperatorDropdownBody, { alignTo: ".gd-mvf-operator-dropdown-button", onSelect: handleOperatorSelected, selectedOperator: props.operator, onClose: closeOperatorDropdown, isAllOperatorDisabled: props.isAllOperatorDisabled, isMobile: props.isMobile })) : null] }));
36
36
  });
@@ -5,6 +5,7 @@ interface IOperatorDropdownBodyProps {
5
5
  onClose: () => void;
6
6
  alignTo: string;
7
7
  isAllOperatorDisabled?: boolean;
8
+ isMobile?: boolean;
8
9
  }
9
10
  export declare const OperatorDropdownBody: import("react").NamedExoticComponent<IOperatorDropdownBodyProps>;
10
11
  export {};
@@ -1,16 +1,56 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  // (C) 2019-2026 GoodData Corporation
3
- import { memo } from "react";
4
- import { useIntl } from "react-intl";
5
- import { Overlay, Separator } from "@gooddata/sdk-ui-kit";
3
+ import { Fragment, memo } from "react";
4
+ import cx from "classnames";
5
+ import { capitalize } from "lodash-es";
6
+ import { defineMessages, useIntl } from "react-intl";
7
+ import { FullScreenOverlay, Overlay, Separator } from "@gooddata/sdk-ui-kit";
6
8
  import { MEASURE_VALUE_FILTER_OPERATOR_DROPDOWN_BODY_CLASS } from "./constants.js";
9
+ import { getOperatorTranslationKey } from "./helpers/measureValueFilterOperator.js";
7
10
  import { OperatorDropdownItem } from "./OperatorDropdownItem.js";
8
- export const OperatorDropdownBody = memo(function OperatorDropdownBody({ onSelect, onClose, selectedOperator, alignTo, isAllOperatorDisabled = false, }) {
11
+ const MOBILE_DROPDOWN_ALIGN_POINTS = [{ align: "tl tl" }];
12
+ // Operators grouped as they appear in the picker; a Separator is rendered between groups
13
+ // (desktop only — mobile rows already carry a bottom divider).
14
+ const OPERATOR_GROUPS = [
15
+ ["ALL"],
16
+ ["GREATER_THAN", "GREATER_THAN_OR_EQUAL_TO"],
17
+ ["LESS_THAN", "LESS_THAN_OR_EQUAL_TO"],
18
+ ["BETWEEN", "NOT_BETWEEN"],
19
+ ["EQUAL_TO", "NOT_EQUAL_TO"],
20
+ ];
21
+ // Operators that surface an explanatory hover bubble next to their label.
22
+ // Declared via `defineMessages` so static i18n analysis (e.g. i18n-toolkit) sees these IDs
23
+ // as referenced and validates their presence in translation bundles — a plain `string` map
24
+ // is invisible to the extractor because it never reaches an `intl.formatMessage({ id })` call site.
25
+ const bubbleMessages = defineMessages({
26
+ BETWEEN: { id: "mvf.operator.between.tooltip.bubble" },
27
+ NOT_BETWEEN: { id: "mvf.operator.notBetween.tooltip.bubble" },
28
+ });
29
+ const OPERATOR_BUBBLE_MESSAGES = {
30
+ BETWEEN: bubbleMessages.BETWEEN,
31
+ NOT_BETWEEN: bubbleMessages.NOT_BETWEEN,
32
+ };
33
+ export const OperatorDropdownBody = memo(function OperatorDropdownBody({ onSelect, onClose, selectedOperator, alignTo, isAllOperatorDisabled = false, isMobile = false, }) {
9
34
  const intl = useIntl();
10
35
  const allOperatorDisabledTooltip = isAllOperatorDisabled
11
36
  ? intl.formatMessage({ id: "mvf.operator.all.disabled.tooltip" })
12
37
  : undefined;
13
- return (_jsx(Overlay, { closeOnOutsideClick: true, alignTo: alignTo, alignPoints: [{ align: "bl tl" }], onClose: onClose, children: _jsx("div", { className: "gd-dropdown overlay", children: _jsxs("div", { className: `${MEASURE_VALUE_FILTER_OPERATOR_DROPDOWN_BODY_CLASS} s-mvf-operator-dropdown-body`, "data-testid": "mvf-operator-dropdown-body", children: [
14
- _jsx(OperatorDropdownItem, { operator: "ALL", selectedOperator: selectedOperator, onClick: onSelect, isDisabled: isAllOperatorDisabled, disabledTooltip: allOperatorDisabledTooltip }), _jsx(Separator, {}), _jsx(OperatorDropdownItem, { operator: "GREATER_THAN", selectedOperator: selectedOperator, onClick: onSelect }), _jsx(OperatorDropdownItem, { operator: "GREATER_THAN_OR_EQUAL_TO", selectedOperator: selectedOperator, onClick: onSelect }), _jsx(Separator, {}), _jsx(OperatorDropdownItem, { operator: "LESS_THAN", selectedOperator: selectedOperator, onClick: onSelect }), _jsx(OperatorDropdownItem, { operator: "LESS_THAN_OR_EQUAL_TO", selectedOperator: selectedOperator, onClick: onSelect }), _jsx(Separator, {}), _jsx(OperatorDropdownItem, { operator: "BETWEEN", selectedOperator: selectedOperator, onClick: onSelect, bubbleText: intl.formatMessage({ id: "mvf.operator.between.tooltip.bubble" }) }), _jsx(OperatorDropdownItem, { operator: "NOT_BETWEEN", selectedOperator: selectedOperator, onClick: onSelect, bubbleText: intl.formatMessage({ id: "mvf.operator.notBetween.tooltip.bubble" }) }), _jsx(Separator, {}), _jsx(OperatorDropdownItem, { operator: "EQUAL_TO", selectedOperator: selectedOperator, onClick: onSelect }), _jsx(OperatorDropdownItem, { operator: "NOT_EQUAL_TO", selectedOperator: selectedOperator, onClick: onSelect })
15
- ] }) }) }));
38
+ const selectedOperatorTranslationKey = getOperatorTranslationKey(selectedOperator);
39
+ const selectedOperatorTitle = capitalize(selectedOperatorTranslationKey === undefined
40
+ ? selectedOperator
41
+ : intl.formatMessage({ id: selectedOperatorTranslationKey }));
42
+ const items = (_jsx("div", { className: cx(MEASURE_VALUE_FILTER_OPERATOR_DROPDOWN_BODY_CLASS, "s-mvf-operator-dropdown-body", {
43
+ "gd-is-mobile": isMobile,
44
+ }), "data-testid": "mvf-operator-dropdown-body", children: OPERATOR_GROUPS.map((group, groupIdx) => (_jsxs(Fragment, { children: [groupIdx > 0 && !isMobile ? _jsx(Separator, {}) : null, group.map((operator) => {
45
+ const bubbleMessage = OPERATOR_BUBBLE_MESSAGES[operator];
46
+ return (_jsx(OperatorDropdownItem, { operator: operator, selectedOperator: selectedOperator, onClick: onSelect, bubbleText: bubbleMessage ? intl.formatMessage(bubbleMessage) : undefined, isDisabled: operator === "ALL" ? isAllOperatorDisabled : undefined, disabledTooltip: operator === "ALL" ? allOperatorDisabledTooltip : undefined, isMobile: isMobile }, operator));
47
+ })] }, groupIdx))) }));
48
+ if (isMobile) {
49
+ return (_jsx(FullScreenOverlay, { alignTo: "body", alignPoints: MOBILE_DROPDOWN_ALIGN_POINTS, onClose: onClose, children: _jsxs("div", { className: "gd-mobile-dropdown-overlay overlay gd-flex-row-container gd-mvf-mobile-dropdown", children: [
50
+ _jsx("div", { className: "gd-mobile-dropdown-header gd-flex-item gd-mvf-mobile-dropdown-header", children: _jsxs("button", { type: "button", className: "gd-mvf-operator-mobile-header s-mvf-operator-mobile-header", onClick: onClose, children: [
51
+ _jsx("span", { className: "gd-mvf-operator-mobile-header__label", children: intl.formatMessage({ id: "mvf.condition" }) }), _jsx("span", { className: "gd-mvf-operator-mobile-header__value", children: selectedOperatorTitle }), _jsx("span", { className: "gd-mvf-operator-mobile-header__chevron gd-icon-navigateup" })
52
+ ] }) }), _jsx("div", { className: "gd-mobile-dropdown-content gd-flex-item-stretch gd-mvf-mobile-dropdown-content", children: items })
53
+ ] }) }));
54
+ }
55
+ return (_jsx(Overlay, { closeOnOutsideClick: true, alignTo: alignTo, alignPoints: [{ align: "bl tl" }], onClose: onClose, children: _jsx("div", { className: "gd-dropdown overlay", children: items }) }));
16
56
  });
@@ -6,6 +6,7 @@ interface IOperatorDropdownItemOwnProps {
6
6
  isDisabled?: boolean;
7
7
  disabledTooltip?: string;
8
8
  onClick: (identifier: MeasureValueFilterOperator) => void;
9
+ isMobile?: boolean;
9
10
  }
10
11
  export declare const OperatorDropdownItem: import("react").NamedExoticComponent<IOperatorDropdownItemOwnProps>;
11
12
  export {};
@@ -8,7 +8,7 @@ import { Bubble, BubbleHoverTrigger } from "@gooddata/sdk-ui-kit";
8
8
  import { simplifyText } from "@gooddata/util";
9
9
  import { getOperatorIcon, getOperatorTranslationKey } from "./helpers/measureValueFilterOperator.js";
10
10
  const BUBBLE_ALIGN_POINTS = [{ align: "cr cl" }, { align: "cl cr" }];
11
- export const OperatorDropdownItem = memo(function OperatorDropdownItem({ operator, selectedOperator, bubbleText, isDisabled = false, disabledTooltip, onClick = () => { }, }) {
11
+ export const OperatorDropdownItem = memo(function OperatorDropdownItem({ operator, selectedOperator, bubbleText, isDisabled = false, disabledTooltip, onClick = () => { }, isMobile = false, }) {
12
12
  const intl = useIntl();
13
13
  const handleOnClick = (e) => {
14
14
  if (isDisabled) {
@@ -29,8 +29,7 @@ export const OperatorDropdownItem = memo(function OperatorDropdownItem({ operato
29
29
  });
30
30
  const operatorTranslationKey = getOperatorTranslationKey(operator);
31
31
  const title = operatorTranslationKey === undefined ? operator : intl.formatMessage({ id: operatorTranslationKey });
32
- const itemContent = (_jsxs("div", { className: className, onClick: handleOnClick, "aria-disabled": isDisabled, "data-testid": `mvf-operator-${simplifyText(operator)}`, children: [
33
- _jsx("div", { className: `gd-icon-${getOperatorIcon(operator)}`, title: title }), _jsx("span", { title: title, children: capitalize(title) }), bubbleText ? renderBubble(bubbleText) : null] }));
32
+ const itemContent = (_jsxs("div", { className: className, onClick: handleOnClick, "aria-disabled": isDisabled, "data-testid": `mvf-operator-${simplifyText(operator)}`, children: [isMobile ? null : _jsx("div", { className: `gd-icon-${getOperatorIcon(operator)}`, title: title }), _jsx("span", { title: title, children: capitalize(title) }), bubbleText && !isMobile ? renderBubble(bubbleText) : null] }));
34
33
  // Wrap disabled item with tooltip if provided
35
34
  if (isDisabled && disabledTooltip) {
36
35
  return (_jsxs(BubbleHoverTrigger, { tagName: "div", showDelay: 400, hideDelay: 200, children: [itemContent, _jsx(Bubble, { className: "bubble-primary", alignPoints: BUBBLE_ALIGN_POINTS, children: disabledTooltip })
@@ -3,6 +3,7 @@ import { type WrappedComponentProps } from "react-intl";
3
3
  interface ITreatNullValuesAsZeroCheckboxProps {
4
4
  checked?: boolean;
5
5
  onChange: (checked: boolean) => void;
6
+ isMobile?: boolean;
6
7
  }
7
- export declare function TreatNullValuesAsZeroCheckbox({ checked, onChange, intl }: ITreatNullValuesAsZeroCheckboxProps & WrappedComponentProps): ReactElement;
8
+ export declare function TreatNullValuesAsZeroCheckbox({ checked, onChange, isMobile, intl }: ITreatNullValuesAsZeroCheckboxProps & WrappedComponentProps): ReactElement;
8
9
  export {};
@@ -1,11 +1,10 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { Bubble, BubbleHoverTrigger } from "@gooddata/sdk-ui-kit";
3
- export function TreatNullValuesAsZeroCheckbox({ checked = false, onChange, intl, }) {
3
+ export function TreatNullValuesAsZeroCheckbox({ checked = false, onChange, isMobile = false, intl, }) {
4
4
  const handleOnChange = (e) => onChange(e.target.checked);
5
5
  return (_jsxs("label", { className: "input-checkbox-label gd-mvf-treat-null-values-as-zero s-treat-null-values-as-zero", "data-testid": "mvf-treat-null-values-as-zero", children: [
6
- _jsx("input", { type: "checkbox", name: "treat-null-values-as", className: "input-checkbox", checked: checked, onChange: handleOnChange }), _jsxs("span", { className: "input-label-text", children: [intl.formatMessage({ id: "mvf.treatNullValuesAsZeroLabel" }), _jsxs(BubbleHoverTrigger, { showDelay: 400, hideDelay: 200, children: [
6
+ _jsx("input", { type: "checkbox", name: "treat-null-values-as", className: "input-checkbox", checked: checked, onChange: handleOnChange }), _jsxs("span", { className: "input-label-text", children: [intl.formatMessage({ id: "mvf.treatNullValuesAsZeroLabel" }), isMobile ? null : (_jsxs(BubbleHoverTrigger, { showDelay: 400, hideDelay: 200, children: [
7
7
  _jsx("span", { className: "inlineBubbleHelp" }), _jsx(Bubble, { className: "bubble-primary", alignPoints: [{ align: "tc bl" }], children: intl.formatMessage({ id: "mvf.treatNullValuesAsZeroTooltip" }) })
8
- ] })
9
- ] })
8
+ ] }))] })
10
9
  ] }));
11
10
  }
@@ -285,6 +285,18 @@ export interface IMeasureValueFilterCommonProps extends IMeasureValueFilterCusto
285
285
  * @beta
286
286
  */
287
287
  alignPoints?: IAlignPoint[];
288
+ /**
289
+ * When `true`, the dropdown takes the entire screen on mobile devices.
290
+ *
291
+ * @remarks
292
+ * Hosts that render the MVF inside responsive surfaces (e.g. dashboards) opt in to
293
+ * switch the overlay to a full-screen presentation on mobile viewports.
294
+ *
295
+ * Defaults to `false`.
296
+ *
297
+ * @beta
298
+ */
299
+ fullscreenOnMobile?: boolean;
288
300
  }
289
301
  /**
290
302
  * These customization properties allow you to specify custom components that the MeasureValueFilter
package/esm/internal.d.ts CHANGED
@@ -7,4 +7,6 @@ export { CalendarTypeTabs } from "./DateFilter/DateFilterBody/CalendarTypeTabs.j
7
7
  export { normalizeSelectedFilterOption } from "./DateFilter/utils/FilterOptionNormalization.js";
8
8
  export { ListItem } from "./DateFilter/ListItem/ListItem.js";
9
9
  export { ListItemTooltip } from "./DateFilter/ListItemTooltip/ListItemTooltip.js";
10
+ export { DimensionalitySection } from "./MeasureValueFilter/DimensionalitySection.js";
10
11
  export { MeasureValueFilterDetailsBubble } from "./MeasureValueFilter/MeasureValueFilterDetailsBubble.js";
12
+ export type { IDimensionalityItem } from "./MeasureValueFilter/typings.js";
package/esm/internal.js CHANGED
@@ -9,4 +9,5 @@ export { CalendarTypeTabs } from "./DateFilter/DateFilterBody/CalendarTypeTabs.j
9
9
  export { normalizeSelectedFilterOption } from "./DateFilter/utils/FilterOptionNormalization.js";
10
10
  export { ListItem } from "./DateFilter/ListItem/ListItem.js";
11
11
  export { ListItemTooltip } from "./DateFilter/ListItemTooltip/ListItemTooltip.js";
12
+ export { DimensionalitySection } from "./MeasureValueFilter/DimensionalitySection.js";
12
13
  export { MeasureValueFilterDetailsBubble } from "./MeasureValueFilter/MeasureValueFilterDetailsBubble.js";
@@ -3759,6 +3759,18 @@ export declare interface IMeasureValueFilterCommonProps extends IMeasureValueFil
3759
3759
  * @beta
3760
3760
  */
3761
3761
  alignPoints?: IAlignPoint[];
3762
+ /**
3763
+ * When `true`, the dropdown takes the entire screen on mobile devices.
3764
+ *
3765
+ * @remarks
3766
+ * Hosts that render the MVF inside responsive surfaces (e.g. dashboards) opt in to
3767
+ * switch the overlay to a full-screen presentation on mobile viewports.
3768
+ *
3769
+ * Defaults to `false`.
3770
+ *
3771
+ * @beta
3772
+ */
3773
+ fullscreenOnMobile?: boolean;
3762
3774
  }
3763
3775
 
3764
3776
  /**
@@ -3890,6 +3902,16 @@ export declare interface IMeasureValueFilterDropdownButtonProps {
3890
3902
  export declare interface IMeasureValueFilterDropdownProps extends IMeasureValueFilterCommonProps {
3891
3903
  onCancel: () => void;
3892
3904
  anchorEl?: HTMLElement | string;
3905
+ /**
3906
+ * Element rendered at the top of the dropdown overlay when displayed in fullscreen mobile mode.
3907
+ *
3908
+ * @remarks
3909
+ * Typically the host's dropdown button — composed by the parent {@link MeasureValueFilter}
3910
+ * so the trigger appears as the overlay header on small viewports.
3911
+ *
3912
+ * @internal
3913
+ */
3914
+ mobileHeader?: ReactNode;
3893
3915
  }
3894
3916
 
3895
3917
  /**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gooddata/sdk-ui-filters",
3
- "version": "11.39.0-alpha.3",
3
+ "version": "11.39.0",
4
4
  "description": "GoodData.UI SDK - Filter Components",
5
5
  "license": "MIT",
6
6
  "author": "GoodData Corporation",
@@ -47,11 +47,11 @@
47
47
  "ts-invariant": "0.10.3",
48
48
  "tslib": "2.8.1",
49
49
  "uuid": "11.1.0",
50
- "@gooddata/sdk-backend-spi": "11.39.0-alpha.3",
51
- "@gooddata/sdk-model": "11.39.0-alpha.3",
52
- "@gooddata/sdk-ui": "11.39.0-alpha.3",
53
- "@gooddata/sdk-ui-kit": "11.39.0-alpha.3",
54
- "@gooddata/util": "11.39.0-alpha.3"
50
+ "@gooddata/sdk-ui": "11.39.0",
51
+ "@gooddata/sdk-model": "11.39.0",
52
+ "@gooddata/sdk-backend-spi": "11.39.0",
53
+ "@gooddata/sdk-ui-kit": "11.39.0",
54
+ "@gooddata/util": "11.39.0"
55
55
  },
56
56
  "devDependencies": {
57
57
  "@microsoft/api-documenter": "^7.17.0",
@@ -93,12 +93,12 @@
93
93
  "typescript": "5.9.3",
94
94
  "vitest": "4.1.0",
95
95
  "vitest-dom": "0.1.1",
96
- "@gooddata/eslint-config": "11.39.0-alpha.3",
97
- "@gooddata/oxlint-config": "11.39.0-alpha.3",
98
- "@gooddata/reference-workspace": "11.39.0-alpha.3",
99
- "@gooddata/sdk-backend-mockingbird": "11.39.0-alpha.3",
100
- "@gooddata/sdk-ui-theme-provider": "11.39.0-alpha.3",
101
- "@gooddata/stylelint-config": "11.39.0-alpha.3"
96
+ "@gooddata/eslint-config": "11.39.0",
97
+ "@gooddata/oxlint-config": "11.39.0",
98
+ "@gooddata/reference-workspace": "11.39.0",
99
+ "@gooddata/sdk-ui-theme-provider": "11.39.0",
100
+ "@gooddata/stylelint-config": "11.39.0",
101
+ "@gooddata/sdk-backend-mockingbird": "11.39.0"
102
102
  },
103
103
  "peerDependencies": {
104
104
  "react": "^18.0.0 || ^19.0.0",
@@ -22,6 +22,7 @@
22
22
  }
23
23
  .dropdown-body .gd-infinite-list.gd-filter-group-body .gd-ui-kit-paged-virtual-list__item:last-child .gd-filter-group-item,
24
24
  .gd-mobile-dropdown-content .gd-infinite-list.gd-filter-group-body .gd-ui-kit-paged-virtual-list__item:last-child .gd-filter-group-item {
25
+ height: 53px;
25
26
  border-bottom: none;
26
27
  }
27
28
  .dropdown-body .gd-infinite-list.gd-filter-group-body .gd-attribute-filter__next,
@@ -1 +1 @@
1
- {"version":3,"sourceRoot":"","sources":["../scss/filterGroup.scss"],"names":[],"mappings":"AAGA;EACI;EACA;;;AAGJ;AAAA;EAEI;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;AAGI;AAAA;EACI;;AAGJ;AAAA;EACI;;AAIR;AAAA;EACI;;AAGJ;AAAA;EACI;;AAGJ;AAAA;EACI;;;AAIR;EACI","file":"filterGroup.css"}
1
+ {"version":3,"sourceRoot":"","sources":["../scss/filterGroup.scss"],"names":[],"mappings":"AAGA;EACI;EACA;;;AAGJ;AAAA;EAEI;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;AAGI;AAAA;EACI;;AAGJ;AAAA;EACI;EACA;;AAIR;AAAA;EACI;;AAGJ;AAAA;EACI;;AAGJ;AAAA;EACI;;;AAIR;EACI","file":"filterGroup.css"}