diff --git a/app/client/cypress/fixtures/widgetPopupDsl.json b/app/client/cypress/fixtures/widgetPopupDsl.json index 9c12598260..138ce99f87 100644 --- a/app/client/cypress/fixtures/widgetPopupDsl.json +++ b/app/client/cypress/fixtures/widgetPopupDsl.json @@ -24,9 +24,8 @@ "widgetName": "TreeSelect1", "displayName": "TreeSelect", "iconSVG": "/static/media/icon.bd99caba.svg", - "labelText": "Label", "topRow": 14, - "bottomRow": 22, + "bottomRow": 18, "parentRowSpace": 10, "type": "SINGLE_SELECT_TREE_WIDGET", "hideCard": false, @@ -63,7 +62,7 @@ "isDisabled": false, "key": "oe8sn5hbxk", "isRequired": false, - "rightColumn": 18, + "rightColumn": 30, "widgetId": "p65c0i01ic", "isVisible": true, "version": 1, @@ -77,9 +76,8 @@ "widgetName": "MultiTreeSelect2", "displayName": "Multi TreeSelect", "iconSVG": "/static/media/icon.b3e28afb.svg", - "labelText": "Label", "topRow": 31, - "bottomRow": 39, + "bottomRow": 35, "parentRowSpace": 10, "type": "MULTI_SELECT_TREE_WIDGET", "hideCard": false, @@ -117,7 +115,7 @@ "isDisabled": false, "key": "oe8sn5hbxk", "isRequired": false, - "rightColumn": 18, + "rightColumn": 30, "widgetId": "buewtu97rf", "isVisible": true, "version": 1, @@ -132,9 +130,8 @@ "isFilterable": true, "displayName": "Select", "iconSVG": "/static/media/icon.bd99caba.svg", - "labelText": "Label", "topRow": 50, - "bottomRow": 58, + "bottomRow": 54, "parentRowSpace": 10, "type": "SELECT_WIDGET", "serverSideFiltering": false, @@ -166,7 +163,7 @@ "isDisabled": false, "key": "1b9j4l2c65", "isRequired": false, - "rightColumn": 18, + "rightColumn": 30, "widgetId": "vnoxjpwd8a", "isVisible": true, "version": 1, @@ -178,9 +175,8 @@ "widgetName": "MultiSelect1", "displayName": "MultiSelect", "iconSVG": "/static/media/icon.a3495809.svg", - "labelText": "Label", "topRow": 67, - "bottomRow": 75, + "bottomRow": 71, "parentRowSpace": 10, "type": "MULTI_SELECT_WIDGET_V2", "serverSideFiltering": false, @@ -211,7 +207,7 @@ "isDisabled": false, "key": "z8p14a1gb8", "isRequired": false, - "rightColumn": 18, + "rightColumn": 30, "widgetId": "c2j24v7j6b", "isVisible": true, "version": 1, diff --git a/app/client/cypress/integration/Smoke_TestSuite/ClientSideTests/FormWidgets/Widget_Popup_spec.js b/app/client/cypress/integration/Smoke_TestSuite/ClientSideTests/FormWidgets/Widget_Popup_spec.js index 279b8d6ed4..3022538781 100644 --- a/app/client/cypress/integration/Smoke_TestSuite/ClientSideTests/FormWidgets/Widget_Popup_spec.js +++ b/app/client/cypress/integration/Smoke_TestSuite/ClientSideTests/FormWidgets/Widget_Popup_spec.js @@ -12,16 +12,16 @@ describe("Dropdown Widget Functionality", function() { cy.get(formWidgetsPage.selectwidget) .find(widgetLocators.dropdownSingleSelect) .invoke("outerWidth") - .should("eq", 147.1875); - cy.get(formWidgetsPage.selectwidget) - .find(widgetLocators.dropdownSingleSelect) - .click({ - force: true, + .then((val) => { + cy.get(formWidgetsPage.selectwidget) + .find(widgetLocators.dropdownSingleSelect) + .click({ + force: true, + }); + cy.get(".select-popover-wrapper") + .invoke("outerWidth") + .should("eq", val); }); - cy.get(".select-popover-wrapper") - .invoke("outerWidth") - .should("eq", 147.1875); - // Menu Button cy.get(formWidgetsPage.menuButtonWidget) .find(widgetLocators.menuButton) @@ -40,42 +40,114 @@ describe("Dropdown Widget Functionality", function() { cy.get(formWidgetsPage.multiselectwidgetv2) .find(".rc-select-multiple") .invoke("width") - .should("eq", 147.1875); - cy.get(formWidgetsPage.multiselectwidgetv2) - .find(".rc-select-selection-search-input") - .first() - .focus({ force: true }) - .type("{uparrow}", { force: true }); - cy.get(".multi-select-dropdown") - .invoke("width") - .should("eq", 147); - + .then((inputWidth) => { + cy.get(formWidgetsPage.multiselectwidgetv2) + .find(".rc-select-selection-search-input") + .first() + .focus({ force: true }) + .type("{uparrow}", { force: true }); + cy.get(".multi-select-dropdown") + .invoke("width") + .then((dropdownWidth) => { + expect(Math.floor(inputWidth)).to.equal(Math.floor(dropdownWidth)); + }); + }); //Multi tree Select cy.get(formWidgetsPage.multiselecttreeWidget) .find(".rc-tree-select-multiple") .invoke("width") - .should("eq", 147.1875); - cy.get(formWidgetsPage.multiselecttreeWidget) - .find(".rc-tree-select-selection-search-input") - .first() - .focus({ force: true }) - .type("{uparrow}", { force: true }); - cy.get(".tree-multiselect-dropdown") - .invoke("outerWidth") - .should("eq", 147.1875); + .then((val) => { + cy.get(formWidgetsPage.multiselecttreeWidget) + .find(".rc-tree-select-selection-search-input") + .first() + .focus({ force: true }) + .type("{uparrow}", { force: true }); + cy.get(".tree-multiselect-dropdown") + .invoke("outerWidth") + .should("eq", val); + }); // Tree Select cy.get(formWidgetsPage.singleselecttreeWidget) .find(".rc-tree-select-single") .invoke("outerWidth") - .should("eq", 147.1875); - cy.get(formWidgetsPage.singleselecttreeWidget) - .find(".rc-tree-select-selection-search-input") - .first() - .focus({ force: true }) - .type("{uparrow}", { force: true }); - cy.get(".single-tree-select-dropdown") + .then((val) => { + cy.get(formWidgetsPage.singleselecttreeWidget) + .find(".rc-tree-select-selection-search-input") + .first() + .focus({ force: true }) + .type("{uparrow}", { force: true }); + cy.get(".single-tree-select-dropdown") + .invoke("outerWidth") + .should("eq", val); + }); + }); + + it("Verify dropdown width of Select widgets with Label", function() { + // Select + cy.openPropertyPane("selectwidget"); + cy.testJsontext("labeltext", "Label"); + cy.get(formWidgetsPage.selectwidget) + .find(widgetLocators.dropdownSingleSelect) .invoke("outerWidth") - .should("eq", 147.1875); + .then((val) => { + cy.get(formWidgetsPage.selectwidget) + .find(widgetLocators.dropdownSingleSelect) + .click({ + force: true, + }); + cy.get(".select-popover-wrapper") + .invoke("outerWidth") + .should("eq", val); + }); + + // MultiSelect + cy.openPropertyPane("multiselectwidgetv2"); + cy.testJsontext("labeltext", "Label"); + cy.get(formWidgetsPage.multiselectwidgetv2) + .find(".rc-select-multiple") + .invoke("width") + .then((val) => { + cy.get(formWidgetsPage.multiselectwidgetv2) + .find(".rc-select-selection-search-input") + .first() + .focus({ force: true }) + .type("{uparrow}", { force: true }); + cy.get(".multi-select-dropdown") + .invoke("width") + .should("eq", val); + }); + //Multi tree Select + cy.openPropertyPane("multiselecttreewidget"); + cy.testJsontext("labeltext", "Label"); + cy.get(formWidgetsPage.multiselecttreeWidget) + .find(".rc-tree-select-multiple") + .invoke("width") + .then((val) => { + cy.get(formWidgetsPage.multiselecttreeWidget) + .find(".rc-tree-select-selection-search-input") + .first() + .focus({ force: true }) + .type("{uparrow}", { force: true }); + cy.get(".tree-multiselect-dropdown") + .invoke("outerWidth") + .should("eq", val); + }); + // Tree Select + cy.openPropertyPane("singleselecttreewidget"); + cy.testJsontext("labeltext", "Label"); + cy.get(formWidgetsPage.singleselecttreeWidget) + .find(".rc-tree-select-single") + .invoke("outerWidth") + .then((val) => { + cy.get(formWidgetsPage.singleselecttreeWidget) + .find(".rc-tree-select-selection-search-input") + .first() + .focus({ force: true }) + .type("{uparrow}", { force: true }); + cy.get(".single-tree-select-dropdown") + .invoke("outerWidth") + .should("eq", val); + }); }); }); diff --git a/app/client/src/widgets/MultiSelectTreeWidget/component/index.styled.tsx b/app/client/src/widgets/MultiSelectTreeWidget/component/index.styled.tsx index 7cd3cbffa7..de0ae5159c 100644 --- a/app/client/src/widgets/MultiSelectTreeWidget/component/index.styled.tsx +++ b/app/client/src/widgets/MultiSelectTreeWidget/component/index.styled.tsx @@ -82,22 +82,9 @@ export const DropdownStyles = createGlobalStyle<{ id: string; }>` ${({ dropDownWidth, id }) => ` - .multiselecttree-popover-width-${id} { + &&.multiselecttree-popover-width-${id} { min-width: ${dropDownWidth}px !important; - - &.tree-multiselect-dropdown { - min-height: 100px; - position: absolute; - background: #fff; - width: auto; - border-radius: 0px; - margin-top: 5px; - background: white; - box-shadow: 0 6px 20px 0px rgba(0, 0, 0, 0.15) !important; - > div { - min-width: ${dropDownWidth}px; - } - } + width: ${dropDownWidth}px !important; } `} .rc-tree-select-dropdown-hidden { @@ -274,6 +261,15 @@ border: 1px solid #E8E8E8; } .tree-multiselect-dropdown { + min-height: 100px; + position: absolute; + background: #fff; + width: auto; + border-radius: 0px; + margin-top: 5px; + background: white; + box-shadow: 0 6px 20px 0px rgba(0, 0, 0, 0.15) !important; + ${CommonSelectFilterStyle} .rc-tree-select-item { font-size: 16px; diff --git a/app/client/src/widgets/MultiSelectTreeWidget/component/index.tsx b/app/client/src/widgets/MultiSelectTreeWidget/component/index.tsx index 06f8aca3c2..e7bd6e309c 100644 --- a/app/client/src/widgets/MultiSelectTreeWidget/component/index.tsx +++ b/app/client/src/widgets/MultiSelectTreeWidget/component/index.tsx @@ -25,7 +25,7 @@ import { TextSize, } from "constants/WidgetConstants"; import { Button, Classes, InputGroup } from "@blueprintjs/core"; -import { WidgetContainerDiff } from "widgets/WidgetUtils"; +import { labelMargin, WidgetContainerDiff } from "widgets/WidgetUtils"; import Icon from "components/ads/Icon"; import { Colors } from "constants/Colors"; @@ -122,6 +122,7 @@ function MultiTreeSelectComponent({ const _menu = useRef(null); const labelRef = useRef(null); const inputRef = useRef(null); + const [memoDropDownWidth, setMemoDropDownWidth] = useState(0); // treeDefaultExpandAll is uncontrolled after first render, // using this to force render to respond to changes in expandAll @@ -151,15 +152,20 @@ function MultiTreeSelectComponent({ setFilter(event.target.value); }, []); - const memoDropDownWidth = useMemo(() => { - if (compactMode && labelRef.current) { - const labelWidth = labelRef.current.clientWidth; - const widthDiff = dropDownWidth - labelWidth; - return widthDiff > dropDownWidth ? widthDiff : dropDownWidth; - } + useEffect(() => { const parentWidth = width - WidgetContainerDiff; - return parentWidth > dropDownWidth ? parentWidth : dropDownWidth; - }, [compactMode, dropDownWidth, width, labelRef.current]); + if (compactMode && labelRef.current) { + const labelWidth = labelRef.current.getBoundingClientRect().width; + const widthDiff = parentWidth - labelWidth - labelMargin; + setMemoDropDownWidth( + widthDiff > dropDownWidth ? widthDiff : dropDownWidth, + ); + return; + } + setMemoDropDownWidth( + parentWidth > dropDownWidth ? parentWidth : dropDownWidth, + ); + }, [compactMode, dropDownWidth, width, labelText]); const dropdownRender = useCallback( ( menu: React.ReactElement>, diff --git a/app/client/src/widgets/MultiSelectWidgetV2/component/index.styled.tsx b/app/client/src/widgets/MultiSelectWidgetV2/component/index.styled.tsx index 394c234c43..affcb60b53 100644 --- a/app/client/src/widgets/MultiSelectWidgetV2/component/index.styled.tsx +++ b/app/client/src/widgets/MultiSelectWidgetV2/component/index.styled.tsx @@ -158,37 +158,7 @@ export const DropdownStyles = createGlobalStyle<{ ${({ dropDownWidth, id }) => ` .multiselect-popover-width-${id} { width: ${dropDownWidth}px !important; - - &.rc-select-dropdown-hidden { - display: none !important; - } - &.multi-select-dropdown { - min-height: 100px; - position: absolute; - background: #fff; - width: auto; - border-radius: 0px; - margin-top: 5px; - background: white; - box-shadow: 0 6px 20px 0px rgba(0, 0, 0, 0.15) !important; - overflow-x: scroll; - > div { - min-width: ${dropDownWidth}px; - } - .rc-select-item { - font-size: 14px; - padding: 5px 16px; - align-items: center; - cursor: pointer; - width: 100%; - height: 38px; - } - .rc-select-item-option-state { - .bp3-control.bp3-checkbox { - margin-bottom: 0; - } - } - } + min-width: ${dropDownWidth}px !important; } `} .rc-select-dropdown-hidden { @@ -315,9 +285,30 @@ ${({ dropDownWidth, id }) => ` animation-play-state: running; } .multi-select-dropdown { + min-height: 100px; + position: absolute; + background: #fff; + width: auto; + border-radius: 0px; + margin-top: 5px; + background: white; + box-shadow: 0 6px 20px 0px rgba(0, 0, 0, 0.15) !important; + overflow-x: scroll; ${CommonSelectFilterStyle} + .rc-select-item { + font-size: 14px; + padding: 5px 16px; + align-items: center; + cursor: pointer; + width: 100%; + height: 38px; + } + .rc-select-item-option-state { + .bp3-control.bp3-checkbox { + margin-bottom: 0; + } + } } - `; export const MultiSelectContainer = styled.div<{ diff --git a/app/client/src/widgets/MultiSelectWidgetV2/component/index.tsx b/app/client/src/widgets/MultiSelectWidgetV2/component/index.tsx index 0e59c320b9..c7f459303a 100644 --- a/app/client/src/widgets/MultiSelectWidgetV2/component/index.tsx +++ b/app/client/src/widgets/MultiSelectWidgetV2/component/index.tsx @@ -26,14 +26,13 @@ import { } from "constants/WidgetConstants"; import Icon from "components/ads/Icon"; import { Button, Classes, InputGroup } from "@blueprintjs/core"; -import { WidgetContainerDiff } from "widgets/WidgetUtils"; +import { labelMargin, WidgetContainerDiff } from "widgets/WidgetUtils"; import { Colors } from "constants/Colors"; import { uniqBy } from "lodash"; const menuItemSelectedIcon = (props: { isSelected: boolean }) => { return ; }; - export interface MultiSelectProps extends Required< Pick< @@ -196,19 +195,19 @@ function MultiSelectComponent({ serverSideFiltering ? [options] : [filter, options], ); useEffect(() => { + const parentWidth = width - WidgetContainerDiff; if (compactMode && labelRef.current) { - const labelWidth = labelRef.current.clientWidth; - const widthDiff = dropDownWidth - labelWidth; + const labelWidth = labelRef.current.getBoundingClientRect().width; + const widthDiff = parentWidth - labelWidth - labelMargin; setMemoDropDownWidth( widthDiff > dropDownWidth ? widthDiff : dropDownWidth, ); return; } - const parentWidth = width - WidgetContainerDiff; setMemoDropDownWidth( parentWidth > dropDownWidth ? parentWidth : dropDownWidth, ); - }, [compactMode, dropDownWidth, width]); + }, [compactMode, dropDownWidth, width, labelText]); const onQueryChange = useCallback((event: ChangeEvent) => { event.stopPropagation(); diff --git a/app/client/src/widgets/MultiSelectWidgetV2/widget/index.tsx b/app/client/src/widgets/MultiSelectWidgetV2/widget/index.tsx index cb05cce6c7..f2b7c96abb 100644 --- a/app/client/src/widgets/MultiSelectWidgetV2/widget/index.tsx +++ b/app/client/src/widgets/MultiSelectWidgetV2/widget/index.tsx @@ -436,7 +436,7 @@ class MultiSelectWidget extends BaseWidget< getPageView() { const options = isArray(this.props.options) ? this.props.options : []; - const dropDownWidth = MinimumPopupRows * this.props.parentColumnSpace; + const minDropDownWidth = MinimumPopupRows * this.props.parentColumnSpace; const { componentWidth } = this.getComponentDimensions(); const values: LabelValueType[] = this.props.selectedOptions ? this.props.selectedOptions.map((o) => @@ -456,7 +456,7 @@ class MultiSelectWidget extends BaseWidget< ) } disabled={this.props.isDisabled ?? false} - dropDownWidth={dropDownWidth} + dropDownWidth={minDropDownWidth} dropdownStyle={{ zIndex: Layers.dropdownModalWidget, }} diff --git a/app/client/src/widgets/SelectWidget/component/index.tsx b/app/client/src/widgets/SelectWidget/component/index.tsx index 5e34bee253..6503c77714 100644 --- a/app/client/src/widgets/SelectWidget/component/index.tsx +++ b/app/client/src/widgets/SelectWidget/component/index.tsx @@ -22,6 +22,7 @@ import { import Fuse from "fuse.js"; import { WidgetContainerDiff } from "widgets/WidgetUtils"; import SelectButton from "./SelectButton"; +import { labelMargin } from "../../WidgetUtils"; const FUSE_OPTIONS = { shouldSort: true, @@ -218,18 +219,16 @@ class SelectComponent extends React.Component< getDropdownWidth = () => { const parentWidth = this.props.width - WidgetContainerDiff; - const dropDownWidth = - parentWidth > this.props.dropDownWidth - ? parentWidth - : this.props.dropDownWidth; if (this.props.compactMode && this.labelRef.current) { - const labelWidth = this.labelRef.current.clientWidth; - const widthDiff = dropDownWidth - labelWidth; + const labelWidth = this.labelRef.current.getBoundingClientRect().width; + const widthDiff = parentWidth - labelWidth - labelMargin; return widthDiff > this.props.dropDownWidth ? widthDiff : this.props.dropDownWidth; } - return dropDownWidth; + return parentWidth > this.props.dropDownWidth + ? parentWidth + : this.props.dropDownWidth; }; render() { diff --git a/app/client/src/widgets/SingleSelectTreeWidget/component/index.styled.tsx b/app/client/src/widgets/SingleSelectTreeWidget/component/index.styled.tsx index a4b6950a4b..341116173d 100644 --- a/app/client/src/widgets/SingleSelectTreeWidget/component/index.styled.tsx +++ b/app/client/src/widgets/SingleSelectTreeWidget/component/index.styled.tsx @@ -82,8 +82,9 @@ export const DropdownStyles = createGlobalStyle<{ id: string; }>` ${({ dropDownWidth, id }) => ` - .treeselect-popover-width-${id} { + &&.treeselect-popover-width-${id} { min-width: ${dropDownWidth}px !important; + width: ${dropDownWidth}px !important; } `} .rc-tree-select-dropdown-hidden { diff --git a/app/client/src/widgets/SingleSelectTreeWidget/component/index.tsx b/app/client/src/widgets/SingleSelectTreeWidget/component/index.tsx index d8250ba824..a3df150ca6 100644 --- a/app/client/src/widgets/SingleSelectTreeWidget/component/index.tsx +++ b/app/client/src/widgets/SingleSelectTreeWidget/component/index.tsx @@ -24,7 +24,7 @@ import { TextSize, } from "constants/WidgetConstants"; import { Button, Classes, InputGroup } from "@blueprintjs/core"; -import { WidgetContainerDiff } from "widgets/WidgetUtils"; +import { labelMargin, WidgetContainerDiff } from "widgets/WidgetUtils"; import Icon from "components/ads/Icon"; import { Colors } from "constants/Colors"; export interface TreeSelectProps @@ -118,6 +118,7 @@ function SingleSelectTreeComponent({ const labelRef = useRef(null); const _menu = useRef(null); const inputRef = useRef(null); + const [memoDropDownWidth, setMemoDropDownWidth] = useState(0); // treeDefaultExpandAll is uncontrolled after first render, // using this to force render to respond to changes in expandAll @@ -152,15 +153,20 @@ function SingleSelectTreeComponent({ setFilter(event.target.value); }, []); - const memoDropDownWidth = useMemo(() => { - if (compactMode && labelRef.current) { - const labelWidth = labelRef.current.clientWidth; - const widthDiff = dropDownWidth - labelWidth; - return widthDiff > dropDownWidth ? widthDiff : dropDownWidth; - } + useEffect(() => { const parentWidth = width - WidgetContainerDiff; - return parentWidth > dropDownWidth ? parentWidth : dropDownWidth; - }, [compactMode, dropDownWidth, width, labelRef.current]); + if (compactMode && labelRef.current) { + const labelWidth = labelRef.current.getBoundingClientRect().width; + const widthDiff = parentWidth - labelWidth - labelMargin; + setMemoDropDownWidth( + widthDiff > dropDownWidth ? widthDiff : dropDownWidth, + ); + return; + } + setMemoDropDownWidth( + parentWidth > dropDownWidth ? parentWidth : dropDownWidth, + ); + }, [compactMode, dropDownWidth, width, labelText]); const dropdownRender = useCallback( ( diff --git a/app/client/src/widgets/WidgetUtils.ts b/app/client/src/widgets/WidgetUtils.ts index 57841faa48..43969fe5e4 100644 --- a/app/client/src/widgets/WidgetUtils.ts +++ b/app/client/src/widgets/WidgetUtils.ts @@ -74,6 +74,8 @@ export const hexToRgb = ( }; // Padding between PositionContainer and Widget export const WidgetContainerDiff = 8; +// MArgin between Label and Input +export const labelMargin = 5; export const hexToRgba = (color: string, alpha: number) => { const value = hexToRgb(color); return `rgba(${value.r}, ${value.g}, ${value.b}, ${alpha});`;