From 2b2b3290e8b378d1e124563ee66a8fe8b97c736e Mon Sep 17 00:00:00 2001 From: Lungan Catalin <98550729+Cata1989@users.noreply.github.com> Date: Fri, 7 Jun 2024 17:50:49 +0300 Subject: [PATCH] fix(Date Picker): clear incomplete range selection (#1074) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Dabiel González Ramos --- package-lock.json | 22 +-- packages/beeq/package.json | 2 +- packages/beeq/src/components.d.ts | 16 +- .../_storybook/bq-date-picker.stories.tsx | 7 +- .../components/date-picker/bq-date-picker.tsx | 167 ++++++++++++------ .../beeq/src/components/date-picker/readme.md | 120 ++++++------- packages/beeq/src/global/scripts/global.ts | 8 +- 7 files changed, 208 insertions(+), 134 deletions(-) diff --git a/package-lock.json b/package-lock.json index 618f8e8e3..67db16dd5 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "beeq", - "version": "1.5.0", + "version": "1.5.1", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "beeq", - "version": "1.5.0", + "version": "1.5.1", "hasInstallScript": true, "license": "Apache-2.0", "workspaces": [ @@ -18342,9 +18342,9 @@ } }, "node_modules/cally": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/cally/-/cally-0.6.1.tgz", - "integrity": "sha512-Tt9qS5JlCrfPLIyy81gKaBlf6SArav77OZBu4rCjSYRXPz3VQMmyQ463a1ktUb6/MMHThqEM0Pmjjr5k/byVgg==", + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/cally/-/cally-0.7.1.tgz", + "integrity": "sha512-pMWInVWdwuQMmXvGQfPVECHRLnQgtwJ4Ya+dIU4D+7I4AQIR7nsVON0cOi4paioNzvtSuu/HiUr22RQOcmiqxA==", "license": "MIT", "dependencies": { "atomico": "^1.76.1" @@ -45184,18 +45184,18 @@ }, "packages/beeq": { "name": "@beeq/core", - "version": "1.5.0", + "version": "1.5.1", "license": "Apache-2.0", "dependencies": { "@floating-ui/core": "^1.6.2", "@floating-ui/dom": "^1.6.5", "@stencil/core": "^4.18.3", - "cally": "0.6.1" + "cally": "0.7.1" } }, "packages/beeq-angular": { "name": "@beeq/angular", - "version": "1.5.0", + "version": "1.5.1", "license": "Apache-2.0", "dependencies": { "@beeq/core": "^1.4.0", @@ -45208,7 +45208,7 @@ }, "packages/beeq-react": { "name": "@beeq/react", - "version": "1.5.0", + "version": "1.5.1", "license": "Apache-2.0", "dependencies": { "@beeq/core": "^1.4.0" @@ -45221,7 +45221,7 @@ }, "packages/beeq-tailwindcss": { "name": "@beeq/tailwindcss", - "version": "1.5.0", + "version": "1.5.1", "license": "Apache-2.0", "peerDependencies": { "tailwindcss": "^3.4.3", @@ -45230,7 +45230,7 @@ }, "packages/beeq-vue": { "name": "@beeq/vue", - "version": "1.5.0", + "version": "1.5.1", "license": "Apache-2.0", "dependencies": { "@beeq/core": "^1.4.0", diff --git a/packages/beeq/package.json b/packages/beeq/package.json index aa5937677..d7a660567 100644 --- a/packages/beeq/package.json +++ b/packages/beeq/package.json @@ -16,7 +16,7 @@ "@floating-ui/core": "^1.6.2", "@floating-ui/dom": "^1.6.5", "@stencil/core": "^4.18.3", - "cally": "0.6.1" + "cally": "0.7.1" }, "repository": { "type": "git", diff --git a/packages/beeq/src/components.d.ts b/packages/beeq/src/components.d.ts index 21f4aa26f..f0fcab37f 100644 --- a/packages/beeq/src/components.d.ts +++ b/packages/beeq/src/components.d.ts @@ -383,9 +383,9 @@ export namespace Components { */ "months": number; /** - * The number of months to display per page when using next/previous buttons. + * Specifies how the next/previous buttons should navigate the calendar. - single: The buttons will navigate by a single month at a time. - months: The buttons will navigate by the number of months displayed per view. */ - "monthsPerView": number; + "monthsPerView": 'single' | 'months'; /** * The Date picker input name. */ @@ -422,6 +422,10 @@ export namespace Components { * Defines the strategy to position the Date picker panel */ "strategy"?: 'fixed' | 'absolute'; + /** + * The date that is tentatively selected e.g. the start of a range selection + */ + "tentative"?: string; /** * It defines how the calendar will behave, allowing single date selection, range selection, or multiple date selection */ @@ -2622,9 +2626,9 @@ declare namespace LocalJSX { */ "months"?: number; /** - * The number of months to display per page when using next/previous buttons. + * Specifies how the next/previous buttons should navigate the calendar. - single: The buttons will navigate by a single month at a time. - months: The buttons will navigate by the number of months displayed per view. */ - "monthsPerView"?: number; + "monthsPerView"?: 'single' | 'months'; /** * The Date picker input name. */ @@ -2677,6 +2681,10 @@ declare namespace LocalJSX { * Defines the strategy to position the Date picker panel */ "strategy"?: 'fixed' | 'absolute'; + /** + * The date that is tentatively selected e.g. the start of a range selection + */ + "tentative"?: string; /** * It defines how the calendar will behave, allowing single date selection, range selection, or multiple date selection */ diff --git a/packages/beeq/src/components/date-picker/_storybook/bq-date-picker.stories.tsx b/packages/beeq/src/components/date-picker/_storybook/bq-date-picker.stories.tsx index 5114cdb22..860fd5547 100644 --- a/packages/beeq/src/components/date-picker/_storybook/bq-date-picker.stories.tsx +++ b/packages/beeq/src/components/date-picker/_storybook/bq-date-picker.stories.tsx @@ -27,7 +27,7 @@ const meta: Meta = { max: { control: 'text' }, min: { control: 'text' }, months: { control: 'number' }, - 'months-per-view': { control: 'number' }, + 'months-per-view': { control: 'select', options: ['single', 'months'] }, name: { control: 'text' }, open: { control: 'boolean' }, 'panel-height': { control: 'text' }, @@ -53,6 +53,7 @@ const meta: Meta = { 'show-outside-days': { control: 'boolean' }, skidding: { control: 'number' }, strategy: { control: 'select', options: ['fixed', 'absolute'] }, + tentative: { control: 'text' }, type: { control: 'select', options: [...DATE_PICKER_TYPE] }, 'validation-status': { control: 'select', options: [...INPUT_VALIDATION] }, value: { control: 'text' }, @@ -85,7 +86,7 @@ const meta: Meta = { max: undefined, min: undefined, months: 1, - 'months-per-view': 1, + 'months-per-view': 'single', name: 'bq-date-picker', open: false, 'panel-height': 'auto', @@ -95,6 +96,7 @@ const meta: Meta = { 'show-outside-days': false, skidding: 0, strategy: 'absolute', + tentative: undefined, type: 'single', 'validation-status': 'none', value: undefined, @@ -177,6 +179,7 @@ const Template = (args: Args) => { show-outside-days=${args['show-outside-days']} skidding=${args.skidding} strategy=${args.strategy} + tentative=${args.tentative} type=${args.type} validation-status=${args['validation-status']} value=${ifDefined(args.value)} diff --git a/packages/beeq/src/components/date-picker/bq-date-picker.tsx b/packages/beeq/src/components/date-picker/bq-date-picker.tsx index 8af188512..e3f5f31c4 100644 --- a/packages/beeq/src/components/date-picker/bq-date-picker.tsx +++ b/packages/beeq/src/components/date-picker/bq-date-picker.tsx @@ -1,8 +1,15 @@ import { Component, Element, Event, EventEmitter, h, Listen, Method, Prop, State, Watch } from '@stencil/core'; +import { CalendarDate } from 'cally'; import { DATE_PICKER_TYPE, DaysOfWeek, TDatePickerType } from './bq-date-picker.types'; import { FloatingUIPlacement } from '../../services/interfaces'; -import { hasSlotContent, isDefined, isHTMLElement, validatePropValue } from '../../shared/utils'; +import { + hasSlotContent, + isDefined, + isEventTargetChildOfElement, + isHTMLElement, + validatePropValue, +} from '../../shared/utils'; import { TInputValidation } from '../input/bq-input.types'; /** @@ -17,31 +24,31 @@ import { TInputValidation } from '../input/bq-input.types'; * @part suffix - The suffix slot container. // Parts from the Cally library for calendar-date and calendar-range components: - * @part container - The container for the entire component. - * @part header - The container for heading and button's. - * @part button - Any button within the component. - * @part previous - The previous page button. - * @part next - The next page button. - * @part disabled - A button that is disabled due to min/max. - * @part heading - The heading containing the month and year. + * @part calendar__container - The container for the entire component. + * @part calendar__header - The container for heading and button's. + * @part calendar__button - Any button within the component. + * @part calendar__previous - The previous page button. + * @part calendar__next - The next page button. + * @part calendar__disabled - A button that is disabled due to min/max. + * @part calendar__heading - The heading containing the month and year. // Parts specific to the calendar-month component: - * @part heading - The heading that labels the month. - * @part table - The element. - * @part tr - Any row within the table. - * @part head - The table's header row. - * @part week - The table's body rows. - * @part th - The table's header cells. - * @part td - The table's body cells. - * @part button - Any button used in the component. - * @part day - The buttons corresponding to each day in the grid. - * @part selected - Any days which are selected. - * @part today - Today's day. - * @part disallowed - Any day that has been disallowed via isDateDisallowed. - * @part outside - Any days which are outside the current month. - * @part range-start - The day at the start of a date range. - * @part range-end - The day at the end of a date range. - * @part range-inner - Any days between the start and end of a date range. + * @part calendar__heading - The heading that labels the month. + * @part calendar__table - The
element. + * @part calendar__tr - Any row within the table. + * @part calendar__head - The table's header row. + * @part calendar__week - The table's body rows. + * @part calendar__th - The table's header cells. + * @part calendar__td - The table's body cells. + * @part calendar__button - Any button used in the component. + * @part calendar__day - The buttons corresponding to each day in the grid. + * @part calendar__selected - Any days which are selected. + * @part calendar__today - Today's day. + * @part calendar__disallowed - Any day that has been disallowed via isDateDisallowed. + * @part calendar__outside - Any days which are outside the current month. + * @part calendar__range-start - The day at the start of a date range. + * @part calendar__range-end - The day at the end of a date range. + * @part calendar__range-inner - Any days between the start and end of a date range. */ @Component({ tag: 'bq-date-picker', @@ -54,6 +61,7 @@ export class BqDatePicker { // Own Properties // ==================== + private callyElem?: InstanceType; private inputElem?: HTMLInputElement; private labelElem?: HTMLElement; private prefixElem?: HTMLElement; @@ -62,9 +70,10 @@ export class BqDatePicker { private fallbackInputId = 'date-picker'; // Export parts of the calendar-month component - private readonly COMMON_EXPORT_PARTS = 'heading,table,tr,head,week,th,td'; + private readonly COMMON_EXPORT_PARTS = + 'calendar__heading,calendar__table,calendar__tr,calendar__head,calendar__week,calendar__th,calendar__td'; private readonly BUTTON_EXPORT_PARTS = - 'button,day,selected,today,disallowed,outside,range-start,range-end,range-inner'; + 'calendar__button,calendar__day,calendar__selected,calendar__today,calendar__disallowed,calendar__outside,calendar__range-start,calendar__range-end,calendar__range-inner'; // Reference to host HTML element // =================================== @@ -75,9 +84,11 @@ export class BqDatePicker { // Inlined decorator, alphabetical order // ======================================= - @State() formattedDate: string; + @State() focusedDate: string; + @State() displayDate: string; @State() hasLabel = false; @State() hasPrefix = false; + @State() hasRangeEnd = false; @State() hasSuffix = false; @State() hasValue = false; @@ -134,8 +145,12 @@ export class BqDatePicker { /** Number of months to show when range is `true` */ @Prop({ reflect: true }) months: number; - /** The number of months to display per page when using next/previous buttons. */ - @Prop({ reflect: true }) monthsPerView: number = 1; + /** + * Specifies how the next/previous buttons should navigate the calendar. + * - single: The buttons will navigate by a single month at a time. + * - months: The buttons will navigate by the number of months displayed per view. + */ + @Prop({ reflect: true }) monthsPerView: 'single' | 'months' = 'single'; /** The Date picker input name. */ @Prop({ reflect: true }) name!: string; @@ -164,6 +179,9 @@ export class BqDatePicker { /** Defines the strategy to position the Date picker panel */ @Prop({ reflect: true }) strategy?: 'fixed' | 'absolute' = 'fixed'; + /** The date that is tentatively selected e.g. the start of a range selection */ + @Prop({ reflect: true, mutable: true }) tentative?: string; + /** It defines how the calendar will behave, allowing single date selection, range selection, or multiple date selection */ @Prop({ reflect: true }) type: TDatePickerType = 'single'; @@ -193,8 +211,10 @@ export class BqDatePicker { return; } - this.formattedDate = this.formatDate(this.value); this.hasValue = isDefined(this.value); + this.displayDate = this.formatDisplayValue(this.value); + + this.setFocusedDate(); } @Watch('type') @@ -225,7 +245,7 @@ export class BqDatePicker { // Ordered by their natural call order // ===================================== - componentDidLoad() { + connectedCallback() { this.handleValueChange(); } @@ -237,6 +257,20 @@ export class BqDatePicker { if (!ev.composedPath().includes(this.el)) return; this.open = ev.detail.open; + this.setFocusedDate(); + } + + @Listen('click', { target: 'body', capture: true }) + handleClickOutside(ev: MouseEvent) { + const { open, type, hasRangeEnd } = this; + if (!open || type !== 'range' || ev.button !== 0) return; + if (isEventTargetChildOfElement(ev, this.el) || hasRangeEnd) return; + if (isEventTargetChildOfElement(ev, this.el)) return; + + if (!hasRangeEnd) { + this.tentative = undefined; + this.hasRangeEnd = false; + } } // Public methods API @@ -278,6 +312,15 @@ export class BqDatePicker { this.bqFocus.emit(this.el); }; + private setFocusedDate = () => { + if (!this.callyElem) return; + // We need to set the focused date in the calendar component via a ref + // because it doesn't work when passed as a prop (the Cally element does not re-render) + this.callyElem.focusedDate = this.value + ? this.formatFocusedDate(this.value) + : new Date().toLocaleDateString('fr-CA'); + }; + private handleChange = (ev: Event) => { if (this.disabled) return; @@ -287,7 +330,7 @@ export class BqDatePicker { if (!isNaN(dateValue.getTime())) { // We need to force the value to respect the format: yyyy-mm-dd, hence the hardcoded locale this.value = dateValue.toLocaleDateString('fr-CA'); - this.formattedDate = this.formatDate(this.value); + this.displayDate = this.formatDisplayValue(this.value); this.bqChange.emit({ value: this.value, el: this.el }); } }; @@ -296,8 +339,8 @@ export class BqDatePicker { const { value } = ev.target as unknown as { value: string }; this.value = value; - this.formattedDate = this.formatDate(this.value); - this.inputElem.value = this.formattedDate; + this.displayDate = this.formatDisplayValue(this.value); + this.inputElem.value = this.displayDate; this.inputElem.focus(); this.bqChange.emit({ value: this.value, el: this.el }); @@ -305,11 +348,21 @@ export class BqDatePicker { this.open = this.type === 'multi'; }; + private handleCalendarRangeStart = (ev: CustomEvent) => { + this.hasRangeEnd = false; + this.tentative = new Date(ev.detail).toLocaleDateString('fr-CA'); + }; + + private handleCalendarRangeEnd = () => { + this.hasRangeEnd = true; + }; + private handleClearClick = (ev: CustomEvent) => { if (this.disabled) return; this.inputElem.value = ''; this.value = this.inputElem.value; + this.hasRangeEnd = false; this.bqClear.emit(this.el); this.bqChange.emit({ value: this.value, el: this.el }); @@ -373,7 +426,7 @@ export class BqDatePicker { * @param value - The value to be processed, can be a string. * @returns The extracted last date portion of the value. */ - private focusedDate = (value: string) => { + private formatFocusedDate = (value: string): string | null => { if (!value) return; const dateRegex = /\b\d{4}-\d{2}-\d{2}\b/; @@ -381,7 +434,7 @@ export class BqDatePicker { return match ? match[0] : null; }; - private formatDate = (value: string): string | undefined => { + private formatDisplayValue = (value: string): string | undefined => { if (!value) return; const dateFormatter = new Intl.DateTimeFormat(this.locale, this.formatOptions); @@ -479,7 +532,7 @@ export class BqDatePicker { required={this.required} spellcheck={false} type="text" - value={this.formattedDate} + value={this.displayDate} part="input" // Events onBlur={this.handleBlur} @@ -515,26 +568,28 @@ export class BqDatePicker { -
- - - + (this.callyElem = elem as InstanceType)} + > + + -
{this.generateCalendarMonths()}
-
-
+
{this.generateCalendarMonths()}
+ ); diff --git a/packages/beeq/src/components/date-picker/readme.md b/packages/beeq/src/components/date-picker/readme.md index cdee3559b..444b62e47 100644 --- a/packages/beeq/src/components/date-picker/readme.md +++ b/packages/beeq/src/components/date-picker/readme.md @@ -7,34 +7,35 @@ ## Properties -| Property | Attribute | Description | Type | Default | -| ------------------- | -------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------- | -| `autofocus` | `autofocus` | If `true`, the Date picker input will be focused on component render | `boolean` | `undefined` | -| `clearButtonLabel` | `clear-button-label` | The clear button aria label | `string` | `'Clear value'` | -| `disableClear` | `disable-clear` | If `true`, the clear button won't be displayed | `boolean` | `false` | -| `disabled` | `disabled` | Indicates whether the Date picker input is disabled or not. If `true`, the Date picker is disabled and cannot be interacted with. | `boolean` | `false` | -| `distance` | `distance` | Represents the distance (gutter or margin) between the Date picker panel and the input element. | `number` | `8` | -| `firstDayOfWeek` | `first-day-of-week` | The first day of the week, where Sunday is 0, Monday is 1, etc | `0 \| 1 \| 2 \| 3 \| 4 \| 5 \| 6` | `1` | -| `form` | `form` | The ID of the form that the Date picker input belongs to. | `string` | `undefined` | -| `formatOptions` | -- | The options to use when formatting the displayed value. Details: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/DateTimeFormat#using_options | `DateTimeFormatOptions` | `{ day: 'numeric', month: 'short', year: 'numeric', }` | -| `isDateDisallowed` | -- | A function that takes a date and returns true if the date should not be selectable | `(date: Date) => boolean` | `undefined` | -| `locale` | `locale` | The locale for formatting dates. If not set, will use the browser's locale. Details: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl#locales_argument | `Locale \| readonly (string \| Locale)[] \| string` | `'en-GB'` | -| `max` | `max` | The latest date that can be selected | `string` | `undefined` | -| `min` | `min` | The earliest date that can be selected | `string` | `undefined` | -| `months` | `months` | Number of months to show when range is `true` | `number` | `undefined` | -| `monthsPerView` | `months-per-view` | The number of months to display per page when using next/previous buttons. | `number` | `1` | -| `name` _(required)_ | `name` | The Date picker input name. | `string` | `undefined` | -| `open` | `open` | If `true`, the Date picker panel will be visible. | `boolean` | `false` | -| `panelHeight` | `panel-height` | When set, it will override the height of the Date picker panel. | `string` | `'auto'` | -| `placeholder` | `placeholder` | The Date picker input placeholder text value | `string` | `undefined` | -| `placement` | `placement` | Position of the Date picker panel | `"bottom" \| "bottom-end" \| "bottom-start" \| "left" \| "left-end" \| "left-start" \| "right" \| "right-end" \| "right-start" \| "top" \| "top-end" \| "top-start"` | `'bottom-end'` | -| `required` | `required` | Indicates whether or not the Date picker input is required to be filled out before submitting the form. | `boolean` | `undefined` | -| `showOutsideDays` | `show-outside-days` | Whether to show days outside the month | `boolean` | `false` | -| `skidding` | `skidding` | Represents the skidding between the Date picker panel and the input element. | `number` | `0` | -| `strategy` | `strategy` | Defines the strategy to position the Date picker panel | `"absolute" \| "fixed"` | `'fixed'` | -| `type` | `type` | It defines how the calendar will behave, allowing single date selection, range selection, or multiple date selection | `"multi" \| "range" \| "single"` | `'single'` | -| `validationStatus` | `validation-status` | The validation status of the Select input. | `"error" \| "none" \| "success" \| "warning"` | `'none'` | -| `value` | `value` | The select input value represents the currently selected date or range and can be used to reset the field to a previous value. All dates are expected in ISO-8601 format (YYYY-MM-DD). | `string` | `undefined` | +| Property | Attribute | Description | Type | Default | +| ------------------- | -------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------- | +| `autofocus` | `autofocus` | If `true`, the Date picker input will be focused on component render | `boolean` | `undefined` | +| `clearButtonLabel` | `clear-button-label` | The clear button aria label | `string` | `'Clear value'` | +| `disableClear` | `disable-clear` | If `true`, the clear button won't be displayed | `boolean` | `false` | +| `disabled` | `disabled` | Indicates whether the Date picker input is disabled or not. If `true`, the Date picker is disabled and cannot be interacted with. | `boolean` | `false` | +| `distance` | `distance` | Represents the distance (gutter or margin) between the Date picker panel and the input element. | `number` | `8` | +| `firstDayOfWeek` | `first-day-of-week` | The first day of the week, where Sunday is 0, Monday is 1, etc | `0 \| 1 \| 2 \| 3 \| 4 \| 5 \| 6` | `1` | +| `form` | `form` | The ID of the form that the Date picker input belongs to. | `string` | `undefined` | +| `formatOptions` | -- | The options to use when formatting the displayed value. Details: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/DateTimeFormat#using_options | `DateTimeFormatOptions` | `{ day: 'numeric', month: 'short', year: 'numeric', }` | +| `isDateDisallowed` | -- | A function that takes a date and returns true if the date should not be selectable | `(date: Date) => boolean` | `undefined` | +| `locale` | `locale` | The locale for formatting dates. If not set, will use the browser's locale. Details: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl#locales_argument | `Locale \| readonly (string \| Locale)[] \| string` | `'en-GB'` | +| `max` | `max` | The latest date that can be selected | `string` | `undefined` | +| `min` | `min` | The earliest date that can be selected | `string` | `undefined` | +| `months` | `months` | Number of months to show when range is `true` | `number` | `undefined` | +| `monthsPerView` | `months-per-view` | Specifies how the next/previous buttons should navigate the calendar. - single: The buttons will navigate by a single month at a time. - months: The buttons will navigate by the number of months displayed per view. | `"months" \| "single"` | `'single'` | +| `name` _(required)_ | `name` | The Date picker input name. | `string` | `undefined` | +| `open` | `open` | If `true`, the Date picker panel will be visible. | `boolean` | `false` | +| `panelHeight` | `panel-height` | When set, it will override the height of the Date picker panel. | `string` | `'auto'` | +| `placeholder` | `placeholder` | The Date picker input placeholder text value | `string` | `undefined` | +| `placement` | `placement` | Position of the Date picker panel | `"bottom" \| "bottom-end" \| "bottom-start" \| "left" \| "left-end" \| "left-start" \| "right" \| "right-end" \| "right-start" \| "top" \| "top-end" \| "top-start"` | `'bottom-end'` | +| `required` | `required` | Indicates whether or not the Date picker input is required to be filled out before submitting the form. | `boolean` | `undefined` | +| `showOutsideDays` | `show-outside-days` | Whether to show days outside the month | `boolean` | `false` | +| `skidding` | `skidding` | Represents the skidding between the Date picker panel and the input element. | `number` | `0` | +| `strategy` | `strategy` | Defines the strategy to position the Date picker panel | `"absolute" \| "fixed"` | `'fixed'` | +| `tentative` | `tentative` | The date that is tentatively selected e.g. the start of a range selection | `string` | `undefined` | +| `type` | `type` | It defines how the calendar will behave, allowing single date selection, range selection, or multiple date selection | `"multi" \| "range" \| "single"` | `'single'` | +| `validationStatus` | `validation-status` | The validation status of the Select input. | `"error" \| "none" \| "success" \| "warning"` | `'none'` | +| `value` | `value` | The select input value represents the currently selected date or range and can be used to reset the field to a previous value. All dates are expected in ISO-8601 format (YYYY-MM-DD). | `string` | `undefined` | ## Events @@ -62,37 +63,38 @@ Type: `Promise` ## Shadow Parts -| Part | Description | -| --------------- | ------------------------------------------------------------------------------------------------------------ | -| `"base"` | The component's base wrapper. | -| `"button"` | The native HTML button used under the hood in the clear button. | -| `"clear-btn"` | The clear button. | -| `"container"` | The container for the entire component. | -| `"control"` | The input control wrapper. | -| `"day"` | The buttons corresponding to each day in the grid. | -| `"disabled"` | A button that is disabled due to min/max. | -| `"disallowed"` | Any day that has been disallowed via isDateDisallowed. | -| `"head"` | The table's header row. | -| `"header"` | The container for heading and button's. | -| `"heading"` | The heading containing the month and year. // Parts specific to the calendar-month component: | -| `"input"` | The native HTML input element used under the hood. | -| `"label"` | The label slot container. | -| `"next"` | The next page button. | -| `"outside"` | Any days which are outside the current month. | -| `"panel"` | The date picker panel container | -| `"prefix"` | The prefix slot container. | -| `"previous"` | The previous page button. | -| `"range-end"` | The day at the end of a date range. | -| `"range-inner"` | Any days between the start and end of a date range. | -| `"range-start"` | The day at the start of a date range. | -| `"selected"` | Any days which are selected. | -| `"suffix"` | The suffix slot container. // Parts from the Cally library for calendar-date and calendar-range components: | -| `"table"` | The
element. | -| `"td"` | The table's body cells. | -| `"th"` | The table's header cells. | -| `"today"` | Today's day. | -| `"tr"` | Any row within the table. | -| `"week"` | The table's body rows. | +| Part | Description | +| ------------------------- | ------------------------------------------------------------------------------------------------------------ | +| `"base"` | The component's base wrapper. | +| `"button"` | The native HTML button used under the hood in the clear button. | +| `"calendar__button"` | Any button within the component. | +| `"calendar__container"` | The container for the entire component. | +| `"calendar__day"` | The buttons corresponding to each day in the grid. | +| `"calendar__disabled"` | A button that is disabled due to min/max. | +| `"calendar__disallowed"` | Any day that has been disallowed via isDateDisallowed. | +| `"calendar__head"` | The table's header row. | +| `"calendar__header"` | The container for heading and button's. | +| `"calendar__heading"` | The heading containing the month and year. // Parts specific to the calendar-month component: | +| `"calendar__next"` | The next page button. | +| `"calendar__outside"` | Any days which are outside the current month. | +| `"calendar__previous"` | The previous page button. | +| `"calendar__range-end"` | The day at the end of a date range. | +| `"calendar__range-inner"` | Any days between the start and end of a date range. | +| `"calendar__range-start"` | The day at the start of a date range. | +| `"calendar__selected"` | Any days which are selected. | +| `"calendar__table"` | The
element. | +| `"calendar__td"` | The table's body cells. | +| `"calendar__th"` | The table's header cells. | +| `"calendar__today"` | Today's day. | +| `"calendar__tr"` | Any row within the table. | +| `"calendar__week"` | The table's body rows. | +| `"clear-btn"` | The clear button. | +| `"control"` | The input control wrapper. | +| `"input"` | The native HTML input element used under the hood. | +| `"label"` | The label slot container. | +| `"panel"` | The date picker panel container | +| `"prefix"` | The prefix slot container. | +| `"suffix"` | The suffix slot container. // Parts from the Cally library for calendar-date and calendar-range components: | ## Dependencies diff --git a/packages/beeq/src/global/scripts/global.ts b/packages/beeq/src/global/scripts/global.ts index 5f1438f29..37395c35f 100644 --- a/packages/beeq/src/global/scripts/global.ts +++ b/packages/beeq/src/global/scripts/global.ts @@ -1,12 +1,18 @@ import 'cally'; import type { JSXBase } from '@stencil/core/internal'; import type { CalendarDateProps, CalendarMonthProps, CalendarMultiProps, CalendarRangeProps } from 'cally'; + +type EventName = T extends `on${infer Rest}` ? `on${Capitalize>}` : T; +type MapEvents = { + [K in keyof T as EventName]: T[K]; +}; + declare module '@stencil/core' { // eslint-disable-next-line @typescript-eslint/no-namespace export namespace JSX { interface IntrinsicElements { 'calendar-multi': CalendarMultiProps & JSXBase.HTMLAttributes; - 'calendar-range': CalendarRangeProps & JSXBase.HTMLAttributes; + 'calendar-range': MapEvents & JSXBase.HTMLAttributes; 'calendar-date': CalendarDateProps & JSXBase.HTMLAttributes; 'calendar-month': CalendarMonthProps & JSXBase.HTMLAttributes; }