Skip to content

Commit

Permalink
next: Date Picker (#600)
Browse files Browse the repository at this point in the history
  • Loading branch information
huntabyte authored Jul 8, 2024
1 parent 8f0daac commit b025b0e
Show file tree
Hide file tree
Showing 44 changed files with 835 additions and 1,306 deletions.
16 changes: 13 additions & 3 deletions packages/bits-ui/src/lib/bits/calendar/calendar.svelte.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ import {
type CalendarParts,
} from "$lib/shared/date/calendar-helpers.svelte.js";
import { createFormatter, type Formatter } from "$lib/shared/date/formatter.js";
import type { Month } from "$lib/shared/date/types.js";
import type { DateMatcher, Month } from "$lib/shared/date/types.js";
import { isBefore, toDate } from "$lib/shared/date/utils.js";
import {
getLocalTimeZone,
Expand Down Expand Up @@ -64,15 +64,20 @@ type CalendarRootStateProps = WithRefProps<
pagedNavigation: boolean;
weekStartsOn: 0 | 1 | 2 | 3 | 4 | 5 | 6;
weekdayFormat: Intl.DateTimeFormatOptions["weekday"];
isDateDisabled: (date: DateValue) => boolean;
isDateUnavailable: (date: DateValue) => boolean;
isDateDisabled: DateMatcher;
isDateUnavailable: DateMatcher;
fixedWeeks: boolean;
numberOfMonths: number;
locale: string;
calendarLabel: string;
type: "single" | "multiple";
readonly: boolean;
disableDaysOutsideMonth: boolean;
/**
* This is strictly used by the `DatePicker` component to close the popover when a date
* is selected. It is not intended to be used by the user.
*/
onDateSelect?: () => void;
}>
>;

Expand All @@ -97,6 +102,7 @@ export class CalendarRootState {
type: CalendarRootStateProps["type"];
readonly: CalendarRootStateProps["readonly"];
disableDaysOutsideMonth: CalendarRootStateProps["disableDaysOutsideMonth"];
onDateSelect: CalendarRootStateProps["onDateSelect"];
months: Month<DateValue>[] = $state([]);
visibleMonths = $derived.by(() => this.months.map((month) => month.value));
announcer: Announcer;
Expand Down Expand Up @@ -124,6 +130,7 @@ export class CalendarRootState {
this.id = props.id;
this.ref = props.ref;
this.disableDaysOutsideMonth = props.disableDaysOutsideMonth;
this.onDateSelect = props.onDateSelect;

this.announcer = getAnnouncer();
this.formatter = createFormatter(this.locale.value);
Expand Down Expand Up @@ -382,6 +389,9 @@ export class CalendarRootState {
);
}
this.value.value = next;
if (next !== undefined) {
this.onDateSelect?.value?.();
}
}
}
};
Expand Down
4 changes: 2 additions & 2 deletions packages/bits-ui/src/lib/bits/calendar/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import type {
WithAsChild,
Without,
} from "$lib/internal/types.js";
import type { DateMatcher, Month } from "$lib/shared/date/types.js";
import type { DateMatcher, Month, WeekStartsOn } from "$lib/shared/date/types.js";
import type { DateValue } from "@internationalized/date";
import type { Snippet } from "svelte";

Expand Down Expand Up @@ -85,7 +85,7 @@ type CalendarBaseRootPropsWithoutHTML = Omit<
*
* @defaultValue 0 (Sunday)
*/
weekStartsOn?: 0 | 1 | 2 | 3 | 4 | 5 | 6;
weekStartsOn?: WeekStartsOn;

