Skip to content

Commit

Permalink
Form Components: Convert class selector to data selector (#5721)
Browse files Browse the repository at this point in the history
* fix:Dropdown

* fix:ListBoxItem

* fix:Mention triggerState null safety

* fix:MultiSelect

* fix: TreeSelect

* fix:Dropdown & Mention

* fix:code lint

* fix: Mention

* fix: remove redundant imports

---------

Co-authored-by: Melloware <[email protected]>
  • Loading branch information
kl-nevermore and melloware authored Jan 10, 2024
1 parent 5f6b960 commit 33a8d37
Show file tree
Hide file tree
Showing 11 changed files with 121 additions and 38 deletions.
6 changes: 3 additions & 3 deletions components/lib/dropdown/Dropdown.js
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ export const Dropdown = React.memo(
};

const isClearClicked = (event) => {
return DomHandler.hasClass(event.target, 'p-dropdown-clear-icon') || DomHandler.hasClass(event.target, 'p-dropdown-filter-clear-icon');
return DomHandler.isAttributeEquals(event.target, 'data-pc-section', 'clearicon') || DomHandler.isAttributeEquals(event.target.parentElement || event.target, 'data-pc-section', 'filterclearicon');
};

const onClick = (event) => {
Expand All @@ -93,7 +93,7 @@ export const Dropdown = React.memo(
return;
}

if (DomHandler.hasClass(event.target, 'p-dropdown-clear-icon') || event.target.tagName === 'INPUT') {
if (isClearClicked(event) || event.target.tagName === 'INPUT') {
return;
} else if (!overlayRef.current || !(overlayRef.current && overlayRef.current.contains(event.target))) {
DomHandler.focus(focusInputRef.current);
Expand Down Expand Up @@ -561,7 +561,7 @@ export const Dropdown = React.memo(
};

const scrollInView = () => {
const highlightItem = DomHandler.findSingle(overlayRef.current, 'li.p-highlight');
const highlightItem = DomHandler.findSingle(overlayRef.current, 'li[data-p-highlight="true"]');

if (highlightItem && highlightItem.scrollIntoView) {
highlightItem.scrollIntoView({ block: 'nearest', inline: 'nearest' });
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 @@ -28,6 +28,7 @@ const classes = {
loadingIcon: 'p-dropdown-trigger-icon p-clickable',
clearIcon: 'p-dropdown-clear-icon p-clickable',
filterIcon: 'p-dropdown-filter-icon',
filterClearIcon: 'p-dropdown-filter-clear-icon',
filterContainer: ({ clearIcon }) => classNames('p-dropdown-filter-container', { 'p-dropdown-clearable-filter': !!clearIcon }),
filterInput: 'p-dropdown-filter p-inputtext p-component',
list: ({ virtualScrollerOptions }) => (virtualScrollerOptions ? 'p-dropdown-items' : 'p-dropdown-items'),
Expand Down
7 changes: 4 additions & 3 deletions components/lib/dropdown/DropdownPanel.js
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,8 @@ export const DropdownPanel = React.memo(
const itemGroupProps = mergeProps(
{
className: cx('itemGroup', { optionGroupLabel }),
style
style,
'data-p-highlight': props.selected
},
getPTOptions('itemGroup')
);
Expand Down Expand Up @@ -140,11 +141,11 @@ export const DropdownPanel = React.memo(
const ariaLabel = localeOption('clear');
const clearIconProps = mergeProps(
{
className: cx('clearIcon'),
className: cx('filterClearIcon'),
'aria-label': ariaLabel,
onClick: () => props.onFilterClearIconClick(() => DomHandler.focus(filterInputRef.current))
},
getPTOptions('clearIcon')
getPTOptions('filterClearIcon')
);
const icon = props.filterClearIcon || <TimesIcon {...clearIconProps} />;
const filterClearIcon = IconUtils.getJSXIcon(icon, { ...clearIconProps }, { props });
Expand Down
7 changes: 4 additions & 3 deletions components/lib/listbox/ListBoxItem.js
Original file line number Diff line number Diff line change
Expand Up @@ -83,13 +83,13 @@ export const ListBoxItem = React.memo((props) => {
const findNextItem = (item) => {
const nextItem = item.nextElementSibling;

return nextItem ? (DomHandler.hasClass(nextItem, 'p-disabled') || DomHandler.hasClass(nextItem, 'p-listbox-item-group') ? findNextItem(nextItem) : nextItem) : null;
return nextItem ? (DomHandler.isAttributeEquals(nextItem, 'data-p-disabled', true) || DomHandler.isAttributeEquals(nextItem, 'data-pc-section', 'itemgroup') ? findNextItem(nextItem) : nextItem) : null;
};

const findPrevItem = (item) => {
const prevItem = item.previousElementSibling;

return prevItem ? (DomHandler.hasClass(prevItem, 'p-disabled') || DomHandler.hasClass(prevItem, 'p-listbox-item-group') ? findPrevItem(prevItem) : prevItem) : null;
return prevItem ? (DomHandler.isAttributeEquals(prevItem, 'data-p-disabled', true) || DomHandler.isAttributeEquals(prevItem, 'data-pc-section', 'itemgroup') ? findPrevItem(prevItem) : prevItem) : null;
};

const content = props.template ? ObjectUtils.getJSXElement(props.template, props.option) : props.label;
Expand All @@ -108,7 +108,8 @@ export const ListBoxItem = React.memo((props) => {
key: props.label,
role: 'option',
'aria-selected': props.selected,
'aria-disabled': props.disabled
'aria-disabled': props.disabled,
'data-p-disabled': props.disabled
},
getPTOptions('item')
);
Expand Down
114 changes: 91 additions & 23 deletions components/lib/mention/Mention.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ export const Mention = React.memo(
const [focusedState, setFocusedState] = React.useState(false);
const [searchingState, setSearchingState] = React.useState(false);
const [triggerState, setTriggerState] = React.useState(null);
const [highlightState, setHighlightState] = React.useState([]);

const elementRef = React.useRef(null);
const overlayRef = React.useRef(null);
const inputRef = React.useRef(props.inputRef);
Expand All @@ -37,10 +39,13 @@ export const Mention = React.memo(

useHandleStyle(MentionBase.css.styles, isUnstyled, { name: 'mention' });

const getPTOptions = (item, suggestion) => {
const getPTOptions = (item, suggestion, options) => {
return ptm(suggestion, {
context: {
trigger: triggerState ? triggerState.key : ''
},
state: {
...options
}
});
};
Expand Down Expand Up @@ -72,7 +77,13 @@ export const Mention = React.memo(

const onOverlayEntering = () => {
if (props.autoHighlight && props.suggestions && props.suggestions.length) {
DomHandler.addClass(listRef.current.firstChild, 'p-highlight');
setHighlightState((prevState) => {
const newState = [...prevState];

newState[0] = true;

return newState;
});
}
};

Expand All @@ -92,13 +103,15 @@ export const Mention = React.memo(
};

const alignOverlay = () => {
const { key, index } = triggerState;
const value = inputRef.current.value;
const position = DomHandler.getCursorOffset(inputRef.current, value.substring(0, index - 1), value.substring(index), key);

overlayRef.current.style.transformOrigin = 'top';
overlayRef.current.style.left = `calc(${position.left}px + 1rem)`;
overlayRef.current.style.top = `calc(${position.top}px + 1.2rem)`;
if (triggerState) {
const { key, index } = triggerState;
const value = inputRef.current.value;
const position = DomHandler.getCursorOffset(inputRef.current, value.substring(0, index - 1), value.substring(index), key);

overlayRef.current.style.transformOrigin = 'top';
overlayRef.current.style.left = `calc(${position.left}px + 1rem)`;
overlayRef.current.style.top = `calc(${position.top}px + 1.2rem)`;
}
};

const onPanelClick = (event) => {
Expand Down Expand Up @@ -245,9 +258,19 @@ export const Mention = React.memo(

const onInput = (event) => {
props.onInput && props.onInput(event);
const isFilled = event.target.value.length > 0;

if (event.target.value.length > 0) DomHandler.addClass(elementRef.current, 'p-inputwrapper-filled');
else DomHandler.removeClass(elementRef.current, 'p-inputwrapper-filled');
if (isUnstyled()) {
DomHandler.setAttributes(elementRef.current, {
'data-p-inputwrapper-filled': isFilled
});
} else {
if (isFilled) {
DomHandler.addClass(elementRef.current, 'p-inputwrapper-filled');
} else {
DomHandler.removeClass(elementRef.current, 'p-inputwrapper-filled');
}
}
};

const onKeyUp = (event) => {
Expand All @@ -264,7 +287,7 @@ export const Mention = React.memo(

const onKeyDown = (event) => {
if (overlayVisibleState) {
let highlightItem = DomHandler.findSingle(overlayRef.current, 'li.p-highlight');
let highlightItem = DomHandler.findSingle(overlayRef.current, 'li[data-p-highlight="true"]');

switch (event.which) {
//down
Expand All @@ -273,15 +296,33 @@ export const Mention = React.memo(
let nextElement = highlightItem.nextElementSibling;

if (nextElement) {
DomHandler.addClass(nextElement, 'p-highlight');
DomHandler.removeClass(highlightItem, 'p-highlight');
const nextElementIndex = DomHandler.index(nextElement);
const highlightItemIndex = DomHandler.index(highlightItem);

setHighlightState((prevState) => {
const newState = [...prevState];

newState[nextElementIndex] = true;
newState[highlightItemIndex] = false;

return newState;
});

DomHandler.scrollInView(overlayRef.current, nextElement);
}
} else {
highlightItem = DomHandler.findSingle(overlayRef.current, 'li');

if (highlightItem) {
DomHandler.addClass(highlightItem, 'p-highlight');
const highlightItemIndex = DomHandler.index(highlightItem);

setHighlightState((prevState) => {
const newState = [...prevState];

newState[highlightItemIndex] = true;

return newState;
});
}
}

Expand All @@ -294,8 +335,18 @@ export const Mention = React.memo(
let previousElement = highlightItem.previousElementSibling;

if (previousElement) {
DomHandler.addClass(previousElement, 'p-highlight');
DomHandler.removeClass(highlightItem, 'p-highlight');
const previousElementIndex = DomHandler.index(previousElement);
const highlightItemIndex = DomHandler.index(highlightItem);

setHighlightState((prevState) => {
const newState = [...prevState];

newState[previousElementIndex] = true;
newState[highlightItemIndex] = false;

return newState;
});

DomHandler.scrollInView(overlayRef.current, previousElement);
}
}
Expand Down Expand Up @@ -353,16 +404,31 @@ export const Mention = React.memo(
}, [inputRef, props.inputRef]);

useUpdateEffect(() => {
const hasSuggestions = props.suggestions && props.suggestions.length;

if (hasSuggestions) {
const newState = props.suggestions.map(() => false);

setHighlightState(newState);
}

if (searchingState) {
props.suggestions && props.suggestions.length ? show() : hide();
hasSuggestions ? show() : hide();
overlayVisibleState && alignOverlay();
setSearchingState(false);
}
}, [props.suggestions]);

useUpdateEffect(() => {
if (!isFilled && DomHandler.hasClass(elementRef.current, 'p-inputwrapper-filled')) {
DomHandler.removeClass(elementRef.current, 'p-inputwrapper-filled');
const _isUnstyled = isUnstyled();
const isInputWrapperFilled = _isUnstyled ? DomHandler.isAttributeEquals(elementRef.current, 'data-p-inputwrapper-filled', true) : DomHandler.hasClass(elementRef.current, 'p-inputwrapper-filled');

if (!isFilled && isInputWrapperFilled) {
_isUnstyled
? DomHandler.setAttributes(elementRef.current, {
'data-p-inputwrapper-filled': false
})
: DomHandler.removeClass(elementRef.current, 'p-inputwrapper-filled');
}
}, [isFilled]);

Expand All @@ -373,14 +439,16 @@ export const Mention = React.memo(
const createItem = (suggestion, index) => {
const key = index + '_item';
const content = props.itemTemplate ? ObjectUtils.getJSXElement(props.itemTemplate, suggestion, { trigger: triggerState ? triggerState.key : '', index }) : formatValue(suggestion);
const isSelected = highlightState[index];

const itemProps = mergeProps(
{
key: key,
className: cx('item'),
onClick: (e) => onItemClick(e, suggestion)
className: cx('item', { isSelected }),
onClick: (e) => onItemClick(e, suggestion),
'data-p-highlight': isSelected
},
getPTOptions(suggestion, 'item')
getPTOptions(suggestion, 'item', { selected: isSelected })
);

return (
Expand Down
5 changes: 4 additions & 1 deletion components/lib/mention/MentionBase.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,10 @@ import { ComponentBase } from '../componentbase/ComponentBase';
import { classNames } from '../utils/Utils';

const classes = {
item: 'p-mention-item',
item: ({ isSelected }) =>
classNames('p-mention-item', {
'p-highlight': isSelected
}),
items: 'p-mention-items',
panel: ({ props }) => classNames('p-mention-panel p-component', props.panelClassName),
input: ({ props }) => classNames('p-mention-input', props.inputClassName),
Expand Down
4 changes: 4 additions & 0 deletions components/lib/mention/mention.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,10 @@ export interface MentionState {
* Current trigger state.
*/
trigger: any;
/**
* For item, this is the state of the item.
*/
selected?: boolean;
}

/**
Expand Down
2 changes: 1 addition & 1 deletion components/lib/multiselect/MultiSelect.js
Original file line number Diff line number Diff line change
Expand Up @@ -267,7 +267,7 @@ export const MultiSelect = React.memo(
};

const scrollInView = () => {
const highlightItem = DomHandler.findSingle(overlayRef.current, 'li.p-highlight');
const highlightItem = DomHandler.findSingle(overlayRef.current, 'li[data-p-highlight="true"]');

if (highlightItem && highlightItem.scrollIntoView) {
highlightItem.scrollIntoView({ block: 'nearest', inline: 'nearest' });
Expand Down
6 changes: 5 additions & 1 deletion components/lib/passthrough/tailwind/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -1286,7 +1286,11 @@ const Tailwind = {
root: 'relative',
panel: 'max-h-[200px] min-w-full overflow-auto bg-white dark:bg-gray-900 text-gray-700 dark:text-white/80 border-0 rounded-md shadow-lg',
items: 'py-3 list-none m-0',
item: 'cursor-pointer font-normal overflow-hidden relative whitespace-nowrap m-0 p-3 border-0 transition-shadow duration-200 rounded-none dark:text-white/80 dark:hover:bg-gray-800 hover:text-gray-700 hover:bg-gray-200',
item: ({ state }) => ({
className: classNames('cursor-pointer font-normal overflow-hidden relative whitespace-nowrap m-0 p-3 border-0 transition-shadow duration-200 rounded-none dark:text-white/80 dark:hover:bg-gray-800 hover:text-gray-700 hover:bg-gray-200', {
'bg-blue-50 text-blue-700 dark:bg-blue-300 dark:text-white/80': state.selected
})
}),
transition: TRANSITIONS.overlay
},
multiselect: {
Expand Down
3 changes: 2 additions & 1 deletion components/lib/tree/UITreeNode.js
Original file line number Diff line number Diff line change
Expand Up @@ -803,7 +803,8 @@ export const UITreeNode = React.memo((props) => {
onDragEnter: onDragEnter,
onDragLeave: onDragLeave,
onDragStart: onDragStart,
onDragEnd: onDragEnd
onDragEnd: onDragEnd,
'data-p-highlight': isCheckboxSelectionMode() ? checked : selected
},
getPTOptions('content')
);
Expand Down
4 changes: 2 additions & 2 deletions components/lib/treeselect/TreeSelect.js
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ export const TreeSelect = React.memo(
};

const onClick = (event) => {
if (!props.disabled && (!overlayRef.current || !overlayRef.current.contains(event.target)) && !DomHandler.hasClass(event.target, 'p-treeselect-close')) {
if (!props.disabled && (!overlayRef.current || !overlayRef.current.contains(event.target)) && !DomHandler.isAttributeEquals(event.target, 'data-pc-section', 'closebutton')) {
DomHandler.focus(focusInputRef.current);
overlayVisibleState ? hide() : show();
}
Expand Down Expand Up @@ -341,7 +341,7 @@ export const TreeSelect = React.memo(
};

const scrollInView = () => {
const highlightItem = DomHandler.findSingle(overlayRef.current, '.p-treenode-content.p-highlight');
const highlightItem = DomHandler.findSingle(overlayRef.current, '[data-pc-section="content"][data-p-highlight="true"]');

if (highlightItem && highlightItem.scrollIntoView) {
highlightItem.scrollIntoView({ block: 'nearest', inline: 'start' });
Expand Down

0 comments on commit 33a8d37

Please sign in to comment.