Skip to content

Commit

Permalink
feat(TimePicker): add typescript typings (#13206)
Browse files Browse the repository at this point in the history
* feat(TimePicker): add TimePicker typescript typings

* chore(TimePicker): update copyright banner

* docs(all-contributors): add `GalvinGao` to `all-contributors`

* fix(TimePicker): fix `js` extension in `-test.js`

* feat(TimePicker): use `as any` for Children.map

use `as any` instead of type assertion to ensure backward compatibility

---------

Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
  • Loading branch information
GalvinGao and kodiakhq[bot] authored Feb 24, 2023
1 parent 495cfe3 commit 0ab5fc1
Show file tree
Hide file tree
Showing 6 changed files with 250 additions and 84 deletions.
9 changes: 9 additions & 0 deletions .all-contributorsrc
Original file line number Diff line number Diff line change
Expand Up @@ -1058,6 +1058,15 @@
"contributions": [
"code"
]
},
{
"login": "GalvinGao",
"name": "GalvinGao",
"avatar_url": "https://avatars.githubusercontent.com/u/12567059?v=4",
"profile": "https://galvingao.com/",
"contributions": [
"code"
]
}
],
"commitConvention": "none"
Expand Down
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -226,6 +226,7 @@ check out our [Contributing Guide](/.github/CONTRIBUTING.md) and our
<td align="center"><a href="https://github.com/remolueoend"><img src="https://avatars.githubusercontent.com/u/7881606?v=4?s=100" width="100px;" alt=""/><br /><sub><b>remolueoend</b></sub></a><br /><a href="https://github.com/carbon-design-system/carbon/commits?author=remolueoend" title="Code">💻</a></td>
<td align="center"><a href="https://jsehull.com/"><img src="https://avatars.githubusercontent.com/u/9935383?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Jesse Hull</b></sub></a><br /><a href="https://github.com/carbon-design-system/carbon/commits?author=jsehull" title="Code">💻</a></td>
<td align="center"><a href="https://github.com/awarrier99"><img src="https://avatars.githubusercontent.com/u/17476235?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Ashvin Warrier</b></sub></a><br /><a href="https://github.com/carbon-design-system/carbon/commits?author=awarrier99" title="Code">💻</a></td>
<td align="center"><a href="https://galvingao.com/"><img src="https://avatars.githubusercontent.com/u/12567059?v=4?s=100" width="100px;" alt=""/><br /><sub><b>GalvinGao</b></sub></a><br /><a href="https://github.com/carbon-design-system/carbon/commits?author=GalvinGao" title="Code">💻</a></td>
</tr>
</table>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
import React from 'react';
import { default as TimePicker } from './TimePicker';
import SelectItem from '../SelectItem';
import TimePickerSelect from '../TimePickerSelect/TimePickerSelect.js';
import TimePickerSelect from '../TimePickerSelect/TimePickerSelect.tsx';
import { render, screen, fireEvent } from '@testing-library/react';
import userEvent from '@testing-library/user-event';

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,128 @@
* LICENSE file in the root directory of this source tree.
*/

import cx from 'classnames';
import PropTypes from 'prop-types';
import React from 'react';
import cx from 'classnames';
import { usePrefix } from '../../internal/usePrefix';
import deprecate from '../../prop-types/deprecate';
import { ForwardRefReturn, ReactAttr } from '../../types/common';

type ExcludedAttributes = 'id' | 'value';

