Skip to content

Commit

Permalink
* dropdown: preserve dropdown nested menu position on searchbox focus.
Browse files Browse the repository at this point in the history
  • Loading branch information
catouse committed Aug 6, 2024
1 parent a0c59d6 commit 8167536
Showing 1 changed file with 36 additions and 2 deletions.
38 changes: 36 additions & 2 deletions lib/dropdown/src/component/dropdown-menu.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import {flip, computePosition, shift, size, offset} from '@floating-ui/dom';
import {SearchMenu} from '@zui/menu/src/component';

import type {ClassNameLike} from '@zui/core';
import type {SearchBoxOptions} from '@zui/search-box';
import type {ListItemsSetting, NestedItem, NestedListProps} from '@zui/list';
import {type ComponentChildren, type RenderableProps, type ComponentChild} from 'preact';
import type {MouseEventInfo} from '@zui/list/src/component';
Expand All @@ -22,6 +23,10 @@ export class DropdownMenu<T extends DropdownMenuOptions = DropdownMenuOptions> e

protected declare _nestedContextMenu: ComponentChild[];

protected declare _searchFocused: boolean;

protected declare _position: {left: number, top: number, width: number, height: number};

get isHoverTrigger(): boolean {
const {nestedTrigger, tree} = this.props;
return nestedTrigger ? nestedTrigger === 'hover' : !tree;
Expand All @@ -33,25 +38,38 @@ export class DropdownMenu<T extends DropdownMenuOptions = DropdownMenuOptions> e
}

const element = this.element?.parentElement;
const $menu = $(element).parent().children('.dropdown-menu');
const $element = $(element);
if (element && this._searchFocused && this._position) {
$element.css(this._position);
}

const $menu = $element.parent().children('.dropdown-menu');
const $trigger = $menu.children(`[z-key-path="${this.props.parentKey}"]`);
const trigger = $trigger[0];
if (!element || !trigger) {
return;
}

let {maxHeight} = this.props;
computePosition(trigger, element, {
placement: this.props.placement,
middleware: [flip(), shift(), offset(1), size({
apply({availableWidth, availableHeight}) {
$(element).css({maxHeight: availableHeight - 2, maxWidth: availableWidth - 2});
if (maxHeight) {
const [maxHeightVal, unit] = parseSize(maxHeight);
maxHeight = Math.min(unit === '%' ? (maxHeightVal * window.innerHeight) : maxHeightVal, availableHeight - 2);
} else {
maxHeight = availableHeight;
}
$element.css({maxHeight, maxWidth: availableWidth - 2});
},
})],
}).then(({x, y}) => {
$element.css({
left: x,
top: y,
});
this._position = {left: x, top: y, width: element.offsetWidth, height: element.offsetHeight};
});
}

Expand Down Expand Up @@ -119,6 +137,22 @@ export class DropdownMenu<T extends DropdownMenuOptions = DropdownMenuOptions> e
return <span className={`${this.name}-toggle nested-toggle-icon`}><span className="caret-right" /></span>;
}

protected _handleSearchFocus = () => {
this._searchFocused = true;
};

protected _handleSearchBlur = () => {
this._searchFocused = false;
};

protected _getSearchBoxProps(props: RenderableProps<T>): SearchBoxOptions {
return {
...super._getSearchBoxProps(props),
onFocus: this._handleSearchFocus,
onBlur: this._handleSearchBlur,
};
}

protected _beforeRender(props: RenderableProps<T>): void | RenderableProps<T> | undefined {
this._nestedContextMenu = [];
return super._beforeRender(props);
Expand Down

0 comments on commit 8167536

Please sign in to comment.