/**
* How the string representation of the weekdays provided via the `weekdays` state store
Expand Down
5 changes: 3 additions & 2 deletions packages/bits-ui/src/lib/bits/date-field/date-field.svelte.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ import { DATE_SEGMENT_PARTS, TIME_SEGMENT_PARTS } from "$lib/shared/date/field/p
import { onDestroy, onMount, untrack } from "svelte";
import { createContext } from "$lib/internal/createContext.js";
import { useId } from "$lib/internal/useId.svelte.js";
import type { Granularity, DateMatcher } from "$lib/shared/date/types.js";
import type { Granularity, DateMatcher, HourCycle } from "$lib/shared/date/types.js";
import type { DateRangeFieldRootState } from "../date-range-field/date-range-field.svelte.js";

export type DateFieldRootStateProps = WritableBoxedValues<{
Expand All @@ -67,7 +67,7 @@ export type DateFieldRootStateProps = WritableBoxedValues<{
disabled: boolean;
readonly: boolean;
granularity: Granularity | undefined;
hourCycle: 12 | 24 | undefined;
hourCycle: HourCycle | undefined;
locale: string;
hideTimeZone: boolean;
name: string;
Expand Down Expand Up @@ -600,6 +600,7 @@ class DateFieldInputState {
"aria-disabled": getAriaDisabled(this.root.disabled.value),
"data-invalid": this.root.isInvalid ? "" : undefined,
"data-disabled": getDataDisabled(this.root.disabled.value),
"data-date-field-input": "",
}) as const
);
}
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,41 +1,56 @@
<script lang="ts">
import { type Month, melt } from "@melt-ui/svelte";
import type { DateValue } from "@internationalized/date";
import { getCtx } from "../ctx.js";
import type { CalendarEvents, CalendarProps } from "../index.js";
import { createDispatcher } from "$lib/internal/events.js";
import { useCalendarRoot } from "$lib/bits/calendar/calendar.svelte.js";
import { useId } from "$lib/internal/useId.svelte.js";
import { box } from "svelte-toolbelt";
import type { CalendarProps } from "../index.js";
import { getDatePickerRootContext } from "../date-picker.svelte.js";
import { mergeProps } from "$lib/internal/mergeProps.js";
type $$Props = CalendarProps;
type $$Events = CalendarEvents;
let {
asChild,
children,
child,
id = useId(),
ref = $bindable(null),
...restProps
}: CalendarProps = $props();
export let asChild: $$Props["asChild"] = false;
export let id: $$Props["id"] = undefined;
export let el: $$Props["el"] = undefined;
const datePickerRootState = getDatePickerRootContext();
const {
elements: { calendar },
states: { months: localMonths, weekdays },
ids,
getCalendarAttrs,
} = getCtx();
const calendarState = useCalendarRoot({
id: box.with(() => id),
ref: box.with(
() => ref,
(v) => (ref = v)
),
calendarLabel: datePickerRootState.props.calendarLabel,
fixedWeeks: datePickerRootState.props.fixedWeeks,
isDateDisabled: datePickerRootState.props.isDateDisabled,
isDateUnavailable: datePickerRootState.props.isDateUnavailable,
locale: datePickerRootState.props.locale,
numberOfMonths: datePickerRootState.props.numberOfMonths,
pagedNavigation: datePickerRootState.props.pagedNavigation,
preventDeselect: datePickerRootState.props.preventDeselect,
readonly: datePickerRootState.props.readonly,
type: box.with(() => "single"),
weekStartsOn: datePickerRootState.props.weekStartsOn,
weekdayFormat: datePickerRootState.props.weekdayFormat,
disabled: datePickerRootState.props.disabled,
disableDaysOutsideMonth: datePickerRootState.props.disableDaysOutsideMonth,
maxValue: datePickerRootState.props.maxValue,
minValue: datePickerRootState.props.minValue,
placeholder: datePickerRootState.props.placeholder,
value: datePickerRootState.props.value,
onDateSelect: datePickerRootState.props.onDateSelect,
});
$: if (id) {
ids.calendar.calendar.set(id);
}
const attrs = getCalendarAttrs("root");
const dispatch = createDispatcher();
$: builder = $calendar;
$: Object.assign(builder, attrs);
let months: Month<DateValue>[] = $localMonths;
$: months = $localMonths;
const mergedProps = $derived(mergeProps(restProps, calendarState.props));
</script>

{#if asChild}
<slot {builder} {months} weekdays={$weekdays} />
{@render child?.({ props: mergedProps, ...calendarState.snippetProps })}
{:else}
<div bind:this={ref} use:melt={builder} {...$$restProps} on:m-keydown={dispatch}>
<slot {builder} {months} weekdays={$weekdays} />
<div {...mergedProps}>
{@render children?.(calendarState.snippetProps)}
</div>
{/if}

This file was deleted.

This file was deleted.

Loading

0 comments on commit b025b0e

Please sign in to comment.