Skip to content

Commit 109f645

Browse files
committed
Add cursor loading state during initialization.
The initialization function in this library blocks the main thread with a synchronous loop over all possible months. This commit doesn't fix that, it just shows a loading spinner instead.
1 parent 0be4f78 commit 109f645

File tree

3 files changed

+277
-232
lines changed

3 files changed

+277
-232
lines changed

Diff for: src/components/DatePicker.svelte

+13-230
Original file line numberDiff line numberDiff line change
@@ -1,235 +1,18 @@
11
<script>
2-
import { createEventDispatcher, getContext, setContext } from 'svelte'
3-
import { CalendarStyle } from '../calendar-style.js'
4-
import { contextKey, setup } from './lib/context'
5-
import { dayjs } from './lib/date-utils'
6-
import { createViewContext } from './lib/view-context.js'
7-
import Popover from './Popover.svelte'
8-
import Toolbar from './Toolbar.svelte'
9-
import View from './view/View.svelte'
2+
import { onMount } from 'svelte'
3+
import DatePickerInner from './DatePickerInner.svelte'
4+
import { setLoadingCursor } from './lib/context'
105
11-
export let range = false
12-
export let defaultRange = [ 1, 'month' ]
13-
export let placeholder = 'Choose Date'
14-
export let format = 'DD / MM / YYYY'
15-
export let start = dayjs().subtract(1, 'year')
16-
export let end = dayjs().add(1, 'year')
17-
export let trigger = null
18-
export let selectableCallback = null
19-
export let styling = new CalendarStyle()
20-
export let selected
21-
export let closeOnFocusLoss = true
22-
export let time = false
23-
export let morning = 7
24-
export let night = 19
25-
export let minuteStep = 5
26-
export let continueText = 'Continue'
6+
let ready = false
277
28-
const dispatch = createEventDispatcher()
29-
30-
const startContextKey = {}
31-
const endContextKey = {}
32-
33-
const config = {
34-
start: dayjs(start),
35-
end: dayjs(end),
36-
isRangePicker: range,
37-
defaultRange,
38-
isTimePicker: time,
39-
closeOnFocusLoss,
40-
format,
41-
morning,
42-
night,
43-
selectableCallback,
44-
minuteStep: parseInt(minuteStep)
45-
}
46-
47-
setContext(contextKey, setup(selected, config))
48-
const {
49-
selectedStartDate,
50-
selectedEndDate,
51-
isOpen,
52-
isClosing,
53-
highlighted,
54-
formatter,
55-
isDateChosen,
56-
isSelectingFirstDate
57-
} = getContext(contextKey)
58-
59-
setContext(startContextKey, createViewContext(true, getContext(contextKey)))
60-
61-
if (config.isRangePicker) {
62-
setContext(endContextKey, createViewContext(false, getContext(contextKey)))
63-
}
64-
65-
let popover
66-
67-
function initialisePicker () {
68-
highlighted.set($selectedStartDate)
69-
dispatch('open')
70-
}
71-
72-
function setRangeValue () {
73-
selected = [ $selectedStartDate, $selectedEndDate ]
74-
dispatch('range-selected', {
75-
from: $selectedStartDate.toDate(),
76-
to: $selectedEndDate.toDate()
77-
})
78-
}
79-
80-
function setDateValue () {
81-
selected = $selectedStartDate.toDate()
82-
dispatch('date-selected', {
83-
date: $selectedStartDate.toDate()
84-
})
85-
}
86-
87-
function swapDatesIfRequired () {
88-
if (!config.isRangePicker) { return }
89-
const from = $selectedStartDate
90-
const to = $selectedEndDate
91-
if (to.isBefore(from)) {
92-
selectedStartDate.set(to)
93-
selectedEndDate.set(from)
94-
}
95-
}
96-
97-
function addDate (e) {
98-
const { date } = e.detail
99-
if ($isSelectingFirstDate) {
100-
selectedStartDate.set(date)
101-
} else {
102-
selectedEndDate.set(date)
103-
}
104-
swapDatesIfRequired()
105-
config.isRangePicker && isSelectingFirstDate.update(v => !v)
106-
}
107-
108-
function close () {
109-
swapDatesIfRequired()
110-
popover.close()
111-
}
112-
113-
$: {
114-
if ($isDateChosen) {
115-
config.isRangePicker ? setRangeValue() : setDateValue()
116-
dispatch('change')
117-
}
118-
}
119-
120-
/**
121-
* Allow external sources to update dates by binding to selected prop
122-
* and updating with JS Date objects
123-
*/
124-
$: {
125-
if (config.isRangePicker && selected) {
126-
if (selected[0] instanceof Date) {
127-
selectedStartDate.set(dayjs(selected[0]))
128-
}
129-
if (selected[1] instanceof Date) {
130-
selectedEndDate.set(dayjs(selected[1]))
131-
}
132-
}
133-
}
134-
135-
/**
136-
* Allow external sources to react to internal selections via event forwarding
137-
*/
138-
$: {
139-
if ($selectedStartDate) dispatch('updateStart', $selectedStartDate.toDate())
140-
}
141-
$: {
142-
if ($selectedEndDate) dispatch('updateEnd', $selectedEndDate.toDate())
143-
}
8+
onMount(async () => {
9+
await setLoadingCursor()
10+
ready = true
11+
})
14412
</script>
14513

