@dhis2-ui/calendar 10.16.1 → 10.16.3-alpha.1

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.
Files changed (26) hide show
  1. package/package.json +10 -9
  2. package/src/__e2e__/calendar-input.e2e.stories.js +22 -0
  3. package/src/calendar/calendar-container.js +99 -0
  4. package/src/calendar/calendar-table-cell.js +97 -0
  5. package/src/calendar/calendar-table-days-header.js +40 -0
  6. package/src/calendar/calendar-table.js +74 -0
  7. package/src/calendar/calendar.js +104 -0
  8. package/src/calendar/navigation-container.js +295 -0
  9. package/src/calendar-input/__tests__/calendar-input.test.js +344 -0
  10. package/src/calendar-input/calendar-input.js +262 -0
  11. package/src/features/supports_calendar_clear_button/supports_calendar_clear_button.js +64 -0
  12. package/src/features/supports_calendar_clear_button.feature +23 -0
  13. package/src/features/supports_ethiopic_calendar/supports_ethiopic_calendar.js +61 -0
  14. package/src/features/supports_ethiopic_calendar.feature +20 -0
  15. package/src/features/supports_gregorian_calendar/supports_gregorian_calendar.js +62 -0
  16. package/src/features/supports_gregorian_calendar.feature +19 -0
  17. package/src/features/supports_islamic_calendar/supports_islamic_calendar.js +17 -0
  18. package/src/features/supports_islamic_calendar.feature +5 -0
  19. package/src/features/supports_nepali_calendar/supports_nepali_calendar.js +60 -0
  20. package/src/features/supports_nepali_calendar.feature +19 -0
  21. package/src/index.js +2 -0
  22. package/src/locales/en/translations.json +6 -0
  23. package/src/locales/index.js +16 -0
  24. package/src/stories/calendar-input.prod.stories.js +255 -0
  25. package/src/stories/calendar-story-wrapper.js +161 -0
  26. package/src/stories/calendar.prod.stories.js +91 -0