export interface TimePickerProps
extends Omit<ReactAttr<HTMLInputElement>, ExcludedAttributes> {
/**
* Pass in the children that will be rendered next to the form control
*/
children?: React.ReactNode;

/**
* Specify an optional className to be applied to the container node
*/
className?: string;

/**
* Specify whether the `<input>` should be disabled
*/
disabled?: boolean;

/**
* Specify whether you want the underlying label to be visually hidden
*/
hideLabel?: boolean;

/**
* Specify a custom `id` for the `<input>`
*/
id: string;

/**
* Specify whether the control is currently invalid
*/
invalid?: boolean;

const TimePicker = React.forwardRef(function TimePicker(
/**
* Provide the text that is displayed when the control is in an invalid state
*/
invalidText?: React.ReactNode;

/**
* Provide the text that will be read by a screen reader when visiting this
* control
*/
labelText?: React.ReactNode;

/**
* The `light` prop for `TimePicker` has been deprecated. It will be removed in v12. Use the `Layer` component instead.
*
* @deprecated The `light` prop for `TimePicker` is no longer needed and has been deprecated. It will be removed in the next major release. Use the `Layer` component instead.
*/
light?: boolean;

/**
* Specify the maximum length of the time string in `<input>`
*/
maxLength?: number;

/**
* Optionally provide an `onBlur` handler that is called whenever the
* `<input>` loses focus
*/
onBlur?: React.FocusEventHandler<HTMLInputElement>;

/**
* Optionally provide an `onChange` handler that is called whenever `<input>`
* is updated
*/
onChange?: React.ChangeEventHandler<HTMLInputElement>;

/**
* Optionally provide an `onClick` handler that is called whenever the
* `<input>` is clicked
*/
onClick?: React.MouseEventHandler<HTMLInputElement>;

/**
* Specify the regular expression working as the pattern of the time string in `<input>`
*/
pattern?: string;

/**
* Specify the placeholder attribute for the `<input>`
*/
placeholder?: string;

/**
* Specify whether the TimePicker should be read-only
*/
readOnly?: boolean;

/**
* Specify the size of the Time Picker.
*/
size?: 'sm' | 'md' | 'lg';

/**
* Specify the type of the `<input>`
*/
type?: string;

/**
* Specify the value of the `<input>`
*/
value?: string;
}

export type TimePickerComponent = ForwardRefReturn<
HTMLInputElement,
TimePickerProps
>;

const TimePicker: TimePickerComponent = React.forwardRef<
HTMLInputElement,
TimePickerProps
>(function TimePicker(
{
children,
className,
Expand All @@ -34,7 +149,7 @@ const TimePicker = React.forwardRef(function TimePicker(
value,
...rest
},
ref
ref: React.LegacyRef<HTMLInputElement>
) {
const prefix = usePrefix();

Expand Down Expand Up @@ -86,7 +201,7 @@ const TimePicker = React.forwardRef(function TimePicker(
[`${prefix}--time-picker--invalid`]: invalid,
[`${prefix}--time-picker--readonly`]: readOnly,
[`${prefix}--time-picker--${size}`]: size,
[className]: className,
...(className && { [className]: true }),
});

const labelClasses = cx(`${prefix}--label`, {
Expand Down Expand Up @@ -124,8 +239,10 @@ const TimePicker = React.forwardRef(function TimePicker(
};

const mappedChildren = React.Children.map(children, (pickerSelect) => {
return React.cloneElement(pickerSelect, {
...pickerSelect.props,
const item = pickerSelect as any;

return React.cloneElement(item, {
...item.props,
disabled: disabled,
readOnly: readOnly,
...readOnlyEventHandlers,
Expand Down
77 changes: 0 additions & 77 deletions packages/react/src/components/TimePickerSelect/TimePickerSelect.js

This file was deleted.

116 changes: 116 additions & 0 deletions packages/react/src/components/TimePickerSelect/TimePickerSelect.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
/**
* Copyright IBM Corp. 2016, 2023
*
* 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 { ChevronDown } from '@carbon/icons-react';
import cx from 'classnames';
import PropTypes from 'prop-types';
import React from 'react';

import { usePrefix } from '../../internal/usePrefix';
import { ForwardRefReturn } from '../../types/common';

export type TimePickerSelectProps = {
/**
* Provide the contents of your TimePickerSelect
*/
children?: React.ReactNode;

/**
* Specify an optional className to be applied to the node containing the label and the select box
*/
className?: string;

/**
* Optionally provide the default value of the `<select>`
*/
defaultValue?: any;

/**
* Specify whether the control is disabled
*/
disabled?: boolean;

/**
* Specify a custom `id` for the `<select>`
*/
id: string;
} & React.SelectHTMLAttributes<HTMLSelectElement> &
React.InputHTMLAttributes<HTMLSelectElement>;

type TimePickerSelectComponent = ForwardRefReturn<
HTMLSelectElement,
TimePickerSelectProps
>;

const TimePickerSelect: TimePickerSelectComponent = React.forwardRef(
function TimePickerSelect(
{
['aria-label']: ariaLabel = 'open list of options',
children,
id,
disabled = false,
className,
...rest
},
ref
) {
const prefix = usePrefix();

const selectClasses = cx({
[`${prefix}--select`]: true,
[`${prefix}--time-picker__select`]: true,
...(className && { [className]: true }),
});

return (
<div className={selectClasses}>
<select
aria-label={ariaLabel}
className={`${prefix}--select-input`}
disabled={disabled}
id={id}
ref={ref}
{...rest}>
{children}
</select>
<ChevronDown
className={`${prefix}--select__arrow`}
aria-hidden="true"
/>
</div>
);
}
);

TimePickerSelect.propTypes = {
/**
* Provide the contents of your TimePickerSelect
*/
children: PropTypes.node,

/**
* Specify an optional className to be applied to the node containing the label and the select box
*/
className: PropTypes.string,

/**
* Optionally provide the default value of the `<select>`
*/
defaultValue: PropTypes.any,

/**
* Specify whether the control is disabled
*/
disabled: PropTypes.bool,

/**
* Specify a custom `id` for the `<select>`
*/
id: PropTypes.string.isRequired,
};

export default TimePickerSelect;

0 comments on commit 0ab5fc1

Please sign in to comment.