Skip to content

Commit 316ecf2

Browse files
committed
Creates DateInputSegment subcomponent
1 parent ddf8af2 commit 316ecf2

File tree

9 files changed

+291
-24
lines changed

9 files changed

+291
-24
lines changed

packages/date-picker/package.json

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,11 @@
1616
},
1717
"dependencies": {
1818
"@leafygreen-ui/emotion": "^4.0.7",
19-
"@leafygreen-ui/lib": "^10.4.3",
20-
"@leafygreen-ui/tokens": "^2.1.4"
19+
"@leafygreen-ui/hooks": "^7.7.8",
20+
"@leafygreen-ui/lib": "^11.0.0",
21+
"@leafygreen-ui/palette": "^4.0.7",
22+
"@leafygreen-ui/tokens": "^2.1.4",
23+
"@leafygreen-ui/typography": "^16.5.5"
2124
},
2225
"peerDependencies": {
2326
"@leafygreen-ui/leafygreen-provider": "^3.1.6"
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
/** The minimum number for each segment */
2+
export const defaultMin = {
3+
day: 1,
4+
month: 1,
5+
year: 1970,
6+
} as const;
7+
8+
/** The maximum number for each segment */
9+
export const defaultMax = {
10+
day: 31,
11+
month: 12,
12+
year: 2038,
13+
} as const;
14+
15+
/** The shorthand for each char */
16+
export const placeholderChar = {
17+
day: 'D',
18+
month: 'M',
19+
year: 'Y',
20+
};
21+
22+
export const charsPerSegment = {
23+
day: 2,
24+
month: 2,
25+
year: 4,
26+
};
27+
28+
const makePlaceholder = (n: number, s: string) => new Array(n).fill(s).join('');
29+
30+
/** The default placeholders for each segment */
31+
export const defaultPlaceholder = {
32+
day: makePlaceholder(charsPerSegment.day, placeholderChar.day),
33+
month: makePlaceholder(charsPerSegment.month, placeholderChar.month),
34+
year: makePlaceholder(charsPerSegment.year, placeholderChar.year),
35+
} as const;
36+
37+
/** The percentage of 1ch these specific characters take up */
38+
export const characterWidth = {
39+
D: 1.1875,
40+
M: 1.375,
41+
Y: 1.125,
42+
} as const;
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
import React from 'react';
2+
import { StoryFn } from '@storybook/react';
3+
4+
import LeafyGreenProvider from '@leafygreen-ui/leafygreen-provider';
5+
import { StoryMetaType } from '@leafygreen-ui/lib';
6+
7+
import { DateInputSegment } from './DateInputSegment';
8+
9+
const meta: StoryMetaType<typeof DateInputSegment> = {
10+
title: 'Components/DatePicker/DateInputSegment',
11+
component: DateInputSegment,
12+
parameters: {
13+
default: null,
14+
generate: {
15+
combineArgs: {
16+
darkMode: [false, true],
17+
value: [undefined, 6, 2023],
18+
segment: ['day', 'month', 'year'],
19+
},
20+
excludeCombinations: [
21+
{
22+
value: 6,
23+
segment: 'year',
24+
},
25+
{
26+
value: 2023,
27+
segment: ['day', 'month'],
28+
},
29+
],
30+
},
31+
},
32+
args: {
33+
segment: 'day',
34+
},
35+
argTypes: {
36+
segment: {
37+
control: 'select',
38+
options: ['day', 'month', 'year'],
39+
},
40+
},
41+
};
42+
43+
export default meta;
44+
45+
const Template: StoryFn<typeof DateInputSegment> = props => (
46+
<LeafyGreenProvider>
47+
<DateInputSegment {...props} />
48+
</LeafyGreenProvider>
49+
);
50+
51+
export const Basic = Template.bind({});
52+
53+
export const Generated = () => {};
Lines changed: 92 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,94 @@
1-
21
import { css } from '@leafygreen-ui/emotion';
2+
import { Theme } from '@leafygreen-ui/lib';
3+
import { palette } from '@leafygreen-ui/palette';
4+
import {
5+
BaseFontSize,
6+
fontFamilies,
7+
Size,
8+
typeScales,
9+
} from '@leafygreen-ui/tokens';
10+
11+
import { characterWidth } from './DateInputSegment.constants';
12+
import { DateSegment } from './DateInputSegment.types';
13+
14+
export const baseStyles = css`
15+
font-family: ${fontFamilies.default};
16+
font-size: ${BaseFontSize.Body1}px;
17+
border: none;
18+
border-radius: 0;
19+
padding: 0;
20+
21+
&::-webkit-outer-spin-button,
22+
&::-webkit-inner-spin-button {
23+
-webkit-appearance: none;
24+
margin: 0;
25+
}
26+
-moz-appearance: textfield; /* Firefox */
27+
28+
&:focus {
29+
outline: none;
30+
}
31+
`;
32+
33+
export const segmentThemeStyles: Record<Theme, string> = {
34+
[Theme.Light]: css`
35+
background-color: transparent;
36+
color: ${palette.black};
37+
38+
&::placeholder {
39+
color: ${palette.gray.light1};
40+
}
41+
42+
&:focus {
43+
background-color: ${palette.blue.light3};
44+
}
45+
`,
46+
[Theme.Dark]: css`
47+
background-color: transparent;
48+
color: ${palette.gray.light2};
49+
50+
&::placeholder {
51+
color: ${palette.gray.dark1};
52+
}
53+
54+
&:focus {
55+
background-color: ${palette.blue.dark3};
56+
}
57+
`,
58+
};
59+
60+
export const fontSizeStyles: Record<BaseFontSize, string> = {
61+
[BaseFontSize.Body1]: css`
62+
--base-font-size: ${BaseFontSize.Body1}px;
63+
`,
64+
[BaseFontSize.Body2]: css`
65+
--base-font-size: ${BaseFontSize.Body2}px;
66+
`,
67+
};
68+
69+
export const segmentSizeStyles: Record<Size, string> = {
70+
[Size.XSmall]: css`
71+
font-size: ${typeScales.body1.fontSize}px;
72+
`,
73+
[Size.Small]: css`
74+
font-size: ${typeScales.body1.fontSize}px;
75+
`,
76+
[Size.Default]: css`
77+
font-size: var(--base-font-size, ${typeScales.body1.fontSize}px);
78+
`,
79+
[Size.Large]: css`
80+
font-size: ${18}px; // Intentionally off-token
81+
`,
82+
};
383

4-
export const baseStyles = css``;
84+
export const segmentWidthStyles: Record<DateSegment, string> = {
85+
day: css`
86+
width: ${2 * characterWidth.D}ch;
87+
`,
88+
month: css`
89+
width: ${2 * characterWidth.M}ch;
90+
`,
91+
year: css`
92+
width: ${4 * characterWidth.Y}ch;
93+
`,
94+
};
Lines changed: 60 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,65 @@
1-
21
import React from 'react';
2+
import { padStart } from 'lodash';
3+
4+
import { cx } from '@leafygreen-ui/emotion';
5+
import { useControlledValue } from '@leafygreen-ui/hooks';
6+
import { useDarkMode } from '@leafygreen-ui/leafygreen-provider';
7+
import { Size } from '@leafygreen-ui/tokens';
8+
import { useUpdatedBaseFontSize } from '@leafygreen-ui/typography';
9+
10+
import {
11+
charsPerSegment,
12+
defaultMax,
13+
defaultMin,
14+
defaultPlaceholder,
15+
} from './DateInputSegment.constants';
16+
import {
17+
baseStyles,
18+
fontSizeStyles,
19+
segmentSizeStyles,
20+
segmentThemeStyles,
21+
segmentWidthStyles,
22+
} from './DateInputSegment.styles';
23+
import { DateInputSegmentProps } from './DateInputSegment.types';
24+
25+
export function DateInputSegment({
26+
segment,
27+
value: controlledValue,
28+
min: minProp,
29+
max: maxProp,
30+
onChange,
31+
darkMode,
32+
}: DateInputSegmentProps) {
33+
const min = minProp ?? defaultMin[segment];
34+
const max = maxProp ?? defaultMax[segment];
35+
36+
const { value, handleChange } = useControlledValue(controlledValue, onChange);
37+
38+
const { theme } = useDarkMode(darkMode);
39+
const baseFontSize = useUpdatedBaseFontSize();
40+
// TODO: implement context
41+
// const { size } = useDatePickerContext();
42+
const size = Size.Default;
343

4-
// TODO: forwardRef
5-
export function DateInputSegment({}) {
6-
return <div>your content here</div>;
44+
return (
45+
<input
46+
type="number"
47+
value={
48+
value ? padStart(value?.toString(), charsPerSegment[segment], '0') : ''
49+
}
50+
min={min}
51+
max={max}
52+
placeholder={defaultPlaceholder[segment]}
53+
onChange={handleChange}
54+
className={cx(
55+
baseStyles,
56+
fontSizeStyles[baseFontSize],
57+
segmentThemeStyles[theme],
58+
// segmentSizeStyles[size],
59+
segmentWidthStyles[segment],
60+
)}
61+
/>
62+
);
763
}
864

965
DateInputSegment.displayName = 'DateInputSegment';
Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1,22 @@
1-
export interface DateInputSegmentProps {}
1+
import { ChangeEventHandler } from 'react';
2+
3+
import { DarkModeProps } from '@leafygreen-ui/lib';
4+
5+
export type DateSegment = 'day' | 'month' | 'year';
6+
7+
export interface DateInputSegmentProps extends DarkModeProps {
8+
/** Which date segment this input represents. Determines the aria-label, and min/max values where relevant */
9+
segment: DateSegment;
10+
11+
/** The value of the date segment */
12+
value?: number;
13+
14+
/** Optional minimum value. Defaults to 0 for day/month segments, and 1970 for year segments */
15+
min?: number;
16+
17+
/** Optional maximum value. Defaults to 31 for day, 12 for month, 2038 for year */
18+
max?: number;
19+
20+
/** Callback fired when the value changes */
21+
onChange?: ChangeEventHandler<HTMLInputElement>;
22+
}

packages/date-picker/src/types.ts

Lines changed: 1 addition & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,5 @@
11
import { DarkModeProps } from '@leafygreen-ui/lib';
2-
import { BaseFontSize } from '@leafygreen-ui/tokens';
3-
4-
const Size = {
5-
xsmall: 'xsmall',
6-
small: 'small',
7-
default: 'default',
8-
large: 'large',
9-
};
10-
type Size = typeof Size[keyof typeof Size];
2+
import { BaseFontSize, Size } from '@leafygreen-ui/tokens';
113

124
export interface BaseDatePickerProps extends DarkModeProps {
135
/**

packages/date-picker/tsconfig.json

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,14 +18,23 @@
1818
{
1919
"path": "../emotion"
2020
},
21+
{
22+
"path": "../hooks"
23+
},
2124
{
2225
"path": "../leafygreen-provider"
2326
},
2427
{
2528
"path": "../lib"
2629
},
30+
{
31+
"path": "../palette"
32+
},
2733
{
2834
"path": "../tokens"
35+
},
36+
{
37+
"path": "../typography"
2938
}
3039
]
3140
}

yarn.lock

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4242,9 +4242,9 @@
42424242
csstype "^3.0.2"
42434243

42444244
"@types/react@^17.0.2":
4245-
version "17.0.62"
4246-
resolved "https://registry.yarnpkg.com/@types/react/-/react-17.0.62.tgz#2efe8ddf8533500ec44b1334dd1a97caa2f860e3"
4247-
integrity sha512-eANCyz9DG8p/Vdhr0ZKST8JV12PhH2ACCDYlFw6DIO+D+ca+uP4jtEDEpVqXZrh/uZdXQGwk7whJa3ah5DtyLw==
4245+
version "17.0.65"
4246+
resolved "https://registry.yarnpkg.com/@types/react/-/react-17.0.65.tgz#95f6a2ab61145ffb69129d07982d047f9e0870cd"
4247+
integrity sha512-oxur785xZYHvnI7TRS61dXbkIhDPnGfsXKv0cNXR/0ml4SipRIFpSMzA7HMEfOywFwJ5AOnPrXYTEiTRUQeGlQ==
42484248
dependencies:
42494249
"@types/prop-types" "*"
42504250
"@types/scheduler" "*"
@@ -5514,9 +5514,9 @@ camelcase@^7.0.0:
55145514
integrity sha512-xlx1yCK2Oc1APsPXDL2LdlNP6+uu8OCDdhOBSVT279M/S+y75O30C2VuD8T2ogdePBBl7PfPF4504tnLgX3zfw==
55155515

55165516
caniuse-lite@^1.0.30001135, caniuse-lite@^1.0.30001406, caniuse-lite@^1.0.30001517:
5517-
version "1.0.30001519"
5518-
resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001519.tgz#3e7b8b8a7077e78b0eb054d69e6edf5c7df35601"
5519-
integrity sha512-0QHgqR+Jv4bxHMp8kZ1Kn8CH55OikjKJ6JmKkZYP1F3D7w+lnFXF70nG5eNfsZS89jadi5Ywy5UCSKLAglIRkg==
5517+
version "1.0.30001522"
5518+
resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001522.tgz#44b87a406c901269adcdb834713e23582dd71856"
5519+
integrity sha512-TKiyTVZxJGhsTszLuzb+6vUZSjVOAhClszBr2Ta2k9IwtNBT/4dzmL6aywt0HCgEZlmwJzXJd8yNiob6HgwTRg==
55205520

55215521
case-sensitive-paths-webpack-plugin@^2.4.0:
55225522
version "2.4.0"
@@ -13228,6 +13228,7 @@ wordwrap@^1.0.0:
1322813228
integrity sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q==
1322913229

1323013230
"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0", wrap-ansi@^7.0.0:
13231+
name wrap-ansi-cjs
1323113232
version "7.0.0"
1323213233
resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43"
1323313234
integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==

0 commit comments

Comments
 (0)