Skip to content

Commit

Permalink
Merge branch 'main' into 18027-combobox-onchange-clear
Browse files Browse the repository at this point in the history
  • Loading branch information
Neues authored Nov 14, 2024
2 parents 1682e9a + ad23c63 commit e72e48e
Show file tree
Hide file tree
Showing 5 changed files with 160 additions and 27 deletions.
48 changes: 38 additions & 10 deletions packages/react/src/components/DataTable/TableSelectRow.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -87,29 +87,57 @@ const TableSelectRow = ({
}: TableSelectRowProps) => {
const prefix = usePrefix();
const uniqueNameId = useId();

const handleRadioChange = onChange
? (
value: string | number | undefined,
name: string | undefined,
event: React.ChangeEvent<HTMLInputElement>
) => {
// Convert the radio value to boolean for consistency
onChange(!!value, name || '', event);
}
: undefined;

const handleCheckboxChange = onChange
? (
checked: boolean,
name: string,
event: React.ChangeEvent<HTMLInputElement>
) => {
onChange(checked, name, event);
}
: undefined;

const selectionInputProps = {
id,
name: name ? name : uniqueNameId,
onClick: onSelect,
onChange,
checked,
disabled,
};
const InlineInputComponent = radio ? RadioButton : InlineCheckbox;

const labelValue = ariaLabel || deprecatedAriaLabel || '';
const tableSelectRowClasses = classNames(`${prefix}--table-column-checkbox`, {
...(className && { [className]: true }),
[`${prefix}--table-column-radio`]: radio,
});
return (
<td className={tableSelectRowClasses} aria-live="off">
<InlineInputComponent
{...selectionInputProps}
{...(radio && {
labelText: ariaLabel || deprecatedAriaLabel,
hideLabel: true,
})}
{...(!radio && { 'aria-label': ariaLabel || deprecatedAriaLabel })}
/>
{radio ? (
<RadioButton
{...selectionInputProps}
labelText={labelValue}
onChange={handleRadioChange}
hideLabel={true}
/>
) : (
<InlineCheckbox
{...selectionInputProps}
aria-label={labelValue}
onChange={handleCheckboxChange}
/>
)}
</td>
);
};
Expand Down
41 changes: 41 additions & 0 deletions packages/react/src/components/DatePicker/DatePicker-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -712,4 +712,45 @@ describe('Date picker with minDate and maxDate', () => {
await userEvent.keyboard('{escape}');
expect(screen.getByRole('application')).not.toHaveClass('open');
});
it('clearing end date should not cause console warnings', async () => {
const warn = jest.spyOn(console, 'warn').mockImplementation(() => {});

render(
<DatePicker onChange={() => {}} datePickerType="range" dateFormat="m/d/Y">
<DatePickerInput
id="date-picker-input-id-start"
placeholder="mm/dd/yyyy"
labelText="Start Date"
data-testid="input-value-start"
/>
<DatePickerInput
id="date-picker-input-id-end"
placeholder="mm/dd/yyyy"
labelText="End Date"
data-testid="input-value-end"
/>
</DatePicker>
);
await userEvent.type(
screen.getByLabelText('Start Date'),
'01/01/2024{enter}'
);
await userEvent.type(
screen.getByLabelText('End Date'),
'01/15/2024{enter}'
);

// Ensure the dates are correctly populated
expect(screen.getByLabelText('Start Date')).toHaveValue('01/01/2024');
expect(screen.getByLabelText('End Date')).toHaveValue('01/15/2024');

// Clear the end date
await userEvent.clear(screen.getByLabelText('End Date'));
expect(screen.getByLabelText('End Date')).toHaveValue('');

// Click on the start date input after clearing the end date
await userEvent.click(screen.getByLabelText('Start Date'));
expect(warn).not.toHaveBeenCalled();
warn.mockRestore();
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ export default (config) => (fp) => {
if (inputTo === target && fp.selectedDates[1]) {
// Using getTime() enables the ability to more readily compare the date currently
// selected in the calendar and the date currently in the value of the input
const withoutTime = (date) => date.setHours(0, 0, 0, 0);
const withoutTime = (date) => date?.setHours(0, 0, 0, 0);
const selectedToDate = withoutTime(new Date(fp.selectedDates[1]));
const currentValueToDate = withoutTime(
parseDateWithFormat(inputTo.value)
Expand All @@ -104,7 +104,7 @@ export default (config) => (fp) => {
}
}

const isValidDate = (date) => date.toString() !== 'Invalid Date';
const isValidDate = (date) => date?.toString() !== 'Invalid Date';
// save end date in calendar inmediately after it's been written down
if (inputTo === target && fp.selectedDates.length === 1 && inputTo.value) {
if (isValidDate(parseDateWithFormat(inputTo.value))) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,78 @@
* This source code is licensed under the Apache-2.0 license found in the
* LICENSE file in the root directory of this source tree.
*/

import PropTypes from 'prop-types';
import React, { useEffect, useRef } from 'react';
import deprecate from '../../prop-types/deprecate';
import { usePrefix } from '../../internal/usePrefix';
import { useMergedRefs } from '../../internal/useMergedRefs';

/** @type any */
const InlineCheckbox = React.forwardRef(
export interface InlineCheckboxProps {
/*
* Specify the label for the control
*/
'aria-label': string;

/**
* Deprecated, please use `aria-label` instead.
* Specify the label for the control
*/
ariaLabel?: string;

/**
* Specify whether the underlying control is checked,
* or not
* @default false
* */
checked?: boolean;

/**
* Specify whether the underlying input control should be disabled
* @default false
*/
disabled?: boolean;

/**
* Provide an `id` for the underlying input control
*/
id: string;

/**
* Specify whether the control is in an indeterminate state
*/
indeterminate?: boolean;

/**
* Provide a `name` for the underlying input control
*/
name: string;

/**
* Provide an optional hook that is called each time the input is updated
*/
onChange?: (
checked: boolean,
id: string,
event: React.ChangeEvent<HTMLInputElement>
) => void;

/**
* Provide a handler that is invoked when a user clicks on the control
*/
onClick?: (event: React.MouseEvent<HTMLInputElement>) => void;

/**
* Provide a handler that is invoked on the key down event for the control
*/
onKeyDown?: (event: React.KeyboardEvent<HTMLInputElement>) => void;

/**
* Provide an optional tooltip for the InlineCheckbox
*/
title?: string;
}

const InlineCheckbox = React.forwardRef<HTMLInputElement, InlineCheckboxProps>(
function InlineCheckbox(props, forwardRef) {
const {
['aria-label']: ariaLabel,
Expand All @@ -28,16 +91,19 @@ const InlineCheckbox = React.forwardRef(
title,
} = props;
const prefix = usePrefix();
const inputRef = useRef(null);
const inputRef = useRef<HTMLInputElement>(null);
const ref = useMergedRefs([inputRef, forwardRef]);
const inputProps = {

const inputProps: React.InputHTMLAttributes<HTMLInputElement> & {
ref: React.Ref<HTMLInputElement>;
} = {
checked,
className: `${prefix}--checkbox`,
disabled,
id,
name,
onClick: onClick ? onClickCheckBoxInput : onClick,
onChange: (evt) => {
onChange: (evt: React.ChangeEvent<HTMLInputElement>) => {
onChange(evt.target.checked, id, evt);
},
onKeyDown,
Expand All @@ -51,16 +117,15 @@ const InlineCheckbox = React.forwardRef(

useEffect(() => {
if (inputRef?.current) {
inputRef.current.indeterminate = indeterminate;
inputRef.current.indeterminate = indeterminate || false;
}
}, [indeterminate]);

function onClickCheckBoxInput(evt) {
// If the previous "indeterminate" is true, change "checked" to false. If it is not undefined, we're working on `TableSelectAll`
function onClickCheckBoxInput(evt: React.MouseEvent<HTMLInputElement>) {
if (indeterminate) {
evt.target.checked = false;
(evt.target as HTMLInputElement).checked = false;
}
onClick(evt);
onClick?.(evt);
}

return (
Expand All @@ -72,7 +137,7 @@ const InlineCheckbox = React.forwardRef(
htmlFor={id}
className={`${prefix}--checkbox-label`}
title={title}
onClick={(evt) => {
onClick={(evt: React.MouseEvent) => {
evt.stopPropagation();
}}>
<span className={`${prefix}--visually-hidden`}>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
* LICENSE file in the root directory of this source tree.
*/

import InlineCheckbox from './InlineCheckbox';

import InlineCheckbox, { type InlineCheckboxProps } from './InlineCheckbox';
export default InlineCheckbox;
export { InlineCheckbox };
export { InlineCheckbox, type InlineCheckboxProps };

0 comments on commit e72e48e

Please sign in to comment.