Open yusijs opened 6 months ago
this. for the love of god, this.
@yusijs what I ultimately ended up doing was thinking a little outside the box and just adding a 'hidden' class on the entire DateInput inner component and adding my own span with a formatted date value. everything works exactly the same as before, screen reader behaves the exact same as well. Minus the types and styles, this is my entire date picker component. The styles.input()
class only has a class of hidden
on it.
export const DatePicker = forwardRef<HTMLDivElement, DatePickerProps>(function DatePicker(
{ description, errorMessage, hideLabel = false, label, onChange, placeholder, ...props },
ref,
) {
const formatter = useDateFormatter({ dateStyle: "medium" });
const timezone = getLocalTimeZone();
const isInvalid = Boolean(errorMessage || props.isInvalid);
const styles = datePickerStyles({ isInvalid });
const formatDate = useCallback(
(value: DateValue | null) => (value ? formatter.format(value.toDate(timezone)) : placeholder),
[formatter, placeholder, timezone],
);
const handleChange = useCallback(
(value: DateValue) => onChange && onChange(value.toString()),
[onChange],
);
return (
<AriaDatePicker
{...props}
className={styles.base()}
isInvalid={isInvalid}
onChange={handleChange}
ref={ref}
>
{({ state }) => (
<Fragment>
<div>
<FieldLabel hideLabel={hideLabel}>{label}</FieldLabel>
{description && <FieldDescription>{description}</FieldDescription>}
</div>
<div className={styles.body()}>
<Group className={styles.field()}>
<span className={styles.value()}>{formatDate(state.value)}</span>
<DateInput className={styles.input()}>
{(segment) => <DateSegment className={styles.segment()} segment={segment} />}
</DateInput>
<Button className={styles.button()}>
<Icon.Interface.Calendar />
</Button>
</Group>
<FieldValidation>{errorMessage}</FieldValidation>
</div>
<Popover className={styles.popover()}>
<Dialog>
<Calendar />
</Dialog>
</Popover>
</Fragment>
)}
</AriaDatePicker>
);
});
@binaryartifex I'm looking into creating an overlay that shows the formatted value on blur, but the input as numeric. It will work, but I'd obviously prefer this being something that just works, and also has a forgiving input.
To be clear though, I'm not using react-aria-components, but the hooks from react-aria, so I have a bit more code than you π
Would the formatted value month value revert to a number when the user enters one of the number segments?
Would the formatted value month value revert to a number when the user enters one of the number segments?
Ideally it would be possible to write w/ literals as well, but not sure how feasible that is. I've actually implemented the solution you mention here on my end now, as I figured a neat way to solve it yesterday. Ideally I would like it out of the box, but this works as well tbh.. :)
When using a literal month, the format often turns a bit around: Localized -> December 31, 2024 Numeric -> 31.12.2024 Replaced on blur -> 31. December. 2024
So it's not localized properly, but it works.
From a gut feeling writing the literals seems like it could be pretty hard, just thinking about languages that use a IME like Chinese/Japanese/etc. Would need to experiment with it, but supporting the text representations on blur like you've done might be something we could consider adding ourselves.
From a gut feeling writing the literals seems like it could be pretty hard, just thinking about languages that use a IME like Chinese/Japanese/etc. Would need to experiment with it, but supporting the text representations on blur like you've done might be something we could consider adding ourselves.
Yeah, I imagine it's quite a bit harder to handle in multiple locales. I've handled it previously, but that was only for en-US locale, so it was fairly straight forward to handle.
It would be a great QOL improvement for the display-value to change natively though; it's a bit tedious to handle it now imo:
<Segment
{...segmentProps}
onFocus={(e) => {
setFocus(true)
segmentProps.onFocus(e)
}}
onBlur={(e) => {
setFocus(false)
segmentProps.onBlur(e)
}}>
{focus
? (segment.isPlaceholder || segment.type === 'literal'
? segment.text
: segment.text.padStart(segment.type === 'year' ? 4 : 2, '0') )
: value}
Being able to avoid the focus-check / custom focus-handling would be neat, and reduce the additional code I've had to add quite a bit :)
Provide a general summary of the feature here
Our users are from multiple countries around the world but when they are travelling and work on different locations, there are some "issues" with how the date-inputs are formatted due to the locale on their temporary machines (if not on laptops). A request was made that the input format should be possible to customize to have the literal months rather than numerical.
π€ Expected Behavior?
I would expect something like this:
which would result in an input looking something like this:
π― Current Behavior
The format is always numerical based on the default locale:
π Possible Solution
No response
π¦ Context
Make it easier to have human-readable dates, without the users having to wonder if 03/05/2024 means the 3rd of May or the 5th of March, depending on which computer they are currently working from.
π» Examples
No response
π§’ Your Company/Team
No response
π· Tracking Issue
No response