* feat: When there are multiple input widgets with different label lengths then the input box looks misaligned -- Create a new property control for a label position -- Create a new property control for a label alignment -- Prototype a label section for Input widget * feat: When there are multiple input widgets with different label lengths then the input box looks misaligned -- Add a property, labelWidth in the property pane * feat: Controls for labels in widgets to align the widgets in forms and other places -- Input widget: Implement all the requirements in case its type is Text * feat: Controls for labels in widgets to align the widgets in forms and other places -- Adapt the functionalty on other types of the input widget * feat: Controls for labels in widgets to align the widgets in forms and other places -- Add label functionalities into DropdownWidget -- Clean up for the input widget and DRY * feat: Controls for labels in widgets to align the widgets in forms and other places -- Add label functionalities into MultiSelectWidget -- Eliminate unnecessary component prop, columns * feat: Controls for labels in widgets to align the widgets in forms and other places -- Add label functionalties into Tree Select widget -- Add styles for alignment between lable and input control over the widgets * feat: Controls for labels in widgets to align the widgets in forms and other places -- Add label functionalities into MultiSelectTreeWidget * feat: Controls for labels in widgets to align the widgets in forms and other places -- Introduce label functionalities into DatePickerWidget2 -- Use width instead of columns prop in InputWidget * feat: Controls for labels in widgets to align the widgets in forms and other places -- Apply label functionalities into RichTextEditorWidget -- Eliminate compactMode from StyledLabel * feat: Controls for labels in widgets to align the widgets in forms and other places -- Apply label functionalities into CheckboxGroupWidget * feat: Controls for labels in widgets to align the widgets in forms and other places -- Apply label functionalities into SwitchGroupWidget * feat: Controls for labels in widgets to align the widgets in forms and other places -- Reimplement switch group for the correct meaning of right alignment * feat: Controls for labels in widgets to align the widgets in forms and other places -- Apply label functionalities into RadioGroupWidget -- Add new properties, alignment and inline for consistency * feat: Controls for labels in widgets to align the widgets in forms and other places -- Adjust cols and rows for RadioGroupWidget * feat: Controls for labels in widgets to align the widgets in forms and other places -- Eliminate unused StyledRadioProps * feat: Controls for labels in widgets to align the widgets in forms and other places -- Complete first MVP of enhanced SwitchGroupWidget * feat: Controls for labels in widgets to align the widgets in forms and other places -- Complete the first MVP of enhanced RadioGroupWidget -- Eliminate unused StyledSwitch component for SwitchGroupWidget * feat: Controls for labels in widgets to align the widgets in forms and other places -- Add min-height, align-self rules for LabelContainer * feat: Controls for labels in widgets to align the widgets in forms and other places -- Use original label property for RadioGroupWidget -- Add a migration for adding isInline and alignment properties for RadioGroupWidget * feat: Controls for labels in widgets to align the widgets in forms and other places -- Update version to latest one in DSLMigrationsUtils.test.ts * fix failing jest test * feat: Controls for labels in widgets to align the widgets in forms and other places -- Reimplement label functionalities on BaseInputWidget, InputWidgetV2, CurrencyInputWidget, PhoneInputWidget * feat: Controls for labels in widgets to align the widgets in forms and other places -- Eliminate unused imports in DSLMigrationsUtils * feat: Controls for labels in widgets to align the widgets in forms and other places -- Fix on the label related test case which is failed in Input_spec.js * feat: Controls for labels in widgets to align the widgets in forms and other places -- Fix on #10119: The label text truncates on resizing the input widget * feat: Controls for labels in widgets to align the widgets in forms and other places -- Fix scroll issue when shrink with MultiSelectWidget and MultiSelectTreeWidget * fix: Widget Popup test * feat: Controls for labels in widgets to align the widgets in forms and other places -- Reimplement width and alginment features on the level of label element -- Prevent actual inputs from DropdownWidget, MultiSelectWidget, SingleSelectTreeWidget, MultiSelectTreeWidget from overflow when resizing -- Enable label feature on a RadioGroupWidget * feat: Controls for labels in widgets to align the widgets in forms and other places -- Set label container's default width to 33% when width is not set * feat: Controls for labels in widgets to align the widgets in forms and other places -- Fix crash issue when labelWidth is filled by non-numeric value, eliminating passing NaN as its value * feat: Controls for labels in widgets to align the widgets in forms and other places -- Set flex-grow to zero on input types other than TEXT * feat: Controls for labels in widgets to align the widgets in forms and other places -- Implement label features on newly created MultiSelectWidgetV2 * feat: Controls for labels in widgets to align the widgets in forms and other places -- Eliminate LabelPositionTypes, directly using enum LabelPosition -- Add a comment for a constant LABEL_MAX_WIDTH_RATE -- Directly import React for LabelAlignmentOptionsControl -- Remove unnecessary constructor for LabelAlignmentOptionsControl -- Define handleAlign instance method as a higher-order function -- Only migrate alignment property for RadioGroupWidget -- Use Object.hasOwnProperty instead of in operator * feat: Controls for labels in widgets to align the widgets in forms and other places -- Migrate alignment property of RadioGroupWidget in case of currentDSL.version is 52 * feat: Controls for labels in widgets to align the widgets in forms and other places -- Revert currentDSL.version to 52 * feat: Controls for labels in widgets to align the widgets in forms and other places -- Add a Jest test case for RadioGroupWidget's alignment property migration * feat: Controls for labels in widgets to align the widgets in forms and other places -- Replace all nested ternary operators with if statements * feat: Controls for labels in widgets to align the widgets in forms and other places -- Implement label feature on new version of SelectWidget -- Add Cypress tests for widgets' label section * feat: Controls for labels in widgets to align the widgets in forms and other places -- Refactor code for BaseInputWidget * feat: Controls for labels in widgets to align the widgets in forms and other places -- Change CSS selector for step buttons for Numeric BaseInputWidget -- Directly use migrateRadioGroupAlignmentProperty migration function without using transformDSL * feat: Controls for labels in widgets to align the widgets in forms and other places -- Fix on typo about migrateRadioGroupAlignmentProperty * feat: Controls for labels in widgets to align the widgets in forms and other places -- Add data-testid attributes for Cypress selectors * feat: Deprecate form button widget -- Assert flex-direction to row in CheckboxGroup_spec.js * feat: Controls for labels in widgets to align the widgets in forms and other places -- Add a missing data-testid for SelectWidget * feat: Controls for labels in widgets to align the widgets in forms and other places -- Fix on failed test cases: CheckboxGroup_spec, DatePicker_2_spec, MultiSelectWidgetV2 * fix: Select popup DSL * feat: Controls for labels in widgets to align the widgets in forms and other places -- Create a new property control, NumericInputControl -- Replace all the label properties with the newly created controls * feat: Controls for labels in widgets to align the widgets in forms and other places -- Create a new Cypress command, checkLabelWidth and apply to all related test cases -- Increase width in checkboxgroupDsl.json -- Rename className for label in MultiSelectWidgetV2 * feat: Controls for labels in widgets to align the widgets in forms and other places -- Reimplement the tooltip feature for labels -- Add missing props for labels in DateField, MultiSelectField, RadioGroupField, SelectField fields for JSONFormWidget * feat: Controls for labels in widgets to align the widgets in forms and other places -- Refactor property controls, including LabelPositionOptionsControl, LabelAlignmentOptionsControl, NumericInputControl to keep consistency -- Apply default values into label section * feat: Controls for labels in widgets to align the widgets in forms and other places -- Extract the label related parts from the various widgets as an independent component * feat: Controls for labels in widgets to align the widgets in forms and other places -- Eliminate TypeScript any type from BaseInputComponent * feat: Controls for labels in widgets to align the widgets in forms and other places -- Change labelPosition property type to DROP_DOWN -- Modify LabelAlignmentOptionsControl to use ButtonTabComponent * feat: Controls for labels in widgets to align the widgets in forms and other places -- Define getLabelWidth method into BaseWidget -- Extract the common CSS rules for the widget containers -- Revert rows and columns for SwitchGroupWidget * feat: Controls for labels in widgets to align the widgets in forms and other places -- Fix on the failed test case in DSLMigrationsUtils.test.ts * feat: Controls for labels in widgets to align the widgets in forms and other places -- Fix on overflow issue on CheckboxGroupWidget -- Create a distinctive spec file for label feature -- Eliminate the redundant label specs with the relevant widgets * feat: Controls for labels in widgets to align the widgets in forms and other places -- Delete unnecessary files, including Select_spec.js, LabelButton.tsx and LabelPositionOptionsControl.tsx -- Revise wrong comment for checkLabelForWidget Cypress command * feat: Controls for labels in widgets to align the widgets in forms and other places -- Do not set the label width only if its value is 0 -- Clean up the component for DatePickerWidget2 * feat: Controls for labels in widgets to align the widgets in forms and other places -- Eliminate unused imports in DatePickerWidget2 * feat: Controls for labels in widgets to align the widgets in forms and other places -- Make RadioGroupWidget's layout flexible in all modes * feat: Controls for labels in widgets to align the widgets in forms and other places -- Fix on Cypress test case for RadioGroupWidget in Widgets_Labels_spec -- Change Cypress commands, including addAction, addSuccessMessage, enterActionValue to accept parentSelector * feat: Controls for labels in widgets to align the widgets in forms and other places -- Change getLabelWidth method to not have any argument -- Define some constants for label numbers -- Extract the common styles for SwitchGroupWidget and RadioGroupWidget * feat: Controls for labels in widgets to align the widgets in forms and other places -- Refactor some constants * feat: Controls for labels in widgets to align the widgets in forms and other places -- Eliminate unused width prop from RadioGroupWidget -- Get labelWidth from getLabelWidth * feat: Controls for labels in widgets to align the widgets in forms and other places -- Eliminate the min-height restriction on a label -- Eliminate the scroll on the earlier InputWidgetV2 which was not in compact mode * feat: Controls for labels in widgets to align the widgets in forms and other places -- Add one more condition checking if the current input type is text * feat: Controls for labels in widgets to align the widgets in forms and other places -- Extract common code base for MultiSelectTreeWidget and MultiSelectWidgetV2 -- Apply a few CSS fixes on the scrollbar issue select related widgets * feat: Controls for labels in widgets to align the widgets in forms and other places -- Apply some tweaks for earlier widgets with labels so as not to be broken UX * feat: Controls for labels in widgets to align the widgets in forms and other places -- Fix on the failed Cypress test case in Widget_Popup_spec.js * feat: Controls for labels in widgets to align the widgets in forms and other places -- Add constants, LABEL_DEFAULT_WIDTH_RATE, SELECT_DEFAULT_HEIGHT, LABEL_MARGIN_OLD_SELECT * feat: Controls for labels in widgets to align the widgets in forms and other places -- Increase the widths of CheckboxGroupWidget and SwitchGroupWidget * feat: Controls for labels in widgets to align the widgets in forms and other places -- Set the font size to 14px for NumericInputControl Co-authored-by: ohansFavour <fohanekwu@gmail.com> Co-authored-by: Tolulope Adetula <31691737+Tooluloope@users.noreply.github.com>
301 lines
8.1 KiB
TypeScript
301 lines
8.1 KiB
TypeScript
import React, {
|
|
ChangeEvent,
|
|
ReactNode,
|
|
useCallback,
|
|
useEffect,
|
|
useMemo,
|
|
useRef,
|
|
useState,
|
|
} from "react";
|
|
import TreeSelect, { TreeSelectProps as SelectProps } from "rc-tree-select";
|
|
import {
|
|
TreeSelectContainer,
|
|
DropdownStyles,
|
|
StyledIcon,
|
|
InputContainer,
|
|
} from "./index.styled";
|
|
import "rc-tree-select/assets/index.less";
|
|
import { DefaultValueType } from "rc-tree-select/lib/interface";
|
|
import { TreeNodeProps } from "rc-tree-select/lib/TreeNode";
|
|
import { CheckedStrategy } from "rc-tree-select/lib/utils/strategyUtil";
|
|
import {
|
|
CANVAS_CLASSNAME,
|
|
MODAL_PORTAL_CLASSNAME,
|
|
TextSize,
|
|
} from "constants/WidgetConstants";
|
|
import { Alignment, Button, Classes, InputGroup } from "@blueprintjs/core";
|
|
import { labelMargin, WidgetContainerDiff } from "widgets/WidgetUtils";
|
|
import Icon from "components/ads/Icon";
|
|
import { Colors } from "constants/Colors";
|
|
import { LabelPosition } from "components/constants";
|
|
import LabelWithTooltip from "components/ads/LabelWithTooltip";
|
|
|
|
export interface TreeSelectProps
|
|
extends Required<
|
|
Pick<
|
|
SelectProps,
|
|
| "disabled"
|
|
| "placeholder"
|
|
| "loading"
|
|
| "dropdownStyle"
|
|
| "allowClear"
|
|
| "options"
|
|
>
|
|
> {
|
|
value?: DefaultValueType;
|
|
onChange: (value?: DefaultValueType, labelList?: ReactNode[]) => void;
|
|
expandAll: boolean;
|
|
mode: CheckedStrategy;
|
|
labelText: string;
|
|
labelAlignment?: Alignment;
|
|
labelPosition?: LabelPosition;
|
|
labelWidth?: number;
|
|
labelTextColor?: string;
|
|
labelTextSize?: TextSize;
|
|
labelStyle?: string;
|
|
compactMode: boolean;
|
|
dropDownWidth: number;
|
|
width: number;
|
|
isValid: boolean;
|
|
filterText?: string;
|
|
widgetId: string;
|
|
isFilterable: boolean;
|
|
}
|
|
|
|
const getSvg = (expanded: boolean) => (
|
|
<i
|
|
style={{
|
|
cursor: "pointer",
|
|
backgroundColor: "transparent",
|
|
display: "inline-flex",
|
|
width: "14px",
|
|
height: "100%",
|
|
}}
|
|
>
|
|
<StyledIcon
|
|
className="switcher-icon"
|
|
expanded={expanded}
|
|
fillColor={Colors.GREY_10}
|
|
name="dropdown"
|
|
/>
|
|
</i>
|
|
);
|
|
|
|
const switcherIcon = (treeNode: TreeNodeProps) => {
|
|
if (treeNode.isLeaf) {
|
|
return (
|
|
<i
|
|
style={{
|
|
cursor: "pointer",
|
|
backgroundColor: "white",
|
|
display: "inline-flex",
|
|
width: "14px",
|
|
}}
|
|
/>
|
|
);
|
|
}
|
|
return getSvg(treeNode.expanded);
|
|
};
|
|
const FOCUS_TIMEOUT = 500;
|
|
|
|
function MultiTreeSelectComponent({
|
|
allowClear,
|
|
compactMode,
|
|
disabled,
|
|
dropdownStyle,
|
|
dropDownWidth,
|
|
expandAll,
|
|
filterText,
|
|
isFilterable,
|
|
isValid,
|
|
labelAlignment,
|
|
labelPosition,
|
|
labelStyle,
|
|
labelText,
|
|
labelTextColor,
|
|
labelTextSize,
|
|
labelWidth,
|
|
loading,
|
|
mode,
|
|
onChange,
|
|
options,
|
|
placeholder,
|
|
value,
|
|
widgetId,
|
|
width,
|
|
}: TreeSelectProps): JSX.Element {
|
|
const [key, setKey] = useState(Math.random());
|
|
const [filter, setFilter] = useState(filterText ?? "");
|
|
|
|
const _menu = useRef<HTMLElement | null>(null);
|
|
const labelRef = useRef<HTMLDivElement>(null);
|
|
const inputRef = useRef<HTMLInputElement>(null);
|
|
const [memoDropDownWidth, setMemoDropDownWidth] = useState(0);
|
|
|
|
// treeDefaultExpandAll is uncontrolled after first render,
|
|
// using this to force render to respond to changes in expandAll
|
|
useEffect(() => {
|
|
setKey(Math.random());
|
|
}, [expandAll]);
|
|
|
|
const clearButton = useMemo(
|
|
() =>
|
|
filter ? (
|
|
<Button icon="cross" minimal onClick={() => setFilter("")} />
|
|
) : null,
|
|
[filter],
|
|
);
|
|
|
|
const getDropdownPosition = useCallback(() => {
|
|
const node = _menu.current;
|
|
if (Boolean(node?.closest(`.${MODAL_PORTAL_CLASSNAME}`))) {
|
|
return document.querySelector(
|
|
`.${MODAL_PORTAL_CLASSNAME}`,
|
|
) as HTMLElement;
|
|
}
|
|
return document.querySelector(`.${CANVAS_CLASSNAME}`) as HTMLElement;
|
|
}, []);
|
|
const onQueryChange = useCallback((event: ChangeEvent<HTMLInputElement>) => {
|
|
event.stopPropagation();
|
|
setFilter(event.target.value);
|
|
}, []);
|
|
|
|
useEffect(() => {
|
|
const parentWidth = width - WidgetContainerDiff;
|
|
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<any, string | React.JSXElementConstructor<any>>,
|
|
) => (
|
|
<>
|
|
{isFilterable ? (
|
|
<InputGroup
|
|
autoFocus
|
|
inputRef={inputRef}
|
|
leftIcon="search"
|
|
onChange={onQueryChange}
|
|
onKeyDown={(e) => e.stopPropagation()}
|
|
placeholder="Filter..."
|
|
rightElement={clearButton as JSX.Element}
|
|
small
|
|
type="text"
|
|
value={filter}
|
|
/>
|
|
) : null}
|
|
<div className={`${loading ? Classes.SKELETON : ""}`}>{menu}</div>
|
|
</>
|
|
),
|
|
[loading, isFilterable, filter, onQueryChange],
|
|
);
|
|
|
|
const onOpen = useCallback((open: boolean) => {
|
|
if (open) {
|
|
setTimeout(() => inputRef.current?.focus(), FOCUS_TIMEOUT);
|
|
}
|
|
}, []);
|
|
|
|
const onClear = useCallback(() => onChange([], []), []);
|
|
|
|
return (
|
|
<TreeSelectContainer
|
|
allowClear={allowClear}
|
|
compactMode={compactMode}
|
|
data-testid="multitreeselect-container"
|
|
isValid={isValid}
|
|
labelPosition={labelPosition}
|
|
ref={_menu as React.RefObject<HTMLDivElement>}
|
|
>
|
|
<DropdownStyles dropDownWidth={memoDropDownWidth} id={widgetId} />
|
|
{labelText && (
|
|
<LabelWithTooltip
|
|
alignment={labelAlignment}
|
|
className={`multitree-select-label`}
|
|
color={labelTextColor}
|
|
compact={compactMode}
|
|
disabled={disabled}
|
|
fontSize={labelTextSize}
|
|
fontStyle={labelStyle}
|
|
loading={loading}
|
|
position={labelPosition}
|
|
ref={labelRef}
|
|
text={labelText}
|
|
width={labelWidth}
|
|
/>
|
|
)}
|
|
<InputContainer compactMode={compactMode} labelPosition={labelPosition}>
|
|
<TreeSelect
|
|
allowClear={allowClear}
|
|
animation="slide-up"
|
|
choiceTransitionName="rc-tree-select-selection__choice-zoom"
|
|
className="rc-tree-select"
|
|
clearIcon={
|
|
<Icon
|
|
className="clear-icon"
|
|
fillColor={Colors.GREY_10}
|
|
name="close-x"
|
|
/>
|
|
}
|
|
disabled={disabled}
|
|
dropdownClassName={`tree-multiselect-dropdown multiselecttree-popover-width-${widgetId}`}
|
|
dropdownRender={dropdownRender}
|
|
dropdownStyle={dropdownStyle}
|
|
filterTreeNode
|
|
getPopupContainer={getDropdownPosition}
|
|
inputIcon={
|
|
<Icon
|
|
className="dropdown-icon"
|
|
fillColor={disabled ? Colors.GREY_7 : Colors.GREY_10}
|
|
name="dropdown"
|
|
/>
|
|
}
|
|
key={key}
|
|
loading={loading}
|
|
maxTagCount={"responsive"}
|
|
maxTagPlaceholder={(e) => `+${e.length} more`}
|
|
multiple
|
|
notFoundContent="No Results Found"
|
|
onChange={onChange}
|
|
onClear={onClear}
|
|
onDropdownVisibleChange={onOpen}
|
|
placeholder={placeholder}
|
|
removeIcon={
|
|
<Icon
|
|
className="remove-icon"
|
|
fillColor={Colors.GREY_10}
|
|
name="close-x"
|
|
/>
|
|
}
|
|
searchValue={filter}
|
|
showArrow
|
|
showCheckedStrategy={mode}
|
|
showSearch={false}
|
|
style={{ width: "100%" }}
|
|
switcherIcon={switcherIcon}
|
|
transitionName="rc-tree-select-dropdown-slide-up"
|
|
treeCheckable={
|
|
<span className={`rc-tree-select-tree-checkbox-inner`} />
|
|
}
|
|
treeData={options}
|
|
treeDefaultExpandAll={expandAll}
|
|
treeIcon
|
|
treeNodeFilterProp="label"
|
|
value={value}
|
|
/>
|
|
</InputContainer>
|
|
</TreeSelectContainer>
|
|
);
|
|
}
|
|
|
|
export default MultiTreeSelectComponent;
|