Skip to content

Improve dropdown filter 2.32 #1748

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 14 commits into
base: lts/data-widgets/2.32
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,6 @@ $root: ".widget-dropdown-filter";
&-clear {
@include btn-with-cross;
align-items: center;
align-self: center;
display: flex;
flex-shrink: 0;
justify-self: end;
Expand All @@ -150,6 +149,11 @@ $root: ".widget-dropdown-filter";
&:has(+ #{$root}-toggle) {
border-inline-end: 1px solid var(--gray, #787d87);
}

&:focus {
border-radius: 2px;
outline: 2px solid var(--brand-primary, $brand-primary);
}
}

&-state-icon {
Expand Down Expand Up @@ -262,9 +266,13 @@ $root: ".widget-dropdown-filter";
justify-content: center;
line-height: 1.334;
padding: var(--wdf-tag-padding);
margin: var(--spacing-smallest, 2px);
&:focus-visible {
outline: var(--brand-primary, #264ae5) auto 1px;
}
&:focus {
background-color: var(--color-primary-light, $color-primary-light);
}
}

#{$root}-input {
Expand All @@ -273,6 +281,14 @@ $root: ".widget-dropdown-filter";
width: initial;
}

&:not(:focus-within):not([data-empty]) {
#{$root}-input {
opacity: 0;
flex-shrink: 1;
min-width: 1px;
}
}

