-
Notifications
You must be signed in to change notification settings - Fork 277
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[Feature] Datepicker (Experimental) #29
Comments
Hi, using datepicker in sveltekit , breaking my app, the browser console shows follwing error |
In addition to getting this error, when using |
It would be nice to add a way to exclude dates from the datepicker. This can be used to e.g block users for preventing holiday dates for a delivery or not book already booked dates |
There is also no way to collect the value selected by the user, or any events that you can even use. |
Any known workaround to get the value from user? |
@reaper-king were you able to find a solution to this? i'm facing the same issue currently |
anyone having this error: Datepicker component expects attribute prop to be non falsy value. meaning you need to pass something to it. the problem resolves ex:
|
This did resolve the issue but when I click on the input field the date dropdown does not pop up. |
that's odd. it's working fine for me. tho i have one more prop defined which is |
If you use Datepicker in a form and submit it, you can read the values that way, at least with
|
I struggled on a few projects over the past few months to get this working correctly, so I gave up and made my own component. Code for peeps curious. // CC0 DateCalender.svelte
<script lang="ts">
import { createEventDispatcher } from 'svelte';
import { Button, Modal } from 'flowbite-svelte';
import { ChevronLeftOutline, ChevronRightOutline } from 'flowbite-svelte-icons';
// Props
export let currentDate: Date = new Date();
export let open = false;
export let locale: string = 'default';
export let firstDayOfWeek: number = 0;
export let showToday: boolean = true;
export let showClose: boolean = true;
export let dateFormat: Intl.DateTimeFormatOptions = { month: 'long', year: 'numeric' };
export let dayLabelFormat: 'short' | 'narrow' | 'long' = 'short';
export let customClass: string = '';
export let primaryColor: string = 'blue';
export let secondaryColor: string = 'gray';
// Internal state
const dispatch = createEventDispatcher();
let currentMonth: Date = new Date(currentDate.getFullYear(), currentDate.getMonth(), 1);
let daysInMonth: Date[] = getDaysInMonth(currentMonth);
// Functions
function getDaysInMonth(date: Date): Date[] {
const year = date.getFullYear();
const month = date.getMonth();
const firstDay = new Date(year, month, 0);
const lastDay = new Date(year, month + 1, 0);
const daysArray = [];
// Adjust the start of the week based on firstDayOfWeek
let start = firstDay.getDay() - firstDayOfWeek;
if (start < 0) start += 7;
// Add days from previous month to fill the first week
for (let i = 0; i < start; i++) {
const prevMonthDay = new Date(year, month, -i);
daysArray.unshift(prevMonthDay);
}
// Add days of the current month
for (let i = 1; i <= lastDay.getDate(); i++) {
daysArray.push(new Date(year, month, i));
}
// Add days from next month to fill the last week
const remainingDays = 7 - (daysArray.length % 7);
if (remainingDays < 7) {
for (let i = 1; i <= remainingDays; i++) {
daysArray.push(new Date(year, month + 1, i));
}
}
return daysArray;
}
function changeMonth(increment: number) {
currentMonth = new Date(currentMonth.getFullYear(), currentMonth.getMonth() + increment, 1);
daysInMonth = getDaysInMonth(currentMonth);
}
function handleDaySelect(day: Date) {
dispatch('selectDay', day);
open = false;
}
function isCurrentMonth(day: Date): boolean {
return day.getMonth() === currentMonth.getMonth();
}
function handleClose() {
open = false;
dispatch('close');
}
function goToToday() {
const today = new Date();
currentMonth = new Date(today.getFullYear(), today.getMonth(), 1);
daysInMonth = getDaysInMonth(currentMonth);
currentDate = today;
handleDaySelect(today);
}
function isToday(day: Date): boolean {
const today = new Date();
return (
day.getDate() === today.getDate() &&
day.getMonth() === today.getMonth() &&
day.getFullYear() === today.getFullYear()
);
}
// Computed values
$: weekdays = [...Array(7)].map((_, i) => {
const day = new Date(2021, 5, i + firstDayOfWeek);
return day.toLocaleString(locale, { weekday: dayLabelFormat });
});
// Exports
export function setDate(date: Date) {
currentDate = date;
currentMonth = new Date(date.getFullYear(), date.getMonth(), 1);
daysInMonth = getDaysInMonth(currentMonth);
}
export function nextMonth() {
changeMonth(1);
}
export function previousMonth() {
changeMonth(-1);
}
export function setMonth(month: number) {
currentMonth = new Date(currentMonth.getFullYear(), month, 1);
daysInMonth = getDaysInMonth(currentMonth);
}
export function setYear(year: number) {
currentMonth = new Date(year, currentMonth.getMonth(), 1);
daysInMonth = getDaysInMonth(currentMonth);
}
</script>
<Modal bind:open size="xs" autoclose={false} class={`w-full ${customClass}`}>
<div class="w-full max-w-md rounded-lg p-6">
<div class="mb-4 flex items-center justify-between">
<Button size="sm" on:click={() => changeMonth(-1)} color={primaryColor}>
<ChevronLeftOutline size="md" />
</Button>
<span class="text-lg font-semibold">
{currentMonth.toLocaleString(locale, dateFormat)}
</span>
<Button size="sm" on:click={() => changeMonth(1)} color={primaryColor}>
<ChevronRightOutline size="md" />
</Button>
</div>
<div class="grid grid-cols-7 gap-2">
{#each weekdays as day}
<div class="text-center text-sm font-medium">{day}</div>
{/each}
{#each daysInMonth as day}
<Button
size="sm"
color={currentDate.toDateString() === day.toDateString()
? primaryColor
: isToday(day)
? secondaryColor
: 'alternative'}
class={!isCurrentMonth(day) ? 'opacity-50' : ''}
on:click={() => handleDaySelect(day)}
>
{day.getDate()}
</Button>
{/each}
</div>
<div class="mt-4 flex justify-between">
{#if showToday}
<Button size="sm" color={primaryColor} on:click={goToToday}>Today</Button>
{/if}
{#if showClose}
<Button size="sm" color={primaryColor} on:click={handleClose}>Close</Button>
{/if}
</div>
</div>
</Modal> |
@Chizaruu Thank you for sharing the code. Can you add an example how you use it?
|
This should work well as an example for the component I made; however, if you want support for the current DatePicker Component, I'm happy to update it and submit a Pull Request. (I didn't want to intrude on the good thing you got going. :P) <script lang="ts">
import DateCalender from '$lib/components/DateCalender.svelte';
import { Button } from 'flowbite-svelte';
let selectedDate: Date = new Date(); // Default to today, This will be updated when a date is selected
let showDateCalender = false;
function handleDateSelect(event: CustomEvent<Date>) {
selectedDate = event.detail;
console.log('Selected date:', selectedDate);
}
function openDateCalender() {
showDateCalender = true;
}
function closeDateCalender() {
showDateCalender = false;
}
</script>
<main>
<h1>Date Calender Example</h1>
<p>Selected Date: {selectedDate.toDateString()}</p>
<Button color="blue" on:click={openDateCalender}>Open Date Calender</Button>
<DateCalender
bind:open={showDateCalender}
bind:currentDate={selectedDate}
on:selectDay={handleDateSelect}
on:close={closeDateCalender}
locale="en-US"
firstDayOfWeek={0}
showToday={true}
showClose={true}
primaryColor="blue"
secondaryColor="gray"
/>
</main> |
@Chizaruu
Yes, it will be great. You can overwrite Datepicker.svelte. Please add some examples in this file. React team has Datepicker and some functions can be useful. |
@Chizaruu |
Ah, I fixed that issue in the code but didn't update the picture. Accidentally used a 1 instead of 0 for the first day. |
Experimental
Date picker component.
The text was updated successfully, but these errors were encountered: