Skip to content

Commit

Permalink
Merge branch 'primefaces:master' into master
Browse files Browse the repository at this point in the history
  • Loading branch information
nitrogenous authored Jan 24, 2024
2 parents 4ccacaf + 99ce10e commit b56d0d0
Show file tree
Hide file tree
Showing 9 changed files with 172 additions and 14 deletions.
6 changes: 3 additions & 3 deletions components/doc/common/apidoc/index.json
Original file line number Diff line number Diff line change
Expand Up @@ -20840,7 +20840,7 @@
},
{
"name": "layout",
"optional": false,
"optional": true,
"type": "\"grid\" | \"list\" | string & Record<string, unknown>",
"description": "Current layout."
}
Expand All @@ -20858,12 +20858,12 @@
},
{
"name": "layout",
"optional": false,
"optional": true,
"type": "\"grid\" | \"list\" | string & Record<string, unknown>",
"description": "Current layout."
}
],
"returnType": "ReactNode[]",
"returnType": "undefined | ReactNode[]",
"description": "Function that gets the options along with the layout mode and returns the content."
},
{
Expand Down
3 changes: 2 additions & 1 deletion components/lib/chips/Chips.js
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,7 @@ export const Chips = React.memo(

const onPaste = (event) => {
if (props.separator) {
let separator = props.separator.replace('\\n', '\n').replace('\\r', '\r').replace('\\t', '\t');
let pastedData = (event.clipboardData || window['clipboardData']).getData('Text');

if (props.keyfilter) {
Expand All @@ -170,7 +171,7 @@ export const Chips = React.memo(

if (pastedData) {
let values = props.value || [];
let pastedValues = pastedData.split(props.separator);
let pastedValues = pastedData.split(separator);

pastedValues = pastedValues.filter((val) => (props.allowDuplicate || values.indexOf(val) === -1) && val.trim().length);
values = [...values, ...pastedValues];
Expand Down
4 changes: 2 additions & 2 deletions components/lib/dataview/dataview.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -336,13 +336,13 @@ export interface DataViewProps extends Omit<React.DetailedHTMLProps<React.HTMLAt
* @param {*} item - Current item.
* @param {'list' | 'grid' | (string & Record<string, unknown>)} layout - Current layout.
*/
itemTemplate?(item: any, layout: 'list' | 'grid' | (string & Record<string, unknown>)): React.ReactNode;
itemTemplate?(item: any, layout?: 'list' | 'grid' | (string & Record<string, unknown>)): React.ReactNode | undefined;
/**
* Function that gets the options along with the layout mode and returns the content.
* @param {*} item - Current item.
* @param {'list' | 'grid' | (string & Record<string, unknown>)} layout - Current layout.
*/
listTemplate?(items: any[], layout: 'list' | 'grid' | (string & Record<string, unknown>)): React.ReactNode[];
listTemplate?(items: any[], layout?: 'list' | 'grid' | (string & Record<string, unknown>)): React.ReactNode[] | undefined;
/**
* Used to get the child elements of the component.
* @readonly
Expand Down
2 changes: 1 addition & 1 deletion components/lib/editor/Editor.js
Original file line number Diff line number Diff line change
Expand Up @@ -189,7 +189,7 @@ export const Editor = React.memo(
</span>
<span {...formatsProps}>
<button {...getMergeProps({ type: 'button', className: 'ql-list', value: 'ordered', 'aria-label': 'Ordered List' }, 'list')}></button>
<button {...getMergeProps({ type: 'button', className: cx('list'), value: 'bullet', 'aria-label': 'Unordered List' }, 'list')}></button>
<button {...getMergeProps({ type: 'button', className: 'ql-list', value: 'bullet', 'aria-label': 'Unordered List' }, 'list')}></button>
<select {...getMergeProps({ className: 'ql-align' }, 'select')}>
<option {...getMergeProps({ defaultValue: true }, 'option')}></option>
<option {...getMergeProps({ value: 'center' }, 'option')}></option>
Expand Down
118 changes: 118 additions & 0 deletions components/lib/focustrap/FocusTrap.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
import React from 'react';
import { PrimeReactContext } from '../api/Api';
import { useMountEffect, useStyle } from '../hooks/Hooks';
import { DomHandler } from '../utils/Utils';
import { FocusTrapBase } from './FocusTrapBase';

export const FocusTrap = React.memo(
React.forwardRef((inProps, ref) => {
const targetRef = React.useRef(null);
const firstFocusableElementRef = React.useRef(null);
const lastFocusableElementRef = React.useRef(null);
const context = React.useContext(PrimeReactContext);
const props = FocusTrapBase.getProps(inProps, context);

const metaData = {
props
};

useStyle(FocusTrapBase.css.styles, { name: 'focustrap' });

const { ptm } = FocusTrapBase.setMetaData({
...metaData
});

React.useImperativeHandle(ref, () => ({
props,
getInk: () => firstFocusableElementRef.current,
getTarget: () => targetRef.current
}));

useMountEffect(() => {
if (!props.disabled) {
targetRef.current = getTarget();
setAutoFocus(targetRef.current, props);
}
});

const getTarget = () => {
return firstFocusableElementRef.current && firstFocusableElementRef.current.parentElement;
};

const setAutoFocus = (target) => {
const { autoFocusSelector = '', firstFocusableSelector = '', autoFocus = false } = props || {};

let focusableElement = DomHandler.getFirstFocusableElement(target, `[autofocus]${getComputedSelector(autoFocusSelector)}`);

autoFocus && !focusableElement && (focusableElement = DomHandler.getFirstFocusableElement(target, getComputedSelector(firstFocusableSelector)));

DomHandler.focus(focusableElement);
};

const getComputedSelector = (selector) => {
return `:not(.p-hidden-focusable):not([data-p-hidden-focusable="true"])${selector ?? ''}`;
};

const onFirstHiddenElementFocus = (event) => {
const { currentTarget, relatedTarget } = event;

const focusableElement =
relatedTarget === currentTarget.$_pfocustrap_lasthiddenfocusableelement || !targetRef.current?.contains(relatedTarget)
? DomHandler.getFirstFocusableElement(currentTarget.parentElement, getComputedSelector(currentTarget.$_pfocustrap_focusableselector))
: currentTarget.$_pfocustrap_lasthiddenfocusableelement;

DomHandler.focus(focusableElement);
};

const onLastHiddenElementFocus = (event) => {
const { currentTarget, relatedTarget } = event;

const focusableElement =
relatedTarget === currentTarget.$_pfocustrap_firsthiddenfocusableelement || !targetRef.current?.contains(relatedTarget)
? DomHandler.getLastFocusableElement(currentTarget.parentElement, getComputedSelector(currentTarget.$_pfocustrap_focusableselector))
: currentTarget.$_pfocustrap_firsthiddenfocusableelement;

DomHandler.focus(focusableElement);
};

const createHiddenFocusableElements = () => {
const { tabIndex = 0 } = props || {};

const createFocusableElement = (onFocus, section) => {
return (
<span
ref={section === 'firstfocusableelement' ? firstFocusableElementRef : lastFocusableElementRef}
className={'p-hidden-accessible p-hidden-focusable'}
tabIndex={tabIndex}
role={'presentation'}
aria-hidden={true}
data-p-hidden-accessible={true}
data-p-hidden-focusable={true}
onFocus={onFocus}
data-pc-section={section}
></span>
);
};

const firstFocusableElement = createFocusableElement(onFirstHiddenElementFocus, 'firstfocusableelement');
const lastFocusableElement = createFocusableElement(onLastHiddenElementFocus, 'lastfocusableelement');

if (firstFocusableElement.ref.current && lastFocusableElement.ref.current) {
firstFocusableElement.ref.current.$_pfocustrap_lasthiddenfocusableelement = lastFocusableElement.ref.current;
lastFocusableElement.ref.current.$_pfocustrap_firsthiddenfocusableelement = firstFocusableElement.ref.current;
}

return (
<>
{firstFocusableElement}
{props.children}
{lastFocusableElement}
</>
);
};

return createHiddenFocusableElements();
})
);

export default FocusTrap;
16 changes: 16 additions & 0 deletions components/lib/focustrap/FocusTrapBase.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { ComponentBase } from '../componentbase/ComponentBase';
import { ObjectUtils } from '../utils/Utils';

const styles = ``;

export const FocusTrapBase = ComponentBase.extend({
defaultProps: {
__TYPE: 'FocusTrap',
children: undefined
},
css: {
styles
},
getProps: (props) => ObjectUtils.getMergedProps(props, FocusTrapBase.defaultProps),
getOtherProps: (props) => ObjectUtils.getDiffProps(props, FocusTrapBase.defaultProps)
});
7 changes: 7 additions & 0 deletions components/lib/focustrap/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"main": "./focustrap.cjs.js",
"module": "./focustrap.esm.js",
"unpkg": "./focustrap.min.js",
"types": "./focustrap.d.ts",
"sideEffects": false
}
4 changes: 4 additions & 0 deletions components/lib/menubar/MenubarSub.js
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,10 @@ export const MenubarSub = React.memo(
};

const getItemId = (processedItem) => {
if (processedItem.item && processedItem.item.id) {
return processedItem.item.id;
}

return `${props.id}_${processedItem.key}`;
};

Expand Down
26 changes: 19 additions & 7 deletions components/lib/panelmenu/PanelMenu.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ import { PrimeReactContext } from '../api/Api';
import { useHandleStyle } from '../componentbase/ComponentBase';
import { CSSTransition } from '../csstransition/CSSTransition';
import { useMergeProps, useMountEffect } from '../hooks/Hooks';
import { useUpdateEffect } from '../hooks/useUpdateEffect';
import { ChevronDownIcon } from '../icons/chevrondown';
import { ChevronRightIcon } from '../icons/chevronright';
import { DomHandler, IconUtils, ObjectUtils, UniqueComponentId, classNames } from '../utils/Utils';
Expand Down Expand Up @@ -60,7 +59,11 @@ export const PanelMenu = React.memo(
};

const isItemActive = (item) => {
return props.expandedKeys ? props.expandedKeys[getItemProp(item, 'key')] : props.multiple ? activeItemsState.some((subItem) => ObjectUtils.equals(item, subItem)) : ObjectUtils.equals(item, activeItemState);
if (props.expandedKeys) {
return props.expandedKeys[getItemProp(item, 'key')];
} else {
return props.multiple ? activeItemsState.some((subItem) => ObjectUtils.equals(item, subItem)) : ObjectUtils.equals(item, activeItemState);
}
};

const isItemVisible = (item) => {
Expand Down Expand Up @@ -181,7 +184,7 @@ export const PanelMenu = React.memo(
const changeActiveItem = (event, item) => {
if (!isItemDisabled(item)) {
const active = isItemActive(item);
const isOpen = !active;
const isExpanded = !active;
const _activeItemState = activeItemState && ObjectUtils.equals(item, activeItemState) ? null : item;

setActiveItemState(_activeItemState);
Expand All @@ -202,8 +205,8 @@ export const PanelMenu = React.memo(
setActiveItemsState(activeItems);
}

changeExpandedKeys({ item, expanded: !active });
isOpen ? props.onOpen && props.onOpen({ originalEvent: event, item }) : props.onClose && props.onClose({ originalEvent: event, item });
changeExpandedKeys({ item, expanded: isExpanded });
isExpanded && event ? props.onOpen && props.onOpen({ originalEvent: event, item }) : props.onClose && props.onClose({ originalEvent: event, item });
}
};

Expand Down Expand Up @@ -242,8 +245,17 @@ export const PanelMenu = React.memo(
!idState && setIdState(UniqueComponentId());
});

useUpdateEffect(() => {
React.useEffect(() => {
setAnimationDisabled(true);

props.model &&
props.model.forEach((item) => {
if (item.expanded) {
changeActiveItem(null, item);
item.expanded = false;
}
});
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [props.model]);

const onEnter = () => {
Expand All @@ -256,7 +268,7 @@ export const PanelMenu = React.memo(
}

const key = item.id || idState + '_' + index;
const active = isItemActive(item);
const active = isItemActive(item) || item.expanded;
const iconClassName = classNames('p-menuitem-icon', item.icon);
const headerIconProps = mergeProps(
{
Expand Down

0 comments on commit b56d0d0

Please sign in to comment.