@pingux/astro 2.70.0 → 2.71.0-alpha.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/cjs/components/SelectFieldBase/SelectFieldBase.js +3 -1
- package/lib/cjs/components/TimeField/TimeField.d.ts +7 -0
- package/lib/cjs/components/TimeField/TimeField.js +105 -0
- package/lib/cjs/components/TimeField/TimeField.mdx +35 -0
- package/lib/cjs/components/TimeField/TimeField.stories.d.ts +27 -0
- package/lib/cjs/components/TimeField/TimeField.stories.js +96 -0
- package/lib/cjs/components/TimeField/TimeField.styles.d.ts +865 -0
- package/lib/cjs/components/TimeField/TimeField.styles.js +47 -0
- package/lib/cjs/components/TimeField/TimeField.test.d.ts +1 -0
- package/lib/cjs/components/TimeField/TimeField.test.js +194 -0
- package/lib/cjs/components/TimeField/TimeSegment.d.ts +4 -0
- package/lib/cjs/components/TimeField/TimeSegment.js +64 -0
- package/lib/cjs/components/TimeField/index.d.ts +2 -0
- package/lib/cjs/components/TimeField/index.js +33 -0
- package/lib/cjs/index.d.ts +2 -0
- package/lib/cjs/index.js +23 -4
- package/lib/cjs/recipes/DateTimeRangePicker.stories.js +182 -0
- package/lib/cjs/styles/forms/index.js +2 -0
- package/lib/cjs/styles/variants/variants.js +2 -0
- package/lib/cjs/types/index.d.ts +1 -0
- package/lib/cjs/types/index.js +13 -2
- package/lib/cjs/types/timefield.d.ts +69 -0
- package/lib/cjs/types/timefield.js +6 -0
- package/lib/cjs/utils/designUtils/figmaLinks.d.ts +3 -0
- package/lib/cjs/utils/designUtils/figmaLinks.js +3 -0
- package/lib/components/SelectFieldBase/SelectFieldBase.js +3 -1
- package/lib/components/TimeField/TimeField.js +92 -0
- package/lib/components/TimeField/TimeField.mdx +35 -0
- package/lib/components/TimeField/TimeField.stories.js +75 -0
- package/lib/components/TimeField/TimeField.styles.js +39 -0
- package/lib/components/TimeField/TimeField.test.js +191 -0
- package/lib/components/TimeField/TimeSegment.js +50 -0
- package/lib/components/TimeField/index.js +2 -0
- package/lib/index.js +2 -0
- package/lib/recipes/DateTimeRangePicker.stories.js +167 -0
- package/lib/styles/forms/index.js +2 -0
- package/lib/styles/variants/variants.js +2 -0
- package/lib/types/index.js +1 -0
- package/lib/types/timefield.js +1 -0
- package/lib/utils/designUtils/figmaLinks.js +3 -0
- package/package.json +4 -4
package/lib/cjs/types/index.js
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
"use strict";
|
2
2
|
|
3
|
-
var _context, _context2, _context3, _context4, _context5, _context6, _context7, _context8, _context9, _context10, _context11, _context12, _context13, _context14, _context15, _context16, _context17, _context18, _context19, _context20, _context21, _context22, _context23, _context24, _context25, _context26, _context27, _context28, _context29, _context30, _context31, _context32, _context33, _context34, _context35, _context36, _context37, _context38, _context39, _context40, _context41, _context42, _context43, _context44, _context45, _context46, _context47;
|
3
|
+
var _context, _context2, _context3, _context4, _context5, _context6, _context7, _context8, _context9, _context10, _context11, _context12, _context13, _context14, _context15, _context16, _context17, _context18, _context19, _context20, _context21, _context22, _context23, _context24, _context25, _context26, _context27, _context28, _context29, _context30, _context31, _context32, _context33, _context34, _context35, _context36, _context37, _context38, _context39, _context40, _context41, _context42, _context43, _context44, _context45, _context46, _context47, _context48;
|
4
4
|
var _Object$defineProperty = require("@babel/runtime-corejs3/core-js-stable/object/define-property");
|
5
5
|
var _forEachInstanceProperty = require("@babel/runtime-corejs3/core-js-stable/instance/for-each");
|
6
6
|
var _Object$keys = require("@babel/runtime-corejs3/core-js-stable/object/keys");
|
@@ -513,8 +513,19 @@ _forEachInstanceProperty(_context46 = _Object$keys(_text)).call(_context46, func
|
|
513
513
|
}
|
514
514
|
});
|
515
515
|
});
|
516
|
+
var _timefield = require("./timefield");
|
517
|
+
_forEachInstanceProperty(_context47 = _Object$keys(_timefield)).call(_context47, function (key) {
|
518
|
+
if (key === "default" || key === "__esModule") return;
|
519
|
+
if (key in exports && exports[key] === _timefield[key]) return;
|
520
|
+
_Object$defineProperty(exports, key, {
|
521
|
+
enumerable: true,
|
522
|
+
get: function get() {
|
523
|
+
return _timefield[key];
|
524
|
+
}
|
525
|
+
});
|
526
|
+
});
|
516
527
|
var _tooltipTrigger = require("./tooltipTrigger");
|
517
|
-
_forEachInstanceProperty(
|
528
|
+
_forEachInstanceProperty(_context48 = _Object$keys(_tooltipTrigger)).call(_context48, function (key) {
|
518
529
|
if (key === "default" || key === "__esModule") return;
|
519
530
|
if (key in exports && exports[key] === _tooltipTrigger[key]) return;
|
520
531
|
_Object$defineProperty(exports, key, {
|
@@ -0,0 +1,69 @@
|
|
1
|
+
import React, { FocusEvent, KeyboardEvent } from 'react';
|
2
|
+
import { CalendarDateTime, Time, ZonedDateTime } from '@internationalized/date';
|
3
|
+
import type { DateSegment, TimeFieldState } from '@react-stately/datepicker';
|
4
|
+
import type { TimeValue } from '@react-types/datepicker';
|
5
|
+
import { DOMAttributes, StyleProps } from './shared';
|
6
|
+
export type HourCycle = 12 | 24;
|
7
|
+
export type Granularity = 'hour' | 'minute' | 'second';
|
8
|
+
export type ValidationBehavior = 'native' | 'aria';
|
9
|
+
export type MappedTimeValue<T> = T extends ZonedDateTime ? ZonedDateTime : T extends CalendarDateTime ? CalendarDateTime : T extends Time ? Time : never;
|
10
|
+
export interface TimeFieldProps extends StyleProps, DOMAttributes {
|
11
|
+
/** Whether to display the time in 12 or 24 hour format. Default is determined by user's locale */
|
12
|
+
hourCycle?: HourCycle;
|
13
|
+
/** Determines the smallest unit that is displayed in the time picker. */
|
14
|
+
granularity?: Granularity;
|
15
|
+
/** Whether to always show leading zeros in the hour field. */
|
16
|
+
shouldForceLeadingZeros?: boolean;
|
17
|
+
/** A placeholder time that influences the format of
|
18
|
+
the placeholder shown when no value is selected. */
|
19
|
+
placeholderValue?: TimeValue | string;
|
20
|
+
/** The minimum allowed time that a user may select. */
|
21
|
+
minValue?: TimeValue | string;
|
22
|
+
/** The maximum allowed time that a user may select. */
|
23
|
+
maxValue?: TimeValue | string;
|
24
|
+
/** Whether the input is disabled. */
|
25
|
+
isDisabled?: boolean;
|
26
|
+
/** Whether the input can be selected but not changed by the user. */
|
27
|
+
isReadOnly?: boolean;
|
28
|
+
/** Whether user input is required on the input before form submission. */
|
29
|
+
isRequired?: boolean;
|
30
|
+
/** Whether the input value is invalid. */
|
31
|
+
isInvalid?: boolean;
|
32
|
+
/** Whether the element should receive focus on render. */
|
33
|
+
autoFocus?: boolean;
|
34
|
+
/** The current value (controlled). */
|
35
|
+
value?: TimeValue | string | null;
|
36
|
+
/** The default value (uncontrolled). */
|
37
|
+
defaultValue?: TimeValue | string | null;
|
38
|
+
/** The name of the input element, used when submitting an HTML form. */
|
39
|
+
name?: string;
|
40
|
+
/** Whether to use native HTML form validation to prevent form submission
|
41
|
+
when the value is missing or invalid, or mark the field as required or invalid via ARIA. */
|
42
|
+
validationBehavior?: ValidationBehavior;
|
43
|
+
/** The content to display as the label. */
|
44
|
+
label?: React.ReactNode;
|
45
|
+
/** Handler that is called when the element receives focus. */
|
46
|
+
onFocus?: (e: FocusEvent) => void;
|
47
|
+
/** Handler that is called when the element loses focus. */
|
48
|
+
onBlur?: (e: FocusEvent) => void;
|
49
|
+
/** Handler that is called when the element's focus status changes. */
|
50
|
+
onFocusChange?: (isFocused: boolean) => void;
|
51
|
+
/** Handler that is called when a key is pressed. */
|
52
|
+
onKeyDown?: (e: KeyboardEvent) => void;
|
53
|
+
/** Handler that is called when a key is released. */
|
54
|
+
onKeyUp?: (e: KeyboardEvent) => void;
|
55
|
+
/** Handler that is called when the value changes. */
|
56
|
+
onChange?: (value: MappedTimeValue<TimeValue>) => void;
|
57
|
+
/** A slot name for the component. Slots allow the component to receive props from a parent
|
58
|
+
* component. An explicit null value indicates that the local props completely
|
59
|
+
* override all props received from a parent. */
|
60
|
+
slot?: string | null;
|
61
|
+
/** The element's unique identifier. */
|
62
|
+
id?: string;
|
63
|
+
}
|
64
|
+
export interface TimeSegmentProps {
|
65
|
+
state: TimeFieldState;
|
66
|
+
segment: DateSegment;
|
67
|
+
segments: DateSegment[];
|
68
|
+
segmentIndex: number;
|
69
|
+
}
|
@@ -86,6 +86,9 @@ var FIGMA_LINKS = {
|
|
86
86
|
countryPicker: {
|
87
87
|
"default": 'https://www.figma.com/file/Oa6VYtJcUJzEJuuRp0p4ls/Astro?type=design&node-id=4568-7532&mode=design&t=eSfQYHRFNPf37J4C-0'
|
88
88
|
},
|
89
|
+
dateTimeRangePicker: {
|
90
|
+
"default": 'https://www.figma.com/design/bpbEw54gTTcdIiZs4PKK1p/Astro-Specs?node-id=49152-4497&t=n7OkhpTOBBWW4rme-0'
|
91
|
+
},
|
89
92
|
helpHint: {
|
90
93
|
"default": 'https://www.figma.com/file/Oa6VYtJcUJzEJuuRp0p4ls/Astro?type=design&node-id=0%3A4534&t=We3h7LaaFJQnxdSy-1',
|
91
94
|
withLink: 'https://www.figma.com/file/bpbEw54gTTcdIiZs4PKK1p/Astro-Specs?type=design&node-id=28958%3A40081&mode=design&t=WmSYPx1hR8kxFiXf-1'
|
@@ -73,7 +73,7 @@ var SelectFieldBase = /*#__PURE__*/forwardRef(function (_ref, ref) {
|
|
73
73
|
variant: "forms.select"
|
74
74
|
}, triggerProps, ariaProps, {
|
75
75
|
"aria-describedby": helperText && helperTextId
|
76
|
-
}), ___EmotionJSX(Box, _extends({
|
76
|
+
}), slots === null || slots === void 0 ? void 0 : slots.leftOfData, ___EmotionJSX(Box, _extends({
|
77
77
|
as: "span",
|
78
78
|
variant: "forms.select.currentValue"
|
79
79
|
}, valueProps), state.selectedItem ? state.selectedItem.rendered : ___EmotionJSX(Text, {
|
@@ -148,6 +148,8 @@ SelectFieldBase.propTypes = _objectSpread(_objectSpread({
|
|
148
148
|
}),
|
149
149
|
/** Provides a way to insert markup in specified places. */
|
150
150
|
slots: PropTypes.shape({
|
151
|
+
/** The given node will be inserted before the text in field container. */
|
152
|
+
leftOfData: PropTypes.node,
|
151
153
|
/** The given node will be inserted into the field container. */
|
152
154
|
inContainer: PropTypes.node
|
153
155
|
}),
|
@@ -0,0 +1,92 @@
|
|
1
|
+
import _Object$keys from "@babel/runtime-corejs3/core-js-stable/object/keys";
|
2
|
+
import _Object$getOwnPropertySymbols from "@babel/runtime-corejs3/core-js-stable/object/get-own-property-symbols";
|
3
|
+
import _filterInstanceProperty from "@babel/runtime-corejs3/core-js-stable/instance/filter";
|
4
|
+
import _Object$getOwnPropertyDescriptor from "@babel/runtime-corejs3/core-js-stable/object/get-own-property-descriptor";
|
5
|
+
import _forEachInstanceProperty from "@babel/runtime-corejs3/core-js-stable/instance/for-each";
|
6
|
+
import _Object$getOwnPropertyDescriptors from "@babel/runtime-corejs3/core-js-stable/object/get-own-property-descriptors";
|
7
|
+
import _Object$defineProperties from "@babel/runtime-corejs3/core-js-stable/object/define-properties";
|
8
|
+
import _Object$defineProperty from "@babel/runtime-corejs3/core-js-stable/object/define-property";
|
9
|
+
import _extends from "@babel/runtime-corejs3/helpers/esm/extends";
|
10
|
+
import _defineProperty from "@babel/runtime-corejs3/helpers/esm/defineProperty";
|
11
|
+
import _objectWithoutProperties from "@babel/runtime-corejs3/helpers/esm/objectWithoutProperties";
|
12
|
+
var _excluded = ["className", "isDisabled", "isReadOnly"];
|
13
|
+
import _mapInstanceProperty from "@babel/runtime-corejs3/core-js-stable/instance/map";
|
14
|
+
function ownKeys(object, enumerableOnly) { var keys = _Object$keys(object); if (_Object$getOwnPropertySymbols) { var symbols = _Object$getOwnPropertySymbols(object); enumerableOnly && (symbols = _filterInstanceProperty(symbols).call(symbols, function (sym) { return _Object$getOwnPropertyDescriptor(object, sym).enumerable; })), keys.push.apply(keys, symbols); } return keys; }
|
15
|
+
function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var _context2, _context3; var source = null != arguments[i] ? arguments[i] : {}; i % 2 ? _forEachInstanceProperty(_context2 = ownKeys(Object(source), !0)).call(_context2, function (key) { _defineProperty(target, key, source[key]); }) : _Object$getOwnPropertyDescriptors ? _Object$defineProperties(target, _Object$getOwnPropertyDescriptors(source)) : _forEachInstanceProperty(_context3 = ownKeys(Object(source))).call(_context3, function (key) { _Object$defineProperty(target, key, _Object$getOwnPropertyDescriptor(source, key)); }); } return target; }
|
16
|
+
import React, { forwardRef, useRef } from 'react';
|
17
|
+
import { FocusScope } from 'react-aria';
|
18
|
+
import { parseTime, Time } from '@internationalized/date';
|
19
|
+
import { useTimeField } from '@react-aria/datepicker';
|
20
|
+
import { useLocale } from '@react-aria/i18n';
|
21
|
+
import { useTimeFieldState } from '@react-stately/datepicker';
|
22
|
+
import { useField, useLocalOrForwardRef, useStatusClasses } from '../../hooks';
|
23
|
+
import { Box, Label } from '../../index';
|
24
|
+
import TimeSegment from './TimeSegment';
|
25
|
+
import { jsx as ___EmotionJSX } from "@emotion/react";
|
26
|
+
export var parseTimeIfString = function parseTimeIfString(value) {
|
27
|
+
return typeof value === 'string' ? parseTime(value) : value;
|
28
|
+
};
|
29
|
+
var TimeField = /*#__PURE__*/forwardRef(function (props, ref) {
|
30
|
+
var _state$value, _context;
|
31
|
+
var className = props.className,
|
32
|
+
isDisabled = props.isDisabled,
|
33
|
+
isReadOnly = props.isReadOnly,
|
34
|
+
others = _objectWithoutProperties(props, _excluded);
|
35
|
+
var _useLocale = useLocale(),
|
36
|
+
locale = _useLocale.locale;
|
37
|
+
var timeFieldRef = useLocalOrForwardRef(ref);
|
38
|
+
var fieldRef = useRef(null);
|
39
|
+
var labelRef = useRef(null);
|
40
|
+
var parsedTimes = {
|
41
|
+
value: props.value && parseTimeIfString(props.value),
|
42
|
+
defaultValue: props.defaultValue ? parseTimeIfString(props.defaultValue) : new Time(),
|
43
|
+
placeholderValue: props.placeholderValue && parseTimeIfString(props.placeholderValue),
|
44
|
+
minValue: props.minValue && parseTimeIfString(props.minValue),
|
45
|
+
maxValue: props.maxValue && parseTimeIfString(props.maxValue)
|
46
|
+
};
|
47
|
+
var state = useTimeFieldState(_objectSpread(_objectSpread(_objectSpread({}, props), parsedTimes), {}, {
|
48
|
+
locale: locale
|
49
|
+
}));
|
50
|
+
var _useStatusClasses = useStatusClasses(className, {
|
51
|
+
isDisabled: isDisabled,
|
52
|
+
isReadOnly: isReadOnly,
|
53
|
+
is24Hour: props.hourCycle === 24
|
54
|
+
}),
|
55
|
+
classNames = _useStatusClasses.classNames;
|
56
|
+
var _useTimeField = useTimeField(_objectSpread(_objectSpread({}, props), parsedTimes), state, fieldRef),
|
57
|
+
fieldProps = _useTimeField.fieldProps;
|
58
|
+
var _useField = useField(_objectSpread(_objectSpread({}, others), {}, {
|
59
|
+
value: (state === null || state === void 0 || (_state$value = state.value) === null || _state$value === void 0 ? void 0 : _state$value.toString()) || ''
|
60
|
+
})),
|
61
|
+
fieldContainerProps = _useField.fieldContainerProps,
|
62
|
+
fieldLabelProps = _useField.fieldLabelProps;
|
63
|
+
return ___EmotionJSX(Box, _extends({
|
64
|
+
variant: "forms.input.fieldContainer"
|
65
|
+
}, fieldContainerProps, {
|
66
|
+
ref: timeFieldRef
|
67
|
+
}), ___EmotionJSX(Label, _extends({}, fieldLabelProps, {
|
68
|
+
ref: labelRef
|
69
|
+
})), ___EmotionJSX(Box, {
|
70
|
+
isRow: true,
|
71
|
+
variant: "forms.input.fieldControlWrapper",
|
72
|
+
className: classNames
|
73
|
+
}, ___EmotionJSX(Box, _extends({
|
74
|
+
isRow: true,
|
75
|
+
variant: "forms.timeField.inputField"
|
76
|
+
}, fieldProps, {
|
77
|
+
ref: fieldRef,
|
78
|
+
className: classNames,
|
79
|
+
role: "group"
|
80
|
+
}), ___EmotionJSX(FocusScope, null, _mapInstanceProperty(_context = state.segments).call(_context, function (segment, i) {
|
81
|
+
return ___EmotionJSX(TimeSegment
|
82
|
+
// eslint-disable-next-line react/no-array-index-key
|
83
|
+
, {
|
84
|
+
key: i,
|
85
|
+
segment: segment,
|
86
|
+
state: state,
|
87
|
+
segments: state.segments,
|
88
|
+
segmentIndex: i
|
89
|
+
});
|
90
|
+
})))));
|
91
|
+
});
|
92
|
+
export default TimeField;
|
@@ -0,0 +1,35 @@
|
|
1
|
+
import { Meta } from '@storybook/addon-docs';
|
2
|
+
|
3
|
+
<Meta title="Experimental/TimeField/TimeField" />
|
4
|
+
|
5
|
+
# TimeField
|
6
|
+
|
7
|
+
The TimeField component allows users to enter and edit time values using a keyboard. Each part of the time is displayed in individual editable segments.
|
8
|
+
|
9
|
+
When using strings as props for different TimeValues, ensure that they adhere to the [ISO 8601](https://en.wikipedia.org/wiki/ISO_8601) format.
|
10
|
+
|
11
|
+
This component is built on [useTimeField](https://react-spectrum.adobe.com/react-aria/useTimeField.html) from React Aria
|
12
|
+
and [useTimeFieldState](https://react-spectrum.adobe.com/react-stately/useTimeFieldState.html) from React Stately.
|
13
|
+
|
14
|
+
### Required components
|
15
|
+
|
16
|
+
This component can be used independently and does not require additional components.
|
17
|
+
|
18
|
+
#### Keyboard Navigation
|
19
|
+
|
20
|
+
These keys provide additional functionality to the component.
|
21
|
+
|
22
|
+
| Keys | Functions |
|
23
|
+
| ---- | --------- |
|
24
|
+
| Tab | Focuses the field and follows the page tab sequence. |
|
25
|
+
| Shift + Tab | Moves focus to the previous focusable component. |
|
26
|
+
| Up and down Arrow keys | When segments are focused, it increments and decrements time values |
|
27
|
+
| Left and right arrows | Moves focus between segments. |
|
28
|
+
|
29
|
+
#### Screen Readers
|
30
|
+
|
31
|
+
This component uses the following attributes to assist screen readers:
|
32
|
+
|
33
|
+
- The **`aria-label`** attribute is used to provide an accessible name.
|
34
|
+
- The hidden input, TimeField, and all spin buttons have an **`aria-labelledby`** attribute pointing to the label ID, along with the **`aria-label`** attribute for an accessible name.
|
35
|
+
- Each spin button has an **`aria-valuenow`**, **`aria-valuemin`**, and **`aria-valuemax`** to represent the current value, minimum allowed value, and maximum allowed value.
|
@@ -0,0 +1,75 @@
|
|
1
|
+
import _slicedToArray from "@babel/runtime-corejs3/helpers/esm/slicedToArray";
|
2
|
+
import _extends from "@babel/runtime-corejs3/helpers/esm/extends";
|
3
|
+
import React, { useState } from 'react';
|
4
|
+
import DocsLayout from '../../../.storybook/storybookDocsLayout';
|
5
|
+
import { TimeField } from '../../index';
|
6
|
+
import TimeFieldReadme from './TimeField.mdx';
|
7
|
+
import { jsx as ___EmotionJSX } from "@emotion/react";
|
8
|
+
export default {
|
9
|
+
title: 'Experimental/TimeField',
|
10
|
+
component: TimeField,
|
11
|
+
parameters: {
|
12
|
+
actions: {
|
13
|
+
argTypesRegex: '^on.*'
|
14
|
+
},
|
15
|
+
docs: {
|
16
|
+
source: {
|
17
|
+
type: 'code'
|
18
|
+
},
|
19
|
+
page: function page() {
|
20
|
+
return ___EmotionJSX(React.Fragment, null, ___EmotionJSX(TimeFieldReadme, null), ___EmotionJSX(DocsLayout, null));
|
21
|
+
}
|
22
|
+
}
|
23
|
+
},
|
24
|
+
argTypes: {}
|
25
|
+
};
|
26
|
+
export var Default = function Default(args) {
|
27
|
+
return ___EmotionJSX(TimeField, _extends({}, args, {
|
28
|
+
"aria-label": "timefield-default"
|
29
|
+
}));
|
30
|
+
};
|
31
|
+
export var DefaultValue = function DefaultValue(args) {
|
32
|
+
return ___EmotionJSX(TimeField, _extends({}, args, {
|
33
|
+
"aria-label": "timefield-default",
|
34
|
+
defaultValue: "12:30"
|
35
|
+
}));
|
36
|
+
};
|
37
|
+
export var Controlled = function Controlled(args) {
|
38
|
+
var _useState = useState('12:30'),
|
39
|
+
_useState2 = _slicedToArray(_useState, 2),
|
40
|
+
time = _useState2[0],
|
41
|
+
setTime = _useState2[1];
|
42
|
+
var onChangeHandler = function onChangeHandler(value) {
|
43
|
+
return setTime(value.toString());
|
44
|
+
};
|
45
|
+
return ___EmotionJSX(TimeField, _extends({}, args, {
|
46
|
+
"aria-label": "timefield-default",
|
47
|
+
value: time,
|
48
|
+
onChange: onChangeHandler
|
49
|
+
}));
|
50
|
+
};
|
51
|
+
export var Disabled = function Disabled(args) {
|
52
|
+
return ___EmotionJSX(TimeField, _extends({}, args, {
|
53
|
+
"aria-label": "timefield-default",
|
54
|
+
isDisabled: true
|
55
|
+
}));
|
56
|
+
};
|
57
|
+
export var ReadOnly = function ReadOnly(args) {
|
58
|
+
return ___EmotionJSX(TimeField, _extends({}, args, {
|
59
|
+
"aria-label": "timefield-default",
|
60
|
+
isReadOnly: true
|
61
|
+
}));
|
62
|
+
};
|
63
|
+
export var Required = function Required(args) {
|
64
|
+
return ___EmotionJSX(TimeField, _extends({}, args, {
|
65
|
+
"aria-label": "timefield-default",
|
66
|
+
isRequired: true,
|
67
|
+
label: "Example label"
|
68
|
+
}));
|
69
|
+
};
|
70
|
+
export var WithLabel = function WithLabel(args) {
|
71
|
+
return ___EmotionJSX(TimeField, _extends({}, args, {
|
72
|
+
label: "Loren Ipsum",
|
73
|
+
"aria-label": "timefield-default"
|
74
|
+
}));
|
75
|
+
};
|
@@ -0,0 +1,39 @@
|
|
1
|
+
import _Object$keys from "@babel/runtime-corejs3/core-js-stable/object/keys";
|
2
|
+
import _Object$getOwnPropertySymbols from "@babel/runtime-corejs3/core-js-stable/object/get-own-property-symbols";
|
3
|
+
import _filterInstanceProperty from "@babel/runtime-corejs3/core-js-stable/instance/filter";
|
4
|
+
import _Object$getOwnPropertyDescriptor from "@babel/runtime-corejs3/core-js-stable/object/get-own-property-descriptor";
|
5
|
+
import _forEachInstanceProperty from "@babel/runtime-corejs3/core-js-stable/instance/for-each";
|
6
|
+
import _Object$getOwnPropertyDescriptors from "@babel/runtime-corejs3/core-js-stable/object/get-own-property-descriptors";
|
7
|
+
import _Object$defineProperties from "@babel/runtime-corejs3/core-js-stable/object/define-properties";
|
8
|
+
import _Object$defineProperty from "@babel/runtime-corejs3/core-js-stable/object/define-property";
|
9
|
+
import _defineProperty from "@babel/runtime-corejs3/helpers/esm/defineProperty";
|
10
|
+
function ownKeys(object, enumerableOnly) { var keys = _Object$keys(object); if (_Object$getOwnPropertySymbols) { var symbols = _Object$getOwnPropertySymbols(object); enumerableOnly && (symbols = _filterInstanceProperty(symbols).call(symbols, function (sym) { return _Object$getOwnPropertyDescriptor(object, sym).enumerable; })), keys.push.apply(keys, symbols); } return keys; }
|
11
|
+
function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var _context, _context2; var source = null != arguments[i] ? arguments[i] : {}; i % 2 ? _forEachInstanceProperty(_context = ownKeys(Object(source), !0)).call(_context, function (key) { _defineProperty(target, key, source[key]); }) : _Object$getOwnPropertyDescriptors ? _Object$defineProperties(target, _Object$getOwnPropertyDescriptors(source)) : _forEachInstanceProperty(_context2 = ownKeys(Object(source))).call(_context2, function (key) { _Object$defineProperty(target, key, _Object$getOwnPropertyDescriptor(source, key)); }); } return target; }
|
12
|
+
import { defaultFocus, input } from '../Input/Input.styles';
|
13
|
+
var inputField = _objectSpread(_objectSpread({}, input), {}, {
|
14
|
+
minWidth: '100px',
|
15
|
+
width: 'auto',
|
16
|
+
position: 'relative',
|
17
|
+
'&:focus-within:not(.is-read-only)': _objectSpread({}, defaultFocus),
|
18
|
+
':hover': {
|
19
|
+
cursor: 'text'
|
20
|
+
},
|
21
|
+
'&.is-read-only': {
|
22
|
+
backgroundColor: 'accent.95',
|
23
|
+
border: 'none'
|
24
|
+
},
|
25
|
+
'&.is-24-hour': {
|
26
|
+
minWidth: '0px'
|
27
|
+
}
|
28
|
+
});
|
29
|
+
var segment = {
|
30
|
+
'&:focus-visible': {
|
31
|
+
outline: '1px solid',
|
32
|
+
outlineColor: 'active',
|
33
|
+
borderRadius: 4
|
34
|
+
}
|
35
|
+
};
|
36
|
+
export default {
|
37
|
+
inputField: inputField,
|
38
|
+
segment: segment
|
39
|
+
};
|
@@ -0,0 +1,191 @@
|
|
1
|
+
import _extends from "@babel/runtime-corejs3/helpers/esm/extends";
|
2
|
+
import _forEachInstanceProperty from "@babel/runtime-corejs3/core-js-stable/instance/for-each";
|
3
|
+
import React from 'react';
|
4
|
+
import { Time } from '@internationalized/date';
|
5
|
+
import { parseTimeIfString, TimeField } from '../../index';
|
6
|
+
import { act, fireEvent, render, screen } from '../../utils/testUtils/testWrapper';
|
7
|
+
import { universalComponentTests } from '../../utils/testUtils/universalComponentTest';
|
8
|
+
import { jsx as ___EmotionJSX } from "@emotion/react";
|
9
|
+
var getComponent = function getComponent() {
|
10
|
+
var props = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
|
11
|
+
return render(___EmotionJSX(TimeField, _extends({}, props, {
|
12
|
+
"aria-label": "TimeField"
|
13
|
+
})));
|
14
|
+
};
|
15
|
+
|
16
|
+
// Needs to be added to each components test file.
|
17
|
+
universalComponentTests({
|
18
|
+
renderComponent: function renderComponent(props) {
|
19
|
+
return ___EmotionJSX(TimeField, _extends({}, props, {
|
20
|
+
"aria-label": "TimeField"
|
21
|
+
}));
|
22
|
+
}
|
23
|
+
});
|
24
|
+
test('renders TimeField component', function () {
|
25
|
+
getComponent();
|
26
|
+
expect(screen.getByRole('group')).toBeInTheDocument();
|
27
|
+
});
|
28
|
+
test('renders the correct number of time segments', function () {
|
29
|
+
getComponent();
|
30
|
+
var timeSegments = screen.getAllByRole('spinbutton');
|
31
|
+
expect(timeSegments.length).toBe(3);
|
32
|
+
});
|
33
|
+
test('renders the correct number of time segments when granularity is set to seconds', function () {
|
34
|
+
getComponent({
|
35
|
+
granularity: 'second'
|
36
|
+
});
|
37
|
+
var timeSegments = screen.getAllByRole('spinbutton');
|
38
|
+
expect(timeSegments.length).toBe(4);
|
39
|
+
});
|
40
|
+
test('renders the correct number of time segments when hourCycle is set to 24', function () {
|
41
|
+
getComponent({
|
42
|
+
hourCycle: 24
|
43
|
+
});
|
44
|
+
var timeSegments = screen.getAllByRole('spinbutton');
|
45
|
+
expect(timeSegments.length).toBe(2);
|
46
|
+
});
|
47
|
+
test('renders the correct number of time segments when hourCycle is set to 24 and granularity is set to seconds', function () {
|
48
|
+
getComponent({
|
49
|
+
hourCycle: 24,
|
50
|
+
granularity: 'second'
|
51
|
+
});
|
52
|
+
var timeSegments = screen.getAllByRole('spinbutton');
|
53
|
+
expect(timeSegments.length).toBe(3);
|
54
|
+
});
|
55
|
+
test('renders the correct time with defaultValue', function () {
|
56
|
+
var defaultValue = new Time(3);
|
57
|
+
getComponent({
|
58
|
+
defaultValue: defaultValue
|
59
|
+
});
|
60
|
+
var timeSegments = screen.getAllByRole('spinbutton');
|
61
|
+
expect(timeSegments[0]).toHaveTextContent('3');
|
62
|
+
expect(timeSegments[1]).toHaveTextContent('00');
|
63
|
+
expect(timeSegments[2]).toHaveTextContent('AM');
|
64
|
+
});
|
65
|
+
test('renders the correct time with controlled value', function () {
|
66
|
+
var value = new Time(3);
|
67
|
+
getComponent({
|
68
|
+
value: value
|
69
|
+
});
|
70
|
+
var timeSegments = screen.getAllByRole('spinbutton');
|
71
|
+
expect(timeSegments[0]).toHaveTextContent('3');
|
72
|
+
expect(timeSegments[1]).toHaveTextContent('00');
|
73
|
+
expect(timeSegments[2]).toHaveTextContent('AM');
|
74
|
+
});
|
75
|
+
test('renders TimeField component with isDisabled', function () {
|
76
|
+
getComponent({
|
77
|
+
isDisabled: true
|
78
|
+
});
|
79
|
+
var timeSegments = screen.getAllByRole('spinbutton');
|
80
|
+
_forEachInstanceProperty(timeSegments).call(timeSegments, function (segment) {
|
81
|
+
expect(segment).toHaveAttribute('aria-disabled', 'true');
|
82
|
+
});
|
83
|
+
});
|
84
|
+
test('renders TimeField component with isReadOnly', function () {
|
85
|
+
getComponent({
|
86
|
+
isReadOnly: true
|
87
|
+
});
|
88
|
+
var timeSegments = screen.getAllByRole('spinbutton');
|
89
|
+
_forEachInstanceProperty(timeSegments).call(timeSegments, function (segment) {
|
90
|
+
expect(segment).toHaveAttribute('aria-readonly', 'true');
|
91
|
+
});
|
92
|
+
});
|
93
|
+
test('should handle autofocus when deleting segments from left to right', function () {
|
94
|
+
var defaultValue = new Time(12, 30);
|
95
|
+
getComponent({
|
96
|
+
defaultValue: defaultValue
|
97
|
+
});
|
98
|
+
var timeSegments = screen.queryAllByRole('spinbutton');
|
99
|
+
var hour = timeSegments[0];
|
100
|
+
var minute = timeSegments[1];
|
101
|
+
var period = timeSegments[2];
|
102
|
+
expect(hour).toHaveTextContent('12');
|
103
|
+
expect(minute).toHaveTextContent('30');
|
104
|
+
expect(period).toHaveTextContent('PM');
|
105
|
+
act(function () {
|
106
|
+
hour.focus();
|
107
|
+
});
|
108
|
+
for (var i = 0; i < 2; i += 1) {
|
109
|
+
fireEvent.keyDown(hour, {
|
110
|
+
key: 'Backspace'
|
111
|
+
});
|
112
|
+
fireEvent.keyUp(hour, {
|
113
|
+
key: 'Backspace'
|
114
|
+
});
|
115
|
+
}
|
116
|
+
expect(minute).toHaveFocus();
|
117
|
+
});
|
118
|
+
test('should handle autofocus when deleting segments from right to left', function () {
|
119
|
+
var defaultValue = new Time(12, 30);
|
120
|
+
getComponent({
|
121
|
+
defaultValue: defaultValue
|
122
|
+
});
|
123
|
+
var timeSegments = screen.queryAllByRole('spinbutton');
|
124
|
+
var hour = timeSegments[0];
|
125
|
+
var minute = timeSegments[1];
|
126
|
+
var period = timeSegments[2];
|
127
|
+
expect(hour).toHaveTextContent('12');
|
128
|
+
expect(minute).toHaveTextContent('30');
|
129
|
+
expect(period).toHaveTextContent('PM');
|
130
|
+
act(function () {
|
131
|
+
minute.focus();
|
132
|
+
});
|
133
|
+
for (var i = 0; i < 2; i += 1) {
|
134
|
+
fireEvent.keyDown(minute, {
|
135
|
+
key: 'Backspace'
|
136
|
+
});
|
137
|
+
fireEvent.keyUp(minute, {
|
138
|
+
key: 'Backspace'
|
139
|
+
});
|
140
|
+
}
|
141
|
+
expect(hour).toHaveFocus();
|
142
|
+
});
|
143
|
+
describe('parseTimeIfString', function () {
|
144
|
+
it('should parse a time with only hours', function () {
|
145
|
+
var time = parseTimeIfString('14');
|
146
|
+
var expected = new Time(14);
|
147
|
+
expect(time).toEqual(expected);
|
148
|
+
});
|
149
|
+
it('should parse a padded time with only hours', function () {
|
150
|
+
var time = parseTimeIfString('04');
|
151
|
+
var expected = new Time(4);
|
152
|
+
expect(time).toEqual(expected);
|
153
|
+
});
|
154
|
+
it('should parse a time with hours and minutes', function () {
|
155
|
+
var time = parseTimeIfString('14:05');
|
156
|
+
var expected = new Time(14, 5);
|
157
|
+
expect(time).toEqual(expected);
|
158
|
+
});
|
159
|
+
it('should parse a time with hours, minutes, and seconds', function () {
|
160
|
+
var time = parseTimeIfString('14:05:25');
|
161
|
+
var expected = new Time(14, 5, 25);
|
162
|
+
expect(time).toEqual(expected);
|
163
|
+
});
|
164
|
+
it('should parse a time with hours, minutes, seconds, and milliseconds', function () {
|
165
|
+
var time = parseTimeIfString('14:05:25.1');
|
166
|
+
var expected = new Time(14, 5, 25, 100);
|
167
|
+
expect(time).toEqual(expected);
|
168
|
+
time = parseTimeIfString('14:05:25.12');
|
169
|
+
expected = new Time(14, 5, 25, 120);
|
170
|
+
expect(time).toEqual(expected);
|
171
|
+
});
|
172
|
+
it('should error if time is not padded', function () {
|
173
|
+
expect(function () {
|
174
|
+
return parseTimeIfString('1');
|
175
|
+
}).toThrow();
|
176
|
+
expect(function () {
|
177
|
+
return parseTimeIfString('01:4');
|
178
|
+
}).toThrow();
|
179
|
+
});
|
180
|
+
it('should error if components are out of range', function () {
|
181
|
+
expect(function () {
|
182
|
+
return parseTimeIfString('45:23');
|
183
|
+
}).toThrow();
|
184
|
+
expect(function () {
|
185
|
+
return parseTimeIfString('12:99');
|
186
|
+
}).toThrow();
|
187
|
+
expect(function () {
|
188
|
+
return parseTimeIfString('12:45:99');
|
189
|
+
}).toThrow();
|
190
|
+
});
|
191
|
+
});
|
@@ -0,0 +1,50 @@
|
|
1
|
+
import _extends from "@babel/runtime-corejs3/helpers/esm/extends";
|
2
|
+
import React, { useCallback, useRef } from 'react';
|
3
|
+
import { useFocusManager } from 'react-aria';
|
4
|
+
import { useDateSegment } from '@react-aria/datepicker';
|
5
|
+
import { Box } from '../../index';
|
6
|
+
import { jsx as ___EmotionJSX } from "@emotion/react";
|
7
|
+
var TimeSegment = function TimeSegment(props) {
|
8
|
+
var state = props.state,
|
9
|
+
segment = props.segment,
|
10
|
+
segments = props.segments,
|
11
|
+
segmentIndex = props.segmentIndex;
|
12
|
+
var text = segment.text,
|
13
|
+
isPlaceholder = segment.isPlaceholder;
|
14
|
+
var ref = useRef(null);
|
15
|
+
var _useDateSegment = useDateSegment(segment, state, ref),
|
16
|
+
segmentProps = _useDateSegment.segmentProps;
|
17
|
+
delete segmentProps.role;
|
18
|
+
var focusManager = useFocusManager();
|
19
|
+
var handleKeyEvents = useCallback(function (e) {
|
20
|
+
var getSegmentValue = function getSegmentValue(seg) {
|
21
|
+
if (!seg) return false;
|
22
|
+
var isNumber = /^\d+$/.test(seg.text);
|
23
|
+
return isNumber;
|
24
|
+
};
|
25
|
+
if (e.key === 'Backspace' && isPlaceholder) {
|
26
|
+
var nextSegmentIndex = segmentIndex + 1;
|
27
|
+
while (segments[nextSegmentIndex] && segments[nextSegmentIndex].type === 'literal') {
|
28
|
+
nextSegmentIndex += 1;
|
29
|
+
}
|
30
|
+
var nextSegment = segments[nextSegmentIndex];
|
31
|
+
var previousSegmentIndex = segmentIndex - 1;
|
32
|
+
while (segments[previousSegmentIndex] && segments[previousSegmentIndex].type === 'literal') {
|
33
|
+
previousSegmentIndex -= 1;
|
34
|
+
}
|
35
|
+
var previousSegment = segments[previousSegmentIndex];
|
36
|
+
if (getSegmentValue(nextSegment)) return focusManager.focusNext();
|
37
|
+
if (!getSegmentValue(nextSegment) && getSegmentValue(previousSegment)) {
|
38
|
+
return focusManager.focusPrevious();
|
39
|
+
}
|
40
|
+
}
|
41
|
+
return null;
|
42
|
+
}, [focusManager, isPlaceholder, segments, segmentIndex]);
|
43
|
+
return ___EmotionJSX(Box, _extends({}, segmentProps, {
|
44
|
+
ref: ref,
|
45
|
+
variant: "forms.timeField.segment",
|
46
|
+
onKeyUp: handleKeyEvents,
|
47
|
+
role: "spinbutton"
|
48
|
+
}), text);
|
49
|
+
};
|
50
|
+
export default TimeSegment;
|
package/lib/index.js
CHANGED
@@ -180,6 +180,8 @@ export { default as TextAreaField } from './components/TextAreaField';
|
|
180
180
|
export * from './components/TextAreaField';
|
181
181
|
export { default as TextField } from './components/TextField';
|
182
182
|
export * from './components/TextField';
|
183
|
+
export { default as TimeField } from './components/TimeField';
|
184
|
+
export * from './components/TimeField';
|
183
185
|
export { default as TimeZonePicker } from './components/TimeZonePicker';
|
184
186
|
export { default as TooltipTrigger } from './components/TooltipTrigger';
|
185
187
|
export * from './components/TooltipTrigger';
|