@loadsmart/loadsmart-ui 5.16.1 → 5.17.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.
- package/dist/components/Calendar/DateFormat.helper.d.ts +4 -2
- package/dist/index.js +23 -23
- package/dist/index.js.map +1 -1
- package/dist/utils/toolset/getOrdinalSuffix.d.ts +1 -0
- package/dist/utils/toolset/getOrdinalSuffix.test.d.ts +1 -0
- package/package.json +1 -1
- package/src/components/Calendar/DateFormat.helper.test.ts +27 -0
- package/src/components/Calendar/DateFormat.helper.ts +41 -9
- package/src/utils/toolset/getOrdinalSuffix.test.ts +27 -0
- package/src/utils/toolset/getOrdinalSuffix.ts +15 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const getOrdinalSuffix: (number: number) => 'st' | 'nd' | 'rd' | 'th';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/package.json
CHANGED
|
@@ -134,5 +134,32 @@ describe('DateFormatHelper', () => {
|
|
|
134
134
|
)
|
|
135
135
|
).toBe('02/01/2022 11:22:33')
|
|
136
136
|
})
|
|
137
|
+
|
|
138
|
+
it('formats compound tokens', () => {
|
|
139
|
+
expect(
|
|
140
|
+
DateFormatHelper('ddd, Do, MMM').format(
|
|
141
|
+
DateHelper('2021-05-04T04:00:00Z', {
|
|
142
|
+
normalize: false,
|
|
143
|
+
})
|
|
144
|
+
)
|
|
145
|
+
).toBe('Tue, 4th, May')
|
|
146
|
+
expect(
|
|
147
|
+
DateFormatHelper('ddd, DDo, MMM').format(
|
|
148
|
+
DateHelper('2021-05-05T04:00:00Z', {
|
|
149
|
+
normalize: false,
|
|
150
|
+
})
|
|
151
|
+
)
|
|
152
|
+
).toBe('Wed, 05th, May')
|
|
153
|
+
})
|
|
154
|
+
|
|
155
|
+
it('does not formats a compound token when the previous token is invalid', () => {
|
|
156
|
+
expect(
|
|
157
|
+
DateFormatHelper('ddd, YYYYo, MMM').format(
|
|
158
|
+
DateHelper('2021-05-10T04:00:00Z', {
|
|
159
|
+
normalize: false,
|
|
160
|
+
})
|
|
161
|
+
)
|
|
162
|
+
).toBe('Mon, 2021o, May')
|
|
163
|
+
})
|
|
137
164
|
})
|
|
138
165
|
})
|
|
@@ -2,11 +2,18 @@ import { identity } from '@loadsmart/utils-function'
|
|
|
2
2
|
import { padded } from './Date.helper'
|
|
3
3
|
|
|
4
4
|
import type { CalendarDate } from './Date.helper'
|
|
5
|
+
import { getOrdinalSuffix } from 'utils/toolset/getOrdinalSuffix'
|
|
5
6
|
|
|
6
7
|
export interface DateFormat {
|
|
7
8
|
format(date: CalendarDate): string
|
|
8
9
|
}
|
|
9
10
|
|
|
11
|
+
const getTokenValue = (date: CalendarDate, token: string) => {
|
|
12
|
+
const value = DEFAULT_FORMATTERS[token].format(date.get())
|
|
13
|
+
|
|
14
|
+
return (ADDITIONAL_FORMATTERS[token] || identity)(value)
|
|
15
|
+
}
|
|
16
|
+
|
|
10
17
|
/**
|
|
11
18
|
* This helpers provides a convenient layer on top of `Intl.DateTimeFormat`,
|
|
12
19
|
* using common tokens (based on `momentjs`) to format dates.
|
|
@@ -17,11 +24,16 @@ export default function DateFormatHelper(format: string): DateFormat {
|
|
|
17
24
|
return {
|
|
18
25
|
format(date: CalendarDate) {
|
|
19
26
|
return tokens
|
|
20
|
-
.map((token) => {
|
|
27
|
+
.map((token, index) => {
|
|
28
|
+
const previousIndex = index - 1
|
|
29
|
+
const previousToken = tokens[previousIndex]
|
|
30
|
+
|
|
21
31
|
if (token in DEFAULT_FORMATTERS) {
|
|
22
|
-
|
|
32
|
+
return getTokenValue(date, token)
|
|
33
|
+
}
|
|
23
34
|
|
|
24
|
-
|
|
35
|
+
if (token in COMPOUND_FORMATTERS && COMPOUND_FORMATTERS[token].valid(previousToken)) {
|
|
36
|
+
return COMPOUND_FORMATTERS[token].format(getTokenValue(date, previousToken))
|
|
25
37
|
}
|
|
26
38
|
|
|
27
39
|
return token
|
|
@@ -39,16 +51,18 @@ export default function DateFormatHelper(format: string): DateFormat {
|
|
|
39
51
|
*| Month | MM | 01, 02, ..., 11, 12 |
|
|
40
52
|
*| | MMM | Jan, Feb, ..., Nov, Dec |
|
|
41
53
|
*| | MMMM | January, February, ..., November,December |
|
|
42
|
-
*| Day of Month |
|
|
54
|
+
*| Day of Month | D | 1, 2, ..., 30, 31 |
|
|
55
|
+
*| Day of Month with leading 0 | DD | 01, 02, ..., 30, 31 |
|
|
43
56
|
*| Day of week | ddd | Sun, Mon, ... Fri, Sat |
|
|
44
57
|
*| | dddd | Sunday, Monday, ..., Friday, Saturday |
|
|
45
58
|
*| Year | YYYY | 1970, 1971, ..., 2029, 2030 |
|
|
46
59
|
*| Hour | HH | 00, 01, ..., 22, 23 |
|
|
47
60
|
*| | hh | 00, 01, ..., 11, 12 |
|
|
48
|
-
*| Minute | mm | 01, 02, ...,
|
|
61
|
+
*| Minute | mm | 01, 02, ..., 58, 59 |
|
|
49
62
|
*| Seconds | ss | 01, 02, ..., 58, 59 |
|
|
50
63
|
*| Post or ante meridiem | a | am, pm |
|
|
51
64
|
*| | A | AM, PM |
|
|
65
|
+
*| Ordinal numbers | o | 1st, 2nd, 3rd, ..., 10th |
|
|
52
66
|
*| Scaped sequence | [] | |
|
|
53
67
|
*
|
|
54
68
|
* @param format
|
|
@@ -56,7 +70,10 @@ export default function DateFormatHelper(format: string): DateFormat {
|
|
|
56
70
|
*/
|
|
57
71
|
export function tokenizer(format: string): string[] {
|
|
58
72
|
function getType(char?: string): string {
|
|
59
|
-
if (
|
|
73
|
+
if (
|
|
74
|
+
char != undefined &&
|
|
75
|
+
['M', 'd', 'D', 'Y', 'H', 'h', 'm', 's', 'A', 'a', 'o'].includes(char)
|
|
76
|
+
) {
|
|
60
77
|
return 'token'
|
|
61
78
|
}
|
|
62
79
|
|
|
@@ -110,6 +127,9 @@ const DEFAULT_FORMATTERS: Record<string, Intl.DateTimeFormat> = {
|
|
|
110
127
|
MMMM: new Intl.DateTimeFormat('en-US', {
|
|
111
128
|
month: 'long',
|
|
112
129
|
}),
|
|
130
|
+
D: new Intl.DateTimeFormat('en-US', {
|
|
131
|
+
day: 'numeric',
|
|
132
|
+
}),
|
|
113
133
|
DD: new Intl.DateTimeFormat('en-US', {
|
|
114
134
|
day: '2-digit',
|
|
115
135
|
}),
|
|
@@ -154,10 +174,22 @@ const DEFAULT_FORMATTERS: Record<string, Intl.DateTimeFormat> = {
|
|
|
154
174
|
* Padding, for example, is applied in some cases due to [this](https://bugs.chromium.org/p/chromium/issues/detail?id=527926) bug.
|
|
155
175
|
*/
|
|
156
176
|
const ADDITIONAL_FORMATTERS: Record<string, (value: string) => string> = {
|
|
157
|
-
hh: (value: string) => (value ? padded(value.split(
|
|
177
|
+
hh: (value: string) => (value ? padded(value.split(/\s/)[0], 2) : value),
|
|
158
178
|
HH: (value: string) => (value ? padded(value, 2) : value),
|
|
159
179
|
mm: (value: string) => (value ? padded(value, 2) : value),
|
|
160
180
|
ss: (value: string) => (value ? padded(value, 2) : value),
|
|
161
|
-
a: (value: string) => (value ? (value.split(
|
|
162
|
-
A: (value: string) => (value ? (value.split(
|
|
181
|
+
a: (value: string) => (value ? (value.split(/\s/)[1] || '').toLowerCase() : value),
|
|
182
|
+
A: (value: string) => (value ? (value.split(/\s/)[1] || '').toUpperCase() : value),
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
type CompoundFormatter = {
|
|
186
|
+
valid: (token: string) => boolean
|
|
187
|
+
format: (value: string) => string
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
const COMPOUND_FORMATTERS: Record<string, CompoundFormatter> = {
|
|
191
|
+
o: {
|
|
192
|
+
valid: (token) => new Set(['D', 'DD']).has(token),
|
|
193
|
+
format: (value: string) => getOrdinalSuffix(parseInt(value, 10)),
|
|
194
|
+
},
|
|
163
195
|
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { getOrdinalSuffix } from './getOrdinalSuffix'
|
|
2
|
+
|
|
3
|
+
it('should return "st" for numbers ending with 1', () => {
|
|
4
|
+
expect(getOrdinalSuffix(1)).toBe('st')
|
|
5
|
+
expect(getOrdinalSuffix(101)).toBe('st')
|
|
6
|
+
expect(getOrdinalSuffix(1001)).toBe('st')
|
|
7
|
+
})
|
|
8
|
+
|
|
9
|
+
it('should return "nd" for numbers ending with 2', () => {
|
|
10
|
+
expect(getOrdinalSuffix(2)).toBe('nd')
|
|
11
|
+
expect(getOrdinalSuffix(102)).toBe('nd')
|
|
12
|
+
expect(getOrdinalSuffix(1002)).toBe('nd')
|
|
13
|
+
})
|
|
14
|
+
|
|
15
|
+
it('should return "rd" for numbers ending with 3', () => {
|
|
16
|
+
expect(getOrdinalSuffix(3)).toBe('rd')
|
|
17
|
+
expect(getOrdinalSuffix(103)).toBe('rd')
|
|
18
|
+
expect(getOrdinalSuffix(1003)).toBe('rd')
|
|
19
|
+
})
|
|
20
|
+
|
|
21
|
+
it('should return "th" for 0 and numbers higher than 3 but not ending with 1, 2 or 3', () => {
|
|
22
|
+
expect(getOrdinalSuffix(0)).toBe('th')
|
|
23
|
+
expect(getOrdinalSuffix(4)).toBe('th')
|
|
24
|
+
expect(getOrdinalSuffix(10)).toBe('th')
|
|
25
|
+
expect(getOrdinalSuffix(100)).toBe('th')
|
|
26
|
+
expect(getOrdinalSuffix(1000)).toBe('th')
|
|
27
|
+
})
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export const getOrdinalSuffix = (number: number): 'st' | 'nd' | 'rd' | 'th' => {
|
|
2
|
+
if (number % 10 === 1 && number !== 11) {
|
|
3
|
+
return 'st'
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
if (number % 10 === 2 && number !== 12) {
|
|
7
|
+
return 'nd'
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
if (number % 10 === 3 && number !== 13) {
|
|
11
|
+
return 'rd'
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
return 'th'
|
|
15
|
+
}
|