146-
<style>
147-
.datepicker {
148-
display: inline-block;
149-
text-align: center;
150-
overflow: visible;
151-
width: var(--datepicker-width);
152-
}
153-
154-
.calendar-button {
155-
padding: 10px 20px;
156-
border: 1px solid var(--button-border-color);
157-
display: block;
158-
text-align: center;
159-
width: var(--button-width);
160-
text-decoration: none;
161-
cursor: pointer;
162-
background: var(--button-background-color);
163-
color: var(--button-text-color);
164-
border-radius: 7px;
165-
box-shadow: 0px 0px 3px rgba(0, 0, 0, 0.1);
166-
}
167-
168-
*,
169-
*:before,
170-
*:after {
171-
box-sizing: inherit;
172-
}
173-
174-
.contents {
175-
min-width: 320px;
176-
width: 100%;
177-
display: flex;
178-
flex-direction: column;
179-
background: var(--content-background);
180-
}
181-
182-
.view {
183-
display: flex;
184-
flex-direction: column;
185-
align-items: center;
186-
}
187-
188-
@media (min-width: 680px) {
189-
.view {
190-
flex-direction: row;
191-
justify-content: center;
192-
}
193-
}
194-
</style>
195-
196-
<div
197-
class="datepicker"
198-
class:open={$isOpen}
199-
class:closing={$isClosing}
200-
style={styling.toWrapperStyle()}>
201-
<Popover
202-
{trigger}
203-
bind:this={popover}
204-
on:opened={initialisePicker}
205-
on:closed={() => dispatch('close')}>
206-
<div slot="trigger">
207-
<slot formatted={$formatter}>
208-
{#if !trigger}
209-
<button class="calendar-button" type="button">
210-
{#if $isDateChosen}
211-
{$formatter.formattedCombined}
212-
{:else}
213-
{placeholder}
214-
{/if}
215-
</button>
216-
{/if}
217-
</slot>
218-
</div>
219-
<div class="contents" slot="contents" class:is-range-picker={config.isRangePicker}>
220-
<div class="view">
221-
<View
222-
viewContextKey={startContextKey}
223-
on:chosen={addDate}
224-
/>
225-
{#if config.isRangePicker}
226-
<View
227-
viewContextKey={endContextKey}
228-
on:chosen={addDate}
229-
/>
230-
{/if}
231-
</div>
232-
<Toolbar continueText={continueText} on:close={close} />
233-
</div>
234-
</Popover>
235-
</div>
14+
{#if ready}
15+
<DatePickerInner {...$$props}>
16+
<slot />
17+
</DatePickerInner>
18+
{/if}

0 commit comments

Comments
 (0)