Skip to content

Commit

Permalink
Merge pull request primefaces#6109 from nitrogenous/structure-enhance…
Browse files Browse the repository at this point in the history
…ments

Structure enhancements
  • Loading branch information
nitrogenous authored Mar 13, 2024
2 parents f1b8237 + b324773 commit 2d66a30
Show file tree
Hide file tree
Showing 18 changed files with 300 additions and 514 deletions.
5 changes: 1 addition & 4 deletions components/doc/togglebutton/theming/tailwinddoc.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,11 @@ export function TailwindDoc(props) {
basic: `
const Tailwind = {
togglebutton: {
root: ({ props, state }) => ({
root: ({ props }) => ({
className: classNames(
'inline-flex cursor-pointer select-none items-center align-bottom text-center overflow-hidden relative',
'px-4 py-3 rounded-md text-base w-36',
'border transition duration-200 ease-in-out',
{
'outline-none outline-offset-0 shadow-[0_0_0_0.2rem_rgba(191,219,254,1)] dark:shadow-[0_0_0_0.2rem_rgba(147,197,253,0.5)]': state.focused
},
{
'bg-white dark:bg-gray-900 border-gray-300 dark:border-blue-900/40 text-gray-700 dark:text-white/80 hover:bg-gray-100 dark:hover:bg-gray-800/80 hover:border-gray-300 dark:hover:bg-gray-800/70 hover:text-gray-700 dark:hover:text-white/80':
!props.checked,
Expand Down
139 changes: 61 additions & 78 deletions components/lib/checkbox/Checkbox.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,32 +12,30 @@ export const Checkbox = React.memo(
const mergeProps = useMergeProps();
const context = React.useContext(PrimeReactContext);
const props = CheckboxBase.getProps(inProps, context);
const [focusedState, setFocusedState] = React.useState(false);
const { ptm, cx, isUnstyled } = CheckboxBase.setMetaData({
props,
state: {
focused: focusedState
},
context: {
checked: props.checked === props.trueValue,
disabled: props.disabled
}
});

useHandleStyle(CheckboxBase.css.styles, isUnstyled, { name: 'checkbox', styled: true });
useHandleStyle(CheckboxBase.css.styles, isUnstyled, { name: 'checkbox' });

const elementRef = React.useRef(null);
const inputRef = React.useRef(props.inputRef);

const onClick = (event) => {
if (props.disabled || props.readOnly) {
const isChecked = () => {
return props.checked === props.trueValue;
};

const onChange = (event) => {
if (props.disabled || props.readonly) {
return;
}

if (props.onChange || props.onClick) {
if (props.onChange) {
const checked = isChecked();
const checkboxClicked = event.target instanceof HTMLDivElement || event.target instanceof HTMLSpanElement || event.target instanceof Object;
const isInputToggled = event.target === inputRef.current;
const isCheckboxToggled = checkboxClicked && event.target.checked !== checked;
const value = checked ? props.falseValue : props.trueValue;
const eventData = {
originalEvent: event,
Expand All @@ -58,39 +56,23 @@ export const Checkbox = React.memo(
}
};

props.onClick && props.onClick(eventData);
props.onChange && props.onChange(eventData);

// do not continue if the user defined click wants to prevent
if (event.defaultPrevented) {
return;
}

if (isInputToggled || isCheckboxToggled) {
props.onChange && props.onChange(eventData);
}

DomHandler.focus(inputRef.current);
event.preventDefault();
}
};

const onFocus = () => {
setFocusedState(true);
props?.onFocus?.();
};

const onBlur = () => {
setFocusedState(false);
};

const onKeyDown = (event) => {
if (event.code === 'Space' || event.key === ' ') {
// event.key is for Android support
onClick(event);
}
};

const isChecked = () => {
return props.checked === props.trueValue;
props?.onBlur?.();
};

React.useImperativeHandle(ref, () => ({
Expand All @@ -117,21 +99,11 @@ export const Checkbox = React.memo(
const checked = isChecked();
const hasTooltip = ObjectUtils.isNotEmpty(props.tooltip);
const otherProps = CheckboxBase.getOtherProps(props);
const ariaProps = ObjectUtils.reduceKeys(otherProps, DomHandler.ARIA_PROPS);
const iconProps = mergeProps(
{
className: cx('icon')
},
ptm('icon')
);
const icon = checked ? props.icon || <CheckIcon {...iconProps} /> : null;
const checkboxIcon = IconUtils.getJSXIcon(icon, { ...iconProps }, { props, checked });
const rootProps = mergeProps(
{
id: props.id,
className: classNames(props.className, cx('root', { checked, focusedState })),
className: classNames(props.className, cx('root', { checked })),
style: props.style,
onClick: (e) => onClick(e),
'data-p-highlight': checked,
'data-p-disabled': props.disabled,
onContextMenu: props.onContextMenu,
Expand All @@ -141,48 +113,59 @@ export const Checkbox = React.memo(
ptm('root')
);

const hiddenInputWrapperProps = mergeProps(
{
className: 'p-hidden-accessible'
},
ptm('hiddenInputWrapper')
);

const hiddenInputProps = mergeProps(
{
id: props.inputId,
type: 'checkbox',
name: props.name,
tabIndex: props.tabIndex,
defaultChecked: checked,
onFocus: (e) => onFocus(e),
onBlur: (e) => onBlur(e),
onKeyDown: (e) => onKeyDown(e),
disabled: props.disabled,
readOnly: props.readOnly,
required: props.required,
...ariaProps
},
ptm('hiddenInput')
);
const createInputElement = () => {
const ariaProps = ObjectUtils.reduceKeys(otherProps, DomHandler.ARIA_PROPS);
const inputProps = mergeProps(
{
id: props.inputId,
type: 'checkbox',
className: cx('input'),
name: props.name,
tabIndex: props.tabIndex,
defaultChecked: checked,
onFocus: (e) => onFocus(e),
onBlur: (e) => onBlur(e),
onChange: (e) => onChange(e),
disabled: props.disabled,
readOnly: props.readOnly,
required: props.required,
'aria-invalid': props.invalid,
checked: isChecked(),
...ariaProps
},
ptm('input')
);

return <input ref={inputRef} {...inputProps} />;
};

const inputProps = mergeProps(
{
className: cx('input', { checked, focusedState }),
'data-p-highlight': checked,
'data-p-disabled': props.disabled,
'data-p-focus': focusedState
},
ptm('input')
);
const createBoxElement = () => {
const iconProps = mergeProps(
{
className: cx('icon')
},
ptm('icon')
);
const boxProps = mergeProps(
{
className: cx('box', { checked }),
'data-p-highlight': checked,
'data-p-disabled': props.disabled
},
ptm('box')
);

const icon = checked ? props.icon || <CheckIcon {...iconProps} /> : null;
const checkboxIcon = IconUtils.getJSXIcon(icon, { ...iconProps }, { props, checked });

return <div {...boxProps}>{checkboxIcon}</div>;
};

return (
<>
<div ref={elementRef} {...rootProps}>
<div {...hiddenInputWrapperProps}>
<input ref={inputRef} {...hiddenInputProps} />
</div>
<div {...inputProps}>{checkboxIcon}</div>
{createInputElement()}
{createBoxElement()}
</div>
{hasTooltip && <Tooltip target={elementRef} content={props.tooltip} pt={ptm('tooltip')} {...props.tooltipOptions} />}
</>
Expand Down
39 changes: 8 additions & 31 deletions components/lib/checkbox/CheckboxBase.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,40 +2,18 @@ import { ComponentBase } from '../componentbase/ComponentBase';
import { classNames } from '../utils/Utils';

const classes = {
icon: 'p-checkbox-icon p-c',
input: ({ props, checked, focusedState }) =>
classNames('p-checkbox-box', {
box: 'p-checkbox-box',
input: 'p-checkbox-input',
icon: 'p-checkbox-icon',
root: ({ props, checked }) =>
classNames('p-checkbox p-component', {
'p-highlight': checked,
'p-disabled': props.disabled,
'p-focus': focusedState
}),
root: ({ props, checked, focusedState }) =>
classNames('p-checkbox p-component', {
'p-checkbox-checked': checked,
'p-checkbox-disabled': props.disabled,
'p-checkbox-focused': focusedState
'p-invalid': props.invalid,
'p-variant-filled': props.variant === 'filled'
})
};

const styles = `
.p-checkbox {
display: inline-flex;
cursor: pointer;
user-select: none;
vertical-align: bottom;
position: relative;
}
.p-checkbox.p-checkbox-disabled {
cursor: auto;
}
.p-checkbox-box {
display: flex;
justify-content: center;
align-items: center;
}
`;

export const CheckboxBase = ComponentBase.extend({
defaultProps: {
Expand Down Expand Up @@ -65,7 +43,6 @@ export const CheckboxBase = ComponentBase.extend({
children: undefined
},
css: {
classes,
styles
classes
}
});
38 changes: 5 additions & 33 deletions components/lib/checkbox/checkbox.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@ export declare type CheckboxPassThroughType<T> = PassThroughType<T, CheckboxPass
*/
export interface CheckboxPassThroughMethodOptions {
props: CheckboxProps;
state: CheckboxState;
context: CheckboxContext;
}

Expand All @@ -39,6 +38,10 @@ export interface CheckboxPassThroughOptions {
* Uses to pass attributes to the input's DOM element.
*/
input?: CheckboxPassThroughType<React.HTMLAttributes<HTMLDivElement>>;
/**
* Used to pass attributes to the box's DOM element.
*/
box?: CheckboxPassThroughType<React.HTMLAttributes<HTMLDivElement>>;
/**
* Uses to pass attributes to the icon's DOM element.
*/
Expand All @@ -48,14 +51,6 @@ export interface CheckboxPassThroughOptions {
* @type {TooltipPassThroughOptions}
*/
tooltip?: TooltipPassThroughOptions;
/**
* Uses to pass attributes to the hidden input wrapper's DOM element.
*/
hiddenInputWrapper?: CheckboxPassThroughType<React.HTMLAttributes<HTMLDivElement>>;
/**
* Uses to pass attributes to the hidden input's DOM element.
*/
hiddenInput?: CheckboxPassThroughType<React.HTMLAttributes<HTMLInputElement>>;
/**
* Used to manage all lifecycle hooks
* @see {@link ComponentHooks}
Expand All @@ -79,16 +74,6 @@ export interface CheckboxContext {
disabled: boolean;
}

/**
* Defines current inline state in Checkbox component.
*/
export interface CheckboxState {
/**
* Current focus state as a boolean.
* @defaultValue false
*/
focused: boolean;
}

/**
* Custom change event.
Expand All @@ -98,19 +83,11 @@ export interface CheckboxState {
*/
interface CheckboxChangeEvent extends FormEvent {}

/**
* Custom click event.
* @see {@link CheckboxProps.onClick}
* @extends {FormEvent }
* @event
*/
interface CheckboxClickEvent extends FormEvent {}

/**
* Defines valid properties in Checkbox component. In addition to these, all properties of HTMLDivElement can be used in this component.
* @group Properties
*/
export interface CheckboxProps extends Omit<React.DetailedHTMLProps<React.InputHTMLAttributes<HTMLDivElement>, HTMLDivElement>, 'onChange' | 'onClick' | 'ref'> {
export interface CheckboxProps extends Omit<React.DetailedHTMLProps<React.InputHTMLAttributes<HTMLDivElement>, HTMLDivElement>, 'onChange' | 'ref'> {
/**
* Unique identifier of the element.
*/
Expand Down Expand Up @@ -197,11 +174,6 @@ export interface CheckboxProps extends Omit<React.DetailedHTMLProps<React.InputH
* @param {CheckboxChangeEvent} event - Custom change event
*/
onChange?(event: CheckboxChangeEvent): void;
/**
* Callback to invoke on value change. Mark the event with preventDefault to prevent the option from changing.
* @param {CheckboxClickEvent} event - Custom click event
*/
onClick?(event: CheckboxClickEvent): void;
/**
* Callback to invoke to when a mouse button is pressed.
* @param {React.MouseEvent<HTMLElement>} event - Browser event
Expand Down
Loading

0 comments on commit 2d66a30

Please sign in to comment.