@sproutsocial/seeds-react-datepicker 1.0.0

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.
@@ -0,0 +1,73 @@
1
+ import React, { useCallback, useState } from "react";
2
+ import moment from "moment";
3
+ import DayPickerSingleDateController from "react-dates/lib/components/DayPickerSingleDateController";
4
+ import { ReactDatesCssOverrides } from "../styles";
5
+ import {
6
+ commonDatePickerProps,
7
+ DefaultSetStatusText,
8
+ getVisibleMonths,
9
+ } from "../common";
10
+ import type { TypeSingleDatePickerProps } from "./SingleDatePickerTypes";
11
+ import { VisuallyHidden } from "@sproutsocial/seeds-react-visually-hidden";
12
+
13
+ const noop = () => {};
14
+
15
+ const SingleDatePicker = ({
16
+ onDateChange,
17
+ setStatusText = DefaultSetStatusText,
18
+ date = null,
19
+ focused = false,
20
+ onFocusChange = noop,
21
+ initialVisibleMonth,
22
+ numberOfMonths = 1,
23
+ onBlur,
24
+ ...rest
25
+ }: TypeSingleDatePickerProps) => {
26
+ const [statusText, updateStatusText] = useState(() =>
27
+ setStatusText(
28
+ getVisibleMonths(
29
+ moment(initialVisibleMonth?.() || date || undefined),
30
+ numberOfMonths
31
+ )
32
+ )
33
+ );
34
+
35
+ const handleMonthClick = useCallback(
36
+ // @ts-ignore unknown types
37
+ (date) => {
38
+ updateStatusText(setStatusText(getVisibleMonths(date, numberOfMonths)));
39
+ },
40
+ [numberOfMonths, setStatusText]
41
+ );
42
+ const wrappedOnBlur = useCallback<React.KeyboardEventHandler<HTMLDivElement>>(
43
+ (event) => {
44
+ onFocusChange?.({ focused: false });
45
+ onBlur?.(event);
46
+ },
47
+ [onBlur, onFocusChange]
48
+ );
49
+
50
+ return (
51
+ <>
52
+ <ReactDatesCssOverrides />
53
+ <VisuallyHidden>
54
+ <div role="status">{statusText}</div>
55
+ </VisuallyHidden>
56
+ <DayPickerSingleDateController
57
+ {...commonDatePickerProps}
58
+ date={date}
59
+ numberOfMonths={numberOfMonths}
60
+ onDateChange={onDateChange}
61
+ initialVisibleMonth={initialVisibleMonth || null}
62
+ focused={focused}
63
+ onBlur={wrappedOnBlur}
64
+ onFocusChange={onFocusChange}
65
+ onPrevMonthClick={handleMonthClick}
66
+ onNextMonthClick={handleMonthClick}
67
+ {...rest}
68
+ />
69
+ </>
70
+ );
71
+ };
72
+
73
+ export default React.memo<TypeSingleDatePickerProps>(SingleDatePicker);
@@ -0,0 +1,25 @@
1
+ import type { Moment } from "moment";
2
+ import type { TypeCommonDatePickerProps } from "../types";
3
+
4
+ export interface TypeStatefulSingleDatePickerProps
5
+ extends TypeCommonDatePickerProps {
6
+ date?: Moment | null;
7
+ onDateChange?: (date: Moment | null) => void;
8
+ focused?: boolean;
9
+ onFocusChange?: (arg0: { focused: boolean }) => void;
10
+ setStatusText?: (dates: Moment[]) => string;
11
+ }
12
+
13
+ export interface TypeSingleDatePickerProps
14
+ extends Required<Pick<TypeStatefulSingleDatePickerProps, "onDateChange">>,
15
+ Pick<
16
+ TypeStatefulSingleDatePickerProps,
17
+ | "date"
18
+ | "focused"
19
+ | "onFocusChange"
20
+ | "setStatusText"
21
+ | "initialVisibleMonth"
22
+ | "numberOfMonths"
23
+ > {
24
+ onBlur?: React.KeyboardEventHandler<HTMLDivElement> | undefined;
25
+ }
@@ -0,0 +1,25 @@
1
+ import React, { useState } from "react";
2
+ import type { TypeStatefulSingleDatePickerProps } from "./SingleDatePickerTypes";
3
+ import SingleDatePicker from "./SingleDatePicker";
4
+
5
+ export const StatefulSingleDatePicker = ({
6
+ date,
7
+ onDateChange,
8
+ ...rest
9
+ }: TypeStatefulSingleDatePickerProps) => {
10
+ const [stateDate, setDate] = useState(date);
11
+
12
+ // @ts-ignore unknown types
13
+ const handleDateChange = (date) => {
14
+ onDateChange && onDateChange(date);
15
+ setDate(date);
16
+ };
17
+
18
+ return (
19
+ <SingleDatePicker
20
+ date={stateDate}
21
+ onDateChange={handleDateChange}
22
+ {...rest}
23
+ />
24
+ );
25
+ };
@@ -0,0 +1,155 @@
1
+ import React from "react";
2
+ import moment, { type Moment } from "moment";
3
+ import {
4
+ render,
5
+ fireEvent,
6
+ screen,
7
+ waitFor,
8
+ act,
9
+ } from "@sproutsocial/seeds-react-testing-library";
10
+ import {
11
+ formatDateAsCalendarDay,
12
+ formatDateAsCalendarHeader,
13
+ getVisibleMonthWithReactDatesInternalApi,
14
+ } from "../../common";
15
+ import { SingleDatePicker, StatefulSingleDatePicker } from "../index";
16
+ import Popout from "@sproutsocial/seeds-react-popout";
17
+ import Button from "@sproutsocial/seeds-react-button";
18
+
19
+ const today = moment();
20
+
21
+ describe("SingleDatePicker", () => {
22
+ beforeEach(() => {
23
+ jest.useFakeTimers();
24
+ });
25
+
26
+ test("should select today's date", async () => {
27
+ render(<StatefulSingleDatePicker date={today} setStatusText={() => ""} />);
28
+ await waitFor(() => {
29
+ expect(
30
+ screen.getByLabelText(`Selected. ${formatDateAsCalendarDay(today)}`)
31
+ ).toBeInTheDocument();
32
+ });
33
+ });
34
+
35
+ test("should change dates", async () => {
36
+ render(<StatefulSingleDatePicker date={today} setStatusText={() => ""} />);
37
+ const threeDaysFromNow = formatDateAsCalendarDay(
38
+ today.clone().add(3, "days")
39
+ );
40
+ fireEvent.click(screen.getByLabelText(threeDaysFromNow));
41
+ await waitFor(() => {
42
+ expect(
43
+ screen.getByLabelText(`Selected. ${threeDaysFromNow}`)
44
+ ).toBeInTheDocument();
45
+ expect(
46
+ screen.queryByLabelText(`Selected. ${formatDateAsCalendarDay(today)}`)
47
+ ).not.toBeInTheDocument();
48
+ });
49
+ });
50
+
51
+ test("should go to previous month", async () => {
52
+ const { container } = render(
53
+ <StatefulSingleDatePicker date={today} setStatusText={() => ""} />
54
+ );
55
+ expect(getVisibleMonthWithReactDatesInternalApi(container)).toEqual(
56
+ formatDateAsCalendarHeader(today)
57
+ );
58
+ fireEvent.click(
59
+ screen.getByLabelText("Move backward to switch to the previous month.")
60
+ );
61
+ await waitFor(() => {
62
+ expect(getVisibleMonthWithReactDatesInternalApi(container)).toEqual(
63
+ formatDateAsCalendarHeader(today.clone().subtract(1, "month"))
64
+ );
65
+ });
66
+ });
67
+
68
+ test("should go to next month", async () => {
69
+ const { container } = render(
70
+ <StatefulSingleDatePicker date={today} setStatusText={() => ""} />
71
+ );
72
+ expect(getVisibleMonthWithReactDatesInternalApi(container)).toEqual(
73
+ formatDateAsCalendarHeader(today)
74
+ );
75
+ fireEvent.click(
76
+ screen.getByLabelText("Move forward to switch to the next month.")
77
+ );
78
+ await waitFor(() => {
79
+ expect(getVisibleMonthWithReactDatesInternalApi(container)).toEqual(
80
+ formatDateAsCalendarHeader(today.clone().add(1, "month"))
81
+ );
82
+ });
83
+ });
84
+
85
+ test("should call onDateChange", async () => {
86
+ const onDateChange = jest.fn();
87
+ render(
88
+ <StatefulSingleDatePicker
89
+ date={today}
90
+ onDateChange={onDateChange}
91
+ setStatusText={() => ""}
92
+ />
93
+ );
94
+ const threeDaysFromNow = today.clone().add(3, "days");
95
+ fireEvent.click(
96
+ screen.getByLabelText(formatDateAsCalendarDay(threeDaysFromNow))
97
+ );
98
+ await waitFor(() => {
99
+ expect(onDateChange).toHaveBeenCalledTimes(1);
100
+ expect(onDateChange.mock.calls[0][0].isValid()).toEqual(true);
101
+ });
102
+ });
103
+
104
+ // TODO: This test times out. We'll come back to fix later
105
+ xtest("should close on escape key press", async () => {
106
+ const buttonText = "Date Picker";
107
+ const initialDate = moment("2020-01-01");
108
+
109
+ const FocusControlledPopoutDatePicker = () => {
110
+ const [focused, setIsFocused] = React.useState(false);
111
+ const [date, pickDate] = React.useState<Moment | null>(initialDate);
112
+
113
+ const onFocusChange = ({ focused }: { focused: boolean }) =>
114
+ setIsFocused(focused);
115
+
116
+ return (
117
+ <Popout
118
+ isOpen={focused}
119
+ setIsOpen={setIsFocused}
120
+ content={
121
+ <Popout.Content p={0} py={400}>
122
+ <SingleDatePicker
123
+ date={date}
124
+ onDateChange={pickDate}
125
+ focused={focused}
126
+ onFocusChange={onFocusChange}
127
+ setStatusText={() => "status text"}
128
+ />
129
+ </Popout.Content>
130
+ }
131
+ >
132
+ <Button appearance="secondary" onClick={() => setIsFocused(true)}>
133
+ {buttonText}
134
+ </Button>
135
+ </Popout>
136
+ );
137
+ };
138
+
139
+ render(<FocusControlledPopoutDatePicker />);
140
+
141
+ expect(screen.getByText(buttonText)).toBeInTheDocument();
142
+
143
+ fireEvent.click(screen.getByText(buttonText));
144
+
145
+ await waitFor(() => {
146
+ expect(screen.getByText("January 2020")).toBeInTheDocument();
147
+ });
148
+
149
+ fireEvent.keyDown(screen.getByText("January 2020"), { key: "Escape" });
150
+
151
+ await waitFor(() => {
152
+ expect(screen.queryByText("January 2020")).not.toBeInTheDocument();
153
+ });
154
+ });
155
+ });
@@ -0,0 +1,24 @@
1
+ import * as React from "react";
2
+ import { SingleDatePicker, StatefulSingleDatePicker } from "../index";
3
+
4
+ const mockedRequiredProps = {
5
+ onDateChange: jest.fn(),
6
+ setStatusText: jest.fn(),
7
+ };
8
+
9
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
10
+ function SingleDatePickerTypes() {
11
+ return (
12
+ <>
13
+ <StatefulSingleDatePicker setStatusText={() => ""} />
14
+ <StatefulSingleDatePicker date={null} setStatusText={() => ""} />
15
+ {/* @ts-expect-error - test that invalid type is rejected */}
16
+ <StatefulSingleDatePicker date="invalid" />
17
+
18
+ <SingleDatePicker {...mockedRequiredProps} />
19
+ <SingleDatePicker {...mockedRequiredProps} date={null} />
20
+ {/* @ts-expect-error - test missing required props is rejected */}
21
+ <SingleDatePicker />
22
+ </>
23
+ );
24
+ }
@@ -0,0 +1,6 @@
1
+ import SingleDatePicker from "./SingleDatePicker";
2
+
3
+ export default SingleDatePicker;
4
+ export { SingleDatePicker };
5
+ export * from "./StatefulSingleDatePicker";
6
+ export * from "./SingleDatePickerTypes";
package/src/common.tsx ADDED
@@ -0,0 +1,60 @@
1
+ import "react-dates/initialize";
2
+ import "react-dates/lib/css/_datepicker.css";
3
+ import type { Moment } from "moment";
4
+ import React from "react";
5
+ import Icon, { type TypeIconName } from "@sproutsocial/seeds-react-icon";
6
+ import { CalendarDay } from "./styles";
7
+ import type { TypeCommonDatePickerProps } from "./types";
8
+
9
+ type TypeCalendarNavButtonType = "left" | "right";
10
+
11
+ const iconNames: { [key in TypeCalendarNavButtonType]: TypeIconName } = {
12
+ left: "arrow-left-solid",
13
+ right: "arrow-right-solid",
14
+ };
15
+
16
+ export const CalendarNavButton = ({
17
+ type,
18
+ }: {
19
+ type: TypeCalendarNavButtonType;
20
+ }) => <Icon size="mini" name={iconNames[type]} aria-hidden />;
21
+
22
+ export const commonDatePickerProps: TypeCommonDatePickerProps = {
23
+ hideKeyboardShortcutsPanel: true,
24
+ daySize: 30,
25
+ navPrev: <CalendarNavButton type="left" />,
26
+ navNext: <CalendarNavButton type="right" />,
27
+ renderDayContents: (day, modifiers) => (
28
+ <CalendarDay day={day} modifiers={modifiers}>
29
+ {day.format("D")}
30
+ </CalendarDay>
31
+ ),
32
+ initialVisibleMonth: null,
33
+ };
34
+ // Testing utilities
35
+
36
+ export const formatDateAsCalendarHeader = (date: Moment): string =>
37
+ date.format("MMMM YYYY");
38
+
39
+ export const formatDateAsCalendarDay = (date: Moment): string =>
40
+ date.format("dddd, MMMM D, YYYY");
41
+
42
+ export const getVisibleMonthWithReactDatesInternalApi = (
43
+ container: HTMLElement
44
+ ): string =>
45
+ container.querySelector("[data-visible=true] strong")?.textContent ?? "";
46
+
47
+ // Receives a single Moment and returns an array of Moments, one for each currently visible month.
48
+ // @ts-ignore unknown types
49
+ export const getVisibleMonths = (initialMonth, numberOfMonths) => {
50
+ const months = [initialMonth];
51
+ for (let i = 1; i < numberOfMonths; i++) {
52
+ months.push(initialMonth.clone().add(i, "month"));
53
+ }
54
+ return months;
55
+ };
56
+
57
+ // Default setStatusText prop for both SingleDatePicker and DateRangePicker
58
+ // @ts-ignore unknown types
59
+ export const DefaultSetStatusText = (dates) =>
60
+ dates.map(formatDateAsCalendarHeader).join(", ");
package/src/index.ts ADDED
@@ -0,0 +1,2 @@
1
+ export * from "./SingleDatePicker";
2
+ export * from "./DateRangePicker";
@@ -0,0 +1,7 @@
1
+ import "styled-components";
2
+ import { TypeTheme } from "@sproutsocial/seeds-react-theme";
3
+
4
+ declare module "styled-components" {
5
+ // eslint-disable-next-line @typescript-eslint/no-empty-interface
6
+ export interface DefaultTheme extends TypeTheme {}
7
+ }
package/src/styles.ts ADDED
@@ -0,0 +1,224 @@
1
+ import styled, { createGlobalStyle, css } from "styled-components";
2
+ import moment from "moment";
3
+ import type { ModifiersShape } from "react-dates";
4
+ import { disabled } from "@sproutsocial/seeds-react-mixins";
5
+ import Box from "@sproutsocial/seeds-react-box";
6
+
7
+ /*
8
+ * Partial list of modifiers given to renderDayContents by airbnb/react-dates. There may be more.
9
+ *
10
+ * today, blocked, blocked-calendar, blocked-out-of-range, highlighted-calendar, valid,
11
+ * selected, selected-start, selected-end, blocked-minimum-nights, selected-span, last-in-range,
12
+ * hovered, hovered-span, hovered-offset, after-hovered-start, first-day-of-week, last-day-of-week,
13
+ * hovered-start-first-possible-end, hovered-start-blocked-minimum-nights, before-hovered-end,
14
+ * no-selected-start-before-selected-end, selected-start-in-hovered-span, selected-start-no-selected-end,
15
+ * selected-end-no-selected-start
16
+ *
17
+ */
18
+ const isSelected = (modifiers: ModifiersShape) =>
19
+ modifiers.has("selected-span") ||
20
+ modifiers.has("selected") ||
21
+ modifiers.has("selected-start") ||
22
+ modifiers.has("selected-end") ||
23
+ modifiers.has("hovered-span") ||
24
+ modifiers.has("after-hovered-start");
25
+
26
+ const isOutOfRange = (modifiers: ModifiersShape) =>
27
+ modifiers.has("blocked-out-of-range");
28
+
29
+ const isHoveredAndInRange = (modifiers: ModifiersShape) =>
30
+ modifiers.has("hovered") && !modifiers.has("blocked-out-of-range");
31
+
32
+ const shouldHaveLeftPill = (modifiers: ModifiersShape, day: moment.Moment) => {
33
+ if (!isSelected(modifiers)) {
34
+ return false;
35
+ }
36
+
37
+ if (
38
+ modifiers.has("selected") ||
39
+ modifiers.has("selected-start") ||
40
+ modifiers.has("first-day-of-week") ||
41
+ day.isSame(moment(day).startOf("month"), "day")
42
+ ) {
43
+ return true;
44
+ }
45
+
46
+ return false;
47
+ };
48
+
49
+ const shouldHaveRightPill = (modifiers: ModifiersShape, day: moment.Moment) => {
50
+ if (!isSelected(modifiers)) {
51
+ return false;
52
+ }
53
+
54
+ if (
55
+ modifiers.has("selected") ||
56
+ modifiers.has("selected-end") ||
57
+ modifiers.has("last-day-of-week") ||
58
+ day.isSame(moment(day).endOf("month"), "day")
59
+ ) {
60
+ return true;
61
+ }
62
+
63
+ return false;
64
+ };
65
+
66
+ export const CalendarDay = styled(Box)<{
67
+ modifiers: ModifiersShape;
68
+ day: moment.Moment;
69
+ }>`
70
+ ${({ modifiers, day, theme }) => {
71
+ if (isSelected(modifiers)) {
72
+ return css`
73
+ background-color: ${theme.colors.container.background.selected};
74
+ color: ${theme.colors.text.inverse};
75
+ margin-left: ${shouldHaveLeftPill(modifiers, day) && theme.space[200]};
76
+ margin-right: ${shouldHaveRightPill(modifiers, day) &&
77
+ theme.space[200]};
78
+ border-top-left-radius: ${shouldHaveLeftPill(modifiers, day) &&
79
+ theme.radii.pill};
80
+ border-bottom-left-radius: ${shouldHaveLeftPill(modifiers, day) &&
81
+ theme.radii.pill};
82
+ border-top-right-radius: ${shouldHaveRightPill(modifiers, day) &&
83
+ theme.radii.pill};
84
+ border-bottom-right-radius: ${shouldHaveRightPill(modifiers, day) &&
85
+ theme.radii.pill};
86
+ `;
87
+ }
88
+
89
+ if (isHoveredAndInRange(modifiers)) {
90
+ return css`
91
+ margin: 0 ${theme.space[200]};
92
+ border-radius: ${theme.radii.pill};
93
+ border: 1px solid ${theme.colors.container.border.selected};
94
+ `;
95
+ } else if (isOutOfRange(modifiers)) {
96
+ return css`
97
+ color: ${theme.colors.text.subtext};
98
+ ${disabled};
99
+ `;
100
+ }
101
+ }};
102
+ `;
103
+
104
+ export const ReactDatesCssOverrides = createGlobalStyle`
105
+ .DayPicker {
106
+ box-sizing: content-box;
107
+ font-weight: ${({ theme }) => theme.fontWeights.normal};
108
+ font-family: ${(props) => props.theme.fontFamily};
109
+
110
+ /* override react-dates height to better reflect how tall the component actually is */
111
+ /* adding margin/padding will be more truer to our seeds system because the height */
112
+ /* of the calendar adds an extra row of padding if we do not override it */
113
+ &_transitionContainer {
114
+ /* need !important because react-dates sets height on the element itself */
115
+ height: 228px !important;
116
+ }
117
+
118
+ &_weekHeader {
119
+ color: ${({ theme }) => theme.colors.text.headline};
120
+ border-bottom: 1px solid ${({ theme }) => theme.colors.container.border.base};
121
+
122
+ /* Magic number to match position of .CalendarMonth_caption */
123
+ top: 26px;
124
+
125
+ /* Magic number to make the bottom border line stretch the full width */
126
+ width: 230px;
127
+
128
+ &_ul {
129
+ /* Magic number to line up day name headings over the correct numbers */
130
+ padding-left: 10px;
131
+ }
132
+ }
133
+
134
+ &_weekHeaders__horizontal {
135
+ margin-left: 0
136
+ }
137
+
138
+ &_weekHeader_li {
139
+ ${({ theme }) => theme.typography[200]}
140
+ color: ${({ theme }) => theme.colors.text.subtext};
141
+ font-weight: ${({ theme }) => theme.fontWeights.semibold};
142
+ margin: 0;
143
+ }
144
+
145
+ &__horizontal {
146
+ box-shadow: none;
147
+ background: ${({ theme }) => theme.colors.container.background.base};
148
+ }
149
+ }
150
+
151
+ .CalendarDay {
152
+ background-color: transparent;
153
+
154
+ &__selected, &__selected_span, &:hover {
155
+ background-color: transparent;
156
+ }
157
+
158
+ &__default {
159
+ color: ${({ theme }) => theme.colors.text.body};
160
+ }
161
+ &__default,
162
+ &__default:hover {
163
+ border: none;
164
+ color: ${({ theme }) => theme.colors.text.body};
165
+ }
166
+ }
167
+
168
+ .CalendarMonth {
169
+ ${({ theme }) => theme.typography[200]}
170
+ background: ${({ theme }) => theme.colors.container.background.base};
171
+
172
+ /* spacing between visible months and months off canvas */
173
+ padding: 0 15px;
174
+
175
+ &_caption {
176
+ ${({ theme }) => theme.typography[200]}
177
+ color: ${({ theme }) => theme.colors.text.headline};
178
+ padding-top: 0;
179
+ background: ${({ theme }) => theme.colors.container.background.base};
180
+
181
+ strong {
182
+ font-weight: ${({ theme }) => theme.fontWeights.semibold};
183
+ }
184
+
185
+ }
186
+ &_table {
187
+ line-height: 21.333px;
188
+ tr {
189
+ vertical-align: middle;
190
+ }
191
+ td {
192
+ padding: 0;
193
+ border-bottom: none;
194
+ }
195
+ }
196
+ }
197
+
198
+ .CalendarMonthGrid {
199
+ background: ${({ theme }) => theme.colors.container.background.base};
200
+ }
201
+
202
+ /* Left and Right Arrow Buttons to navigate months */
203
+ .DayPickerNavigation_button__horizontal {
204
+ color: ${({ theme }) => theme.colors.button.pill.text.base};
205
+ top: -4px;
206
+ padding: 7px 8px;
207
+ position: absolute;
208
+ line-height: 0.78;
209
+ border-radius: 9999px;
210
+ border: none;
211
+ background: ${({ theme }) => theme.colors.button.pill.background.base};
212
+
213
+ &:nth-child(1) {
214
+ left: 22px;
215
+ }
216
+ &:nth-child(2) {
217
+ right: 22px;
218
+ }
219
+
220
+ &:hover {
221
+ background: ${({ theme }) => theme.colors.button.pill.background.hover};
222
+ }
223
+ }
224
+ `;
package/src/types.ts ADDED
@@ -0,0 +1,24 @@
1
+ import * as React from "react";
2
+ import type { Moment } from "moment";
3
+ import type { ModifiersShape } from "react-dates";
4
+
5
+ export interface TypeCommonDatePickerProps {
6
+ daySize?: number;
7
+ isOutsideRange?: (date: Moment) => boolean;
8
+ hideKeyboardShortcutsPanel?: boolean;
9
+ navPrev?: React.ReactNode;
10
+ navNext?: React.ReactNode;
11
+ numberOfMonths?: number;
12
+ renderDayContents?: (
13
+ day: Moment,
14
+ modifiers: ModifiersShape
15
+ ) => React.ReactNode;
16
+ keepOpenOnDateSelect?: boolean;
17
+ initialVisibleMonth?: (() => Moment) | null;
18
+ minimumNights?: number;
19
+ phrases?: Record<
20
+ string,
21
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
22
+ Node | ((arg0: { date: Moment }) => React.ReactNode)
23
+ >;
24
+ }
package/tsconfig.json ADDED
@@ -0,0 +1,9 @@
1
+ {
2
+ "extends": "@sproutsocial/seeds-tsconfig/bundler/dom/library-monorepo",
3
+ "compilerOptions": {
4
+ "jsx": "react-jsx",
5
+ "module": "esnext"
6
+ },
7
+ "include": ["src/**/*"],
8
+ "exclude": ["node_modules", "dist", "coverage"]
9
+ }
package/tsup.config.ts ADDED
@@ -0,0 +1,12 @@
1
+ import { defineConfig } from "tsup";
2
+
3
+ export default defineConfig((options) => ({
4
+ entry: ["src/index.ts"],
5
+ format: ["cjs", "esm"],
6
+ clean: true,
7
+ legacyOutput: true,
8
+ dts: options.dts,
9
+ external: ["react"],
10
+ sourcemap: true,
11
+ metafile: options.metafile,
12
+ }));