From 250587ea37bcf3967c6ccfc1b70e41dd4b86a556 Mon Sep 17 00:00:00 2001 From: Fabian Engelniederhammer <92720311+fengelniederhammer@users.noreply.github.com> Date: Tue, 4 Feb 2025 09:41:32 +0100 Subject: [PATCH] feat(components): gs-date-range-selector: make the component controllable from a surrounding JS app (#710) BREAKING CHANGE: gs-date-range-selector: remove `initialValue`, `initialDateFrom`, `initialDateTo`. Use `value` instead. resolves #683 --- components/.storybook-preact/preview.ts | 4 + .../computeInitialValues.spec.ts | 54 +++++++----- .../dateRangeSelector/computeInitialValues.ts | 46 +++++----- .../date-range-selector.stories.tsx | 87 ++++++++++++++++--- .../dateRangeSelector/date-range-selector.tsx | 49 ++++++----- .../dateRangeSelector/dateRangeOption.ts | 12 ++- .../input/gs-date-range-selector.stories.ts | 17 ++-- .../input/gs-date-range-selector.tsx | 53 ++++------- examples/React/src/App.tsx | 2 +- examples/plainJavascript/index.html | 2 +- 10 files changed, 201 insertions(+), 125 deletions(-) diff --git a/components/.storybook-preact/preview.ts b/components/.storybook-preact/preview.ts index 7d565959..15851014 100644 --- a/components/.storybook-preact/preview.ts +++ b/components/.storybook-preact/preview.ts @@ -1,4 +1,5 @@ import type { Preview } from '@storybook/preact'; +import { clearAllMocks } from '@storybook/test'; import '../src/styles/tailwind.css'; import { withActions } from '@storybook/addon-actions/decorator'; @@ -15,6 +16,9 @@ const preview: Preview = { actions: { handles: [GS_ERROR_EVENT_TYPE] }, }, decorators: [withActions], + beforeEach: () => { + clearAllMocks(); + }, }; export default preview; diff --git a/components/src/preact/dateRangeSelector/computeInitialValues.spec.ts b/components/src/preact/dateRangeSelector/computeInitialValues.spec.ts index 74e85b49..a087a0de 100644 --- a/components/src/preact/dateRangeSelector/computeInitialValues.spec.ts +++ b/components/src/preact/dateRangeSelector/computeInitialValues.spec.ts @@ -18,8 +18,8 @@ const dateRangeOptions = [ ]; describe('computeInitialValues', () => { - it('should compute for initial value if initial "from" and "to" are unset', () => { - const result = computeInitialValues(fromToOption, undefined, undefined, earliestDate, dateRangeOptions); + it('should compute initial value if value is dateRangeOption label', () => { + const result = computeInitialValues(fromToOption, earliestDate, dateRangeOptions); expect(result.initialSelectedDateRange).toEqual(fromToOption); expectDateMatches(result.initialSelectedDateFrom, new Date(dateFromOptionValue)); @@ -27,7 +27,7 @@ describe('computeInitialValues', () => { }); it('should use today as "dateTo" if it is unset in selected option', () => { - const result = computeInitialValues(fromOption, undefined, undefined, earliestDate, dateRangeOptions); + const result = computeInitialValues(fromOption, earliestDate, dateRangeOptions); expect(result.initialSelectedDateRange).toEqual(fromOption); expectDateMatches(result.initialSelectedDateFrom, new Date(dateFromOptionValue)); @@ -35,7 +35,7 @@ describe('computeInitialValues', () => { }); it('should use earliest date as "dateFrom" if it is unset in selected option', () => { - const result = computeInitialValues(toOption, undefined, undefined, earliestDate, dateRangeOptions); + const result = computeInitialValues(toOption, earliestDate, dateRangeOptions); expect(result.initialSelectedDateRange).toEqual(toOption); expectDateMatches(result.initialSelectedDateFrom, new Date(earliestDate)); @@ -43,7 +43,7 @@ describe('computeInitialValues', () => { }); it('should fall back to full range if initial value is not set', () => { - const result = computeInitialValues(undefined, undefined, undefined, earliestDate, dateRangeOptions); + const result = computeInitialValues(undefined, earliestDate, dateRangeOptions); expect(result.initialSelectedDateRange).toBeUndefined(); expectDateMatches(result.initialSelectedDateFrom, new Date(earliestDate)); @@ -51,39 +51,46 @@ describe('computeInitialValues', () => { }); it('should throw when initial value is unknown', () => { - expect(() => - computeInitialValues('not a known value', undefined, undefined, earliestDate, dateRangeOptions), - ).toThrowError(/Invalid initialValue "not a known value", It must be one of/); + expect(() => computeInitialValues('not a known value', earliestDate, dateRangeOptions)).toThrowError( + /Invalid value "not a known value", It must be one of/, + ); }); it('should throw when initial value is set but no options are provided', () => { - expect(() => computeInitialValues('not a known value', undefined, undefined, earliestDate, [])).toThrowError( + expect(() => computeInitialValues('not a known value', earliestDate, [])).toThrowError( /There are no selectable options/, ); }); - it('should overwrite initial value if initial "from" is set', () => { + it('should select from date until today if only dateFrom is given', () => { const initialDateFrom = '2020-01-01'; - const result = computeInitialValues(fromOption, initialDateFrom, undefined, earliestDate, dateRangeOptions); + const result = computeInitialValues({ dateFrom: initialDateFrom }, earliestDate, dateRangeOptions); expect(result.initialSelectedDateRange).toBeUndefined(); expectDateMatches(result.initialSelectedDateFrom, new Date(initialDateFrom)); expectDateMatches(result.initialSelectedDateTo, today); }); - it('should overwrite initial value if initial "to" is set', () => { + it('should select from earliest date until date if only dateTo is given', () => { const initialDateTo = '2020-01-01'; - const result = computeInitialValues(fromOption, undefined, initialDateTo, earliestDate, dateRangeOptions); + const result = computeInitialValues({ dateTo: initialDateTo }, earliestDate, dateRangeOptions); expect(result.initialSelectedDateRange).toBeUndefined(); expectDateMatches(result.initialSelectedDateFrom, new Date(earliestDate)); expectDateMatches(result.initialSelectedDateTo, new Date(initialDateTo)); }); - it('should overwrite initial value if initial "to" and "from" are set', () => { + it('should select date range is dateFrom and dateTo are given', () => { const initialDateFrom = '2020-01-01'; const initialDateTo = '2022-01-01'; - const result = computeInitialValues(fromOption, initialDateFrom, initialDateTo, earliestDate, dateRangeOptions); + const result = computeInitialValues( + { + dateFrom: initialDateFrom, + dateTo: initialDateTo, + }, + earliestDate, + dateRangeOptions, + ); expect(result.initialSelectedDateRange).toBeUndefined(); expectDateMatches(result.initialSelectedDateFrom, new Date(initialDateFrom)); @@ -93,7 +100,14 @@ describe('computeInitialValues', () => { it('should set initial "to" to "from" if "from" is after "to"', () => { const initialDateFrom = '2020-01-01'; const initialDateTo = '1900-01-01'; - const result = computeInitialValues(undefined, initialDateFrom, initialDateTo, earliestDate, dateRangeOptions); + const result = computeInitialValues( + { + dateFrom: initialDateFrom, + dateTo: initialDateTo, + }, + earliestDate, + dateRangeOptions, + ); expect(result.initialSelectedDateRange).toBeUndefined(); expectDateMatches(result.initialSelectedDateFrom, new Date(initialDateFrom)); @@ -101,14 +115,14 @@ describe('computeInitialValues', () => { }); it('should throw if initial "from" is not a valid date', () => { - expect(() => computeInitialValues(undefined, 'not a date', undefined, earliestDate, [])).toThrowError( - 'Invalid initialDateFrom', + expect(() => computeInitialValues({ dateFrom: 'not a date' }, earliestDate, [])).toThrowError( + 'Invalid value.dateFrom', ); }); it('should throw if initial "to" is not a valid date', () => { - expect(() => computeInitialValues(undefined, undefined, 'not a date', earliestDate, [])).toThrowError( - 'Invalid initialDateTo', + expect(() => computeInitialValues({ dateTo: 'not a date' }, earliestDate, [])).toThrowError( + 'Invalid value.dateTo', ); }); diff --git a/components/src/preact/dateRangeSelector/computeInitialValues.ts b/components/src/preact/dateRangeSelector/computeInitialValues.ts index d3d70c2b..e679f060 100644 --- a/components/src/preact/dateRangeSelector/computeInitialValues.ts +++ b/components/src/preact/dateRangeSelector/computeInitialValues.ts @@ -1,11 +1,9 @@ -import { type DateRangeOption } from './dateRangeOption'; +import { type DateRangeOption, type DateRangeValue } from './dateRangeOption'; import { getDatesForSelectorValue, getSelectableOptions } from './selectableOptions'; import { UserFacingError } from '../components/error-display'; export function computeInitialValues( - initialValue: string | undefined, - initialDateFrom: string | undefined, - initialDateTo: string | undefined, + value: DateRangeValue | undefined, earliestDate: string, dateRangeOptions: DateRangeOption[], ): { @@ -13,20 +11,26 @@ export function computeInitialValues( initialSelectedDateFrom: Date; initialSelectedDateTo: Date; } { - if (isUndefinedOrEmpty(initialDateFrom) && isUndefinedOrEmpty(initialDateTo)) { + if (value === undefined) { + const { dateFrom, dateTo } = getDatesForSelectorValue(undefined, dateRangeOptions, earliestDate); + return { + initialSelectedDateRange: undefined, + initialSelectedDateFrom: dateFrom, + initialSelectedDateTo: dateTo, + }; + } + + if (typeof value === 'string') { const selectableOptions = getSelectableOptions(dateRangeOptions); - const initialSelectedDateRange = selectableOptions.find((option) => option.value === initialValue)?.value; + const initialSelectedDateRange = selectableOptions.find((option) => option.value === value)?.value; - if (initialValue !== undefined && initialSelectedDateRange === undefined) { + if (initialSelectedDateRange === undefined) { if (selectableOptions.length === 0) { - throw new UserFacingError( - 'Invalid initialValue', - 'There are no selectable options, but initialValue is set.', - ); + throw new UserFacingError('Invalid value', 'There are no selectable options, but value is set.'); } throw new UserFacingError( - 'Invalid initialValue', - `Invalid initialValue "${initialValue}", It must be one of ${selectableOptions.map((option) => `'${option.value}'`).join(', ')}`, + 'Invalid value', + `Invalid value "${value}", It must be one of ${selectableOptions.map((option) => `'${option.value}'`).join(', ')}`, ); } @@ -39,21 +43,21 @@ export function computeInitialValues( }; } - const initialSelectedDateFrom = isUndefinedOrEmpty(initialDateFrom) - ? new Date(earliestDate) - : new Date(initialDateFrom); - let initialSelectedDateTo = isUndefinedOrEmpty(initialDateTo) ? new Date() : new Date(initialDateTo); + const { dateFrom, dateTo } = value; + + const initialSelectedDateFrom = isUndefinedOrEmpty(dateFrom) ? new Date(earliestDate) : new Date(dateFrom); + let initialSelectedDateTo = isUndefinedOrEmpty(dateTo) ? new Date() : new Date(dateTo); if (isNaN(initialSelectedDateFrom.getTime())) { throw new UserFacingError( - 'Invalid initialDateFrom', - `Invalid initialDateFrom "${initialDateFrom}", It must be of the format YYYY-MM-DD`, + 'Invalid value.dateFrom', + `Invalid value.dateFrom "${dateFrom}", It must be of the format YYYY-MM-DD`, ); } if (isNaN(initialSelectedDateTo.getTime())) { throw new UserFacingError( - 'Invalid initialDateTo', - `Invalid initialDateTo "${initialDateTo}", It must be of the format YYYY-MM-DD`, + 'Invalid value.dateTo', + `Invalid value.dateTo "${dateTo}", It must be of the format YYYY-MM-DD`, ); } diff --git a/components/src/preact/dateRangeSelector/date-range-selector.stories.tsx b/components/src/preact/dateRangeSelector/date-range-selector.stories.tsx index 754fc02f..eaf6804a 100644 --- a/components/src/preact/dateRangeSelector/date-range-selector.stories.tsx +++ b/components/src/preact/dateRangeSelector/date-range-selector.stories.tsx @@ -2,6 +2,7 @@ import { type Meta, type PreactRenderer, type StoryObj } from '@storybook/preact import { expect, fn, userEvent, waitFor, within } from '@storybook/test'; import type { StepFunction } from '@storybook/types'; import dayjs from 'dayjs/esm'; +import { useEffect, useRef, useState } from 'preact/hooks'; import { DateRangeSelector, type DateRangeSelectorProps } from './date-range-selector'; import { previewHandles } from '../../../.storybook/preview'; @@ -28,11 +29,10 @@ const meta: Meta = { fetchMock: {}, }, argTypes: { - initialValue: { + value: { control: { - type: 'select', + type: 'object', }, - options: [dateRangeOptionPresets.lastMonth.label, dateRangeOptionPresets.allTimes.label, 'CustomDateRange'], }, dateRangeOptions: { control: { @@ -53,11 +53,9 @@ const meta: Meta = { args: { dateRangeOptions: [dateRangeOptionPresets.lastMonth, dateRangeOptionPresets.allTimes, customDateRange], earliestDate, - initialValue: dateRangeOptionPresets.lastMonth.label, + value: undefined, lapisDateField: 'aDateColumn', width: '100%', - initialDateFrom: undefined, - initialDateTo: undefined, }, }; @@ -75,7 +73,7 @@ export const SetCorrectInitialValues: StoryObj = { ...Primary, args: { ...Primary.args, - initialValue: 'CustomDateRange', + value: 'CustomDateRange', }, play: async ({ canvasElement }) => { const canvas = within(canvasElement); @@ -94,7 +92,7 @@ export const SetCorrectInitialDateFrom: StoryObj = { ...Primary, args: { ...Primary.args, - initialDateFrom, + value: { dateFrom: initialDateFrom }, }, play: async ({ canvasElement }) => { const canvas = within(canvasElement); @@ -113,7 +111,7 @@ export const SetCorrectInitialDateTo: StoryObj = { ...Primary, args: { ...Primary.args, - initialDateTo, + value: { dateTo: initialDateTo }, }, play: async ({ canvasElement }) => { const canvas = within(canvasElement); @@ -128,6 +126,10 @@ export const SetCorrectInitialDateTo: StoryObj = { export const ChangingDateSetsOptionToCustom: StoryObj = { ...Primary, + args: { + ...Primary.args, + value: dateRangeOptionPresets.lastMonth.label, + }, play: async ({ canvasElement, step }) => { const { canvas, filterChangedListenerMock, optionChangedListenerMock } = await prepare(canvasElement, step); @@ -165,8 +167,36 @@ export const ChangingDateSetsOptionToCustom: StoryObj = }, }; -export const ChangingDateOption: StoryObj = { +export const ChangingTheValueProgrammatically: StoryObj = { ...Primary, + render: (args) => { + const StatefulWrapper = () => { + const [value, setValue] = useState('Last month'); + const ref = useRef(null); + + useEffect(() => { + ref.current?.addEventListener('gs-date-range-option-changed', (event) => { + setValue((event as CustomEvent).detail); + }); + }, []); + + return ( +
+ + + + + +
+ ); + }; + + return ; + }, play: async ({ canvasElement, step }) => { const { canvas, filterChangedListenerMock, optionChangedListenerMock } = await prepare(canvasElement, step); @@ -174,6 +204,41 @@ export const ChangingDateOption: StoryObj = { await expect(selectField(canvas)).toHaveValue('Last month'); }); + await step('Change the value of the component programmatically', async () => { + await userEvent.click(canvas.getByRole('button', { name: 'Set to Custom' })); + await waitFor(async () => { + await expect(selectField(canvas)).toHaveValue(customDateRange.label); + }); + + await userEvent.click(canvas.getByRole('button', { name: 'Set to Last month' })); + await waitFor(async () => { + await expect(selectField(canvas)).toHaveValue('Last month'); + }); + + await expect(filterChangedListenerMock).toHaveBeenCalledTimes(0); + await expect(optionChangedListenerMock).toHaveBeenCalledTimes(0); + }); + + await step('Changing the value from within the component is still possible', async () => { + await userEvent.selectOptions(selectField(canvas), 'All times'); + await waitFor(async () => { + await expect(selectField(canvas)).toHaveValue('All times'); + }); + await expect(filterChangedListenerMock).toHaveBeenCalledTimes(1); + await expect(optionChangedListenerMock).toHaveBeenCalledTimes(1); + }); + }, +}; + +export const ChangingDateOption: StoryObj = { + ...Primary, + play: async ({ canvasElement, step }) => { + const { canvas, filterChangedListenerMock, optionChangedListenerMock } = await prepare(canvasElement, step); + + await waitFor(async () => { + await expect(selectField(canvas)).toHaveValue('Custom'); + }); + await step('Change date to custom', async () => { await userEvent.selectOptions(selectField(canvas), 'CustomDateRange'); @@ -203,7 +268,7 @@ export const HandlesInvalidInitialDateFrom: StoryObj = { ...Primary, args: { ...Primary.args, - initialDateFrom: 'not a date', + value: { dateFrom: 'not a date' }, }, play: async ({ canvasElement }) => { const canvas = within(canvasElement); diff --git a/components/src/preact/dateRangeSelector/date-range-selector.tsx b/components/src/preact/dateRangeSelector/date-range-selector.tsx index b7878f68..1e87a66f 100644 --- a/components/src/preact/dateRangeSelector/date-range-selector.tsx +++ b/components/src/preact/dateRangeSelector/date-range-selector.tsx @@ -1,11 +1,16 @@ import flatpickr from 'flatpickr'; import 'flatpickr/dist/flatpickr.min.css'; -import { useEffect, useRef, useState } from 'preact/hooks'; +import { useEffect, useMemo, useRef, useState } from 'preact/hooks'; import z from 'zod'; import { computeInitialValues } from './computeInitialValues'; import { toYYYYMMDD } from './dateConversion'; -import { DateRangeOptionChangedEvent, dateRangeOptionSchema, type DateRangeSelectOption } from './dateRangeOption'; +import { + DateRangeOptionChangedEvent, + dateRangeOptionSchema, + type DateRangeSelectOption, + dateRangeValueSchema, +} from './dateRangeOption'; import { getDatesForSelectorValue, getSelectableOptions } from './selectableOptions'; import { ErrorBoundary } from '../components/error-boundary'; import { Select } from '../components/select'; @@ -16,9 +21,7 @@ const customOption = 'Custom'; const dateRangeSelectorInnerPropsSchema = z.object({ dateRangeOptions: z.array(dateRangeOptionSchema), earliestDate: z.string().date(), - initialValue: z.string().optional(), - initialDateFrom: z.string().date().optional(), - initialDateTo: z.string().date().optional(), + value: dateRangeValueSchema.optional(), lapisDateField: z.string().min(1), }); @@ -45,17 +48,12 @@ export const DateRangeSelector = (props: DateRangeSelectorProps) => { export const DateRangeSelectorInner = ({ dateRangeOptions, earliestDate = '1900-01-01', - initialValue, + value, lapisDateField, - initialDateFrom, - initialDateTo, }: DateRangeSelectorInnerProps) => { - const initialValues = computeInitialValues( - initialValue, - initialDateFrom, - initialDateTo, - earliestDate, - dateRangeOptions, + const initialValues = useMemo( + () => computeInitialValues(value, earliestDate, dateRangeOptions), + [value, earliestDate, dateRangeOptions], ); const fromDatePickerRef = useRef(null); @@ -74,6 +72,12 @@ export const DateRangeSelectorInner = ({ }); useEffect(() => { + setSelectedDateRange(initialValues.initialSelectedDateRange); + setSelectedDates({ + dateFrom: initialValues.initialSelectedDateFrom, + dateTo: initialValues.initialSelectedDateTo, + }); + const commonConfig = { allowInput: true, dateFormat: 'Y-m-d', @@ -83,7 +87,7 @@ export const DateRangeSelectorInner = ({ setDateFromPicker( flatpickr(fromDatePickerRef.current, { ...commonConfig, - defaultDate: selectedDates.dateFrom, + defaultDate: initialValues.initialSelectedDateFrom, }), ); } @@ -92,17 +96,22 @@ export const DateRangeSelectorInner = ({ setDateToPicker( flatpickr(toDatePickerRef.current, { ...commonConfig, - defaultDate: selectedDates.dateTo, + defaultDate: initialValues.initialSelectedDateTo, }), ); } return () => { - dateFromPicker?.destroy(); - dateToPicker?.destroy(); + setDateFromPicker((prev) => { + prev?.destroy(); + return null; + }); + setDateToPicker((prev) => { + prev?.destroy(); + return null; + }); }; - // eslint-disable-next-line react-hooks/exhaustive-deps - }, [fromDatePickerRef, toDatePickerRef]); + }, [fromDatePickerRef, toDatePickerRef, initialValues]); const onSelectChange = (value: string) => { setSelectedDateRange(value); diff --git a/components/src/preact/dateRangeSelector/dateRangeOption.ts b/components/src/preact/dateRangeSelector/dateRangeOption.ts index fa93f657..9583b0bf 100644 --- a/components/src/preact/dateRangeSelector/dateRangeOption.ts +++ b/components/src/preact/dateRangeSelector/dateRangeOption.ts @@ -22,7 +22,17 @@ export const dateRangeOptionSchema = z.object({ export type DateRangeOption = z.infer; -export type DateRangeSelectOption = string | { dateFrom: string; dateTo: string }; +export const dateRangeValueSchema = z.union([ + z.string(), + z.object({ + dateFrom: z.string().date().optional(), + dateTo: z.string().date().optional(), + }), +]); + +export type DateRangeValue = z.infer; + +export type DateRangeSelectOption = Required; export class DateRangeOptionChangedEvent extends CustomEvent { constructor(detail: DateRangeSelectOption) { diff --git a/components/src/web-components/input/gs-date-range-selector.stories.ts b/components/src/web-components/input/gs-date-range-selector.stories.ts index dc4b2a8f..2ab0f796 100644 --- a/components/src/web-components/input/gs-date-range-selector.stories.ts +++ b/components/src/web-components/input/gs-date-range-selector.stories.ts @@ -16,9 +16,7 @@ const codeExample = String.raw` `; @@ -40,11 +38,10 @@ const meta: Meta> = { }, }), argTypes: { - initialValue: { + value: { control: { - type: 'select', + type: 'object', }, - options: [dateRangeOptionPresets.lastMonth.label, dateRangeOptionPresets.allTimes.label, 'CustomDateRange'], }, lapisDateField: { control: { type: 'text' } }, dateRangeOptions: { @@ -71,11 +68,9 @@ const meta: Meta> = { customDateRange, ], earliestDate: '1970-01-01', - initialValue: dateRangeOptionPresets.lastMonth.label, + value: dateRangeOptionPresets.lastMonth.label, lapisDateField: 'aDateColumn', width: '100%', - initialDateFrom: undefined, - initialDateTo: undefined, }, tags: ['autodocs'], }; @@ -89,9 +84,7 @@ export const Default: StoryObj> = { diff --git a/components/src/web-components/input/gs-date-range-selector.tsx b/components/src/web-components/input/gs-date-range-selector.tsx index 750066f9..6e1e4f7f 100644 --- a/components/src/web-components/input/gs-date-range-selector.tsx +++ b/components/src/web-components/input/gs-date-range-selector.tsx @@ -46,15 +46,18 @@ import { PreactLitAdapter } from '../PreactLitAdapter'; * Contains the selected dateRangeOption or when users select custom values it contains the selected dates. * * Use this event, when you want to control this component in your JS application. + * You can supply the `detail` of this event to the `value` attribute of this component. */ @customElement('gs-date-range-selector') export class DateRangeSelectorComponent extends PreactLitAdapter { /** * An array of date range options that the select field should provide. - * The `label` will be shown to the user, and it will be available as `initialValue`. + * The `label` will be shown to the user, and it will be available as `value`. * The dates must be in the format `YYYY-MM-DD`. * * If dateFrom or dateTo is not set, the component will default to the `earliestDate` or the current date. + * + * We provide some options in `dateRangeOptionPresets` for convenience. */ @property({ type: Array }) dateRangeOptions: { label: string; dateFrom?: string; dateTo?: string }[] = []; @@ -66,33 +69,17 @@ export class DateRangeSelectorComponent extends PreactLitAdapter { earliestDate: string = '1900-01-01'; /** - * The initial value to use for this date range selector. - * Must be a valid label from the `dateRangeOptions`. - * - * If the value is not set, the component will default to the range `earliestDate` until today. - * - * It will be overwritten if `initialDateFrom` or `initialDateTo` is set. + * The value to use for this date range selector. + * - If it is a string, then it must be a valid label from the `dateRangeOptions`. + * - If it is an object, then it accepts dates in the format `YYYY-MM-DD` for the keys `dateFrom` and `dateTo`. + * Keys that are not set will default to the `earliestDate` or the current date respectively. + * - If the attribute is not set, the component will default to the range `earliestDate` until today. * - * We provide some options in `dateRangeOptionPresets` for convenience. - */ - @property() - initialValue: string | undefined = undefined; - - /** - * A date string in the format `YYYY-MM-DD`. - * If set, the date range selector will be initialized with the given date (overwriting `initialValue` to `custom`). - * If `initialDateTo` is set, but this is unset, it will default to `earliestDate`. - */ - @property() - initialDateFrom: string | undefined = undefined; - - /** - * A date string in the format `YYYY-MM-DD`. - * If set, the date range selector will be initialized with the given date (overwriting `initialValue` to `custom`). - * If `initialDateFrom` is set, but this is unset, it will default to the current date. + * The `detail` of the `gs-date-range-option-changed` event can be used for this attribute, + * if you want to control this component in your JS application. */ - @property() - initialDateTo: string | undefined = undefined; + @property({ type: Object }) + value: string | { dateFrom?: string; dateTo?: string } | undefined = undefined; /** * The width of the component. @@ -113,9 +100,7 @@ export class DateRangeSelectorComponent extends PreactLitAdapter { @@ -150,15 +135,7 @@ type CustomSelectOptionsMatches = Expect< type EarliestDateMatches = Expect< Equals >; -type InitialValueMatches = Expect< - Equals ->; -type InitialDateFromMatches = Expect< - Equals ->; -type InitialDateToMatches = Expect< - Equals ->; +type ValueMatches = Expect>; type WidthMatches = Expect>; type DateColumnMatches = Expect< Equals diff --git a/examples/React/src/App.tsx b/examples/React/src/App.tsx index b8cb99de..189f0da2 100644 --- a/examples/React/src/App.tsx +++ b/examples/React/src/App.tsx @@ -76,7 +76,7 @@ function App() { >
diff --git a/examples/plainJavascript/index.html b/examples/plainJavascript/index.html index 535dda4a..a01c6371 100644 --- a/examples/plainJavascript/index.html +++ b/examples/plainJavascript/index.html @@ -22,7 +22,7 @@ >