@flightlesslabs/dodo-ui-date 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +3 -0
- package/dist/components/Calendar/Calendar.scss +147 -0
- package/dist/components/Calendar/Calendar.stories.svelte +136 -0
- package/dist/components/Calendar/Calendar.stories.svelte.d.ts +22 -0
- package/dist/components/Calendar/Calendar.svelte +59 -0
- package/dist/components/Calendar/Calendar.svelte.d.ts +6 -0
- package/dist/components/Calendar/CalendarGrid/CalendarGrid.svelte +16 -0
- package/dist/components/Calendar/CalendarGrid/CalendarGrid.svelte.d.ts +4 -0
- package/dist/components/Calendar/CalendarGrid/TableBody.svelte +25 -0
- package/dist/components/Calendar/CalendarGrid/TableBody.svelte.d.ts +8 -0
- package/dist/components/Calendar/CalendarGrid/TableHead.svelte +19 -0
- package/dist/components/Calendar/CalendarGrid/TableHead.svelte.d.ts +6 -0
- package/dist/components/Calendar/Header.svelte +25 -0
- package/dist/components/Calendar/Header.svelte.d.ts +3 -0
- package/dist/components/DatePicker/DatePicker.scss +55 -0
- package/dist/components/DatePicker/DatePicker.stories.svelte +136 -0
- package/dist/components/DatePicker/DatePicker.stories.svelte.d.ts +22 -0
- package/dist/components/DatePicker/DatePicker.svelte +134 -0
- package/dist/components/DatePicker/DatePicker.svelte.d.ts +63 -0
- package/dist/components/DatePicker/DatePickerInput/DatePickerInput.svelte +95 -0
- package/dist/components/DatePicker/DatePickerInput/DatePickerInput.svelte.d.ts +22 -0
- package/dist/components/DatePicker/DatePickerInput/Segments.svelte +17 -0
- package/dist/components/DatePicker/DatePickerInput/Segments.svelte.d.ts +8 -0
- package/dist/components/DatePicker/DatePickerInput/utils.d.ts +10 -0
- package/dist/components/DatePicker/DatePickerInput/utils.js +26 -0
- package/dist/components/DatePicker/DatePickerPopup/CalendarGrid.svelte +35 -0
- package/dist/components/DatePicker/DatePickerPopup/CalendarGrid.svelte.d.ts +4 -0
- package/dist/components/DatePicker/DatePickerPopup/DatePickerPopup.svelte +50 -0
- package/dist/components/DatePicker/DatePickerPopup/DatePickerPopup.svelte.d.ts +6 -0
- package/dist/components/DatePicker/DatePickerPopup/Header.svelte +25 -0
- package/dist/components/DatePicker/DatePickerPopup/Header.svelte.d.ts +3 -0
- package/dist/index.d.ts +10 -0
- package/dist/index.js +10 -0
- package/dist/storybook-types.d.ts +129 -0
- package/dist/storybook-types.js +1 -0
- package/dist/styles/global/_breakpoints.scss +38 -0
- package/dist/styles/main.css +155 -0
- package/dist/styles/main.css.map +1 -0
- package/dist/styles/main.scss +2 -0
- package/dist/test/setup.d.ts +1 -0
- package/dist/test/setup.js +12 -0
- package/package.json +114 -0
- package/src/lib/components/Calendar/Calendar.scss +147 -0
- package/src/lib/components/Calendar/Calendar.stories.svelte +136 -0
- package/src/lib/components/Calendar/Calendar.svelte +59 -0
- package/src/lib/components/Calendar/CalendarGrid/CalendarGrid.svelte +16 -0
- package/src/lib/components/Calendar/CalendarGrid/TableBody.svelte +25 -0
- package/src/lib/components/Calendar/CalendarGrid/TableHead.svelte +19 -0
- package/src/lib/components/Calendar/Header.svelte +25 -0
- package/src/lib/components/DatePicker/DatePicker.scss +55 -0
- package/src/lib/components/DatePicker/DatePicker.stories.svelte +136 -0
- package/src/lib/components/DatePicker/DatePicker.svelte +134 -0
- package/src/lib/components/DatePicker/DatePickerInput/DatePickerInput.svelte +95 -0
- package/src/lib/components/DatePicker/DatePickerInput/Segments.svelte +17 -0
- package/src/lib/components/DatePicker/DatePickerInput/utils.ts +55 -0
- package/src/lib/components/DatePicker/DatePickerPopup/CalendarGrid.svelte +35 -0
- package/src/lib/components/DatePicker/DatePickerPopup/DatePickerPopup.svelte +50 -0
- package/src/lib/components/DatePicker/DatePickerPopup/Header.svelte +25 -0
- package/src/lib/index.ts +16 -0
- package/src/lib/storybook-types.ts +182 -0
- package/src/lib/styles/global/_breakpoints.scss +38 -0
- package/src/lib/styles/main.scss +2 -0
- package/src/lib/test/setup.ts +13 -0
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
<script module lang="ts">
|
|
2
|
+
import { defineMeta } from '@storybook/addon-svelte-csf';
|
|
3
|
+
import Calendar from './Calendar.svelte';
|
|
4
|
+
import type { CalendarProps } from './Calendar.svelte';
|
|
5
|
+
import type { ArgTypes } from 'storybook/internal/csf';
|
|
6
|
+
import { CalendarDate, type DateValue } from '@internationalized/date';
|
|
7
|
+
import {
|
|
8
|
+
cardColorOptions,
|
|
9
|
+
componentRoundnessOptions,
|
|
10
|
+
ComponentShadowOptions,
|
|
11
|
+
componentThemeColorsOptions,
|
|
12
|
+
componentVariantOptions,
|
|
13
|
+
Theme,
|
|
14
|
+
} from '@flightlesslabs/dodo-ui';
|
|
15
|
+
|
|
16
|
+
const description = `
|
|
17
|
+
a plug and play Calendar component based on bits-ui [calendar](https://bits-ui.com/docs/components/calendar).
|
|
18
|
+
|
|
19
|
+
\`\`\`ts
|
|
20
|
+
import { Calendar } from '@flightlesslabs/dodo-ui-date';
|
|
21
|
+
\`\`\`
|
|
22
|
+
`;
|
|
23
|
+
|
|
24
|
+
// ------------------------------
|
|
25
|
+
// Storybook ArgTypes
|
|
26
|
+
// ------------------------------
|
|
27
|
+
export const storyCalendarArgTypes: Partial<ArgTypes<CalendarProps>> = {
|
|
28
|
+
// ------------------------------
|
|
29
|
+
// Core
|
|
30
|
+
// ------------------------------
|
|
31
|
+
class: { table: { category: 'API', subcategory: 'Base' } },
|
|
32
|
+
value: {
|
|
33
|
+
control: { type: 'text' },
|
|
34
|
+
table: { category: 'API', subcategory: 'Base' },
|
|
35
|
+
},
|
|
36
|
+
|
|
37
|
+
// ------------------------------
|
|
38
|
+
// State
|
|
39
|
+
// ------------------------------
|
|
40
|
+
disabled: {
|
|
41
|
+
control: { type: 'boolean' },
|
|
42
|
+
description: 'Disabled state of the input',
|
|
43
|
+
table: { category: 'API', subcategory: 'State', defaultValue: { summary: 'false' } },
|
|
44
|
+
},
|
|
45
|
+
|
|
46
|
+
// ------------------------------
|
|
47
|
+
// Appearance
|
|
48
|
+
// ------------------------------
|
|
49
|
+
shadow: {
|
|
50
|
+
control: { type: 'select' },
|
|
51
|
+
options: ComponentShadowOptions,
|
|
52
|
+
description: 'Component Shadow',
|
|
53
|
+
table: { category: 'API', subcategory: 'Appearance', defaultValue: { summary: '1' } },
|
|
54
|
+
},
|
|
55
|
+
color: {
|
|
56
|
+
control: { type: 'select' },
|
|
57
|
+
options: cardColorOptions,
|
|
58
|
+
description: 'Color theme token',
|
|
59
|
+
table: { category: 'API', subcategory: 'Appearance', defaultValue: { summary: 'default' } },
|
|
60
|
+
},
|
|
61
|
+
variant: {
|
|
62
|
+
control: { type: 'select' },
|
|
63
|
+
options: componentVariantOptions,
|
|
64
|
+
description: 'Visual variant of the card',
|
|
65
|
+
table: { category: 'API', subcategory: 'Appearance', defaultValue: { summary: 'text' } },
|
|
66
|
+
},
|
|
67
|
+
roundness: {
|
|
68
|
+
control: { type: 'select' },
|
|
69
|
+
options: componentRoundnessOptions,
|
|
70
|
+
description: 'Border radius token',
|
|
71
|
+
table: { category: 'API', subcategory: 'Appearance' },
|
|
72
|
+
},
|
|
73
|
+
outline: {
|
|
74
|
+
control: { type: 'boolean' },
|
|
75
|
+
description: 'Render outlined style',
|
|
76
|
+
table: { category: 'API', subcategory: 'Appearance' },
|
|
77
|
+
},
|
|
78
|
+
active: {
|
|
79
|
+
control: { type: 'boolean' },
|
|
80
|
+
description: 'Add mouse hover and active effects',
|
|
81
|
+
table: { category: 'API', subcategory: 'Appearance' },
|
|
82
|
+
},
|
|
83
|
+
theme: {
|
|
84
|
+
control: { type: 'select' },
|
|
85
|
+
options: componentThemeColorsOptions,
|
|
86
|
+
description: 'Theme color',
|
|
87
|
+
table: { category: 'API', subcategory: 'Base', defaultValue: { summary: 'undefined' } },
|
|
88
|
+
},
|
|
89
|
+
};
|
|
90
|
+
|
|
91
|
+
// ------------------------------
|
|
92
|
+
// Storybook Meta
|
|
93
|
+
// ------------------------------
|
|
94
|
+
const { Story } = defineMeta({
|
|
95
|
+
component: Calendar,
|
|
96
|
+
tags: ['autodocs'],
|
|
97
|
+
argTypes: storyCalendarArgTypes,
|
|
98
|
+
parameters: {
|
|
99
|
+
docs: {
|
|
100
|
+
description: {
|
|
101
|
+
component: description,
|
|
102
|
+
},
|
|
103
|
+
},
|
|
104
|
+
},
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
let myValue = $state<DateValue>(new CalendarDate(2026, 4, 7));
|
|
108
|
+
</script>
|
|
109
|
+
|
|
110
|
+
<!-- ------------------------------ -->
|
|
111
|
+
<!-- Stories -->
|
|
112
|
+
<!-- ------------------------------ -->
|
|
113
|
+
|
|
114
|
+
<Story name="Default" />
|
|
115
|
+
|
|
116
|
+
<Story name="Controlled" asChild>
|
|
117
|
+
<Calendar bind:value={myValue} />
|
|
118
|
+
</Story>
|
|
119
|
+
|
|
120
|
+
<Story name="Starts On Sunday" args={{ weekStartsOn: 0 }} />
|
|
121
|
+
|
|
122
|
+
<Story name="Min Date" args={{ minValue: new CalendarDate(2026, 4, 7) }} />
|
|
123
|
+
|
|
124
|
+
<Story name="Max Date" args={{ maxValue: new CalendarDate(2026, 4, 7) }} />
|
|
125
|
+
|
|
126
|
+
<Story name="Light Theme" asChild>
|
|
127
|
+
<Theme type="light">
|
|
128
|
+
<Calendar />
|
|
129
|
+
</Theme>
|
|
130
|
+
</Story>
|
|
131
|
+
|
|
132
|
+
<Story name="Dark Theme" asChild globals={{ backgrounds: { value: 'dark' } }}>
|
|
133
|
+
<Theme type="dark">
|
|
134
|
+
<Calendar />
|
|
135
|
+
</Theme>
|
|
136
|
+
</Story>
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
<script lang="ts" module>
|
|
2
|
+
export type CalendarProps = Omit<CalendarSingleRootProps, 'type'> &
|
|
3
|
+
Omit<CardProps, 'children' | 'ref'>;
|
|
4
|
+
</script>
|
|
5
|
+
|
|
6
|
+
<script lang="ts">
|
|
7
|
+
import { Calendar as CalendarBitsUi, type CalendarSingleRootProps } from 'bits-ui';
|
|
8
|
+
import Header from './Header.svelte';
|
|
9
|
+
import CalendarGrid from './CalendarGrid/CalendarGrid.svelte';
|
|
10
|
+
import { useThemeContext, type CardProps } from '@flightlesslabs/dodo-ui';
|
|
11
|
+
let {
|
|
12
|
+
roundness = 1,
|
|
13
|
+
outline = true,
|
|
14
|
+
class: className = '',
|
|
15
|
+
theme: cardTheme,
|
|
16
|
+
color = 'default',
|
|
17
|
+
variant = 'text',
|
|
18
|
+
shadow = 0,
|
|
19
|
+
active = false,
|
|
20
|
+
weekStartsOn = 1,
|
|
21
|
+
weekdayFormat = 'short',
|
|
22
|
+
fixedWeeks = true,
|
|
23
|
+
value = $bindable(undefined),
|
|
24
|
+
...restProps
|
|
25
|
+
}: CalendarProps = $props();
|
|
26
|
+
|
|
27
|
+
const themeContext = useThemeContext();
|
|
28
|
+
const theme = $derived(cardTheme ? cardTheme : themeContext.theme);
|
|
29
|
+
|
|
30
|
+
const popupClasses = $derived(
|
|
31
|
+
[
|
|
32
|
+
'dodo-ui-Card',
|
|
33
|
+
'dodo-ui-Calendar',
|
|
34
|
+
`color--${color}`,
|
|
35
|
+
`variant--${variant}`,
|
|
36
|
+
`roundness--${roundness}`,
|
|
37
|
+
`dodo-shadow-${shadow}`,
|
|
38
|
+
outline && 'outline',
|
|
39
|
+
active && 'active',
|
|
40
|
+
theme ? `dodo-theme--${theme}` : '',
|
|
41
|
+
className,
|
|
42
|
+
].filter(Boolean),
|
|
43
|
+
);
|
|
44
|
+
</script>
|
|
45
|
+
|
|
46
|
+
<CalendarBitsUi.Root
|
|
47
|
+
{...restProps}
|
|
48
|
+
{weekStartsOn}
|
|
49
|
+
{weekdayFormat}
|
|
50
|
+
{fixedWeeks}
|
|
51
|
+
bind:value
|
|
52
|
+
type="single"
|
|
53
|
+
class={popupClasses.join(' ')}
|
|
54
|
+
>
|
|
55
|
+
{#snippet children(calendarRootSnippetProps)}
|
|
56
|
+
<Header />
|
|
57
|
+
<CalendarGrid {...calendarRootSnippetProps} />
|
|
58
|
+
{/snippet}
|
|
59
|
+
</CalendarBitsUi.Root>
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import { Calendar, type CalendarRootSnippetProps } from 'bits-ui';
|
|
3
|
+
import TableHead from './TableHead.svelte';
|
|
4
|
+
import TableBody from './TableBody.svelte';
|
|
5
|
+
|
|
6
|
+
let { months, weekdays }: CalendarRootSnippetProps = $props();
|
|
7
|
+
</script>
|
|
8
|
+
|
|
9
|
+
<div class="CalendarGrid">
|
|
10
|
+
{#each months as month (month.value)}
|
|
11
|
+
<Calendar.Grid>
|
|
12
|
+
<TableHead {weekdays} />
|
|
13
|
+
<TableBody {month} />
|
|
14
|
+
</Calendar.Grid>
|
|
15
|
+
{/each}
|
|
16
|
+
</div>
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import type { DateValue } from '@internationalized/date';
|
|
3
|
+
import { Calendar, type Month } from 'bits-ui';
|
|
4
|
+
|
|
5
|
+
type Props = {
|
|
6
|
+
month: Month<DateValue>;
|
|
7
|
+
};
|
|
8
|
+
|
|
9
|
+
let { month }: Props = $props();
|
|
10
|
+
</script>
|
|
11
|
+
|
|
12
|
+
<Calendar.GridBody>
|
|
13
|
+
{#each month.weeks as weekDates (weekDates)}
|
|
14
|
+
<Calendar.GridRow>
|
|
15
|
+
{#each weekDates as date (date)}
|
|
16
|
+
<Calendar.Cell {date} month={month.value}>
|
|
17
|
+
<Calendar.Day>
|
|
18
|
+
<div></div>
|
|
19
|
+
{date.day}
|
|
20
|
+
</Calendar.Day>
|
|
21
|
+
</Calendar.Cell>
|
|
22
|
+
{/each}
|
|
23
|
+
</Calendar.GridRow>
|
|
24
|
+
{/each}
|
|
25
|
+
</Calendar.GridBody>
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import { Calendar } from 'bits-ui';
|
|
3
|
+
|
|
4
|
+
type Props = {
|
|
5
|
+
weekdays: string[];
|
|
6
|
+
};
|
|
7
|
+
|
|
8
|
+
let { weekdays }: Props = $props();
|
|
9
|
+
</script>
|
|
10
|
+
|
|
11
|
+
<Calendar.GridHead>
|
|
12
|
+
<Calendar.GridRow>
|
|
13
|
+
{#each weekdays as day (day)}
|
|
14
|
+
<Calendar.HeadCell>
|
|
15
|
+
<div>{day.slice(0, 2)}</div>
|
|
16
|
+
</Calendar.HeadCell>
|
|
17
|
+
{/each}
|
|
18
|
+
</Calendar.GridRow>
|
|
19
|
+
</Calendar.GridHead>
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import Icon from '@iconify/svelte';
|
|
3
|
+
import { Calendar } from 'bits-ui';
|
|
4
|
+
|
|
5
|
+
const triggerClasses = $derived(
|
|
6
|
+
[
|
|
7
|
+
'dodo-ui-Button',
|
|
8
|
+
'compact',
|
|
9
|
+
'size--normal',
|
|
10
|
+
'variant--text',
|
|
11
|
+
'color--primary',
|
|
12
|
+
'roundness--1',
|
|
13
|
+
].filter(Boolean),
|
|
14
|
+
);
|
|
15
|
+
</script>
|
|
16
|
+
|
|
17
|
+
<Calendar.Header>
|
|
18
|
+
<Calendar.PrevButton class={triggerClasses.join(' ')}>
|
|
19
|
+
<Icon icon="material-symbols:chevron-left-rounded" />
|
|
20
|
+
</Calendar.PrevButton>
|
|
21
|
+
<Calendar.Heading />
|
|
22
|
+
<Calendar.NextButton class={triggerClasses.join(' ')}>
|
|
23
|
+
<Icon icon="material-symbols:chevron-right-rounded" />
|
|
24
|
+
</Calendar.NextButton>
|
|
25
|
+
</Calendar.Header>
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
.dodo-ui-DatePicker {
|
|
2
|
+
button[data-popover-trigger] {
|
|
3
|
+
font-size: 1.4em;
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
[data-date-field-input] {
|
|
7
|
+
display: flex;
|
|
8
|
+
align-items: center;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
[data-date-field-segment] {
|
|
12
|
+
height: 80%;
|
|
13
|
+
display: inline-flex;
|
|
14
|
+
align-items: center;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
[data-segment='literal'] {
|
|
18
|
+
color: var(--dodo-color-neutral-500);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
// ----------------------------------------
|
|
22
|
+
// Sizes
|
|
23
|
+
// ----------------------------------------
|
|
24
|
+
&.size {
|
|
25
|
+
&--normal {
|
|
26
|
+
button[data-popover-trigger] {
|
|
27
|
+
margin: 0 calc(var(--dodo-ui-space) / 2.5);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
[data-date-field-segment] {
|
|
31
|
+
padding: 0 calc(var(--dodo-ui-space) / 3);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
&--small {
|
|
36
|
+
button[data-popover-trigger] {
|
|
37
|
+
margin: 0 calc(var(--dodo-ui-space--small) / 2.5);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
[data-date-field-segment] {
|
|
41
|
+
padding: 0 calc(var(--dodo-ui-space-small) / 3);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
&--large {
|
|
46
|
+
button[data-popover-trigger] {
|
|
47
|
+
margin: 0 calc(var(--dodo-ui-space--large) / 2.5);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
[data-date-field-segment] {
|
|
51
|
+
padding: 0 calc(var(--dodo-ui-space-large) / 3);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
}
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
<script module lang="ts">
|
|
2
|
+
import { defineMeta } from '@storybook/addon-svelte-csf';
|
|
3
|
+
import DatePicker from './DatePicker.svelte';
|
|
4
|
+
import type { DatePickerProps } from './DatePicker.svelte';
|
|
5
|
+
import type { ArgTypes } from 'storybook/internal/csf';
|
|
6
|
+
import { CalendarDate, type DateValue } from '@internationalized/date';
|
|
7
|
+
import { componentSizeOptions, componentRoundnessOptions, Theme } from '@flightlesslabs/dodo-ui';
|
|
8
|
+
|
|
9
|
+
const description = `
|
|
10
|
+
A sleek, plug and play Date Picker based on bits-ui [date-picker](https://bits-ui.com/docs/components/date-picker).
|
|
11
|
+
\`\`\`ts
|
|
12
|
+
import { DatePicker } from '@flightlesslabs/dodo-ui-date';
|
|
13
|
+
|
|
14
|
+
import { CalendarDate, type DateValue } from '@internationalized/date';
|
|
15
|
+
\`\`\`
|
|
16
|
+
`;
|
|
17
|
+
|
|
18
|
+
// ------------------------------
|
|
19
|
+
// Storybook ArgTypes
|
|
20
|
+
// ------------------------------
|
|
21
|
+
export const storyDatePickerArgTypes: Partial<ArgTypes<DatePickerProps>> = {
|
|
22
|
+
// ------------------------------
|
|
23
|
+
// Core
|
|
24
|
+
// ------------------------------
|
|
25
|
+
class: { table: { category: 'API', subcategory: 'Base' } },
|
|
26
|
+
value: {
|
|
27
|
+
control: { type: 'text' },
|
|
28
|
+
table: { category: 'API', subcategory: 'Base' },
|
|
29
|
+
},
|
|
30
|
+
dateFormat: {
|
|
31
|
+
control: { type: 'text' },
|
|
32
|
+
table: { category: 'API', subcategory: 'Base', defaultValue: { summary: 'dd/mm/yyyy' } },
|
|
33
|
+
},
|
|
34
|
+
|
|
35
|
+
// ------------------------------
|
|
36
|
+
// State
|
|
37
|
+
// ------------------------------
|
|
38
|
+
disabled: {
|
|
39
|
+
control: { type: 'boolean' },
|
|
40
|
+
description: 'Disabled state of the input',
|
|
41
|
+
table: { category: 'API', subcategory: 'State', defaultValue: { summary: 'false' } },
|
|
42
|
+
},
|
|
43
|
+
focused: {
|
|
44
|
+
control: { type: 'boolean' },
|
|
45
|
+
description: 'Force focused visual state',
|
|
46
|
+
table: { category: 'API', subcategory: 'State', defaultValue: { summary: 'false' } },
|
|
47
|
+
},
|
|
48
|
+
error: {
|
|
49
|
+
control: { type: 'boolean' },
|
|
50
|
+
description: 'Error visual state',
|
|
51
|
+
table: { category: 'API', subcategory: 'State', defaultValue: { summary: 'false' } },
|
|
52
|
+
},
|
|
53
|
+
|
|
54
|
+
// ------------------------------
|
|
55
|
+
// Appearance
|
|
56
|
+
// ------------------------------
|
|
57
|
+
size: {
|
|
58
|
+
control: { type: 'select' },
|
|
59
|
+
options: componentSizeOptions,
|
|
60
|
+
description: 'Visual size token',
|
|
61
|
+
table: { category: 'API', subcategory: 'Appearance', defaultValue: { summary: 'normal' } },
|
|
62
|
+
},
|
|
63
|
+
roundness: {
|
|
64
|
+
control: { type: 'select' },
|
|
65
|
+
options: componentRoundnessOptions,
|
|
66
|
+
description: 'Border radius token',
|
|
67
|
+
table: { category: 'API', subcategory: 'Appearance', defaultValue: { summary: '1' } },
|
|
68
|
+
},
|
|
69
|
+
outline: {
|
|
70
|
+
control: { type: 'boolean' },
|
|
71
|
+
description: 'Render outlined enclosure',
|
|
72
|
+
table: { category: 'API', subcategory: 'Appearance', defaultValue: { summary: 'true' } },
|
|
73
|
+
},
|
|
74
|
+
|
|
75
|
+
// ------------------------------
|
|
76
|
+
// Slots (Snippets)
|
|
77
|
+
// ------------------------------
|
|
78
|
+
before: {
|
|
79
|
+
table: { category: 'API', subcategory: 'Slots' },
|
|
80
|
+
description: 'Content rendered before the input',
|
|
81
|
+
},
|
|
82
|
+
after: {
|
|
83
|
+
table: { category: 'API', subcategory: 'Slots' },
|
|
84
|
+
description: 'Content rendered after the input',
|
|
85
|
+
},
|
|
86
|
+
};
|
|
87
|
+
|
|
88
|
+
// ------------------------------
|
|
89
|
+
// Storybook Meta
|
|
90
|
+
// ------------------------------
|
|
91
|
+
const { Story } = defineMeta({
|
|
92
|
+
component: DatePicker,
|
|
93
|
+
tags: ['autodocs'],
|
|
94
|
+
argTypes: storyDatePickerArgTypes,
|
|
95
|
+
parameters: {
|
|
96
|
+
docs: {
|
|
97
|
+
description: {
|
|
98
|
+
component: description,
|
|
99
|
+
},
|
|
100
|
+
story: { height: '420px' },
|
|
101
|
+
},
|
|
102
|
+
},
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
let myValue = $state<DateValue>(new CalendarDate(2026, 4, 7));
|
|
106
|
+
</script>
|
|
107
|
+
|
|
108
|
+
<!-- ------------------------------ -->
|
|
109
|
+
<!-- Stories -->
|
|
110
|
+
<!-- ------------------------------ -->
|
|
111
|
+
|
|
112
|
+
<Story name="Default" />
|
|
113
|
+
|
|
114
|
+
<Story name="Controlled" asChild>
|
|
115
|
+
<DatePicker bind:value={myValue} />
|
|
116
|
+
</Story>
|
|
117
|
+
|
|
118
|
+
<Story name="Starts On Sunday" args={{ weekStartsOn: 0 }} />
|
|
119
|
+
|
|
120
|
+
<Story name="Date Format" args={{ dateFormat: 'mm/dd/yyyy' }} />
|
|
121
|
+
|
|
122
|
+
<Story name="Min Date" args={{ minValue: new CalendarDate(2026, 4, 7) }} />
|
|
123
|
+
|
|
124
|
+
<Story name="Max Date" args={{ maxValue: new CalendarDate(2026, 4, 7) }} />
|
|
125
|
+
|
|
126
|
+
<Story name="Light Theme" asChild>
|
|
127
|
+
<Theme type="light">
|
|
128
|
+
<DatePicker />
|
|
129
|
+
</Theme>
|
|
130
|
+
</Story>
|
|
131
|
+
|
|
132
|
+
<Story name="Dark Theme" asChild globals={{ backgrounds: { value: 'dark' } }}>
|
|
133
|
+
<Theme type="dark">
|
|
134
|
+
<DatePicker />
|
|
135
|
+
</Theme>
|
|
136
|
+
</Story>
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
<script lang="ts" module>
|
|
2
|
+
export type DatePickerProps = DatePickerRootPropsWithoutHTML & {
|
|
3
|
+
/** Visual size token (e.g. small, normal, large) */
|
|
4
|
+
size?: ComponentSize;
|
|
5
|
+
|
|
6
|
+
/** Border radius token (e.g. 1–3, "pill") */
|
|
7
|
+
roundness?: ComponentRoundnessShape;
|
|
8
|
+
|
|
9
|
+
/** Render an outlined enclosure (shows border) */
|
|
10
|
+
outline?: boolean;
|
|
11
|
+
|
|
12
|
+
/** Custom CSS class names applied to the InputEnclosure */
|
|
13
|
+
class?: string;
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Error visual state.
|
|
17
|
+
*
|
|
18
|
+
* When true, applies error styling to the enclosure.
|
|
19
|
+
* Intended for validation errors.
|
|
20
|
+
*/
|
|
21
|
+
error?: boolean;
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Focused visual state.
|
|
25
|
+
*
|
|
26
|
+
* When true, forces focused styling on the enclosure.
|
|
27
|
+
* Usually controlled automatically via focus/blur.
|
|
28
|
+
*/
|
|
29
|
+
focused?: boolean;
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Content rendered before the input (prefix).
|
|
33
|
+
*
|
|
34
|
+
* Use {#snippet before} in Svelte.
|
|
35
|
+
*/
|
|
36
|
+
before?: Snippet;
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Content rendered after the input (suffix).
|
|
40
|
+
*
|
|
41
|
+
* Use {#snippet after} in Svelte.
|
|
42
|
+
*/
|
|
43
|
+
after?: Snippet;
|
|
44
|
+
|
|
45
|
+
/** Select placeholder */
|
|
46
|
+
placeholder?: string;
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Date display format for the input segments.
|
|
50
|
+
*
|
|
51
|
+
* Controls the visual order and separators of the date parts
|
|
52
|
+
* (e.g. "dd/mm/yyyy", "mm-dd-yyyy", "yyyy.mm.dd").
|
|
53
|
+
*
|
|
54
|
+
* This only affects how the date is rendered in the input,
|
|
55
|
+
* not the internal parsing or keyboard interaction behavior
|
|
56
|
+
* of the DatePicker.
|
|
57
|
+
*/
|
|
58
|
+
dateFormat?: DatePickerFormat;
|
|
59
|
+
|
|
60
|
+
/** bits ui dateFieldInputProps */
|
|
61
|
+
dateFieldInputProps?: DateFieldInputProps;
|
|
62
|
+
|
|
63
|
+
/** bits ui datePickerTriggerProps */
|
|
64
|
+
datePickerTriggerProps?: DatePickerTriggerProps;
|
|
65
|
+
|
|
66
|
+
/** Props for Popup */
|
|
67
|
+
popupProps?: DatePickerPopupProps;
|
|
68
|
+
};
|
|
69
|
+
</script>
|
|
70
|
+
|
|
71
|
+
<script lang="ts">
|
|
72
|
+
import {
|
|
73
|
+
DatePicker as DatePickerBitsUi,
|
|
74
|
+
type DateFieldInputProps,
|
|
75
|
+
type DatePickerRootPropsWithoutHTML,
|
|
76
|
+
type DatePickerTriggerProps,
|
|
77
|
+
} from 'bits-ui';
|
|
78
|
+
import type { Snippet } from 'svelte';
|
|
79
|
+
import DatepickerInput from './DatePickerInput/DatePickerInput.svelte';
|
|
80
|
+
import type { DatePickerFormat } from './DatePickerInput/utils.js';
|
|
81
|
+
import DatePickerPopup, {
|
|
82
|
+
type DatePickerPopupProps,
|
|
83
|
+
} from './DatePickerPopup/DatePickerPopup.svelte';
|
|
84
|
+
import type { ComponentSize, ComponentRoundnessShape } from '@flightlesslabs/dodo-ui';
|
|
85
|
+
|
|
86
|
+
let {
|
|
87
|
+
size = 'normal',
|
|
88
|
+
roundness = 1,
|
|
89
|
+
outline = true,
|
|
90
|
+
class: className = '',
|
|
91
|
+
disabled = false,
|
|
92
|
+
error = false,
|
|
93
|
+
focused: forcedFocused = false,
|
|
94
|
+
before,
|
|
95
|
+
after,
|
|
96
|
+
open = $bindable(false),
|
|
97
|
+
value = $bindable(undefined),
|
|
98
|
+
placeholder,
|
|
99
|
+
weekdayFormat = 'short',
|
|
100
|
+
fixedWeeks = true,
|
|
101
|
+
dateFieldInputProps,
|
|
102
|
+
datePickerTriggerProps,
|
|
103
|
+
weekStartsOn = 1,
|
|
104
|
+
dateFormat = 'dd/mm/yyyy',
|
|
105
|
+
popupProps,
|
|
106
|
+
...restProps
|
|
107
|
+
}: DatePickerProps = $props();
|
|
108
|
+
</script>
|
|
109
|
+
|
|
110
|
+
<DatePickerBitsUi.Root
|
|
111
|
+
{...restProps}
|
|
112
|
+
bind:value
|
|
113
|
+
bind:open
|
|
114
|
+
{weekdayFormat}
|
|
115
|
+
{weekStartsOn}
|
|
116
|
+
{fixedWeeks}
|
|
117
|
+
>
|
|
118
|
+
<DatepickerInput
|
|
119
|
+
{size}
|
|
120
|
+
{roundness}
|
|
121
|
+
{outline}
|
|
122
|
+
class={className}
|
|
123
|
+
{disabled}
|
|
124
|
+
{error}
|
|
125
|
+
{dateFieldInputProps}
|
|
126
|
+
{datePickerTriggerProps}
|
|
127
|
+
focused={forcedFocused}
|
|
128
|
+
{before}
|
|
129
|
+
{after}
|
|
130
|
+
{placeholder}
|
|
131
|
+
{dateFormat}
|
|
132
|
+
/>
|
|
133
|
+
<DatePickerPopup {...popupProps} />
|
|
134
|
+
</DatePickerBitsUi.Root>
|