#{$root}-clear {
border-color: transparent;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ export function getProperties(values: DatagridDropdownFilterPreviewProps, defaul
if (values.filterable) {
hidePropertyIn(defaultProperties, values, "clearable");
hidePropertyIn(defaultProperties, values, "emptyOptionCaption");
} else {
hidePropertyIn(defaultProperties, values, "filterInputPlaceholderCaption");
}

if (!showSelectedItemsStyle) {
Expand Down Expand Up @@ -54,7 +56,7 @@ export const getPreview = (values: DatagridDropdownFilterPreviewProps, isDarkMod
text({
fontColor: palette.text.secondary,
italic: true
})(values.emptyOptionCaption || " ")
})(values.emptySelectionCaption || " ")
],
grow: 1
} as ContainerProps,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ function Preview(props: DatagridDropdownFilterPreviewProps): ReactElement {
options={[]}
empty={!props.clearable}
clearable={props.clearable}
showCheckboxes={false}
value={getPreviewValue(props)}
onClear={noop}
useSelectProps={() => ({ items: [] })}
Expand All @@ -25,11 +26,7 @@ const noop = (): void => {};

function getPreviewValue(props: DatagridDropdownFilterPreviewProps): string {
let value = props.defaultValue;
if (!props.filterable) {
value ||= props.emptyOptionCaption || "Select";
} else {
value ||= "Search";
}
value ||= props.emptySelectionCaption || (props.filterable ? "Search" : "Select");
return value;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,9 @@ function Container(props: DatagridDropdownFilterContainerProps & Select_FilterAP
parentChannelName: props.parentChannelName,
name: props.name,
multiselect: props.multiSelect,
emptyCaption: props.emptyOptionCaption?.value,
emptySelectionCaption: props.emptySelectionCaption?.value ?? "",
emptyOptionCaption: props.emptyOptionCaption?.value ?? "",
placeholder: props.filterInputPlaceholderCaption?.value ?? "",
defaultValue: props.defaultValue?.value,
filterable: props.filterable,
selectionMethod: props.selectionMethod,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -83,13 +83,23 @@
</property>
</propertyGroup>
</propertyGroup>
<propertyGroup caption="Accessibility">
<propertyGroup caption="Advanced">
<propertyGroup caption="Accessibility">
<property key="ariaLabel" type="textTemplate" required="false">
<caption>Input caption</caption>
<description>Assistive technology will read this upon reaching the input element.</description>
</property>
</propertyGroup>
<propertyGroup caption="Texts">
<property key="emptySelectionCaption" type="textTemplate" required="false">
<caption>Empty selection caption</caption>
<description>This text is shown if no options are selected. For example 'No options are selected' or 'Select color'.</description>
</property>
<property key="filterInputPlaceholderCaption" type="textTemplate" required="false">
<caption>Filter input placeholder</caption>
<description>This text is shown as placeholder for filterable filters. For example 'type to search'.</description>
</property>
</propertyGroup>
</propertyGroup>
</properties>
</widget>
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,9 @@ export interface RefFilterContainerProps {
ariaLabel?: string;
className?: string;
defaultValue?: string;
emptyCaption?: string;
emptyOptionCaption: string;
emptySelectionCaption: string;
placeholder: string;
filterStore: RefFilterStore;
multiselect: boolean;
name: string;
Expand Down Expand Up @@ -80,6 +82,7 @@ const ComboboxWidget = observer(function ComboboxWidget(props: RefFilterContaine
<Combobox
options={ctrl2.options}
inputPlaceholder={ctrl2.inputPlaceholder}
emptyCaption={ctrl2.emptyCaption}
useComboboxProps={ctrl2.useComboboxProps}
onClear={ctrl2.handleClear}
onFocus={ctrl2.handleFocus}
Expand Down Expand Up @@ -109,6 +112,7 @@ const TagPickerWidget = observer(function TagPickerWidget(props: RefFilterContai
onFocus={ctrl3.handleFocus}
onMenuScroll={handleMenuScroll}
inputPlaceholder={ctrl3.inputPlaceholder}
emptyCaption={ctrl3.emptyCaption}
empty={ctrl3.isEmpty}
showCheckboxes={props.selectionMethod === "checkbox"}
selectedStyle={props.selectedItemsStyle}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,9 @@ export interface StaticFilterContainerProps {
ariaLabel?: string;
className?: string;
defaultValue?: string;
emptyCaption?: string;
emptyOptionCaption: string;
emptySelectionCaption: string;
placeholder: string;
filterOptions: FilterOptionsType[];
filterStore: StaticSelectFilterStore;
multiselect: boolean;
Expand Down Expand Up @@ -81,6 +83,7 @@ const ComboboxWidget = observer(function ComboboxWidget(props: StaticFilterConta
<Combobox
options={ctrl2.options}
inputPlaceholder={ctrl2.inputPlaceholder}
emptyCaption={ctrl2.emptyCaption}
useComboboxProps={ctrl2.useComboboxProps}
onClear={ctrl2.handleClear}
onFocus={ctrl2.handleFocus}
Expand All @@ -106,6 +109,7 @@ const TagPickerWidget = observer(function TagPickerWidget(props: StaticFilterCon
onClear={ctrl3.handleClear}
onBlur={ctrl3.handleBlur}
inputPlaceholder={ctrl3.inputPlaceholder}
emptyCaption={ctrl3.emptyCaption}
empty={ctrl3.isEmpty}
showCheckboxes={props.selectionMethod === "checkbox"}
selectedStyle={props.selectedItemsStyle}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ const commonProps = {
groupKey: "dropdown-filter",
filterable: false,
clearable: true,
emptyOptionCaption: dynamicValue("None"),
emptySelectOptionCaption: dynamicValue("Select"),
selectionMethod: "checkbox" as const,
selectedItemsStyle: "text" as const
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@ export interface DatagridDropdownFilterContainerProps {
valueAttribute?: EditableValue<string>;
onChange?: ActionValue;
ariaLabel?: DynamicValue<string>;
emptySelectionCaption?: DynamicValue<string>;
filterInputPlaceholderCaption?: DynamicValue<string>;
}

export interface DatagridDropdownFilterPreviewProps {
Expand All @@ -62,4 +64,6 @@ export interface DatagridDropdownFilterPreviewProps {
valueAttribute: string;
onChange: {} | null;
ariaLabel: string;
emptySelectionCaption: string;
filterInputPlaceholderCaption: string;
}
Original file line number Diff line number Diff line change
Expand Up @@ -58,5 +58,6 @@ export interface PickerBaseControllerProps<S extends FilterStore> {
multiselect: boolean;
onChange?: ActionValue;
valueAttribute?: EditableValue<string>;
emptyCaption?: string;
emptyOptionCaption?: string;
emptySelectionCaption?: string;
}
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ export interface RefBaseControllerProps {
multiselect: boolean;
onChange?: ActionValue;
valueAttribute?: EditableValue<string>;
emptyCaption?: string;
placeholder?: string;
emptyOptionCaption: string;
emptySelectionCaption: string;
placeholder: string;
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@ import { RefBaseController, RefBaseControllerProps } from "./RefBaseController";
export class RefComboboxController extends ComboboxControllerMixin(RefBaseController) {
constructor(props: RefBaseControllerProps) {
super({ ...props, multiselect: false });
this.inputPlaceholder = props.placeholder ?? "Search";
this.inputPlaceholder = props.placeholder;
this.emptyCaption = props.emptySelectionCaption;
}

handleFocus = (event: React.FocusEvent<HTMLInputElement>): void => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ import { SelectControllerMixin } from "./mixins/SelectControllerMixin";
export class RefSelectController extends SelectControllerMixin(RefBaseController) {
constructor(props: RefBaseControllerProps) {
super(props);
this.emptyOption.caption = props.emptyCaption || "None";
this.placeholder = props.placeholder || "Search";
this.emptyOption.caption = props.emptyOptionCaption;
this.emptyCaption = props.emptySelectionCaption;
}

handleFocus = (): void => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,8 @@ export class RefTagPickerController extends TagPickerControllerMixin(RefBaseCont

constructor(props: Props) {
super(props);
this.inputPlaceholder = props.placeholder ?? "Search";
this.inputPlaceholder = props.placeholder;
this.emptyCaption = props.emptySelectionCaption;
this.filterSelectedOptions = props.selectionMethod === "rowClick";
this.selectedStyle = props.selectedItemsStyle;
this.selectionMethod = this.selectedStyle === "boxes" ? props.selectionMethod : "checkbox";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,8 +55,9 @@ export interface StaticBaseControllerProps {
multiselect: boolean;
onChange?: ActionValue;
valueAttribute?: EditableValue<string>;
emptyCaption?: string;
placeholder?: string;
emptyOptionCaption: string;
emptySelectionCaption: string;
placeholder: string;
}

export interface CustomOption<T> {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,6 @@ export class StaticComboboxController extends ComboboxControllerMixin(StaticBase
constructor(props: StaticBaseControllerProps) {
super({ ...props, multiselect: false });
this.inputPlaceholder = props.placeholder ?? "Search";
this.emptyCaption = props.emptySelectionCaption;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { SelectControllerMixin } from "./mixins/SelectControllerMixin";
export class StaticSelectController extends SelectControllerMixin(StaticBaseController) {
constructor(props: StaticBaseControllerProps) {
super(props);
this.emptyOption.caption = props.emptyCaption || "None";
this.placeholder = props.emptyCaption || "Select";
this.emptyOption.caption = props.emptyOptionCaption;
this.emptyCaption = props.emptySelectionCaption;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,8 @@ export class StaticTagPickerController extends TagPickerControllerMixin(StaticBa

constructor(props: Props) {
super(props);
this.inputPlaceholder = props.placeholder ?? "Search";
this.inputPlaceholder = props.placeholder;
this.emptyCaption = props.emptySelectionCaption;
this.filterSelectedOptions = props.selectionMethod === "rowClick";
this.selectedStyle = props.selectedItemsStyle;
this.selectionMethod = this.selectedStyle === "boxes" ? props.selectionMethod : "checkbox";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ export function ComboboxControllerMixin<TBase extends BaseController>(Base: TBas
touched = false;
inputValue = "";
inputPlaceholder = "";
emptyCaption = "";

constructor(...args: any[]) {
super(...args);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,11 @@ const none = "[[__none__]]" as const;
// eslint-disable-next-line @typescript-eslint/explicit-function-return-type
export function SelectControllerMixin<TBase extends BaseController>(Base: TBase) {
return class SelectControllerMixin extends Base {
placeholder = "Select";
emptyCaption = "";

readonly emptyOption = {
value: none,
caption: "None",
caption: "",
selected: false
};

Expand All @@ -41,6 +41,9 @@ export function SelectControllerMixin<TBase extends BaseController>(Base: TBase)
}

get options(): OptionWithState[] {
if (this.multiselect) {
return this.filterStore.options;
}
return [this.emptyOption, ...this.filterStore.options];
}

Expand All @@ -52,7 +55,7 @@ export function SelectControllerMixin<TBase extends BaseController>(Base: TBase)
const selected = this.filterStore.selectedOptions;

if (selected.length < 1) {
return this.placeholder;
return this.emptyCaption;
}

return selected.map(option => option.caption).join(", ");
Expand Down Expand Up @@ -84,6 +87,18 @@ export function SelectControllerMixin<TBase extends BaseController>(Base: TBase)
if (this.multiselect) {
props.stateReducer = (state, { changes, type }) => {
switch (type) {
case useSelect.stateChangeTypes.ToggleButtonClick:
if (state.isOpen) {
return {
...changes,
isOpen: true,
highlightedIndex: state.highlightedIndex
};
}

return {
...changes
};
case useSelect.stateChangeTypes.ToggleButtonKeyDownEnter:
case useSelect.stateChangeTypes.ItemClick:
return {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ export function TagPickerControllerMixin<TBase extends BaseController>(Base: TBa
touched = false;
inputValue = "";
inputPlaceholder = "";
emptyCaption = "";
filterSelectedOptions = false;

constructor(...args: any[]) {
Expand Down Expand Up @@ -142,6 +143,15 @@ export function TagPickerControllerMixin<TBase extends BaseController>(Base: TBa
highlightedIndex: state.highlightedIndex,
inputValue: state.inputValue
};
case useCombobox.stateChangeTypes.InputClick:
if (state.isOpen) {
return {
...changes,
isOpen: true,
highlightedIndex: state.highlightedIndex
};
}
return changes;
default:
return {
...changes,
Expand Down
Loading
Loading