Skip to content

Commit 7c9c02f

Browse files
E&A Date Picker (Part Two) - react-calendar with USWDS tokens (#1048)
**Related Ticket:** _{link related ticket here}_ ### Description of Changes We're introducing a more flexible calendar component which will use some USWDS design tokens and icons. The change is made based on this discussion: #1044 (comment) ### Notes & Questions About Changes _{Add additonal notes and outstanding questions here related to changes in this pull request}_ ### Validation / Testing _{Update with info on what can be manually validated in the Deploy Preview link for example "Validate style updates to selection modal do NOT affect cards"}_
2 parents 45437b9 + 20842be commit 7c9c02f

File tree

11 files changed

+464
-156
lines changed

11 files changed

+464
-156
lines changed
Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
// @NOTE: Optimize the import paths to the file
2+
@use "uswds-core/src/styles/functions/utilities" as utils;
3+
@use "uswds-core/src/styles/mixins/utilities" as mixins;
4+
@use "uswds-core/src/styles/mixins/typography" as typography;
5+
6+
.react-calendar {
7+
z-index: 99999;
8+
font-family: inherit !important;
9+
10+
* {
11+
@include typography.typeset('ui', 3);
12+
font-family: inherit !important;
13+
}
14+
15+
&__navigation {
16+
margin-bottom: 0 !important;
17+
}
18+
19+
&__month-view__weekdays__weekday {
20+
color: utils.color('gray-90');
21+
}
22+
23+
&__tile {
24+
25+
&--active,
26+
&--hasActive {
27+
background-color: utils.color('primary-vivid') !important;
28+
color: utils.color('base-lightest');
29+
}
30+
31+
&--now:not(&--active),
32+
&--now:not(&--hasActive) {
33+
background: none !important;
34+
color: utils.color('gray-90') !important;
35+
36+
&:hover,
37+
&:focus {
38+
background-color: utils.color('gray-10') !important;
39+
}
40+
}
41+
}
42+
43+
.usa-icon {
44+
width: 32px;
45+
height: 20px;
46+
}
47+
48+
&__navigation-button {
49+
min-width: 32px;
50+
}
51+
52+
[class*="--weekend"]:not(.react-calendar__tile--active) {
53+
color: utils.color('gray-90') !important;
54+
}
55+
56+
abbr[title] {
57+
@include mixins.u-text('normal');
58+
text-decoration: none;
59+
}
60+
61+
&__tippy {
62+
box-shadow: none !important;
63+
border: none !important;
64+
background: transparent !important;
65+
66+
&[data-placement^='top'] > .tippy-arrow::before {
67+
border-top-color: transparent !important;
68+
}
69+
70+
&[data-placement^='bottom'] > .tippy-arrow::before {
71+
border-bottom-color: transparent !important;
72+
}
73+
74+
&[data-placement^='left'] > .tippy-arrow::before {
75+
border-left-color: transparent !important;
76+
}
77+
78+
&[data-placement^='right'] > .tippy-arrow::before {
79+
border-right-color: transparent !important;
80+
}
81+
82+
.tippy-content {
83+
padding: 0 !important;
84+
}
85+
}
86+
}
Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
import React, { ReactNode, useRef, useState } from "react";
2+
import { Icon } from "@trussworks/react-uswds";
3+
import Calendar from 'react-calendar';
4+
import Tippy from "@tippyjs/react";
5+
import styled from "styled-components";
6+
7+
import 'react-calendar/dist/Calendar.css';
8+
import './index.scss';
9+
10+
interface SimpleDatePickerProps {
11+
disabled: boolean;
12+
tipContent: ReactNode;
13+
onConfirm: (date: Date | null) => void;
14+
triggerHeadReference: string;
15+
selectedDay: Date | null;
16+
renderTriggerElement: (props: {
17+
onClick: () => void;
18+
disabled: boolean;
19+
tipContent: ReactNode;
20+
triggerHeadReference: string;
21+
selectedDay: Date | null;
22+
}) => ReactNode;
23+
}
24+
25+
const TriggerWrapper = styled.div`
26+
display: flex;
27+
`;
28+
29+
export const SimpleDatePicker = ({
30+
disabled,
31+
tipContent,
32+
onConfirm,
33+
triggerHeadReference,
34+
selectedDay,
35+
renderTriggerElement
36+
}: SimpleDatePickerProps) => {
37+
const [isCalendarOpen, setIsCalendarOpen] = useState(false);
38+
const triggerRef = useRef<HTMLDivElement>(null);
39+
40+
const handleDateChange = (date: Date) => {
41+
onConfirm(date);
42+
setIsCalendarOpen(false);
43+
};
44+
45+
const handleTriggerClick = () => {
46+
setIsCalendarOpen(!isCalendarOpen);
47+
};
48+
49+
const handleClickOutside = (event) => {
50+
if (triggerRef.current && !triggerRef.current.contains(event.target as Node)) {
51+
setIsCalendarOpen(false);
52+
}
53+
};
54+
55+
return (
56+
<div>
57+
<TriggerWrapper ref={triggerRef}>
58+
{renderTriggerElement({
59+
onClick: handleTriggerClick,
60+
disabled,
61+
tipContent,
62+
triggerHeadReference,
63+
selectedDay,
64+
})}
65+
</TriggerWrapper>
66+
{isCalendarOpen && (
67+
<Tippy
68+
className='react-calendar__tippy'
69+
visible={isCalendarOpen}
70+
onClickOutside={(_, event) => handleClickOutside(event)}
71+
interactive={true}
72+
placement='bottom'
73+
content={
74+
<Calendar
75+
onChange={handleDateChange}
76+
value={selectedDay}
77+
className='react-calendar'
78+
maxDetail='month'
79+
nextLabel={<Icon.NavigateNext />}
80+
prevLabel={<Icon.NavigateBefore />}
81+
prev2Label={<Icon.NavigateFarBefore />}
82+
next2Label={<Icon.NavigateFarNext />}
83+
/>
84+
}
85+
>
86+
<div />
87+
</Tippy>
88+
)}
89+
</div>
90+
);
91+
};

app/scripts/components/datasets/s-explore/panel-date-widget.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ interface PanelDateWidgetProps {
5151
children?: ReactNode;
5252
}
5353

54-
const formatDate = (date: Date | null, view: string) => {
54+
export const formatDate = (date: Date | null, view: string) => {
5555
if (!date) return 'Date';
5656

5757
switch (view) {

0 commit comments

Comments
 (0)