Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Looping inputs #316

Open
wants to merge 4 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 5 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,8 +46,8 @@ Add React-Time-Picker to your project by executing `npm install react-time-picke

Here's an example of basic usage:

```js
import React, { useState } from 'react';
```tsx
import { useState } from 'react';
import TimePicker from 'react-time-picker';

function MyApp() {
Expand All @@ -65,7 +65,7 @@ function MyApp() {

If you want to use default React-Date-Picker and React-Clock styling to build upon it, you can import them by using:

```js
```ts
import 'react-time-picker/dist/TimePicker.css';
import 'react-clock/dist/Clock.css';
```
Expand All @@ -88,7 +88,7 @@ Displays an input field complete with custom inputs, native input and a clock.
| clockAriaLabel | `aria-label` for the clock button. | n/a | `"Toggle clock"` |
| clockClassName | Class name(s) that will be added along with `"react-clock"` to the main React-Clock `<time>` element. | n/a | <ul><li>String: `"class1 class2"`</li><li>Array of strings: `["class1", "class2 class3"]`</li></ul> |
| clockIcon | Content of the clock button. Setting the value explicitly to `null` will hide the icon. | (default icon) | <ul><li>String: `"Clock"`</li><li>React element: `<ClockIcon />`</li><li>React function: `ClockIcon`</li></ul> |
| closeClock | Whether to close the clock on value selection. Note: It's recommended to use shouldCloseClock function instead. | `true` | `false` |
| closeClock | Whether to close the clock on value selection. **Note**: It's recommended to use shouldCloseClock function instead. | `true` | `false` |
| data-testid | `data-testid` attribute for the main React-Time-Picker `<div>` element. | n/a | `"date-picker"` |
| disabled | Whether the time picker should be disabled. | `false` | `true` |
| disableClock | When set to `true`, will remove the clock and the button toggling its visibility. | `false` | `true` |
Expand All @@ -109,7 +109,7 @@ Displays an input field complete with custom inputs, native input and a clock.
| onClockOpen | Function called when the clock opens. | n/a | `() => alert('Clock opened')` |
| onFocus | Function called when the focuses an input. | n/a | `(event) => alert('Focused input: ', event.target.name)` |
| onInvalidChange | Function called when the user picks an invalid time. | n/a | `() => alert('Invalid time')` |
| openClockOnFocus | Whether to open the clock on input focus. Note: It's recommended to use shouldOpenClock function instead. | `true` | `false` |
| openClockOnFocus | Whether to open the clock on input focus. **Note**: It's recommended to use shouldOpenClock function instead. | `true` | `false` |
| portalContainer | Element to render the clock in using portal. | n/a | `document.getElementById('my-div')` |
| required | Whether date input should be required. | `false` | `true` |
| secondAriaLabel | `aria-label` for the second input. | n/a | `"Second"` |
Expand Down
7 changes: 7 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@
"@testing-library/react": "^14.0.0",
"@testing-library/user-event": "^14.4.0",
"@types/node": "*",
"@types/react": "*",
"eslint": "^8.26.0",
"eslint-config-wojtekmaj": "^0.9.0",
"husky": "^8.0.0",
Expand All @@ -65,9 +66,15 @@
"vitest-canvas-mock": "^0.2.2"
},
"peerDependencies": {
"@types/react": "^16.8.0 || ^17.0.0 || ^18.0.0",
"react": "^16.8.0 || ^17.0.0 || ^18.0.0",
"react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0"
},
"peerDependenciesMeta": {
"@types/react": {
"optional": true
}
},
"publishConfig": {
"access": "public",
"provenance": true
Expand Down
24 changes: 24 additions & 0 deletions src/TimeInput.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,7 @@ type TimeInputProps = {
hourPlaceholder?: string;
isClockOpen?: boolean | null;
locale?: string;
loopInputs?: boolean;
maxDetail?: Detail;
maxTime?: string;
minTime?: string;
Expand All @@ -134,6 +135,7 @@ export default function TimeInput({
hourPlaceholder,
isClockOpen: isClockOpenProps = null,
locale,
loopInputs = false,
maxDetail = 'minute',
maxTime,
minTime,
Expand Down Expand Up @@ -282,6 +284,27 @@ export default function TimeInput({
focus(nextInput);
break;
}
// if looping inputs is enabled and we try, for example, to go past
// 59 seconds, we'll intervene and "loop" back to the min.
// Because of how the events trigger,
// we actually have to 'fix' the value.
case 'ArrowUp':
if (loopInputs && event.target instanceof HTMLInputElement) {
const { value, max, min } = event.target;
if (value === max) {
event.target.value = (Number(min) - 1).toString();
}
}
break;
// Same in the other direction.
case 'ArrowDown':
if (loopInputs && event.target instanceof HTMLInputElement) {
const { value, max, min } = event.target;
if (value === min) {
event.target.value = (Number(max) + 1).toString();
}
}
break;
default:
}
}
Expand Down Expand Up @@ -615,6 +638,7 @@ TimeInput.propTypes = {
hourPlaceholder: PropTypes.string,
isClockOpen: PropTypes.bool,
locale: PropTypes.string,
loopInputs: PropTypes.bool,
maxDetail: PropTypes.oneOf(allViews),
maxTime: isTime,
minTime: isTime,
Expand Down
9 changes: 9 additions & 0 deletions src/TimePicker.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,12 @@ export type TimePickerProps = {
id?: string;
isOpen?: boolean;
locale?: string;
/**
* If enabled, inputs will loop to the min or max when going out of range.
* For example, if seconds is currently 59 and the arrow up key is pressed,
* the seconds value will go to 0.
*/
loopInputs?: boolean;
maxDetail?: Detail;
maxTime?: string;
minTime?: string;
Expand Down Expand Up @@ -115,6 +121,7 @@ export default function TimePicker(props: TimePickerProps) {
id,
isOpen: isOpenProps = null,
locale,
loopInputs = false,
maxTime,
maxDetail = 'minute',
minTime,
Expand Down Expand Up @@ -307,6 +314,7 @@ export default function TimePicker(props: TimePickerProps) {
format={format}
isClockOpen={isOpen}
locale={locale}
loopInputs={loopInputs}
maxDetail={maxDetail}
maxTime={maxTime}
minTime={minTime}
Expand Down Expand Up @@ -433,6 +441,7 @@ TimePicker.propTypes = {
id: PropTypes.string,
isOpen: PropTypes.bool,
locale: PropTypes.string,
loopInputs: PropTypes.bool,
maxDetail: PropTypes.oneOf(allViews),
maxTime: isTime,
minTime: isTime,
Expand Down
5 changes: 5 additions & 0 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -4405,6 +4405,7 @@ __metadata:
"@testing-library/react": ^14.0.0
"@testing-library/user-event": ^14.4.0
"@types/node": "*"
"@types/react": "*"
"@wojtekmaj/date-utils": ^1.1.3
clsx: ^2.0.0
eslint: ^8.26.0
Expand All @@ -4427,8 +4428,12 @@ __metadata:
vitest: ^0.30.1
vitest-canvas-mock: ^0.2.2
peerDependencies:
"@types/react": ^16.8.0 || ^17.0.0 || ^18.0.0
react: ^16.8.0 || ^17.0.0 || ^18.0.0
react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0
peerDependenciesMeta:
"@types/react":
optional: true
languageName: unknown
linkType: soft

Expand Down