sanity-plugin-recurring-dates 1.1.0 → 1.2.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/README.md +6 -0
- package/dist/index.d.ts +6 -1
- package/dist/index.esm.js +302 -4864
- package/dist/index.esm.js.map +1 -1
- package/dist/index.js +306 -4868
- package/dist/index.js.map +1 -1
- package/package.json +27 -26
- package/src/components/CustomRule/CustomRule.tsx +100 -107
- package/src/components/CustomRule/Monthly.tsx +1 -1
- package/src/components/CustomRule/Weekly.tsx +1 -1
- package/src/components/DateInputs/CommonDateTimeInput.tsx +5 -4
- package/src/components/DateInputs/DateInput.tsx +1 -1
- package/src/components/DateInputs/DateTimeInput.tsx +1 -1
- package/src/components/DateInputs/base/DatePicker.tsx +4 -2
- package/src/components/DateInputs/base/DateTimeInput.tsx +8 -4
- package/src/components/DateInputs/base/LazyTextInput.tsx +13 -14
- package/src/components/DateInputs/base/calendar/Calendar.tsx +18 -16
- package/src/components/DateInputs/base/calendar/CalendarDay.tsx +1 -1
- package/src/components/DateInputs/base/calendar/CalendarMonth.tsx +3 -2
- package/src/components/DateInputs/base/calendar/YearInput.tsx +4 -3
- package/src/components/RecurringDate.tsx +21 -4
- package/src/components/RemoveEndDate.tsx +3 -2
- package/src/schema/recurringDates.tsx +9 -5
- package/src/types.ts +6 -2
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "sanity-plugin-recurring-dates",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.2.0",
|
|
4
4
|
"description": "Add a custom input component to your Sanity Studio to manage recurring dates (e.g. for events)",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"sanity",
|
|
@@ -53,39 +53,40 @@
|
|
|
53
53
|
"sanity-plugin-utils": "^1.6.2"
|
|
54
54
|
},
|
|
55
55
|
"devDependencies": {
|
|
56
|
-
"@commitlint/cli": "^18.
|
|
57
|
-
"@commitlint/config-conventional": "^18.
|
|
58
|
-
"@sanity/pkg-utils": "^3.3.
|
|
59
|
-
"@sanity/plugin-kit": "^3.1.
|
|
60
|
-
"@sanity/semantic-release-preset": "^4.1.
|
|
61
|
-
"@types/react": "^18.
|
|
62
|
-
"@typescript-eslint/eslint-plugin": "^6.
|
|
63
|
-
"@typescript-eslint/parser": "^6.
|
|
64
|
-
"eslint": "^8.
|
|
56
|
+
"@commitlint/cli": "^18.6.1",
|
|
57
|
+
"@commitlint/config-conventional": "^18.6.3",
|
|
58
|
+
"@sanity/pkg-utils": "^3.3.8",
|
|
59
|
+
"@sanity/plugin-kit": "^3.1.12",
|
|
60
|
+
"@sanity/semantic-release-preset": "^4.1.8",
|
|
61
|
+
"@types/react": "^18.3.5",
|
|
62
|
+
"@typescript-eslint/eslint-plugin": "^6.21.0",
|
|
63
|
+
"@typescript-eslint/parser": "^6.21.0",
|
|
64
|
+
"eslint": "^8.57.0",
|
|
65
65
|
"eslint-config-prettier": "^9.1.0",
|
|
66
|
-
"eslint-config-sanity": "^7.
|
|
67
|
-
"eslint-plugin-prettier": "^5.1
|
|
68
|
-
"eslint-plugin-react": "^7.
|
|
69
|
-
"eslint-plugin-react-hooks": "^4.6.
|
|
66
|
+
"eslint-config-sanity": "^7.1.2",
|
|
67
|
+
"eslint-plugin-prettier": "^5.2.1",
|
|
68
|
+
"eslint-plugin-react": "^7.35.2",
|
|
69
|
+
"eslint-plugin-react-hooks": "^4.6.2",
|
|
70
70
|
"eslint-plugin-simple-import-sort": "^10.0.0",
|
|
71
71
|
"husky": "^8.0.3",
|
|
72
72
|
"lint-staged": "^15.2.0",
|
|
73
|
-
"npm-run-
|
|
74
|
-
"prettier": "^3.
|
|
75
|
-
"prettier-plugin-packagejson": "^2.
|
|
76
|
-
"react": "^18.
|
|
77
|
-
"react-dom": "^18.
|
|
78
|
-
"react-is": "^18.
|
|
73
|
+
"npm-run-all2": "^5.0.0",
|
|
74
|
+
"prettier": "^3.3.3",
|
|
75
|
+
"prettier-plugin-packagejson": "^2.5.2",
|
|
76
|
+
"react": "^18.3.1",
|
|
77
|
+
"react-dom": "^18.3.1",
|
|
78
|
+
"react-is": "^18.3.1",
|
|
79
79
|
"rimraf": "^5.0.1",
|
|
80
|
-
"sanity": "^3.
|
|
81
|
-
"styled-components": "^6.1.
|
|
82
|
-
"typescript": "^5.
|
|
80
|
+
"sanity": "^3.57.0",
|
|
81
|
+
"styled-components": "^6.1.13",
|
|
82
|
+
"typescript": "^5.5.4"
|
|
83
83
|
},
|
|
84
84
|
"peerDependencies": {
|
|
85
|
-
"
|
|
86
|
-
"sanity": "^3",
|
|
85
|
+
"@sanity/icons": ">= 2",
|
|
87
86
|
"@sanity/ui": "^1 || ^2.0.0-beta",
|
|
88
|
-
"@sanity/
|
|
87
|
+
"@sanity/util": "^3.57.0",
|
|
88
|
+
"react": "^18",
|
|
89
|
+
"sanity": "^3"
|
|
89
90
|
},
|
|
90
91
|
"engines": {
|
|
91
92
|
"node": ">=14"
|
|
@@ -23,7 +23,7 @@ export function CustomRule({
|
|
|
23
23
|
initialValue: string
|
|
24
24
|
startDate: string | undefined
|
|
25
25
|
dateTimeOptions: PluginConfig['dateTimeOptions']
|
|
26
|
-
}) {
|
|
26
|
+
}): React.JSX.Element {
|
|
27
27
|
const initialRule = useMemo(() => {
|
|
28
28
|
return initialValue ? rrulestr(initialValue) : new RRule()
|
|
29
29
|
}, [initialValue])
|
|
@@ -48,8 +48,6 @@ export function CustomRule({
|
|
|
48
48
|
setFrequency(Number(value))
|
|
49
49
|
} else if (name === 'interval') {
|
|
50
50
|
setInterval(Number(value))
|
|
51
|
-
} else if (name === 'interval') {
|
|
52
|
-
setCount(Number(value))
|
|
53
51
|
} else if (name === 'count') {
|
|
54
52
|
setCount(Number(value))
|
|
55
53
|
}
|
|
@@ -113,118 +111,113 @@ export function CustomRule({
|
|
|
113
111
|
onChange(set(newRule.toString(), ['rrule']))
|
|
114
112
|
}, [byweekday, count, frequency, interval, onChange, onClose, until])
|
|
115
113
|
|
|
116
|
-
return (
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
>
|
|
125
|
-
<
|
|
126
|
-
<
|
|
127
|
-
<
|
|
114
|
+
return open ? (
|
|
115
|
+
<Dialog
|
|
116
|
+
header="Custom recurrence"
|
|
117
|
+
id="dialog-example"
|
|
118
|
+
onClose={onClose}
|
|
119
|
+
zOffset={1000}
|
|
120
|
+
width={1}
|
|
121
|
+
>
|
|
122
|
+
<Flex direction="column">
|
|
123
|
+
<Box flex={1} overflow="auto" padding={4}>
|
|
124
|
+
<Stack space={4}>
|
|
125
|
+
<Flex gap={2} align="center">
|
|
126
|
+
<Text style={{whiteSpace: 'nowrap'}}>Repeat every</Text>
|
|
127
|
+
<Box style={{width: '75px'}}>
|
|
128
|
+
<TextInput name="interval" type="number" value={interval} onChange={handleChange} />
|
|
129
|
+
</Box>
|
|
130
|
+
<Box>
|
|
131
|
+
<Select name="freq" value={frequency} onChange={handleChange}>
|
|
132
|
+
<option value={RRule.YEARLY}>years</option>
|
|
133
|
+
<option value={RRule.MONTHLY}>months</option>
|
|
134
|
+
<option value={RRule.WEEKLY}>weeks</option>
|
|
135
|
+
<option value={RRule.DAILY}>days</option>
|
|
136
|
+
</Select>
|
|
137
|
+
</Box>
|
|
138
|
+
</Flex>
|
|
139
|
+
|
|
140
|
+
{frequency === RRule.MONTHLY && (
|
|
141
|
+
<Monthly byweekday={byweekday as Weekday} setByweekday={setByweekday} />
|
|
142
|
+
)}
|
|
143
|
+
|
|
144
|
+
{frequency === RRule.WEEKLY && (
|
|
145
|
+
<Weekly byweekday={byweekday as Weekday} setByweekday={setByweekday} />
|
|
146
|
+
)}
|
|
147
|
+
|
|
148
|
+
<Stack space={2}>
|
|
149
|
+
<Text>Ends</Text>
|
|
150
|
+
<Flex gap={2} paddingY={2} align="center">
|
|
151
|
+
<Radio
|
|
152
|
+
checked={!count && !until}
|
|
153
|
+
name="ends"
|
|
154
|
+
onChange={handleEndChange}
|
|
155
|
+
value=""
|
|
156
|
+
id="ends-never"
|
|
157
|
+
/>
|
|
158
|
+
<Text htmlFor="ends-never" as="label">
|
|
159
|
+
Never
|
|
160
|
+
</Text>
|
|
161
|
+
</Flex>
|
|
128
162
|
<Flex gap={2} align="center">
|
|
129
|
-
<
|
|
163
|
+
<Radio
|
|
164
|
+
checked={!!until}
|
|
165
|
+
name="ends"
|
|
166
|
+
onChange={handleEndChange}
|
|
167
|
+
value="until"
|
|
168
|
+
id="ends-until"
|
|
169
|
+
/>
|
|
170
|
+
<Text htmlFor="ends-until" as="label" style={{width: '75px'}}>
|
|
171
|
+
On
|
|
172
|
+
</Text>
|
|
173
|
+
<Box style={{width: '200px'}}>
|
|
174
|
+
<DateInput
|
|
175
|
+
id="until"
|
|
176
|
+
onChange={handleUntilChange}
|
|
177
|
+
type={{
|
|
178
|
+
name: 'until',
|
|
179
|
+
title: 'Date',
|
|
180
|
+
options: dateTimeOptions,
|
|
181
|
+
}}
|
|
182
|
+
value={until ? new Date(until) : getUntilDate()}
|
|
183
|
+
disabled={!until}
|
|
184
|
+
/>
|
|
185
|
+
</Box>
|
|
186
|
+
</Flex>
|
|
187
|
+
<Flex gap={2} align="center">
|
|
188
|
+
<Radio
|
|
189
|
+
checked={!!count}
|
|
190
|
+
name="ends"
|
|
191
|
+
onChange={handleEndChange}
|
|
192
|
+
value="count"
|
|
193
|
+
id="ends-count"
|
|
194
|
+
/>
|
|
195
|
+
<Text htmlFor="ends-count" as="label" style={{width: '75px'}}>
|
|
196
|
+
After
|
|
197
|
+
</Text>
|
|
130
198
|
<Box style={{width: '75px'}}>
|
|
131
199
|
<TextInput
|
|
132
|
-
name="
|
|
200
|
+
name="count"
|
|
133
201
|
type="number"
|
|
134
|
-
value={
|
|
202
|
+
value={count || DEFAULT_COUNTS[frequency]}
|
|
135
203
|
onChange={handleChange}
|
|
204
|
+
disabled={!count}
|
|
136
205
|
/>
|
|
137
206
|
</Box>
|
|
138
|
-
<
|
|
139
|
-
<Select name="freq" value={frequency} onChange={handleChange}>
|
|
140
|
-
<option value={RRule.YEARLY}>years</option>
|
|
141
|
-
<option value={RRule.MONTHLY}>months</option>
|
|
142
|
-
<option value={RRule.WEEKLY}>weeks</option>
|
|
143
|
-
<option value={RRule.DAILY}>days</option>
|
|
144
|
-
</Select>
|
|
145
|
-
</Box>
|
|
207
|
+
<Text style={{whiteSpace: 'nowrap'}}>occurrences</Text>
|
|
146
208
|
</Flex>
|
|
147
|
-
|
|
148
|
-
{frequency === RRule.MONTHLY && (
|
|
149
|
-
<Monthly byweekday={byweekday as Weekday} setByweekday={setByweekday} />
|
|
150
|
-
)}
|
|
151
|
-
|
|
152
|
-
{frequency === RRule.WEEKLY && (
|
|
153
|
-
<Weekly byweekday={byweekday as Weekday} setByweekday={setByweekday} />
|
|
154
|
-
)}
|
|
155
|
-
|
|
156
|
-
<Stack space={2}>
|
|
157
|
-
<Text>Ends</Text>
|
|
158
|
-
<Flex gap={2} paddingY={2} align="center">
|
|
159
|
-
<Radio
|
|
160
|
-
checked={!count && !until}
|
|
161
|
-
name="ends"
|
|
162
|
-
onChange={handleEndChange}
|
|
163
|
-
value=""
|
|
164
|
-
id="ends-never"
|
|
165
|
-
/>
|
|
166
|
-
<Text htmlFor="ends-never" as="label">
|
|
167
|
-
Never
|
|
168
|
-
</Text>
|
|
169
|
-
</Flex>
|
|
170
|
-
<Flex gap={2} align="center">
|
|
171
|
-
<Radio
|
|
172
|
-
checked={!!until}
|
|
173
|
-
name="ends"
|
|
174
|
-
onChange={handleEndChange}
|
|
175
|
-
value="until"
|
|
176
|
-
id="ends-until"
|
|
177
|
-
/>
|
|
178
|
-
<Text htmlFor="ends-until" as="label" style={{width: '75px'}}>
|
|
179
|
-
On
|
|
180
|
-
</Text>
|
|
181
|
-
<Box style={{width: '200px'}}>
|
|
182
|
-
<DateInput
|
|
183
|
-
id="until"
|
|
184
|
-
onChange={handleUntilChange}
|
|
185
|
-
type={{
|
|
186
|
-
name: 'until',
|
|
187
|
-
title: 'Date',
|
|
188
|
-
options: dateTimeOptions,
|
|
189
|
-
}}
|
|
190
|
-
value={until ? new Date(until) : getUntilDate()}
|
|
191
|
-
disabled={!until}
|
|
192
|
-
/>
|
|
193
|
-
</Box>
|
|
194
|
-
</Flex>
|
|
195
|
-
<Flex gap={2} align="center">
|
|
196
|
-
<Radio
|
|
197
|
-
checked={!!count}
|
|
198
|
-
name="ends"
|
|
199
|
-
onChange={handleEndChange}
|
|
200
|
-
value="count"
|
|
201
|
-
id="ends-count"
|
|
202
|
-
/>
|
|
203
|
-
<Text htmlFor="ends-count" as="label" style={{width: '75px'}}>
|
|
204
|
-
After
|
|
205
|
-
</Text>
|
|
206
|
-
<Box style={{width: '75px'}}>
|
|
207
|
-
<TextInput
|
|
208
|
-
name="count"
|
|
209
|
-
type="number"
|
|
210
|
-
value={count || DEFAULT_COUNTS[frequency]}
|
|
211
|
-
onChange={handleChange}
|
|
212
|
-
disabled={!count}
|
|
213
|
-
/>
|
|
214
|
-
</Box>
|
|
215
|
-
<Text style={{whiteSpace: 'nowrap'}}>occurrences</Text>
|
|
216
|
-
</Flex>
|
|
217
|
-
</Stack>
|
|
218
209
|
</Stack>
|
|
219
|
-
</
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
</
|
|
226
|
-
</
|
|
227
|
-
</
|
|
228
|
-
|
|
210
|
+
</Stack>
|
|
211
|
+
</Box>
|
|
212
|
+
<Box paddingX={4} paddingY={3} style={{borderTop: '1px solid var(--card-border-color)'}}>
|
|
213
|
+
<Flex gap={2} justify="flex-end">
|
|
214
|
+
<Button text="Cancel" mode="ghost" onClick={onClose} />
|
|
215
|
+
<Button text="Done" tone="positive" onClick={handleConfirm} />
|
|
216
|
+
</Flex>
|
|
217
|
+
</Box>
|
|
218
|
+
</Flex>
|
|
219
|
+
</Dialog>
|
|
220
|
+
) : (
|
|
221
|
+
<></>
|
|
229
222
|
)
|
|
230
223
|
}
|
|
@@ -9,7 +9,7 @@ interface MonthlyProps {
|
|
|
9
9
|
setByweekday: (value: Options['byweekday']) => void
|
|
10
10
|
}
|
|
11
11
|
|
|
12
|
-
export function Monthly(props: MonthlyProps) {
|
|
12
|
+
export function Monthly(props: MonthlyProps): React.JSX.Element {
|
|
13
13
|
const {byweekday, setByweekday} = props
|
|
14
14
|
|
|
15
15
|
const {weekday: dayNo, n: weekNo} =
|
|
@@ -9,7 +9,7 @@ interface WeeklyProps {
|
|
|
9
9
|
setByweekday: (value: Options['byweekday']) => void
|
|
10
10
|
}
|
|
11
11
|
|
|
12
|
-
export function Weekly(props: WeeklyProps) {
|
|
12
|
+
export function Weekly(props: WeeklyProps): React.JSX.Element {
|
|
13
13
|
const {byweekday, setByweekday} = props
|
|
14
14
|
|
|
15
15
|
const currentWeekdays: number[] = useMemo(() => {
|
|
@@ -48,6 +48,7 @@ export const CommonDateTimeInput = React.forwardRef(function CommonDateTimeInput
|
|
|
48
48
|
}, [value])
|
|
49
49
|
|
|
50
50
|
const handleDatePickerInputChange = React.useCallback(
|
|
51
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
51
52
|
(event: any) => {
|
|
52
53
|
const nextInputValue = event.currentTarget.value
|
|
53
54
|
const result = nextInputValue === '' ? null : parseInputValue(nextInputValue)
|
|
@@ -81,14 +82,14 @@ export const CommonDateTimeInput = React.forwardRef(function CommonDateTimeInput
|
|
|
81
82
|
const parseResult = localValue
|
|
82
83
|
? parseInputValue(localValue)
|
|
83
84
|
: value
|
|
84
|
-
|
|
85
|
-
|
|
85
|
+
? deserialize(value as string)
|
|
86
|
+
: null
|
|
86
87
|
|
|
87
88
|
const inputValue = localValue
|
|
88
89
|
? localValue
|
|
89
90
|
: parseResult?.isValid
|
|
90
|
-
|
|
91
|
-
|
|
91
|
+
? formatInputValue(parseResult.date)
|
|
92
|
+
: (value as string)
|
|
92
93
|
|
|
93
94
|
return readOnly ? (
|
|
94
95
|
<TextInput value={inputValue} readOnly disabled={readOnly} />
|
|
@@ -45,7 +45,7 @@ const serialize = (date: Date) => format(date, VALUE_FORMAT)
|
|
|
45
45
|
/**
|
|
46
46
|
* @hidden
|
|
47
47
|
* @beta */
|
|
48
|
-
export function DateInput(props: DateInputProps) {
|
|
48
|
+
export function DateInput(props: DateInputProps): React.JSX.Element {
|
|
49
49
|
const {id, onChange, type, value, disabled, ...rest} = props
|
|
50
50
|
|
|
51
51
|
const {dateFormat} = parseOptions(type.options)
|
|
@@ -77,7 +77,7 @@ function enforceTimeStep(dateString: string, timeStep: number) {
|
|
|
77
77
|
/**
|
|
78
78
|
* @hidden
|
|
79
79
|
* @beta */
|
|
80
|
-
export function DateTimeInput(props: DateTimeInputProps) {
|
|
80
|
+
export function DateTimeInput(props: DateTimeInputProps): React.JSX.Element {
|
|
81
81
|
const {id, onChange, type, value, disabled, ...rest} = props
|
|
82
82
|
|
|
83
83
|
const {dateFormat, timeFormat, timeStep} = parseOptions(type.options)
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import React from 'react'
|
|
2
|
+
|
|
2
3
|
import {Calendar} from './calendar/Calendar'
|
|
3
4
|
|
|
4
5
|
export const DatePicker = React.forwardRef(function DatePicker(
|
|
@@ -8,17 +9,18 @@ export const DatePicker = React.forwardRef(function DatePicker(
|
|
|
8
9
|
selectTime?: boolean
|
|
9
10
|
timeStep?: number
|
|
10
11
|
},
|
|
11
|
-
ref: React.ForwardedRef<HTMLDivElement
|
|
12
|
+
ref: React.ForwardedRef<HTMLDivElement>,
|
|
12
13
|
) {
|
|
13
14
|
const {value = new Date(), onChange, ...rest} = props
|
|
14
15
|
const [focusedDate, setFocusedDay] = React.useState<Date>()
|
|
15
16
|
|
|
16
17
|
const handleSelect = React.useCallback(
|
|
18
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
17
19
|
(nextDate: any) => {
|
|
18
20
|
onChange(nextDate)
|
|
19
21
|
setFocusedDay(undefined)
|
|
20
22
|
},
|
|
21
|
-
[onChange]
|
|
23
|
+
[onChange],
|
|
22
24
|
)
|
|
23
25
|
|
|
24
26
|
return (
|
|
@@ -1,7 +1,8 @@
|
|
|
1
|
+
import {CalendarIcon} from '@sanity/icons'
|
|
2
|
+
import {Box, Button, LayerProvider, Popover, useClickOutside, useForwardedRef} from '@sanity/ui'
|
|
1
3
|
import React, {forwardRef, useCallback, useRef, useState} from 'react'
|
|
2
4
|
import FocusLock from 'react-focus-lock'
|
|
3
|
-
|
|
4
|
-
import {CalendarIcon} from '@sanity/icons'
|
|
5
|
+
|
|
5
6
|
import {DatePicker} from './DatePicker'
|
|
6
7
|
import {LazyTextInput} from './LazyTextInput'
|
|
7
8
|
|
|
@@ -10,7 +11,9 @@ export interface DateTimeInputProps {
|
|
|
10
11
|
id?: string
|
|
11
12
|
inputValue?: string
|
|
12
13
|
onChange: (date: Date | null) => void
|
|
13
|
-
onInputChange?: (
|
|
14
|
+
onInputChange?: (
|
|
15
|
+
event: React.FocusEvent<HTMLInputElement> | React.ChangeEvent<HTMLInputElement>,
|
|
16
|
+
) => void
|
|
14
17
|
placeholder?: string
|
|
15
18
|
readOnly?: boolean
|
|
16
19
|
selectTime?: boolean
|
|
@@ -20,7 +23,7 @@ export interface DateTimeInputProps {
|
|
|
20
23
|
|
|
21
24
|
export const DateTimeInput = forwardRef(function DateTimeInput(
|
|
22
25
|
props: DateTimeInputProps,
|
|
23
|
-
ref: React.ForwardedRef<HTMLInputElement
|
|
26
|
+
ref: React.ForwardedRef<HTMLInputElement>,
|
|
24
27
|
) {
|
|
25
28
|
const {value, inputValue, onInputChange, onChange, selectTime, timeStep, ...rest} = props
|
|
26
29
|
const [popoverRef, setPopoverRef] = useState<HTMLElement | null>(null)
|
|
@@ -36,6 +39,7 @@ export const DateTimeInput = forwardRef(function DateTimeInput(
|
|
|
36
39
|
forwardedRef.current?.select()
|
|
37
40
|
}, [forwardedRef])
|
|
38
41
|
|
|
42
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
39
43
|
const handleKeyUp = useCallback((e: any) => {
|
|
40
44
|
if (e.key === 'Escape') {
|
|
41
45
|
setPickerOpen(false)
|
|
@@ -1,17 +1,13 @@
|
|
|
1
|
-
import React from 'react'
|
|
2
1
|
import {TextInput} from '@sanity/ui'
|
|
2
|
+
import React from 'react'
|
|
3
3
|
|
|
4
4
|
type TextInputProps = React.ComponentProps<typeof TextInput>
|
|
5
5
|
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
onChange?: (
|
|
12
|
-
event: React.FocusEvent<HTMLInputElement> | React.ChangeEvent<HTMLInputElement>
|
|
13
|
-
) => void
|
|
14
|
-
}
|
|
6
|
+
type Props = Omit<TextInputProps, 'onChange'> & {
|
|
7
|
+
onChange?: (
|
|
8
|
+
event: React.FocusEvent<HTMLInputElement> | React.ChangeEvent<HTMLInputElement>,
|
|
9
|
+
) => void
|
|
10
|
+
}
|
|
15
11
|
|
|
16
12
|
/**
|
|
17
13
|
* A TextInput that only emit onChange when it has to
|
|
@@ -20,15 +16,17 @@ type Props = Workaround &
|
|
|
20
16
|
*/
|
|
21
17
|
export const LazyTextInput = React.forwardRef(function LazyTextInput(
|
|
22
18
|
{onChange, onBlur, onKeyPress, value, ...rest}: Props,
|
|
23
|
-
forwardedRef: React.ForwardedRef<HTMLInputElement
|
|
19
|
+
forwardedRef: React.ForwardedRef<HTMLInputElement>,
|
|
24
20
|
) {
|
|
25
21
|
const [inputValue, setInputValue] = React.useState<string>()
|
|
26
22
|
|
|
23
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
27
24
|
const handleChange = React.useCallback((event: any) => {
|
|
28
25
|
setInputValue(event.currentTarget.value)
|
|
29
26
|
}, [])
|
|
30
27
|
|
|
31
28
|
const checkEvent = React.useCallback(
|
|
29
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
32
30
|
(event: any) => {
|
|
33
31
|
const currentValue = event.currentTarget.value
|
|
34
32
|
if (currentValue !== `${value}`) {
|
|
@@ -38,17 +36,18 @@ export const LazyTextInput = React.forwardRef(function LazyTextInput(
|
|
|
38
36
|
}
|
|
39
37
|
setInputValue(undefined)
|
|
40
38
|
},
|
|
41
|
-
[onChange, value]
|
|
39
|
+
[onChange, value],
|
|
42
40
|
)
|
|
43
41
|
|
|
44
42
|
const handleBlur = React.useCallback(
|
|
43
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
45
44
|
(e: any) => {
|
|
46
45
|
checkEvent(e)
|
|
47
46
|
if (onBlur) {
|
|
48
47
|
onBlur(e)
|
|
49
48
|
}
|
|
50
49
|
},
|
|
51
|
-
[checkEvent, onBlur]
|
|
50
|
+
[checkEvent, onBlur],
|
|
52
51
|
)
|
|
53
52
|
|
|
54
53
|
const handleKeyPress = React.useCallback(
|
|
@@ -60,7 +59,7 @@ export const LazyTextInput = React.forwardRef(function LazyTextInput(
|
|
|
60
59
|
onKeyPress(e)
|
|
61
60
|
}
|
|
62
61
|
},
|
|
63
|
-
[checkEvent, onKeyPress]
|
|
62
|
+
[checkEvent, onKeyPress],
|
|
64
63
|
)
|
|
65
64
|
|
|
66
65
|
return (
|
|
@@ -1,10 +1,11 @@
|
|
|
1
|
-
import {Box, Button, Flex, Grid, Select, Text, useForwardedRef} from '@sanity/ui'
|
|
2
1
|
import {ChevronLeftIcon, ChevronRightIcon} from '@sanity/icons'
|
|
2
|
+
import {Box, Button, Flex, Grid, Select, Text, useForwardedRef} from '@sanity/ui'
|
|
3
3
|
import {addDays, addMonths, setDate, setHours, setMinutes, setMonth, setYear} from 'date-fns'
|
|
4
4
|
import {range} from 'lodash'
|
|
5
5
|
import React, {forwardRef, useCallback, useEffect} from 'react'
|
|
6
|
+
|
|
6
7
|
import {CalendarMonth} from './CalendarMonth'
|
|
7
|
-
import {ARROW_KEYS, HOURS_24, MONTH_NAMES
|
|
8
|
+
import {ARROW_KEYS, DEFAULT_TIME_PRESETS, HOURS_24, MONTH_NAMES} from './constants'
|
|
8
9
|
import {features} from './features'
|
|
9
10
|
import {formatTime} from './utils'
|
|
10
11
|
import {YearInput} from './YearInput'
|
|
@@ -35,7 +36,7 @@ const PRESERVE_FOCUS_ELEMENT = (
|
|
|
35
36
|
|
|
36
37
|
export const Calendar = forwardRef(function Calendar(
|
|
37
38
|
props: CalendarProps,
|
|
38
|
-
forwardedRef: React.ForwardedRef<HTMLDivElement
|
|
39
|
+
forwardedRef: React.ForwardedRef<HTMLDivElement>,
|
|
39
40
|
) {
|
|
40
41
|
const {
|
|
41
42
|
selectTime,
|
|
@@ -49,34 +50,34 @@ export const Calendar = forwardRef(function Calendar(
|
|
|
49
50
|
|
|
50
51
|
const setFocusedDate = useCallback(
|
|
51
52
|
(date: Date) => onFocusedDateChange(date),
|
|
52
|
-
[onFocusedDateChange]
|
|
53
|
+
[onFocusedDateChange],
|
|
53
54
|
)
|
|
54
55
|
|
|
55
56
|
const setFocusedDateMonth = useCallback(
|
|
56
57
|
(month: number) => setFocusedDate(setDate(setMonth(focusedDate, month), 1)),
|
|
57
|
-
[focusedDate, setFocusedDate]
|
|
58
|
+
[focusedDate, setFocusedDate],
|
|
58
59
|
)
|
|
59
60
|
|
|
60
61
|
const handleFocusedMonthChange = useCallback(
|
|
61
62
|
(e: React.FormEvent<HTMLSelectElement>) => setFocusedDateMonth(Number(e.currentTarget.value)),
|
|
62
|
-
[setFocusedDateMonth]
|
|
63
|
+
[setFocusedDateMonth],
|
|
63
64
|
)
|
|
64
65
|
|
|
65
66
|
const moveFocusedDate = useCallback(
|
|
66
67
|
(by: number) => setFocusedDate(addMonths(focusedDate, by)),
|
|
67
|
-
[focusedDate, setFocusedDate]
|
|
68
|
+
[focusedDate, setFocusedDate],
|
|
68
69
|
)
|
|
69
70
|
|
|
70
71
|
const setFocusedDateYear = useCallback(
|
|
71
72
|
(year: number) => setFocusedDate(setYear(focusedDate, year)),
|
|
72
|
-
[focusedDate, setFocusedDate]
|
|
73
|
+
[focusedDate, setFocusedDate],
|
|
73
74
|
)
|
|
74
75
|
|
|
75
76
|
const handleDateChange = useCallback(
|
|
76
77
|
(date: Date) => {
|
|
77
78
|
onSelect(setMinutes(setHours(date, selectedDate.getHours()), selectedDate.getMinutes()))
|
|
78
79
|
},
|
|
79
|
-
[onSelect, selectedDate]
|
|
80
|
+
[onSelect, selectedDate],
|
|
80
81
|
)
|
|
81
82
|
|
|
82
83
|
const handleMinutesChange = useCallback(
|
|
@@ -84,7 +85,7 @@ export const Calendar = forwardRef(function Calendar(
|
|
|
84
85
|
const m = Number(event.currentTarget.value)
|
|
85
86
|
onSelect(setMinutes(selectedDate, m))
|
|
86
87
|
},
|
|
87
|
-
[onSelect, selectedDate]
|
|
88
|
+
[onSelect, selectedDate],
|
|
88
89
|
)
|
|
89
90
|
|
|
90
91
|
const handleHoursChange = useCallback(
|
|
@@ -92,14 +93,14 @@ export const Calendar = forwardRef(function Calendar(
|
|
|
92
93
|
const m = Number(event.currentTarget.value)
|
|
93
94
|
onSelect(setHours(selectedDate, m))
|
|
94
95
|
},
|
|
95
|
-
[onSelect, selectedDate]
|
|
96
|
+
[onSelect, selectedDate],
|
|
96
97
|
)
|
|
97
98
|
|
|
98
99
|
const handleTimeChange = useCallback(
|
|
99
100
|
(hours: number, mins: number) => {
|
|
100
101
|
onSelect(setHours(setMinutes(selectedDate, mins), hours))
|
|
101
102
|
},
|
|
102
|
-
[onSelect, selectedDate]
|
|
103
|
+
[onSelect, selectedDate],
|
|
103
104
|
)
|
|
104
105
|
|
|
105
106
|
const ref = useForwardedRef(forwardedRef)
|
|
@@ -109,6 +110,7 @@ export const Calendar = forwardRef(function Calendar(
|
|
|
109
110
|
}, [ref])
|
|
110
111
|
|
|
111
112
|
const handleKeyDown = useCallback(
|
|
113
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
112
114
|
(event: any) => {
|
|
113
115
|
if (!ARROW_KEYS.includes(event.key)) {
|
|
114
116
|
return
|
|
@@ -133,7 +135,7 @@ export const Calendar = forwardRef(function Calendar(
|
|
|
133
135
|
// set focus temporarily on this element to make sure focus is still inside the calendar-grid after re-render
|
|
134
136
|
ref.current?.querySelector<HTMLElement>('[data-preserve-focus]')?.focus()
|
|
135
137
|
},
|
|
136
|
-
[ref, focusCurrentWeekDay, onFocusedDateChange, focusedDate]
|
|
138
|
+
[ref, focusCurrentWeekDay, onFocusedDateChange, focusedDate],
|
|
137
139
|
)
|
|
138
140
|
|
|
139
141
|
useEffect(() => {
|
|
@@ -142,7 +144,7 @@ export const Calendar = forwardRef(function Calendar(
|
|
|
142
144
|
|
|
143
145
|
useEffect(() => {
|
|
144
146
|
const currentFocusInCalendarGrid = document.activeElement?.matches(
|
|
145
|
-
'[data-calendar-grid], [data-calendar-grid] [data-preserve-focus]'
|
|
147
|
+
'[data-calendar-grid], [data-calendar-grid] [data-preserve-focus]',
|
|
146
148
|
)
|
|
147
149
|
if (
|
|
148
150
|
// Only move focus if it's currently in the calendar grid
|
|
@@ -154,14 +156,14 @@ export const Calendar = forwardRef(function Calendar(
|
|
|
154
156
|
|
|
155
157
|
const handleYesterdayClick = useCallback(
|
|
156
158
|
() => handleDateChange(addDays(new Date(), -1)),
|
|
157
|
-
[handleDateChange]
|
|
159
|
+
[handleDateChange],
|
|
158
160
|
)
|
|
159
161
|
|
|
160
162
|
const handleTodayClick = useCallback(() => handleDateChange(new Date()), [handleDateChange])
|
|
161
163
|
|
|
162
164
|
const handleTomorrowClick = useCallback(
|
|
163
165
|
() => handleDateChange(addDays(new Date(), 1)),
|
|
164
|
-
[handleDateChange]
|
|
166
|
+
[handleDateChange],
|
|
165
167
|
)
|
|
166
168
|
|
|
167
169
|
const handleNowClick = useCallback(() => onSelect(new Date()), [onSelect])
|
|
@@ -10,7 +10,7 @@ interface CalendarDayProps {
|
|
|
10
10
|
selected?: boolean
|
|
11
11
|
}
|
|
12
12
|
|
|
13
|
-
export function CalendarDay(props: CalendarDayProps) {
|
|
13
|
+
export function CalendarDay(props: CalendarDayProps): React.JSX.Element {
|
|
14
14
|
const {date, focused, isCurrentMonth, isToday, onSelect, selected} = props
|
|
15
15
|
|
|
16
16
|
const handleClick = useCallback(() => {
|