@@ -0,0 +1,255 @@
1
+ import { Button } from '@dhis2-ui/button'
2
+ import React, { useState } from 'react'
3
+ import { Field, Form } from 'react-final-form'
4
+ import { CalendarInput } from '../calendar-input/calendar-input.js'
5
+ import { CalendarStoryWrapper } from './calendar-story-wrapper.js'
6
+
7
+ const subtitle = `[Experimental] Calendar Input is a wrapper around Calendar displaying an input that triggers the calendar`
8
+ const description = `
9
+ Use a CalendarInput where there is a need to let the user input a date.
10
+
11
+ Note that it requires a parent, like [Box](../?path=/docs/layout-box--default), to define its size.
12
+
13
+ \`\`\`js
14
+ import { CalendarInput } from '@dhis2/ui'
15
+ \`\`\`
16
+ `
17
+
18
+ export default {
19
+ title: 'CalendarInput',
20
+ component: CalendarInput,
21
+ parameters: {
22
+ componentSubtitle: subtitle,
23
+ docs: { description: { component: description } },
24
+ },
25
+ }
26
+
27
+ const buildCalendar =
28
+ ({ date, locale, calendar }) =>
29
+ () =>
30
+ (
31
+ <CalendarStoryWrapper
32
+ component={CalendarInput}
33
+ dir="ltr"
34
+ timeZone="Africa/Khartoum"
35
+ weekDayFormat="short"
36
+ date={date}
37
+ locale={locale}
38
+ calendar={calendar}
39
+ onDateSelect={() => {}}
40
+ />
41
+ )
42
+
43
+ export const EthiopicWithAmharic = buildCalendar({
44
+ calendar: 'ethiopic',
45
+ locale: 'am-ET',
46
+ date: '2014-02-03', // 13 Oct 2021
47
+ })
48
+
49
+ export const EthiopicWithEnglish = buildCalendar({
50
+ calendar: 'ethiopian', // using "ethiopian" rather than the correct "ethiopic" to immitate DHIS2 calendar types
51
+ locale: 'en-ET',
52
+ date: '2014-02-03', // 13 Oct 2021
53
+ })
54
+
55
+ export const NepaliWithNepali = buildCalendar({
56
+ calendar: 'nepali',
57
+ locale: 'ne-NP',
58
+ date: '2078-06-27', // 13 Oct 2021
59
+ })
60
+
61
+ export const NepaliWithEnglish = buildCalendar({
62
+ calendar: 'nepali',
63
+ locale: 'en-NP',
64
+ date: '2078-06-27', // 13 Oct 2021
65
+ })
66
+
67
+ export const GregorianWithEnglish = buildCalendar({
68
+ calendar: 'gregorian',
69
+ locale: 'en-CA',
70
+ date: '2021-10-13',
71
+ })
72
+
73
+ export const GregorianWithArabic = buildCalendar({
74
+ calendar: 'gregorian',
75
+ locale: 'ar-SD',
76
+ date: '2021-10-13',
77
+ })
78
+
79
+ export const IslamicWithArabic = () => {
80
+ return (
81
+ <div style={{ direction: 'rtl' }}>
82
+ <CalendarStoryWrapper
83
+ component={CalendarInput}
84
+ dir="rtl"
85
+ timeZone="Africa/Khartoum"
86
+ weekDayFormat="short"
87
+ date="1477-01-13"
88
+ locale="ar-SD"
89
+ calendar="islamic-civil"
90
+ clearable={true}
91
+ onDateSelect={() => {}}
92
+ />
93
+ </div>
94
+ )
95
+ }
96
+
97
+ export const CalendarWithClearButton = ({
98
+ calendar = 'gregory',
99
+ date: initialDate = null,
100
+ }) => {
101
+ const [date, setDate] = useState(initialDate)
102
+ return (
103
+ <>
104
+ <CalendarInput
105
+ calendar={calendar}
106
+ date={date}
107
+ onDateSelect={(date) => {
108
+ setDate(date?.calendarDateString)
109
+ }}
110
+ clearable
111
+ />
112
+ <div>
113
+ value:
114
+ <span data-test="storybook-calendar-date-value">
115
+ {date ?? 'undefined'}
116
+ </span>
117
+ </div>
118
+ </>
119
+ )
120
+ }
121
+
122
+ export function CalendarWithStrictValidation() {
123
+ const [validation, setValidation] = useState({})
124
+
125
+ const errored = () => {
126
+ if (validation.error) {
127
+ return { calendar: validation.validationText }
128
+ }
129
+ }
130
+
131
+ return (
132
+ <Form
133
+ onSubmit={(values, meta) => {
134
+ console.log('SUBMITTING', { values, meta })
135
+ }}
136
+ initialValues={{ calendar: '2022-10-12' }}
137
+ validate={errored}
138
+ >
139
+ {({ handleSubmit, invalid }) => {
140
+ return (
141
+ <form onSubmit={handleSubmit}>
142
+ <Field name="calendar">
143
+ {(props) => (
144
+ <CalendarInput
145
+ {...props}
146
+ label="Enter a date"
147
+ helpText="Date has to be after 2022-11-01"
148
+ input={props.input}
149
+ meta={props.meta}
150
+ editable
151
+ date={props.input.value}
152
+ calendar="gregory"
153
+ {...validation}
154
+ minDate="2022-11-01"
155
+ onDateSelect={(date) => {
156
+ const validation = {
157
+ ...date.validation,
158
+ validationText:
159
+ date.validation
160
+ .validationCode ===
161
+ 'WRONG_FORMAT'
162
+ ? 'custom validation message for format'
163
+ : date.validation
164
+ .validationText,
165
+ }
166
+ setValidation(validation)
167
+ props.input.onChange(
168
+ date ? date?.calendarDateString : ''
169
+ )
170
+ }}
171
+ />
172
+ )}
173
+ </Field>
174
+
175
+ <Button
176
+ type="submit"
177
+ disabled={invalid}
178
+ onClick={handleSubmit}
179
+ >
180
+ Submit
181
+ </Button>
182
+ </form>
183
+ )
184
+ }}
185
+ </Form>
186
+ )
187
+ }
188
+
189
+ export function CalendarWithNonStrictValidation() {
190
+ const [validation, setValidation] = useState({})
191
+
192
+ const errored = () => {
193
+ if (validation.error) {
194
+ return { calendar: validation.validationText }
195
+ }
196
+ }
197
+
198
+ return (
199
+ <Form
200
+ onSubmit={(values, meta) => {
201
+ console.log('SUBMITTING', { values, meta })
202
+ }}
203
+ initialValues={{ calendar: '2022-10-12' }}
204
+ validate={errored}
205
+ >
206
+ {({ handleSubmit, invalid }) => {
207
+ return (
208
+ <form onSubmit={handleSubmit}>
209
+ <Field name="calendar">
210
+ {(props) => (
211
+ <CalendarInput
212
+ {...props}
213
+ label="Enter a date"
214
+ helpText="Date has to be after 2022-11-01"
215
+ input={props.input}
216
+ meta={props.meta}
217
+ editable
218
+ date={props.input.value}
219
+ calendar="gregory"
220
+ {...validation}
221
+ minDate="2022-11-01"
222
+ strictValidation={false}
223
+ onDateSelect={(date) => {
224
+ const validation = {
225
+ ...date.validation,
226
+ validationText:
227
+ date.validation
228
+ .validationCode ===
229
+ 'WRONG_FORMAT'
230
+ ? 'custom validation message for format'
231
+ : date.validation
232
+ .validationText,
233
+ }
234
+ setValidation(validation)
235
+ props.input.onChange(
236
+ date ? date?.calendarDateString : ''
237
+ )
238
+ }}
239
+ />
240
+ )}
241
+ </Field>
242
+
243
+ <Button
244
+ type="submit"
245
+ disabled={invalid}
246
+ onClick={handleSubmit}
247
+ >
248
+ Submit
249
+ </Button>
250
+ </form>
251
+ )
252
+ }}
253
+ </Form>
254
+ )
255
+ }
@@ -0,0 +1,161 @@
1
+ import { constants } from '@dhis2/multi-calendar-dates'
2
+ import PropTypes from 'prop-types'
3
+ import React, { useState } from 'react'
4
+ import { Calendar } from '../calendar/calendar.js'
5
+
6
+ const { calendars, numberingSystems } = constants
7
+ export const CalendarStoryWrapper = (props) => {
8
+ const {
9
+ calendar = 'gregory',
10
+ locale,
11
+ timeZone,
12
+ dir,
13
+ component: Component = Calendar,
14
+ date,
15
+ weekDayFormat = 'narrow',
16
+ } = props
17
+ const [selectedCalendar, setSelectedCalendar] = useState(calendar)
18
+ const [selectedNumberingSystem, setSelectedNumberingSystem] = useState()
19
+ const [selectedDirection, setSelectedDirection] = useState(dir)
20
+ const [selectedWeekFormat, setWeekDayFormat] = useState(weekDayFormat)
21
+
22
+ const [selectedLocale, setLocale] = useState(locale)
23
+ const [selectedDate, setSelectedDate] = useState({
24
+ calendarDateString: date,
25
+ })
26
+
27
+ const changeCalendar = ({ target: { value } }) => {
28
+ setSelectedCalendar(value)
29
+ }
30
+ const changeNumberingSystem = ({ target: { value } }) => {
31
+ if (value === '-1') {
32
+ setSelectedNumberingSystem(null)
33
+ } else {
34
+ setSelectedNumberingSystem(value)
35
+ }
36
+ }
37
+ const changeDirection = ({ target: { value } }) => {
38
+ setSelectedDirection(value)
39
+ }
40
+
41
+ const changeWeekFormat = ({ target: { value } }) => {
42
+ setWeekDayFormat(value)
43
+ }
44
+
45
+ const onLocaleChanged = ({ target: { value } }) => {
46
+ setLocale(value)
47
+ }
48
+
49
+ return (
50
+ <div>
51
+ <div
52
+ style={{
53
+ fontSize: '0.8em',
54
+ marginBottom: 20,
55
+ gap: 5,
56
+ display: 'flex',
57
+ alignItems: 'center',
58
+ }}
59
+ >
60
+ <div>Options</div>
61
+ <input
62
+ defaultValue={locale}
63
+ placeholder="locale"
64
+ onBlur={onLocaleChanged}
65
+ />
66
+ <select onChange={changeCalendar} value={selectedCalendar}>
67
+ <option disabled key={calendar} value="-1">
68
+ Select calendar
69
+ </option>
70
+ {calendars.map((calendar) => {
71
+ return (
72
+ <option value={calendar} key={calendar}>
73
+ {calendar}
74
+ </option>
75
+ )
76
+ })}
77
+ </select>
78
+ <select
79
+ onChange={changeNumberingSystem}
80
+ value={selectedNumberingSystem}
81
+ >
82
+ <option disabled key={calendar} value="-1">
83
+ Select numbering system
84
+ </option>
85
+ {numberingSystems.map((system) => {
86
+ return (
87
+ <option value={system} key={system}>
88
+ {system}
89
+ </option>
90
+ )
91
+ })}
92
+ </select>
93
+ <select onChange={changeDirection} value={selectedDirection}>
94
+ <option disabled value="-1">
95
+ Select direction
96
+ </option>
97
+ <option value="ltr">Left-To-Right</option>
98
+ <option value="rtl">Right-To-Left</option>
99
+ </select>
100
+ <select onChange={changeWeekFormat} value={selectedWeekFormat}>
101
+ <option disabled value="-1">
102
+ Select format
103
+ </option>
104
+ <option value="narrow">narrow</option>
105
+ <option value="short">short</option>
106
+ <option value="long">long</option>
107
+ </select>
108
+ </div>
109
+ <Component
110
+ {...props}
111
+ calendar={selectedCalendar}
112
+ dir={selectedDirection}
113
+ locale={selectedLocale}
114
+ date={selectedDate.calendarDateString}
115
+ onDateSelect={(date) => {
116
+ setSelectedDate(date)
117
+ }}
118
+ {...selectedDate.validation}
119
+ timeZone={timeZone}
120
+ weekDayFormat={selectedWeekFormat}
121
+ numberingSystem={selectedNumberingSystem}
122
+ />
123
+ <div
124
+ style={{
125
+ marginTop: 10,
126
+ gap: 5,
127
+ fontSize: '12px',
128
+ display: 'flex',
129
+ flexDirection: 'column',
130
+ }}
131
+ >
132
+ <div>
133
+ {selectedDate && (
134
+ <>
135
+ <div>
136
+ <label>calendar date: </label>
137
+ <span data-test="storybook-calendar-result">
138
+ {selectedDate.calendarDateString}
139
+ </span>
140
+ </div>
141
+ <div>
142
+ <label>callback:</label>
143
+ {JSON.stringify(selectedDate, null, 2)}
144
+ </div>
145
+ </>
146
+ )}
147
+ </div>
148
+ </div>
149
+ </div>
150
+ )
151
+ }
152
+
153
+ CalendarStoryWrapper.propTypes = {
154
+ calendar: PropTypes.string.isRequired,
155
+ component: PropTypes.elementType.isRequired,
156
+ date: PropTypes.string,
157
+ dir: PropTypes.oneOf(['ltr', 'rtl']),
158
+ locale: PropTypes.string,
159
+ timeZone: PropTypes.string,
160
+ weekDayFormat: PropTypes.string,
161
+ }
@@ -0,0 +1,91 @@
1
+ import React from 'react'
2
+ import { Calendar } from '../calendar/calendar.js'
3
+ import { CalendarStoryWrapper } from './calendar-story-wrapper.js'
4
+
5
+ const subtitle = `[Experimental] Calendar component is useful for creating a variety of calendars including Ethiopic, Islamic etc..`
6
+ const description = `
7
+ Use a Calendar where there is a need to let the user select a date.
8
+
9
+ Note that it requires a parent, like [Box](../?path=/docs/layout-box--default), to define its size.
10
+
11
+ \`\`\`js
12
+ import { Calendar } from '@dhis2/ui'
13
+ \`\`\`
14
+ `
15
+
16
+ export default {
17
+ title: 'Calendar',
18
+ component: Calendar,
19
+ parameters: {
20
+ componentSubtitle: subtitle,
21
+ docs: { description: { component: description } },
22
+ },
23
+ argTypes: {
24
+ calendar: {
25
+ control: 'select',
26
+ options: [
27
+ 'gregory',
28
+ 'islamic',
29
+ 'nepali',
30
+ 'ethiopic',
31
+ 'persian',
32
+ 'indian',
33
+ ],
34
+ },
35
+ weekDayFormat: {
36
+ control: 'select',
37
+ options: ['long', 'short', 'narrow'],
38
+ },
39
+ locale: {
40
+ control: 'text',
41
+ },
42
+ numberingSystem: {
43
+ control: 'select',
44
+ options: ['latn', 'arab', 'ethi'],
45
+ },
46
+ pastOnly: {
47
+ control: 'boolean',
48
+ defaultValue: false,
49
+ },
50
+ },
51
+ }
52
+
53
+ export const Basic = (args) => {
54
+ return <Calendar {...args} />
55
+ }
56
+
57
+ Basic.args = {
58
+ onDateSelect: (date) => console.log(date),
59
+ calendar: 'gregory',
60
+ weekDayFormat: 'narrow',
61
+ locale: 'en',
62
+ }
63
+
64
+ export const Ethiopic = (args) => {
65
+ return (
66
+ <CalendarStoryWrapper
67
+ calendar="ethiopic"
68
+ locale="am-et"
69
+ numberingSystem="ethi"
70
+ date="2014-04-05" // 13th of October 2022
71
+ timeZone="Africa/Khartoum"
72
+ {...args}
73
+ />
74
+ )
75
+ }
76
+
77
+ export const Nepali = (args) => {
78
+ return (
79
+ <CalendarStoryWrapper
80
+ calendar="nepali"
81
+ locale="ne-NP"
82
+ date="2079-06-29" // 13th of October 2022
83
+ timeZone="Africa/Khartoum"
84
+ {...args}
85
+ />
86
+ )
87
+ }
88
+
89
+ export const WithAnyCalendar = (args) => {
90
+ return <CalendarStoryWrapper calendar="gregory" locale="en-GB" {...args} />
91
+ }