-
Notifications
You must be signed in to change notification settings - Fork 218
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/2824 date input #2864
base: next
Are you sure you want to change the base?
Feature/2824 date input #2864
Changes from 19 commits
5f76b11
e31bbd4
46dd252
959a449
a9edd33
9da5eb0
49c1bac
923a5f2
af36798
4be852e
0527feb
95667bf
41d31ca
f728875
389ef3d
ef35f7b
175be7f
3150c62
9505d54
d3c9818
a51230d
849bef5
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
--- | ||
'@evidence-dev/core-components': patch | ||
--- | ||
|
||
Feature: DateInput - supports single and ranged calendar date inputs |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -113,4 +113,4 @@ | |
} | ||
}, | ||
"packageManager": "[email protected]+sha512.499434c9d8fdd1a2794ebf4552b3b25c0a633abcee5bb15e7b5de90f32f47b513aca98cd5cfd001c31f0db454bc3804edccd578501e4ca293a6816166bbd9f81" | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,46 @@ | ||
<script context="module"> | ||
/** @type {import("@storybook/svelte").Meta}*/ | ||
export const meta = { | ||
title: 'Atoms/inputs/DateInput', | ||
argTypes: {}, | ||
args: { | ||
title: 'Date Input', | ||
name: 'DateInput', | ||
omitGroup: [] | ||
} | ||
}; | ||
</script> | ||
|
||
<script> | ||
import { Template, Story } from '@storybook/addon-svelte-csf'; | ||
import DateInput from './DateInput.svelte'; | ||
import { getInputContext } from '@evidence-dev/sdk/utils/svelte'; | ||
const inputStore = getInputContext(); | ||
|
||
// Mock "today" | ||
import MockDate from 'mockdate'; | ||
MockDate.set('2024-12-30'); | ||
</script> | ||
|
||
<Template let:args> | ||
<DateInput {...args} /> | ||
</Template> | ||
|
||
<Story name="Basic Usage" let:args> | ||
<h1> | ||
Input Store: | ||
<h2>value: {$inputStore.dateInput.value}</h2> | ||
<h2>start: {$inputStore.dateInput.start}</h2> | ||
<h2>end: {$inputStore.dateInput.end}</h2> | ||
</h1> | ||
<DateInput {...args} name="dateInput" /> | ||
</Story> | ||
<Story name="dateInput_range" let:args> | ||
<h1> | ||
Input Store: | ||
<h2>value: {$inputStore.dateInput_range.value}</h2> | ||
<h2>start: {$inputStore.dateInput_range.start}</h2> | ||
<h2>end: {$inputStore.dateInput_range.end}</h2> | ||
</h1> | ||
<DateInput {...args} name="dateInput_range" range /> | ||
</Story> |
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
@@ -0,0 +1,142 @@ | ||||||
<script context="module"> | ||||||
export const evidenceInclude = true; | ||||||
</script> | ||||||
|
||||||
<script> | ||||||
import DateInput from './_DateInput.svelte'; | ||||||
import { Query } from '@evidence-dev/sdk/usql'; | ||||||
import { getQueryFunction } from '@evidence-dev/component-utilities/buildQuery'; | ||||||
import { getLocalTimeZone } from '@internationalized/date'; | ||||||
import HiddenInPrint from '../shared/HiddenInPrint.svelte'; | ||||||
import { page } from '$app/stores'; | ||||||
import QueryLoad from '$lib/atoms/query-load/QueryLoad.svelte'; | ||||||
import { Skeleton } from '$lib/atoms/skeletons/index.js'; | ||||||
import { getInputContext } from '@evidence-dev/sdk/utils/svelte'; | ||||||
|
||||||
function dateToYYYYMMDD(date) { | ||||||
return date.toISOString().split('T')[0]; | ||||||
} | ||||||
|
||||||
const inputs = getInputContext(); | ||||||
|
||||||
/** @type {string} */ | ||||||
export let name; | ||||||
/** @type {string | undefined} */ | ||||||
export let title; | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. optional props like these should have a default value of |
||||||
/** @type {boolean} */ | ||||||
export let hideDuringPrint = true; | ||||||
|
||||||
/** @type {string | Date | undefined} */ | ||||||
export let start; | ||||||
/** @type {string | Date | undefined} */ | ||||||
export let end; | ||||||
|
||||||
/** @type {Query | string | undefined} */ | ||||||
export let data; | ||||||
/** @type {string | undefined} */ | ||||||
export let dates; | ||||||
/** @type {[]string | undefined} */ | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
export let presetRanges; | ||||||
/** @type {string | undefined} */ | ||||||
export let defaultValue; | ||||||
/** @type {boolean} */ | ||||||
export let range = false; | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. any user facing boolean should accept a string also
as well as
|
||||||
|
||||||
const exec = getQueryFunction(); | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @ItsMeBrianD is there an alternative we should prefer to direct |
||||||
let query; | ||||||
$: if (data && dates) { | ||||||
const source = typeof data === 'string' ? data : `(${data.text})`; | ||||||
query = Query.create( | ||||||
`SELECT min(${dates}) as start, max(${dates}) as end FROM ${source}`, | ||||||
exec, | ||||||
{ | ||||||
initialData: $page?.data?.data[`DateInput-${name}_data`], | ||||||
knownColumns: $page?.data?.data[`DateInput-${name}_columns`], | ||||||
disableCache: true, | ||||||
noResolve: false, | ||||||
id: `DateInput-${name}` | ||||||
} | ||||||
); | ||||||
query.fetch(); | ||||||
} | ||||||
const YYYYMMDD = /^\d{4}-\d{2}-\d{2}$/; | ||||||
$: startString = | ||||||
typeof start === 'string' && YYYYMMDD.test(start) | ||||||
? start | ||||||
: start instanceof Date | ||||||
? dateToYYYYMMDD(start) | ||||||
: $query?.[0].start instanceof Date | ||||||
? dateToYYYYMMDD($query?.[0].start) | ||||||
: dateToYYYYMMDD(new Date(0)); | ||||||
$: endString = | ||||||
typeof end === 'string' && YYYYMMDD.test(end) | ||||||
? end | ||||||
: end instanceof Date | ||||||
? dateToYYYYMMDD(end) | ||||||
: $query?.[0].end instanceof Date | ||||||
? dateToYYYYMMDD($query?.[0].end) | ||||||
: dateToYYYYMMDD(new Date()); | ||||||
|
||||||
$: if ((query && $query.dataLoaded) || !query) { | ||||||
if (range) { | ||||||
$inputs[name] = { value: undefined, start: startString, end: endString }; | ||||||
} else { | ||||||
$inputs[name] = { value: startString, start: startString, end: undefined }; | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Should we set There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Also I'd prefer to omit the undefined props rather than giving them the value of undefined There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This was my suggestion My initial thought was start is probably worth keeping honestly, probably should remove now I think about it you are likely going to have to change the SQL anyway from |
||||||
} | ||||||
} | ||||||
|
||||||
let currentDate = dateToYYYYMMDD(new Date(Date.now())); | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
|
||||||
let selectedDateInput; | ||||||
$: if (selectedDateInput && (selectedDateInput.start || selectedDateInput.end) && range) { | ||||||
$inputs[name] = { | ||||||
value: undefined, | ||||||
start: dateToYYYYMMDD(selectedDateInput.start?.toDate(getLocalTimeZone()) ?? new Date(0)), | ||||||
end: dateToYYYYMMDD(selectedDateInput.end?.toDate(getLocalTimeZone()) ?? new Date()) | ||||||
}; | ||||||
} else if (selectedDateInput && selectedDateInput && !range) { | ||||||
$inputs[name] = { | ||||||
value: dateToYYYYMMDD(selectedDateInput.toDate(getLocalTimeZone()) ?? new Date(0)), | ||||||
start: dateToYYYYMMDD(selectedDateInput.toDate(getLocalTimeZone()) ?? new Date(0)), | ||||||
end: undefined | ||||||
}; | ||||||
} | ||||||
</script> | ||||||
|
||||||
<HiddenInPrint enabled={hideDuringPrint}> | ||||||
<div class="mt-2 mb-4 ml-0 mr-2 inline-block"> | ||||||
{#if title && range} | ||||||
<span class="text-sm text-gray-500 block mb-1">{title}</span> | ||||||
{/if} | ||||||
|
||||||
{#if $query?.error} | ||||||
<span | ||||||
class="group inline-flex items-center relative cursor-help cursor-helpfont-sans px-1 border border-red-200 py-[1px] bg-red-50 rounded" | ||||||
> | ||||||
<span class="inline font-sans font-medium text-xs text-red-600">error</span> | ||||||
<span | ||||||
class="hidden text-white font-sans group-hover:inline absolute -top-1 left-[105%] text-sm z-10 px-2 py-1 bg-gray-800/80 leading-relaxed min-w-[150px] w-max max-w-[400px] rounded-md" | ||||||
> | ||||||
{$query.error} | ||||||
</span> | ||||||
</span> | ||||||
{:else} | ||||||
<QueryLoad data={query} let:loaded> | ||||||
<svelte:fragment slot="skeleton"> | ||||||
<Skeleton class="h-8 w-72" /> | ||||||
</svelte:fragment> | ||||||
<DateInput | ||||||
bind:selectedDateInput | ||||||
start={startString} | ||||||
end={endString} | ||||||
loaded={loaded?.ready ?? true} | ||||||
{presetRanges} | ||||||
{defaultValue} | ||||||
{range} | ||||||
{currentDate} | ||||||
{title} | ||||||
/> | ||||||
</QueryLoad> | ||||||
{/if} | ||||||
</div> | ||||||
</HiddenInPrint> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does this persist after you switch to another story?
Would probably be good to reset it