Skip to content

Commit 7bc70c6

Browse files
committed
feat(DateInput): use standard date format
1 parent 7a3710c commit 7bc70c6

File tree

9 files changed

+89
-9
lines changed

9 files changed

+89
-9
lines changed

.changeset/smart-penguins-press.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@cube-dev/ui-kit': minor
3+
---
4+
5+
Use standard date format for all date inputs.

src/components/forms/DatePicker/DateInput.stories.tsx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,3 +78,6 @@ WithLimitedRange.args = {
7878
minValue: parseAbsoluteDate('2023-10-04'),
7979
maxValue: parseAbsoluteDate('2023-12-15'),
8080
};
81+
82+
export const WithLocale = Template.bind({});
83+
WithLocale.args = { useLocale: true };

src/components/forms/DatePicker/DateInput.tsx

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ import { FieldBaseProps, ValidationState } from '../../../shared';
1919
import { mergeProps } from '../../../utils/react';
2020
import { useFieldProps, useFormProps } from '../Form';
2121

22-
import { useFocusManagerRef } from './utils';
22+
import { formatSegments, useFocusManagerRef } from './utils';
2323
import { DateInputBase } from './DateInputBase';
2424
import { DatePickerSegment } from './DatePickerSegment';
2525
import { DEFAULT_DATE_PROPS } from './props';
@@ -35,6 +35,7 @@ export interface CubeDateInputProps<T extends DateValue = DateValue>
3535
styles?: Styles;
3636
size?: 'small' | 'medium' | 'large' | (string & {});
3737
validationState?: ValidationState;
38+
useLocale?: boolean;
3839
}
3940

4041
function DateInput<T extends DateValue>(
@@ -60,6 +61,7 @@ function DateInput<T extends DateValue>(
6061
isReadOnly,
6162
isRequired,
6263
size = 'medium',
64+
useLocale: useLocaleProp,
6365
} = props;
6466

6567
let styles = extractStyles(props, CONTAINER_STYLES, wrapperStyles);
@@ -72,6 +74,10 @@ function DateInput<T extends DateValue>(
7274
createCalendar,
7375
});
7476

77+
if (!useLocaleProp) {
78+
state.segments = formatSegments(state.segments);
79+
}
80+
7581
let fieldRef = useRef(null);
7682
let { labelProps, fieldProps } = useDateField(props, state, fieldRef);
7783

src/components/forms/DatePicker/DatePicker.stories.tsx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,3 +82,6 @@ WithLimitedRange.args = {
8282
minValue: parseAbsoluteDate('2023-10-04'),
8383
maxValue: parseAbsoluteDate('2023-12-15'),
8484
};
85+
86+
export const WithLocale = Template.bind({});
87+
WithLocale.args = { useLocale: true };

src/components/forms/DatePicker/DatePicker.tsx

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ export interface CubeDatePickerProps<T extends DateValue = DateValue>
4141
validationState?: ValidationState;
4242
maxVisibleMonths?: number;
4343
shouldFlip?: boolean;
44+
useLocale?: boolean;
4445
}
4546

