mirror of
https://github.com/carbon-design-system/carbon-components-svelte.git
synced 2025-09-15 02:11:05 +00:00
170 lines
4 KiB
Svelte
170 lines
4 KiB
Svelte
<script>
|
|
/**
|
|
* Specify the element to append the calendar to
|
|
* @type {HTMLElement} [appendTo=document.body]
|
|
*/
|
|
export let appendTo = document.body;
|
|
export let dateFormat = "m/d/Y";
|
|
export let datePickerType = "simple";
|
|
|
|
/**
|
|
* Set an id for the date picker element
|
|
* @type {string} [id]
|
|
*/
|
|
export let id = "ccs-" + Math.random().toString(36);
|
|
|
|
/**
|
|
* Set to `true` to enable the light variant
|
|
* @type {boolean} [light=false]
|
|
*/
|
|
export let light = false;
|
|
export let locale = "en";
|
|
export let maxDate = null;
|
|
export let minDate = null;
|
|
export let short = false;
|
|
export let value = "";
|
|
|
|
import {
|
|
createEventDispatcher,
|
|
setContext,
|
|
afterUpdate,
|
|
onDestroy,
|
|
} from "svelte";
|
|
import { writable, derived } from "svelte/store";
|
|
import { createCalendar } from "./createCalendar";
|
|
|
|
const dispatch = createEventDispatcher();
|
|
const inputs = writable([]);
|
|
const inputIds = derived(inputs, (_) => _.map(({ id }) => id));
|
|
const labelTextEmpty = derived(
|
|
inputs,
|
|
(_) => _.filter(({ labelText }) => !!labelText).length === 0
|
|
);
|
|
const inputValue = writable(value);
|
|
const mode = writable(datePickerType);
|
|
const range = derived(mode, (_) => _ === "range");
|
|
const hasCalendar = derived(mode, (_) => _ === "single" || _ === "range");
|
|
|
|
let calendar = undefined;
|
|
let datePickerRef = undefined;
|
|
let inputRef = undefined;
|
|
let inputRefTo = undefined;
|
|
|
|
setContext("DatePicker", {
|
|
range,
|
|
inputValue,
|
|
hasCalendar,
|
|
add: (data) => {
|
|
inputs.update((_) => [..._, data]);
|
|
},
|
|
declareRef: ({ id, ref }) => {
|
|
if ($inputIds.indexOf(id) === 0) {
|
|
inputRef = ref;
|
|
} else {
|
|
inputRefTo = ref;
|
|
}
|
|
},
|
|
updateValue: ({ type, value }) => {
|
|
if ((!calendar && type === "input") || type === "change") {
|
|
inputValue.set(value);
|
|
}
|
|
|
|
if (!calendar && type === "change") {
|
|
dispatch("change", value);
|
|
}
|
|
},
|
|
blurInput: (relatedTarget) => {
|
|
if (calendar && !calendar.calendarContainer.contains(relatedTarget)) {
|
|
calendar.close();
|
|
}
|
|
},
|
|
openCalendar: () => {
|
|
calendar.open();
|
|
},
|
|
focusCalendar: () => {
|
|
(
|
|
calendar.selectedDateElem ||
|
|
calendar.todayDateElem ||
|
|
calendar.calendarContainer.querySelector(".flatpickr-day[tabindex]") ||
|
|
calendar.calendarContainer
|
|
).focus();
|
|
},
|
|
});
|
|
|
|
afterUpdate(() => {
|
|
if ($hasCalendar && !calendar) {
|
|
calendar = createCalendar({
|
|
options: {
|
|
appendTo,
|
|
dateFormat,
|
|
defaultDate: $inputValue,
|
|
locale,
|
|
maxDate,
|
|
minDate,
|
|
mode: $mode,
|
|
},
|
|
base: inputRef,
|
|
input: inputRefTo,
|
|
dispatch: (event) => {
|
|
const detail = { selectedDates: calendar.selectedDates };
|
|
|
|
if ($range) {
|
|
detail.dateStr = {
|
|
from: inputRef.value,
|
|
to: inputRefTo.value,
|
|
};
|
|
} else {
|
|
detail.dateStr = inputRef.value;
|
|
}
|
|
|
|
return dispatch(event, detail);
|
|
},
|
|
});
|
|
}
|
|
|
|
if (calendar && !$range) {
|
|
calendar.setDate($inputValue);
|
|
}
|
|
});
|
|
|
|
onDestroy(() => {
|
|
if (calendar) {
|
|
calendar.destroy();
|
|
}
|
|
});
|
|
|
|
$: inputValue.set(value);
|
|
$: value = $inputValue;
|
|
</script>
|
|
|
|
<svelte:body
|
|
on:click={({ target }) => {
|
|
if (!calendar || !calendar.isOpen) {
|
|
return;
|
|
}
|
|
if (datePickerRef && datePickerRef.contains(target)) {
|
|
return;
|
|
}
|
|
if (!calendar.calendarContainer.contains(target)) {
|
|
calendar.close();
|
|
}
|
|
}} />
|
|
|
|
<div
|
|
class:bx--form-item={true}
|
|
{...$$restProps}
|
|
on:click
|
|
on:mouseover
|
|
on:mouseenter
|
|
on:mouseleave>
|
|
<div
|
|
bind:this={datePickerRef}
|
|
{id}
|
|
class:bx--date-picker={true}
|
|
class:bx--date-picker--short={short}
|
|
class:bx--date-picker--light={light}
|
|
class="{datePickerType && `bx--date-picker--${datePickerType}`}
|
|
{datePickerType === 'range' && $labelTextEmpty && 'bx--date-picker--nolabel'}">
|
|
<slot />
|
|
</div>
|
|
</div>
|