Skip to content
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

Closed
6 of 8 tasks
shinokada opened this issue Apr 14, 2022 · 16 comments · Fixed by #1464
Closed
6 of 8 tasks

[Feature] Datepicker (Experimental) #29

shinokada opened this issue Apr 14, 2022 · 16 comments · Fixed by #1464
Labels
enhancement New feature or request help wanted Extra attention is needed

Comments

@shinokada
Copy link
Collaborator

shinokada commented Apr 14, 2022

Experimental

Date picker component.

  • Default
  • Inline date picker
  • Date range picker
  • Autohide
  • Action buttons
  • Date format
  • Orientation
  • Title
@shinokada shinokada added enhancement New feature or request help wanted Extra attention is needed labels Apr 14, 2022
@shinokada shinokada changed the title Datepicker [Feature] Datepicker Jul 21, 2022
This was referenced Jul 22, 2022
@QuantumSolver
Copy link

Hi, using datepicker in sveltekit , breaking my app, the browser console shows follwing error
Uncaught (in promise) DOMException: Failed to execute 'setAttribute' on 'Element': '' is not a valid attribute name.

@oyenmwen
Copy link

Hi, using datepicker in sveltekit , breaking my app, the browser console shows follwing error Uncaught (in promise) DOMException: Failed to execute 'setAttribute' on 'Element': '' is not a valid attribute name.

In addition to getting this error, when using range, the calendar popup just does not show up at all. And with no browser console error either

@shinokada shinokada changed the title [Feature] Datepicker [Feature] Datepicker (Experimental) Nov 2, 2022
@Suya1671
Copy link

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

@DrewRidley
Copy link

There is also no way to collect the value selected by the user, or any events that you can even use.

@fabiot21
Copy link

fabiot21 commented Feb 14, 2023

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?

@outranker
Copy link

outranker commented Jul 31, 2023

Hi, using datepicker in sveltekit , breaking my app, the browser console shows follwing error Uncaught (in promise) DOMException: Failed to execute 'setAttribute' on 'Element': '' is not a valid attribute name.

@reaper-king were you able to find a solution to this? i'm facing the same issue currently

@outranker
Copy link

anyone having this error:
Uncaught (in promise) DOMException: Failed to execute 'setAttribute' on 'Element': '' is not a valid attribute name.

Datepicker component expects attribute prop to be non falsy value. meaning you need to pass something to it. the problem resolves

ex:

<Datepicker
	attribute="aria-label"
	placeholder="some placeholder"
	for="some_for"
	datepickerFormat="dd/mm/yyyy"
	datepickerTitle="some title"
/>

@sachinaugi07
Copy link

anyone having this error: Uncaught (in promise) DOMException: Failed to execute 'setAttribute' on 'Element': '' is not a valid attribute name.

Datepicker component expects attribute prop to be non falsy value. meaning you need to pass something to it. the problem resolves

ex:

<Datepicker
	attribute="aria-label"
	placeholder="some placeholder"
	for="some_for"
	datepickerFormat="dd/mm/yyyy"
	datepickerTitle="some title"
/>

This did resolve the issue but when I click on the input field the date dropdown does not pop up.

@outranker
Copy link

anyone having this error: Uncaught (in promise) DOMException: Failed to execute 'setAttribute' on 'Element': '' is not a valid attribute name.
Datepicker component expects attribute prop to be non falsy value. meaning you need to pass something to it. the problem resolves
ex:

<Datepicker
	attribute="aria-label"
	placeholder="some placeholder"
	for="some_for"
	datepickerFormat="dd/mm/yyyy"
	datepickerTitle="some title"
/>

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 datepickerButtons set to false.
you will need to show some code and any error message that might exist in order for others to help you out with this

@RichardJohnn
Copy link

RichardJohnn commented Nov 22, 2023

If you use Datepicker in a form and submit it, you can read the values that way, at least with range. The inputs are named 'start' and 'end'

[...]
  function handleSubmit(event) {
    event.preventDefault();
    console.log(event.target.elements['start'].value);
    console.log(event.target.elements['end'].value);
  }
</script>

<form on:submit={handleSubmit}>
  <Datepicker 
      range 
      datepickerFormat="yyyy-mm-dd" 
      datepickerButtons=true />
  <button type="submit">
    Submit
  </button>
</form>

@Chizaruu
Copy link
Contributor

Chizaruu commented Oct 1, 2024

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>

@shinokada
Copy link
Collaborator Author

shinokada commented Oct 1, 2024

@Chizaruu Thank you for sharing the code. Can you add an example how you use it?

<script lang="ts">
	import { Button, Datepicker } from 'flowbite-svelte'
	let dateModal = false;
</script>

<div class='p-16'>
	<Button on:click={() => (dateModal = true)}>Datepicker</Button>
	<Datep bind:open={dateModal} />
</div>

@Chizaruu
Copy link
Contributor

Chizaruu commented Oct 1, 2024

@Chizaruu Thank you for sharing the code. Can you add an example how you use it?

<script lang="ts">
	import { Button, Datepicker } from 'flowbite-svelte'
	let dateModal = false;
</script>

<div class='p-16'>
	<Button on:click={() => (dateModal = true)}>Datepicker</Button>
	<Datep bind:open={dateModal} />
</div>

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>

image

@shinokada
Copy link
Collaborator Author

@Chizaruu
I'm happy to update it

and submit a Pull Request.

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.

@shinokada
Copy link
Collaborator Author

@Chizaruu
Why Oct 1, 2024 is Wed? It should be Tue.

@Chizaruu
Copy link
Contributor

Chizaruu commented Oct 1, 2024

@Chizaruu
Why Oct 1, 2024 is Wed? It should be Tue.

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.

@Chizaruu Chizaruu mentioned this issue Oct 15, 2024
7 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request help wanted Extra attention is needed
Projects
None yet
Development

Successfully merging a pull request may close this issue.

10 participants