Skip to content

Commit

Permalink
Merge pull request #6228 from nitrogenous/focus-on-hover-enhancement
Browse files Browse the repository at this point in the history
Enhancement focusOnHover Prop
  • Loading branch information
nitrogenous authored Mar 27, 2024
2 parents 709d5c4 + e7359b7 commit 4ae9526
Show file tree
Hide file tree
Showing 21 changed files with 103 additions and 6 deletions.
3 changes: 1 addition & 2 deletions .eslintignore
Original file line number Diff line number Diff line change
@@ -1,2 +1 @@
//Remove '*' during the development.
*
*
32 changes: 32 additions & 0 deletions components/doc/common/apidoc/index.json
Original file line number Diff line number Diff line change
Expand Up @@ -23094,6 +23094,14 @@
"default": "",
"description": "Reference of the focusable input element."
},
{
"name": "focusOnHover",
"optional": true,
"readonly": false,
"type": "boolean",
"default": "true",
"description": "When enabled, the focus is placed on the hovered option."
},
{
"name": "highlightOnSelect",
"optional": true,
Expand Down Expand Up @@ -35723,6 +35731,14 @@
"default": "false",
"description": "Use flex layout for the items panel."
},
{
"name": "focusOnHover",
"optional": true,
"readonly": false,
"type": "boolean",
"default": "true",
"description": "When enabled, the focus is placed on the hovered option."
},
{
"name": "id",
"optional": true,
Expand Down Expand Up @@ -37376,6 +37392,14 @@
"default": "",
"description": "Custom template of filter element."
},
{
"name": "focusOnHover",
"optional": true,
"readonly": false,
"type": "boolean",
"default": "true",
"description": "When enabled, the focus is placed on the hovered option."
},
{
"name": "header",
"optional": true,
Expand Down Expand Up @@ -41405,6 +41429,14 @@
"default": "contains",
"description": "Defines how the items are filtered, valid values are \"contains\" (default) \"startsWith\", \"endsWith\", \"equals\", \"notEquals\", \"in\", \"notIn\", \"lt\", \"lte\", \"gt\" and \"gte\"."
},
{
"name": "focusOnHover",
"optional": true,
"readonly": false,
"type": "boolean",
"default": "true",
"description": "When enabled, the focus is placed on the hovered option."
},
{
"name": "id",
"optional": true,
Expand Down
6 changes: 3 additions & 3 deletions components/lib/dropdown/Dropdown.js
Original file line number Diff line number Diff line change
Expand Up @@ -1251,9 +1251,9 @@ export const Dropdown = React.memo(
onOptionClick={onOptionClick}
ptm={ptm}
resetFilter={resetFilter}
setFocusedOptionIndex={setFocusedOptionIndex}
firstFocusableElement={<span {...firstHiddenFocusableElementProps}></span>}
lastFocusableElement={<span {...lastHiddenFocusableElementProps}></span>}
changeFocusedOptionIndex={changeFocusedOptionIndex}
firstFocusableElement={<span {...firstHiddenFocusableElementProps} />}
lastFocusableElement={<span {...lastHiddenFocusableElementProps} />}
sx={sx}
/>
</div>
Expand Down
1 change: 1 addition & 0 deletions components/lib/dropdown/DropdownBase.js
Original file line number Diff line number Diff line change
Expand Up @@ -200,6 +200,7 @@ export const DropdownBase = ComponentBase.extend({
optionDisabled: null,
optionGroupChildren: 'items',
selectOnFocus: false,
focusOnHover: true,
autoOptionFocus: false,
optionGroupLabel: null,
optionGroupTemplate: null,
Expand Down
1 change: 1 addition & 0 deletions components/lib/dropdown/DropdownItem.js
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ export const DropdownItem = React.memo((props) => {
className: classNames(option.className, cx('item', { selected, disabled, label, index, focusedOptionIndex, highlightOnSelect })),
style: props.style,
onClick: (e) => onClick(e, index),
onMouseMove: (e) => props?.onMouseMove(e, index),
'aria-label': label,
'aria-selected': selected,
'data-p-highlight': selected,
Expand Down
9 changes: 8 additions & 1 deletion components/lib/dropdown/DropdownPanel.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ export const DropdownPanel = React.memo(
const mergeProps = useMergeProps();
const { ptm, cx, sx } = props;
const context = React.useContext(PrimeReactContext);
const virtualScrollerRef = React.useRef(null);

const filterInputRef = React.useRef(null);
const isEmptyFilter = !(props.visibleOptions && props.visibleOptions.length) && props.hasFilter;
Expand Down Expand Up @@ -71,6 +70,12 @@ export const DropdownPanel = React.memo(
return null;
};

const changeFocusedItemOnHover = (event, index) => {
if (props.focusOnHover) {
props?.changeFocusedOptionIndex?.(event, index);
}
};

const createGroupChildren = (optionGroup, style) => {
const groupChildren = props.getOptionGroupChildren(optionGroup);

Expand All @@ -92,6 +97,7 @@ export const DropdownPanel = React.memo(
highlightOnSelect={props.highlightOnSelect}
disabled={disabled}
onClick={props.onOptionClick}
onMouseMove={changeFocusedItemOnHover}
ptm={ptm}
cx={cx}
checkmark={props.checkmark}
Expand Down Expand Up @@ -163,6 +169,7 @@ export const DropdownPanel = React.memo(
highlightOnSelect={props.highlightOnSelect}
disabled={disabled}
onClick={props.onOptionClick}
onMouseMove={changeFocusedItemOnHover}
ptm={ptm}
cx={cx}
checkmark={props.checkmark}
Expand Down
5 changes: 5 additions & 0 deletions components/lib/dropdown/dropdown.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -355,6 +355,11 @@ export interface DropdownProps extends Omit<React.DetailedHTMLProps<React.InputH
* @defaultValue false
*/
selectOnFocus?: false;
/**
* When enabled, the focus is placed on the hovered option.
* @defaultValue true
*/
focusOnHover?: boolean | undefined;
/**
* Whether to focus on the first visible or selected element.
* @defaultValue false
Expand Down
1 change: 1 addition & 0 deletions components/lib/multiselect/MultiSelect.js
Original file line number Diff line number Diff line change
Expand Up @@ -1107,6 +1107,7 @@ export const MultiSelect = React.memo(
sx={sx}
isUnstyled={isUnstyled}
metaData={metaData}
changeFocusedOptionIndex={changeFocusedOptionIndex}
/>
</div>
{hasTooltip && <Tooltip target={elementRef} content={props.tooltip} pt={ptm('tooltip')} {...props.tooltipOptions} />}
Expand Down
1 change: 1 addition & 0 deletions components/lib/multiselect/MultiSelectBase.js
Original file line number Diff line number Diff line change
Expand Up @@ -221,6 +221,7 @@ export const MultiSelectBase = ComponentBase.extend({
filterInputAutoFocus: true,
filterLocale: undefined,
selectOnFocus: false,
focusOnHover: true,
autoOptionFocus: false,
filterMatchMode: 'contains',
filterPlaceholder: null,
Expand Down
1 change: 1 addition & 0 deletions components/lib/multiselect/MultiSelectItem.js
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ export const MultiSelectItem = React.memo((props) => {
onClick: onClick,
onFocus: onFocus,
onBlur: onBlur,
onMouseMove: (e) => props?.onMouseMove(e, props.index),
tabIndex: tabIndex,
role: 'option',
'aria-selected': props.selected,
Expand Down
8 changes: 8 additions & 0 deletions components/lib/multiselect/MultiSelectPanel.js
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,12 @@ export const MultiSelectPanel = React.memo(
return null;
};

const changeFocusedItemOnHover = (event, index) => {
if (props.focusOnHover) {
props?.changeFocusedOptionIndex?.(event, index);
}
};

const createGroupChildren = (optionGroup, style) => {
const groupChildren = props.getOptionGroupChildren(optionGroup);

Expand All @@ -116,6 +122,7 @@ export const MultiSelectPanel = React.memo(
template={props.itemTemplate}
selected={selected}
onClick={props.onOptionSelect}
onMouseMove={changeFocusedItemOnHover}
tabIndex={tabIndex}
disabled={disabled}
className={props.itemClassName}
Expand Down Expand Up @@ -194,6 +201,7 @@ export const MultiSelectPanel = React.memo(
template={props.itemTemplate}
selected={selected}
onClick={props.onOptionSelect}
onMouseMove={changeFocusedItemOnHover}
tabIndex={tabIndex}
disabled={disabled}
className={props.itemClassName}
Expand Down
5 changes: 5 additions & 0 deletions components/lib/multiselect/multiselect.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -699,6 +699,11 @@ export interface MultiSelectProps extends Omit<React.DetailedHTMLProps<React.Inp
* @defaultValue false
*/
selectOnFocus?: false;
/**
* When enabled, the focus is placed on the hovered option.
* @defaultValue true
*/
focusOnHover?: boolean | undefined;
/**
* Whether to focus on the first visible or selected element.
* @defaultValue false
Expand Down
2 changes: 2 additions & 0 deletions components/lib/orderlist/OrderList.js
Original file line number Diff line number Diff line change
Expand Up @@ -477,6 +477,8 @@ export const OrderList = React.memo(
isUnstyled={isUnstyled}
ptm={ptm}
cx={cx}
changeFocusedOptionIndex={changeFocusedOptionIndex}
{...props}
/>
</div>
);
Expand Down
1 change: 1 addition & 0 deletions components/lib/orderlist/OrderListBase.js
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,7 @@ export const OrderListBase = ComponentBase.extend({
moveBottomIcon: null,
dataKey: null,
autoOptionFocus: true,
focusOnHover: true,
breakpoint: '960px',
onChange: null,
itemTemplate: null,
Expand Down
8 changes: 8 additions & 0 deletions components/lib/orderlist/OrderListSubList.js
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,12 @@ export const OrderListSubList = React.memo(
}
};

const changeFocusedItemOnHover = (event, index) => {
if (props.focusOnHover && props.focused) {
props?.changeFocusedOptionIndex?.(index);
}
};

const createDropPoint = (index, key) => {
const droppointProps = mergeProps(
{
Expand Down Expand Up @@ -142,6 +148,7 @@ export const OrderListSubList = React.memo(
draggable: 'true',
onClick: (e) => props.onItemClick({ originalEvent: e, value: item, index: i }),
onMouseDown: props.onOptionMouseDown,
onMouseMove: (e) => changeFocusedItemOnHover(e, i),
onDragStart: (e) => onDragStart(e, i),
onDragEnd: onDragEnd,
className: classNames(props.className, cx('item', { selected, focused })),
Expand Down Expand Up @@ -175,6 +182,7 @@ export const OrderListSubList = React.memo(
role: 'option',
onClick: (e) => props.onItemClick({ originalEvent: e, value: item, index: i }),
onMouseDown: props.onOptionMouseDown,
onMouseMove: (e) => changeFocusedItemOnHover(e, i),
className: classNames(props.className, cx('item', { selected, focused })),
'aria-selected': selected,
'data-p-highlight': selected,
Expand Down
5 changes: 5 additions & 0 deletions components/lib/orderlist/orderlist.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,11 @@ export interface OrderListProps extends Omit<React.DetailedHTMLProps<React.HTMLA
* @defaultValue true
*/
autoOptionFocus?: boolean | undefined;
/**
* When enabled, the focus is placed on the hovered option.
* @defaultValue true
*/
focusOnHover?: boolean | undefined;
/**
* Inline style of the list element.
*/
Expand Down
6 changes: 6 additions & 0 deletions components/lib/picklist/PickList.js
Original file line number Diff line number Diff line change
Expand Up @@ -652,6 +652,9 @@ export const PickList = React.memo(
sourceFilterIcon={props.sourceFilterIcon}
ptm={ptm}
cx={cx}
focusedList={focused}
changeFocusedOptionIndex={changeFocusedOptionIndex}
focusOnHover={props.focusOnHover}
/>

<PickListTransferControls
Expand Down Expand Up @@ -706,6 +709,9 @@ export const PickList = React.memo(
targetFilterIcon={props.targetFilterIcon}
ptm={ptm}
cx={cx}
focusedList={focused}
changeFocusedOptionIndex={changeFocusedOptionIndex}
focusOnHover={props.focusOnHover}
/>

{props.showTargetControls && (
Expand Down
1 change: 1 addition & 0 deletions components/lib/picklist/PickListBase.js
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,7 @@ export const PickListBase = ComponentBase.extend({
tabIndex: 0,
dataKey: null,
autoOptionFocus: true,
focusOnHover: true,
breakpoint: '960px',
itemTemplate: null,
sourceItemTemplate: null,
Expand Down
1 change: 1 addition & 0 deletions components/lib/picklist/PickListItem.js
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ export const PickListItem = React.memo((props) => {
onKeyDown,
onFocus,
onMouseDown,
onMouseMove: props.onMouseMove,
role: 'option',
'aria-selected': props.selected,
'data-p-highlight': props.selected,
Expand Down
7 changes: 7 additions & 0 deletions components/lib/picklist/PickListSubList.js
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,12 @@ export const PickListSubList = React.memo(
return null;
};

const changeFocusedItemOnHover = (index) => {
if (props.focusOnHover && props.focusedList[props.type]) {
props?.changeFocusedOptionIndex?.(index, props.type);
}
};

const createItems = () => {
if (props.list) {
return props.list.map((item, index) => {
Expand All @@ -76,6 +82,7 @@ export const PickListSubList = React.memo(
onClick={props.onItemClick}
onKeyDown={props.onItemKeyDown}
onMouseDown={(event) => props.onOptionMouseDown({ ...event, index, type: props.type })}
onMouseMove={() => changeFocusedItemOnHover(index)}
ptm={ptm}
cx={cx}
/>
Expand Down
5 changes: 5 additions & 0 deletions components/lib/picklist/picklist.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -264,6 +264,11 @@ export interface PickListProps {
* @defaultValue true
*/
autoOptionFocus?: boolean | undefined;
/**
* When enabled, the focus is placed on the hovered option.
* @defaultValue true
*/
focusOnHover?: boolean | undefined;
/**
* Inline style of the element.
*/
Expand Down

0 comments on commit 4ae9526

Please sign in to comment.