4647
function DatePicker<T extends DateValue>(
@@ -56,7 +57,13 @@ function DatePicker<T extends DateValue>(
5657

5758
let styles = extractStyles(props, CONTAINER_STYLES);
5859

59-
let { size, placeholderValue, isDisabled, validationState } = props;
60+
let {
61+
size,
62+
placeholderValue,
63+
isDisabled,
64+
validationState,
65+
useLocale: useLocaleProp,
66+
} = props;
6067
let targetRef = useRef<HTMLDivElement>(null);
6168
let state = useDatePickerState({
6269
...props,
@@ -101,7 +108,7 @@ function DatePicker<T extends DateValue>(
101108
validationState={validationState}
102109
size={size}
103110
>
104-
<DatePickerInput {...fieldProps} />
111+
<DatePickerInput useLocale={useLocaleProp} {...fieldProps} />
105112
</DateInputBase>
106113
<DialogTrigger
107114
hideArrow

src/components/forms/DatePicker/DatePickerInput.tsx

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import { useLocale } from '@react-aria/i18n';
88
import { tasty } from '../../../tasty';
99

1010
import { DatePickerSegment } from './DatePickerSegment';
11+
import { formatSegments } from './utils';
1112

1213
const DateInputElement = tasty({
1314
role: 'presentation',
@@ -22,12 +23,13 @@ interface CubeDatePickerInputProps<T extends DateValue>
2223
extends SpectrumDatePickerProps<T> {
2324
hideValidationIcon?: boolean;
2425
maxGranularity?: SpectrumDatePickerProps<T>['granularity'];
26+
useLocale?: boolean;
2527
}
2628

2729
export function DatePickerInput<T extends DateValue>(
2830
props: CubeDatePickerInputProps<T>,
2931
) {
30-
let { isDisabled, isReadOnly, isRequired } = props;
32+
let { isDisabled, isReadOnly, isRequired, useLocale: useLocaleProp } = props;
3133
let ref = useRef(null);
3234
let { locale } = useLocale();
3335
let state = useDateFieldState({
@@ -36,6 +38,10 @@ export function DatePickerInput<T extends DateValue>(
3638
createCalendar,
3739
});
3840

41+
if (!useLocaleProp) {
42+
state.segments = formatSegments(state.segments);
43+
}
44+
3945
let { fieldProps } = useDateField(props, state, ref);
4046

4147
return (

src/components/forms/DatePicker/DateRangePicker.stories.tsx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,3 +69,6 @@ Disabled.args = { isDisabled: true };
6969

7070
export const Small = Template.bind({});
7171
Small.args = { size: 'small' };
72+
73+
export const WithLocale = Template.bind({});
74+
WithLocale.args = { useLocale: true };

src/components/forms/DatePicker/DateRangePicker.tsx

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ import { dateMessages } from './intl';
3232
const DateRangeDash = tasty({
3333
'aria-hidden': 'true',
3434
'data-qa': 'DateRangeDash',
35-
children: '–',
35+
children: '–',
3636
styles: {
3737
padding: '0 .5x',
3838
},
@@ -50,6 +50,7 @@ export interface CubeDateRangePickerProps<T extends DateValue = DateValue>
5050
validationState?: ValidationState;
5151
maxVisibleMonths?: number;
5252
shouldFlip?: boolean;
53+
useLocale?: boolean;
5354
}
5455

5556
function DateRangePicker<T extends DateValue>(
@@ -65,8 +66,14 @@ function DateRangePicker<T extends DateValue>(
6566

6667
let styles = extractStyles(props, CONTAINER_STYLES);
6768

68-
let { size, shouldFlip, placeholderValue, isDisabled, validationState } =
69-
props;
69+
let {
70+
size,
71+
shouldFlip,
72+
placeholderValue,
73+
isDisabled,
74+
validationState,
75+
useLocale: useLocaleProp,
76+
} = props;
7077
let targetRef = useRef<HTMLDivElement>(null);
7178
let state = useDateRangePickerState({
7279
...props,
@@ -111,9 +118,9 @@ function DateRangePicker<T extends DateValue>(
111118
size={size}
112119
styles={{ radius: 'left', border: 'top left bottom' }}
113120
>
114-
<DatePickerInput {...startFieldProps} />
121+
<DatePickerInput useLocale={useLocaleProp} {...startFieldProps} />
115122
<DateRangeDash />
116-
<DatePickerInput {...endFieldProps} />
123+
<DatePickerInput useLocale={useLocaleProp} {...endFieldProps} />
117124
</DateInputBase>
118125
<DialogTrigger
119126
hideArrow

src/components/forms/DatePicker/utils.ts

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import { useDateFormatter } from '@react-aria/i18n';
66
import { useDisplayNames } from '@react-aria/datepicker';
77
import { useImperativeHandle, useMemo, useRef, useState } from 'react';
88
import { useLayoutEffect } from '@react-aria/utils';
9+
import { DateSegment } from '@react-stately/datepicker';
910

1011
export function useFormatHelpText(
1112
props: Pick<SpectrumDatePickerBase, 'description' | 'showFormatHelpText'>,
@@ -73,3 +74,42 @@ export function useFocusManagerRef(ref: FocusableRef<HTMLElement>) {
7374
}));
7475
return domRef;
7576
}
77+
78+
export function formatSegments(segments: DateSegment[]) {
79+
segments = JSON.parse(JSON.stringify(segments));
80+
81+
segments.forEach((segment) => {
82+
if (segment.type === 'literal') {
83+
if (segment.text === '/') {
84+
segment.text = '-';
85+
}
86+
87+
if (segment.text === ', ') {
88+
segment.text = ' ';
89+
}
90+
}
91+
});
92+
93+
const year = segments.find((s) => s.type === 'year');
94+
95+
if (year) {
96+
segments.splice(segments.indexOf(year), 1);
97+
segments.unshift(year);
98+
}
99+
100+
const month = segments.find((s) => s.type === 'month');
101+
102+
if (month) {
103+
segments.splice(segments.indexOf(month), 1);
104+
segments.splice(2, 0, month);
105+
}
106+
107+
const day = segments.find((s) => s.type === 'day');
108+
109+
if (day) {
110+
segments.splice(segments.indexOf(day), 1);
111+
segments.splice(4, 0, day);
112+
}
113+
114+
return segments;
115+
}

0 commit comments

Comments
 (0)