From 0bf9969689dfdf8ae883c24162f20d7c7eb106d0 Mon Sep 17 00:00:00 2001 From: Lungan Catalin Date: Mon, 22 Apr 2024 18:59:22 +0300 Subject: [PATCH 01/75] feat(Date Picker): add new bq-date-picker component --- package-lock.json | 8 + packages/beeq/package.json | 3 +- packages/beeq/src/components.d.ts | 204 +++++++++- packages/beeq/src/components/button/readme.md | 2 + .../__tests__/bq-date-picker.e2e.ts | 21 + .../date-picker/_storybook/bq-date-picker.mdx | 15 + .../_storybook/bq-date-picker.stories.tsx | 134 +++++++ .../components/date-picker/bq-date-picker.tsx | 366 ++++++++++++++++++ .../beeq/src/components/date-picker/readme.md | 91 +++++ .../date-picker/scss/bq-date-picker.scss | 141 +++++++ .../scss/bq-date-picker.variables.scss | 56 +++ .../beeq/src/components/dropdown/readme.md | 2 + packages/beeq/src/components/icon/readme.md | 2 + packages/beeq/src/global/scripts/global.ts | 1 + 14 files changed, 1041 insertions(+), 5 deletions(-) create mode 100644 packages/beeq/src/components/date-picker/__tests__/bq-date-picker.e2e.ts create mode 100644 packages/beeq/src/components/date-picker/_storybook/bq-date-picker.mdx create mode 100644 packages/beeq/src/components/date-picker/_storybook/bq-date-picker.stories.tsx create mode 100644 packages/beeq/src/components/date-picker/bq-date-picker.tsx create mode 100644 packages/beeq/src/components/date-picker/readme.md create mode 100644 packages/beeq/src/components/date-picker/scss/bq-date-picker.scss create mode 100644 packages/beeq/src/components/date-picker/scss/bq-date-picker.variables.scss create mode 100644 packages/beeq/src/global/scripts/global.ts diff --git a/package-lock.json b/package-lock.json index 0152db4e3..a6a1451a0 100644 --- a/package-lock.json +++ b/package-lock.json @@ -16318,6 +16318,14 @@ "node": ">=6" } }, + "node_modules/cally": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/cally/-/cally-0.5.2.tgz", + "integrity": "sha512-DoygZJhGp5bPsfiKeCeU+6J555ZkjS+pyyBYnKFeIgjrGncxGfk389zIv8kCHZ2wvH3pW4NlhkSSAf6aknxr2A==", + "dependencies": { + "atomico": "^1.76.1" + } + }, "node_modules/camel-case": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/camel-case/-/camel-case-4.1.2.tgz", diff --git a/packages/beeq/package.json b/packages/beeq/package.json index c06cdf0c3..022fad9f7 100644 --- a/packages/beeq/package.json +++ b/packages/beeq/package.json @@ -26,7 +26,8 @@ "dependencies": { "@floating-ui/core": "^1.6.2", "@floating-ui/dom": "^1.6.5", - "@stencil/core": "^4.18.1" + "@stencil/core": "^4.18.1", + "cally": "0.5.2" }, "repository": { "type": "git", diff --git a/packages/beeq/src/components.d.ts b/packages/beeq/src/components.d.ts index 7c0879d59..46de529b5 100644 --- a/packages/beeq/src/components.d.ts +++ b/packages/beeq/src/components.d.ts @@ -11,13 +11,13 @@ import { TAvatarShape, TAvatarSize } from "./components/avatar/bq-avatar.types"; import { TBadgeSize } from "./components/badge/bq-badge.types"; import { TButtonAppearance, TButtonBorderRadius, TButtonSize, TButtonType, TButtonVariant } from "./components/button/bq-button.types"; import { TCardBorderRadius, TCardType } from "./components/card/bq-card.types"; +import { FloatingUIPlacement } from "./services/interfaces"; +import { TInputType, TInputValidation, TInputValue } from "./components/input/bq-input.types"; import { TDialogBorderRadius, TDialogFooterAppearance, TDialogSize } from "./components/dialog/bq-dialog.types"; import { TDividerOrientation, TDividerStrokeLinecap, TDividerTitleAlignment } from "./components/divider/bq-divider.types"; import { TDrawerPlacement } from "./components/drawer/bq-drawer.types"; -import { FloatingUIPlacement } from "./services/interfaces"; import { TEmptyStateSize } from "./components/empty-state/bq-empty-state.types"; import { TIconWeight } from "./components/icon/bq-icon.types"; -import { TInputType, TInputValidation, TInputValue } from "./components/input/bq-input.types"; import { TNotificationBorderRadius, TNotificationType } from "./components/notification/bq-notification.types"; import { TProgressBorderShape, TProgressThickness, TProgressType } from "./components/progress/bq-progress.types"; import { TRadioGroupOrientation } from "./components/radio-group/bq-radio-group.types"; @@ -39,13 +39,13 @@ export { TAvatarShape, TAvatarSize } from "./components/avatar/bq-avatar.types"; export { TBadgeSize } from "./components/badge/bq-badge.types"; export { TButtonAppearance, TButtonBorderRadius, TButtonSize, TButtonType, TButtonVariant } from "./components/button/bq-button.types"; export { TCardBorderRadius, TCardType } from "./components/card/bq-card.types"; +export { FloatingUIPlacement } from "./services/interfaces"; +export { TInputType, TInputValidation, TInputValue } from "./components/input/bq-input.types"; export { TDialogBorderRadius, TDialogFooterAppearance, TDialogSize } from "./components/dialog/bq-dialog.types"; export { TDividerOrientation, TDividerStrokeLinecap, TDividerTitleAlignment } from "./components/divider/bq-divider.types"; export { TDrawerPlacement } from "./components/drawer/bq-drawer.types"; -export { FloatingUIPlacement } from "./services/interfaces"; export { TEmptyStateSize } from "./components/empty-state/bq-empty-state.types"; export { TIconWeight } from "./components/icon/bq-icon.types"; -export { TInputType, TInputValidation, TInputValue } from "./components/input/bq-input.types"; export { TNotificationBorderRadius, TNotificationType } from "./components/notification/bq-notification.types"; export { TProgressBorderShape, TProgressThickness, TProgressType } from "./components/progress/bq-progress.types"; export { TRadioGroupOrientation } from "./components/radio-group/bq-radio-group.types"; @@ -321,6 +321,83 @@ export namespace Components { */ "value": string; } + interface BqDatePicker { + /** + * If true, the Date picker input will be focused on component render + */ + "autofocus": boolean; + /** + * Clears the selected value. + * @return + * @memberof BqInput + */ + "clear": () => Promise; + /** + * The clear button aria label + */ + "clearButtonLabel"?: string; + /** + * If true, the clear button won't be displayed + */ + "disableClear"?: boolean; + /** + * Indicates whether the Date picker input is disabled or not. If `true`, the Date picker is disabled and cannot be interacted with. + */ + "disabled"?: boolean; + /** + * Represents the distance (gutter or margin) between the Date picker panel and the input element. + */ + "distance"?: number; + /** + * The ID of the form that the Date picker input belongs to. + */ + "form"?: string; + /** + * If true, the Date picker panel will remain open after a selection date is made. + */ + "keepOpenOnSelect"?: boolean; + /** + * The Date picker input name. + */ + "name": string; + /** + * If true, the Date picker panel will be visible. + */ + "open"?: boolean; + /** + * When set, it will override the height of the Date picker panel. + */ + "panelHeight"?: string; + /** + * The Date picker input placeholder text value + */ + "placeholder"?: string; + /** + * Position of the Date picker panel + */ + "placement"?: FloatingUIPlacement; + /** + * Indicates whether or not the Date picker input is required to be filled out before submitting the form. + */ + "required"?: boolean; + /** + * Represents the skidding between the Date picker panel and the input element. + */ + "skidding"?: number; + /** + * Defines the strategy to position the Date picker panel + */ + "strategy"?: 'fixed' | 'absolute'; + /** + * The validation status of the Select input. + * @remarks This property is used to indicate the validation status of the select input. It can be set to one of the following values: - `'none'`: No validation status is set. - `'error'`: The input has a validation error. - `'warning'`: The input has a validation warning. - `'success'`: The input has passed validation. + */ + "validationStatus": TInputValidation; + /** + * The select input value, it can be used to reset the field to a previous value + */ + "value": TInputValue; + } interface BqDialog { /** * Corder radius of the dialog component @@ -1362,6 +1439,10 @@ export interface BqCheckboxCustomEvent extends CustomEvent { detail: T; target: HTMLBqCheckboxElement; } +export interface BqDatePickerCustomEvent extends CustomEvent { + detail: T; + target: HTMLBqDatePickerElement; +} export interface BqDialogCustomEvent extends CustomEvent { detail: T; target: HTMLBqDialogElement; @@ -1593,6 +1674,27 @@ declare global { prototype: HTMLBqCheckboxElement; new (): HTMLBqCheckboxElement; }; + interface HTMLBqDatePickerElementEventMap { + "bqBlur": HTMLBqInputElement; + "bqChange": { value: string | number | string[]; el: HTMLBqInputElement }; + "bqClear": HTMLBqInputElement; + "bqFocus": HTMLBqInputElement; + "bqInput": { value: string | number | string[]; el: HTMLBqInputElement }; + } + interface HTMLBqDatePickerElement extends Components.BqDatePicker, HTMLStencilElement { + addEventListener(type: K, listener: (this: HTMLBqDatePickerElement, ev: BqDatePickerCustomEvent) => any, options?: boolean | AddEventListenerOptions): void; + addEventListener(type: K, listener: (this: Document, ev: DocumentEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void; + addEventListener(type: K, listener: (this: HTMLElement, ev: HTMLElementEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void; + addEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void; + removeEventListener(type: K, listener: (this: HTMLBqDatePickerElement, ev: BqDatePickerCustomEvent) => any, options?: boolean | EventListenerOptions): void; + removeEventListener(type: K, listener: (this: Document, ev: DocumentEventMap[K]) => any, options?: boolean | EventListenerOptions): void; + removeEventListener(type: K, listener: (this: HTMLElement, ev: HTMLElementEventMap[K]) => any, options?: boolean | EventListenerOptions): void; + removeEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | EventListenerOptions): void; + } + var HTMLBqDatePickerElement: { + prototype: HTMLBqDatePickerElement; + new (): HTMLBqDatePickerElement; + }; interface HTMLBqDialogElementEventMap { "bqCancel": void; "bqClose": void; @@ -2067,6 +2169,7 @@ declare global { "bq-button": HTMLBqButtonElement; "bq-card": HTMLBqCardElement; "bq-checkbox": HTMLBqCheckboxElement; + "bq-date-picker": HTMLBqDatePickerElement; "bq-dialog": HTMLBqDialogElement; "bq-divider": HTMLBqDividerElement; "bq-drawer": HTMLBqDrawerElement; @@ -2428,6 +2531,97 @@ declare namespace LocalJSX { */ "value": string; } + interface BqDatePicker { + /** + * If true, the Date picker input will be focused on component render + */ + "autofocus"?: boolean; + /** + * The clear button aria label + */ + "clearButtonLabel"?: string; + /** + * If true, the clear button won't be displayed + */ + "disableClear"?: boolean; + /** + * Indicates whether the Date picker input is disabled or not. If `true`, the Date picker is disabled and cannot be interacted with. + */ + "disabled"?: boolean; + /** + * Represents the distance (gutter or margin) between the Date picker panel and the input element. + */ + "distance"?: number; + /** + * The ID of the form that the Date picker input belongs to. + */ + "form"?: string; + /** + * If true, the Date picker panel will remain open after a selection date is made. + */ + "keepOpenOnSelect"?: boolean; + /** + * The Date picker input name. + */ + "name": string; + /** + * Callback handler emitted when the input loses focus + */ + "onBqBlur"?: (event: BqDatePickerCustomEvent) => void; + /** + * Callback handler emitted when the input value has changed and the input loses focus. This handler is called whenever the user finishes typing or pasting text into the input field and then clicks outside of the input field. + */ + "onBqChange"?: (event: BqDatePickerCustomEvent<{ value: string | number | string[]; el: HTMLBqInputElement }>) => void; + /** + * Callback handler emitted when the input value has been cleared + */ + "onBqClear"?: (event: BqDatePickerCustomEvent) => void; + /** + * Callback handler emitted when the input has received focus + */ + "onBqFocus"?: (event: BqDatePickerCustomEvent) => void; + /** + * Callback handler emitted when the input value changes. This handler is called whenever the user types or pastes text into the input field. + */ + "onBqInput"?: (event: BqDatePickerCustomEvent<{ value: string | number | string[]; el: HTMLBqInputElement }>) => void; + /** + * If true, the Date picker panel will be visible. + */ + "open"?: boolean; + /** + * When set, it will override the height of the Date picker panel. + */ + "panelHeight"?: string; + /** + * The Date picker input placeholder text value + */ + "placeholder"?: string; + /** + * Position of the Date picker panel + */ + "placement"?: FloatingUIPlacement; + /** + * Indicates whether or not the Date picker input is required to be filled out before submitting the form. + */ + "required"?: boolean; + /** + * Represents the skidding between the Date picker panel and the input element. + */ + "skidding"?: number; + /** + * Defines the strategy to position the Date picker panel + */ + "strategy"?: 'fixed' | 'absolute'; + /** + * The validation status of the Select input. + * @remarks This property is used to indicate the validation status of the select input. It can be set to one of the following values: - `'none'`: No validation status is set. - `'error'`: The input has a validation error. - `'warning'`: The input has a validation warning. - `'success'`: The input has passed validation. + */ + "validationStatus"?: TInputValidation; + /** + * The select input value, it can be used to reset the field to a previous value + */ + "value"?: TInputValue; + } interface BqDialog { /** * Corder radius of the dialog component @@ -3594,6 +3788,7 @@ declare namespace LocalJSX { "bq-button": BqButton; "bq-card": BqCard; "bq-checkbox": BqCheckbox; + "bq-date-picker": BqDatePicker; "bq-dialog": BqDialog; "bq-divider": BqDivider; "bq-drawer": BqDrawer; @@ -3643,6 +3838,7 @@ declare module "@stencil/core" { "bq-button": LocalJSX.BqButton & JSXBase.HTMLAttributes; "bq-card": LocalJSX.BqCard & JSXBase.HTMLAttributes; "bq-checkbox": LocalJSX.BqCheckbox & JSXBase.HTMLAttributes; + "bq-date-picker": LocalJSX.BqDatePicker & JSXBase.HTMLAttributes; "bq-dialog": LocalJSX.BqDialog & JSXBase.HTMLAttributes; "bq-divider": LocalJSX.BqDivider & JSXBase.HTMLAttributes; "bq-drawer": LocalJSX.BqDrawer & JSXBase.HTMLAttributes; diff --git a/packages/beeq/src/components/button/readme.md b/packages/beeq/src/components/button/readme.md index 92e3392f6..1a078d1aa 100644 --- a/packages/beeq/src/components/button/readme.md +++ b/packages/beeq/src/components/button/readme.md @@ -51,6 +51,7 @@ Buttons are designed for users to take action on a page or a screen. ### Used by - [bq-alert](../alert) + - [bq-date-picker](../date-picker) - [bq-dialog](../dialog) - [bq-drawer](../drawer) - [bq-input](../input) @@ -67,6 +68,7 @@ Buttons are designed for users to take action on a page or a screen. graph TD; bq-button --> bq-icon bq-alert --> bq-button + bq-date-picker --> bq-button bq-dialog --> bq-button bq-drawer --> bq-button bq-input --> bq-button diff --git a/packages/beeq/src/components/date-picker/__tests__/bq-date-picker.e2e.ts b/packages/beeq/src/components/date-picker/__tests__/bq-date-picker.e2e.ts new file mode 100644 index 000000000..e1d3b2131 --- /dev/null +++ b/packages/beeq/src/components/date-picker/__tests__/bq-date-picker.e2e.ts @@ -0,0 +1,21 @@ +import { newE2EPage } from '@stencil/core/testing'; + +describe('bq-date-picker', () => { + it('should render', async () => { + const page = await newE2EPage({ + html: '', + }); + const element = await page.find('bq-date-picker'); + + expect(element).toHaveClass('hydrated'); + }); + + it('should have shadow root', async () => { + const page = await newE2EPage({ + html: '', + }); + const element = await page.find('bq-date-picker'); + + expect(element.shadowRoot).not.toBeNull(); + }); +}); diff --git a/packages/beeq/src/components/date-picker/_storybook/bq-date-picker.mdx b/packages/beeq/src/components/date-picker/_storybook/bq-date-picker.mdx new file mode 100644 index 000000000..f7cd5c1e1 --- /dev/null +++ b/packages/beeq/src/components/date-picker/_storybook/bq-date-picker.mdx @@ -0,0 +1,15 @@ +import { ArgTypes, Title, Subtitle } from '@storybook/addon-docs'; + +
+
+ Date picker + + Usage + + 👍 When to use + + Properties + + +
+
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 new file mode 100644 index 000000000..cf8fc94b5 --- /dev/null +++ b/packages/beeq/src/components/date-picker/_storybook/bq-date-picker.stories.tsx @@ -0,0 +1,134 @@ +import type { Args, Meta, StoryObj } from '@storybook/web-components'; +import { html, nothing } from 'lit-html'; +import { ifDefined } from 'lit-html/directives/if-defined.js'; + +import mdx from './bq-date-picker.mdx'; +import { INPUT_VALIDATION } from '../../input/bq-input.types'; + +const meta: Meta = { + title: 'Components/Date picker', + component: 'bq-date-picker', + parameters: { + docs: { + page: mdx, + }, + }, + argTypes: { + autofocus: { control: 'boolean' }, + 'clear-button-label': { control: 'text' }, + 'disable-clear': { control: 'boolean' }, + distance: { control: 'number' }, + disabled: { control: 'boolean' }, + form: { control: 'text' }, + 'keep-open-on-select': { control: 'boolean' }, + name: { control: 'text' }, + open: { control: 'boolean' }, + 'panel-height': { control: 'text' }, + placement: { + control: 'select', + options: [ + 'top', + 'top-start', + 'top-end', + 'bottom', + 'bottom-start', + 'bottom-end', + 'right', + 'right-start', + 'right-end', + 'left', + 'left-start', + 'left-end', + ], + }, + placeholder: { control: 'text' }, + required: { control: 'boolean' }, + skidding: { control: 'number' }, + strategy: { control: 'select', options: ['fixed', 'absolute'] }, + 'validation-status': { control: 'select', options: [...INPUT_VALIDATION] }, + value: { control: 'text' }, + // Events + bqBlur: { action: 'bqBlur' }, + bqChange: { action: 'bqChange' }, + bqClear: { action: 'bqClear' }, + bqFocus: { action: 'bqFocus' }, + bqInput: { action: 'bqInput' }, + // Not part of the public API, so we don't want to expose it in the docs + noLabel: { control: 'boolean', table: { disable: true } }, + prefix: { control: 'boolean', table: { disable: true } }, + suffix: { control: 'boolean', table: { disable: true } }, + }, + args: { + autofocus: false, + 'clear-button-label': 'Clear value', + 'disable-clear': false, + distance: 8, + disabled: false, + form: undefined, + 'keep-open-on-select': false, + name: 'bq-date-picker', + open: false, + 'panel-height': undefined, + placement: 'bottom-start', + placeholder: 'Enter your date', + skidding: 0, + strategy: 'absolute', + required: false, + 'validation-status': 'none', + value: undefined, + }, +}; +export default meta; + +type Story = StoryObj; + +const Template = (args: Args) => { + const labelTemplate = html` + + `; + const label = !args.optionalLabel + ? labelTemplate + : html` +
+ ${labelTemplate} + Optional +
+ `; + + return html` +
+ + ${!args.noLabel ? label : nothing} + ${args.prefix ? html`` : nothing} + ${args.suffix ? html`` : nothing} + +
+ `; +}; + +export const Default: Story = { + render: Template, +}; diff --git a/packages/beeq/src/components/date-picker/bq-date-picker.tsx b/packages/beeq/src/components/date-picker/bq-date-picker.tsx new file mode 100644 index 000000000..c121ec659 --- /dev/null +++ b/packages/beeq/src/components/date-picker/bq-date-picker.tsx @@ -0,0 +1,366 @@ +import { Component, Element, Event, EventEmitter, h, Method, Prop, State, Watch } from '@stencil/core'; + +import { FloatingUIPlacement } from '../../services/interfaces'; +import { hasSlotContent, isDefined, isHTMLElement } from '../../shared/utils'; +import { TInputValidation, TInputValue } from '../input/bq-input.types'; + +/** + * @part base - The component's base wrapper. + * @part button - The native HTML button used under the hood in the clear button. + * @part clear-btn - The clear button. + * @part control - The input control wrapper. + * @part input - The native HTML input element used under the hood. + * @part label - The label slot container. + * @part panel - The date picker panel container + * @part prefix - The prefix slot container. + * @part suffix - The suffix slot container. + */ +@Component({ + tag: 'bq-date-picker', + styleUrl: './scss/bq-date-picker.scss', + shadow: { + delegatesFocus: true, + }, +}) +export class BqDatePicker { + // Own Properties + // ==================== + + private inputElem?: HTMLInputElement; + private labelElem?: HTMLElement; + private prefixElem?: HTMLElement; + private suffixElem?: HTMLElement; + + private fallbackInputId = 'date-picker'; + + // Reference to host HTML element + // =================================== + + @Element() el!: HTMLBqInputElement; + + // State() variables + // Inlined decorator, alphabetical order + // ======================================= + + @State() hasLabel = false; + @State() hasPrefix = false; + @State() hasSuffix = false; + @State() hasValue = false; + + // Public Property API + // ======================== + + /** If true, the Date picker input will be focused on component render */ + @Prop({ reflect: true }) autofocus: boolean; + + /** The clear button aria label */ + @Prop({ reflect: true }) clearButtonLabel? = 'Clear value'; + + /** + * Indicates whether the Date picker input is disabled or not. + * If `true`, the Date picker is disabled and cannot be interacted with. + */ + @Prop({ mutable: true }) disabled?: boolean = false; + + /** If true, the clear button won't be displayed */ + @Prop({ reflect: true }) disableClear? = false; + + /** Represents the distance (gutter or margin) between the Date picker panel and the input element. */ + @Prop({ reflect: true }) distance?: number = 8; + + /** The ID of the form that the Date picker input belongs to. */ + @Prop({ reflect: true }) form?: string; + + /** If true, the Date picker panel will remain open after a selection date is made. */ + @Prop({ reflect: true }) keepOpenOnSelect?: boolean = false; + + /** The Date picker input name. */ + @Prop({ reflect: true }) name!: string; + + /** If true, the Date picker panel will be visible. */ + @Prop({ reflect: true, mutable: true }) open?: boolean = false; + + /** When set, it will override the height of the Date picker panel. */ + @Prop({ reflect: true, mutable: true }) panelHeight?: string = 'auto'; + + /** The Date picker input placeholder text value */ + @Prop({ reflect: true }) placeholder?: string; + + /** Position of the Date picker panel */ + @Prop({ reflect: true }) placement?: FloatingUIPlacement = 'bottom-start'; + + /** Indicates whether or not the Date picker input is required to be filled out before submitting the form. */ + @Prop({ reflect: true }) required?: boolean; + + /** Represents the skidding between the Date picker panel and the input element. */ + @Prop({ reflect: true }) skidding?: number = 0; + + /** Defines the strategy to position the Date picker panel */ + @Prop({ reflect: true }) strategy?: 'fixed' | 'absolute' = 'fixed'; + + /** + * The validation status of the Select input. + * + * @remarks + * This property is used to indicate the validation status of the select input. It can be set to one of the following values: + * - `'none'`: No validation status is set. + * - `'error'`: The input has a validation error. + * - `'warning'`: The input has a validation warning. + * - `'success'`: The input has passed validation. + */ + @Prop({ reflect: true }) validationStatus: TInputValidation = 'none'; + + /** The select input value, it can be used to reset the field to a previous value */ + @Prop({ reflect: true, mutable: true }) value: TInputValue; + + // Prop lifecycle events + // ======================= + + @Watch('value') + handleValueChange() { + if (Array.isArray(this.value)) { + this.hasValue = this.value.some((val) => val.length > 0); + return; + } + + this.hasValue = isDefined(this.value); + } + + // Events section + // Requires JSDocs for public API documentation + // ============================================== + + /** Callback handler emitted when the input loses focus */ + @Event() bqBlur!: EventEmitter; + + /** + * Callback handler emitted when the input value has changed and the input loses focus. + * This handler is called whenever the user finishes typing or pasting text into the input field and then clicks outside of the input field. + */ + @Event() bqChange!: EventEmitter<{ value: string | number | string[]; el: HTMLBqInputElement }>; + + /** Callback handler emitted when the input value has been cleared */ + @Event() bqClear!: EventEmitter; + + /** Callback handler emitted when the input has received focus */ + @Event() bqFocus!: EventEmitter; + + /** + * Callback handler emitted when the input value changes. + * This handler is called whenever the user types or pastes text into the input field. + */ + @Event() bqInput!: EventEmitter<{ value: string | number | string[]; el: HTMLBqInputElement }>; + + // Component lifecycle events + // Ordered by their natural call order + // ===================================== + + componentDidLoad() { + this.handleValueChange(); + } + + // Listeners + // ============== + + // Public methods API + // These methods are exposed on the host element. + // Always use two lines. + // Public Methods must be async. + // Requires JSDocs for public API documentation. + // =============================================== + + /** + * Clears the selected value. + * + * @return {Promise} + * @memberof BqInput + */ + @Method() + async clear(): Promise { + if (this.disabled) return; + + this.value = undefined; + + this.bqClear.emit(this.el); + } + + // Local methods + // Internal business logic. + // These methods cannot be called from the host element. + // ======================================================= + + private handleBlur = () => { + if (this.disabled) return; + + this.bqBlur.emit(this.el); + }; + + private handleFocus = () => { + if (this.disabled) return; + + this.bqFocus.emit(this.el); + }; + + private handleInput = (ev: Event) => { + if (this.disabled) return; + + if (!isHTMLElement(ev.target, 'input')) return; + this.value = ev.target.value; + }; + + private handleChange = (ev: Event) => { + if (this.disabled) return; + + if (!isHTMLElement(ev.target, 'input')) return; + this.value = ev.target.value; + + this.bqChange.emit({ value: this.value, el: this.el }); + }; + + private handleClearClick = (ev: CustomEvent) => { + if (this.disabled) return; + + this.inputElem.value = ''; + this.value = this.inputElem.value; + + this.bqClear.emit(this.el); + this.bqInput.emit({ value: this.value, el: this.el }); + this.bqChange.emit({ value: this.value, el: this.el }); + this.inputElem.focus(); + + ev.stopPropagation(); + }; + + private handleLabelSlotChange = () => { + this.hasLabel = hasSlotContent(this.labelElem); + }; + + private handlePrefixSlotChange = () => { + this.hasPrefix = hasSlotContent(this.prefixElem); + }; + + private handleSuffixSlotChange = () => { + this.hasSuffix = hasSlotContent(this.suffixElem); + }; + + // render() function + // Always the last one in the class. + // =================================== + + render() { + const labelId = `bq-date-picker__label-${this.name || this.fallbackInputId}`; + + return ( +
+ {/* Label */} + + {/* Select date picker dropdown */} + + {/* Input control group */} +
+ {/* Prefix */} + (this.prefixElem = spanElem)} + part="prefix" + > + + + {/* HTML Input */} + (this.inputElem = inputElem)} + required={this.required} + spellcheck={false} + type="text" + value={this.value} + part="input" + // Events + onBlur={this.handleBlur} + onFocus={this.handleFocus} + onInput={this.handleInput} + onChange={this.handleChange} + /> + {/* Clear Button */} + {this.hasValue && !this.disabled && !this.disableClear && ( + // The clear button will be visible as long as the input has a value + // and the parent group is hovered or has focus-within + + )} + {/* Suffix */} + (this.suffixElem = spanElem)} + part="suffix" + > + + + + +
+
+ { + this.value = ev.target.value; + }} + > + + +
+
+
+ ); + } +} diff --git a/packages/beeq/src/components/date-picker/readme.md b/packages/beeq/src/components/date-picker/readme.md new file mode 100644 index 000000000..2d9db098e --- /dev/null +++ b/packages/beeq/src/components/date-picker/readme.md @@ -0,0 +1,91 @@ +# bq-date-picker + + + + + + +## 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` | +| `form` | `form` | The ID of the form that the Date picker input belongs to. | `string` | `undefined` | +| `keepOpenOnSelect` | `keep-open-on-select` | If true, the Date picker panel will remain open after a selection date is made. | `boolean` | `false` | +| `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-start'` | +| `required` | `required` | Indicates whether or not the Date picker input is required to be filled out before submitting the form. | `boolean` | `undefined` | +| `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'` | +| `validationStatus` | `validation-status` | The validation status of the Select input. | `"error" \| "none" \| "success" \| "warning"` | `'none'` | +| `value` | `value` | The select input value, it can be used to reset the field to a previous value | `number \| string \| string[]` | `undefined` | + + +## Events + +| Event | Description | Type | +| ---------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------- | +| `bqBlur` | Callback handler emitted when the input loses focus | `CustomEvent` | +| `bqChange` | Callback handler emitted when the input value has changed and the input loses focus. This handler is called whenever the user finishes typing or pasting text into the input field and then clicks outside of the input field. | `CustomEvent<{ value: string \| number \| string[]; el: HTMLBqInputElement; }>` | +| `bqClear` | Callback handler emitted when the input value has been cleared | `CustomEvent` | +| `bqFocus` | Callback handler emitted when the input has received focus | `CustomEvent` | +| `bqInput` | Callback handler emitted when the input value changes. This handler is called whenever the user types or pastes text into the input field. | `CustomEvent<{ value: string \| number \| string[]; el: HTMLBqInputElement; }>` | + + +## Methods + +### `clear() => Promise` + +Clears the selected value. + +#### Returns + +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. | +| `"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. | + + +## Dependencies + +### Depends on + +- [bq-dropdown](../dropdown) +- [bq-button](../button) +- [bq-icon](../icon) + +### Graph +```mermaid +graph TD; + bq-date-picker --> bq-dropdown + bq-date-picker --> bq-button + bq-date-picker --> bq-icon + bq-dropdown --> bq-panel + bq-button --> bq-icon + style bq-date-picker fill:#f9f,stroke:#333,stroke-width:4px +``` + +---------------------------------------------- + +*Built with [StencilJS](https://stenciljs.com/)* diff --git a/packages/beeq/src/components/date-picker/scss/bq-date-picker.scss b/packages/beeq/src/components/date-picker/scss/bq-date-picker.scss new file mode 100644 index 000000000..627cc6435 --- /dev/null +++ b/packages/beeq/src/components/date-picker/scss/bq-date-picker.scss @@ -0,0 +1,141 @@ +/* -------------------------------------------------------------------------- */ +/* Date picker styles */ +/* -------------------------------------------------------------------------- */ + +@import './bq-date-picker.variables'; + +:host { + @apply block w-full; +} + +/* -------------------------------------------------------------------------- */ +/* Label */ +/* -------------------------------------------------------------------------- */ + +.bq-date-picker__label { + @apply mb-[--bq-date-picker--label-margin-bottom] flex flex-grow items-center gap-[--bq-date-picker--gap]; + @apply text-[length:--bq-date-picker--label-text-size] text-[color:--bq-date-picker--label-text-color]; +} + +/* -------------------------------------------------------------------------- */ +/* Date picker input group control */ +/* -------------------------------------------------------------------------- */ + +.bq-date-picker__control { + @apply flex w-full items-center transition-[border-color,box-shadow]; + // Border + @apply rounded-[--bq-date-picker--border-radius] border-[length:--bq-date-picker--border-width] border-[color:--bq-date-picker--border-color]; + // Padding + @apply py-[--bq-date-picker--paddingY] pe-[--bq-date-picker--pading-end] ps-[--bq-date-picker--pading-start]; + // Text + @apply select-none text-[length:--bq-date-picker--text-size] text-[color:--bq-date-picker--text-color] placeholder:text-[color:--bq-date-picker--text-placeholder-color]; + // Hover + @apply [&:not(.disabled):not(:focus-within)]:hover:border-hover-stroke-brand; + + border-style: var(--bq-date-picker--border-style); + + // Focus + &:not(.disabled):focus-within { + --bq-ring-width: 1px; + --bq-ring-offset-width: 0; + --bq-ring-color-focus: var(--bq-date-picker--border-color-focus); + + @apply focus border-[color:--bq-date-picker--border-color-focus]; + } + + // Enable clear button whenever the input group control is hovered or has focus + &:not(.disabled):hover, + &:not(.disabled):focus-within { + .bq-date-picker__control--clear { + @apply inline-block; + } + } +} + +.bq-date-picker__control.disabled { + @apply cursor-not-allowed opacity-60; +} + +/* ------------------------------- Validation ------------------------------- */ + +.bq-date-picker__control.validation-error { + @apply border-stroke-danger [&:not(.disabled):not(:focus-within)]:hover:border-hover-stroke-danger; + + &:not(.disabled):focus-within { + --bq-ring-color-focus: theme('colors.stroke.danger'); + + @apply border-active-stroke-danger; + } +} + +.bq-date-picker__control.validation-success { + @apply border-stroke-success [&:not(.disabled):not(:focus-within)]:hover:border-hover-stroke-success; + + &:not(.disabled):focus-within { + --bq-ring-color-focus: theme('colors.stroke.success'); + + @apply border-active-stroke-success; + } +} + +.bq-date-picker__control.validation-warning { + @apply border-stroke-warning [&:not(.disabled):not(:focus-within)]:hover:border-hover-stroke-warning; + + &:not(.disabled):focus-within { + --bq-ring-color-focus: theme('colors.stroke.warning'); + + @apply border-active-stroke-warning; + } +} + +/* -------------------------------------------------------------------------- */ +/* Native HTML Input */ +/* -------------------------------------------------------------------------- */ + +.bq-date-picker__control--input { + @apply flex-auto cursor-[inherit] select-none appearance-none bg-[inherit] font-[inherit] text-[length:inherit] text-[color:inherit]; + @apply m-0 min-h-[--bq-date-picker--icon-size] min-w-[0] border-none p-0 focus:outline-none focus-visible:outline-none; + + box-shadow: none; + font-weight: inherit; +} + +/* -------------------------------------------------------------------------- */ +/* Clear button */ +/* -------------------------------------------------------------------------- */ + +.bq-date-picker__control--clear::part(button) { + // Since the clear button is inside the input group control, + // we need to reset the focus ring styles + --bq-ring-width: initial; + --bq-ring-offset-width: initial; + --bq-ring-color-focus: initial; + + @apply h-auto rounded-xs border-none p-0; +} + +/* -------------------------------------------------------------------------- */ +/* Prefix and suffix */ +/* -------------------------------------------------------------------------- */ + +.bq-date-picker__control--prefix, +.bq-date-picker__control--suffix { + @apply pointer-events-none flex items-center text-[color:var(--bq-date-picker--text-color)]; +} + +.bq-date-picker__control--prefix { + @apply me-[--bq-date-picker--gap]; +} + +.bq-date-picker__control--suffix { + @apply ms-[--bq-date-picker--gap]; +} + +/* -------------------------------------------------------------------------- */ +/* Slotted and internal icons */ +/* -------------------------------------------------------------------------- */ + +bq-icon, +::slotted(bq-icon) { + --bq-icon--size: var(--bq-date-picker--icon-size) !important; +} diff --git a/packages/beeq/src/components/date-picker/scss/bq-date-picker.variables.scss b/packages/beeq/src/components/date-picker/scss/bq-date-picker.variables.scss new file mode 100644 index 000000000..65d1a82a2 --- /dev/null +++ b/packages/beeq/src/components/date-picker/scss/bq-date-picker.variables.scss @@ -0,0 +1,56 @@ +/* -------------------------------------------------------------------------- */ +/* Date picker custom properties */ +/* -------------------------------------------------------------------------- */ + +:host { + /** + * @prop --bq-date-picker--background-color - Date picker background color + * @prop --bq-date-picker--border-color - Date picker border color + * @prop --bq-date-picker--border-color-focus - Date picker border color on focus + * @prop --bq-date-picker--border-color-disabled - Date picker border color when disabled + * @prop --bq-date-picker--border-radius - Date picker border radius + * @prop --bq-date-picker--border-width - Date picker border width + * @prop --bq-date-picker--border-style - Date picker border style + * @prop --bq-date-picker--gap - Gap between Date picker content and prefix/suffix + * @prop --bq-date-picker--helper-margin-top - Helper text margin top + * @prop --bq-date-picker--helper-text-color - Helper text color + * @prop --bq-date-picker--helper-text-size - Helper text size + * @prop --bq-date-picker--icon-size - Icon size to use in prefix/suffix and clear button + * @prop --bq-date-picker--label-margin-bottom - Date picker label margin bottom + * @prop --bq-date-picker--label-text-color - Date picker label text color + * @prop --bq-date-picker--label-text-size - Date picker label text size + * @prop --bq-date-picker--pading-start - Date picker padding start + * @prop --bq-date-picker--pading-end - Date picker padding end + * @prop --bq-date-picker--paddingY - Date picker padding top and bottom + * @prop --bq-date-picker--text-color - Date picker text color + * @prop --bq-date-picker--text-size - Date picker text size + * @prop --bq-date-picker--text-placeholder-color - Date picker placeholder text color + */ + --bq-date-picker--background-color: theme('colors.ui.primary'); + + --bq-date-picker--border-color: theme('colors.stroke.tertiary'); + --bq-date-picker--border-color-focus: theme('colors.stroke.brand'); + --bq-date-picker--border-radius: theme('borderRadius.s'); + --bq-date-picker--border-width: 1px; + --bq-date-picker--border-style: solid; + + --bq-date-picker--gap: theme('spacing.xs'); + + --bq-date-picker--helper-margin-top: theme('spacing.xs'); + --bq-date-picker--helper-text-size: theme('fontSize.s'); + --bq-date-picker--helper-text-color: theme('colors.text.primary'); + + --bq-date-picker--icon-size: 24px; + + --bq-date-picker--label-margin-bottom: theme('spacing.xs'); + --bq-date-picker--label-text-size: theme('fontSize.s'); + --bq-date-picker--label-text-color: theme('colors.text.primary'); + + --bq-date-picker--pading-start: theme('spacing.m'); + --bq-date-picker--pading-end: theme('spacing.m'); + --bq-date-picker--paddingY: theme('spacing.s'); + + --bq-date-picker--text-color: theme('colors.text.primary'); + --bq-date-picker--text-size: theme('fontSize.m'); + --bq-date-picker--text-placeholder-color: theme('colors.text.secondary'); +} diff --git a/packages/beeq/src/components/dropdown/readme.md b/packages/beeq/src/components/dropdown/readme.md index 71f4012c5..3a2b57f18 100644 --- a/packages/beeq/src/components/dropdown/readme.md +++ b/packages/beeq/src/components/dropdown/readme.md @@ -41,6 +41,7 @@ ### Used by + - [bq-date-picker](../date-picker) - [bq-select](../select) ### Depends on @@ -51,6 +52,7 @@ ```mermaid graph TD; bq-dropdown --> bq-panel + bq-date-picker --> bq-dropdown bq-select --> bq-dropdown style bq-dropdown fill:#f9f,stroke:#333,stroke-width:4px ``` diff --git a/packages/beeq/src/components/icon/readme.md b/packages/beeq/src/components/icon/readme.md index a62613965..506480081 100644 --- a/packages/beeq/src/components/icon/readme.md +++ b/packages/beeq/src/components/icon/readme.md @@ -41,6 +41,7 @@ Icons are simplified images that graphically explain the meaning of an object on - [bq-accordion](../accordion) - [bq-alert](../alert) - [bq-button](../button) + - [bq-date-picker](../date-picker) - [bq-dialog](../dialog) - [bq-drawer](../drawer) - [bq-empty-state](../empty-state) @@ -57,6 +58,7 @@ graph TD; bq-accordion --> bq-icon bq-alert --> bq-icon bq-button --> bq-icon + bq-date-picker --> bq-icon bq-dialog --> bq-icon bq-drawer --> bq-icon bq-empty-state --> bq-icon diff --git a/packages/beeq/src/global/scripts/global.ts b/packages/beeq/src/global/scripts/global.ts new file mode 100644 index 000000000..0840a3cca --- /dev/null +++ b/packages/beeq/src/global/scripts/global.ts @@ -0,0 +1 @@ +import 'cally'; From ea9dd0d660ddae13363c6699a6362ccb20ccbe4f Mon Sep 17 00:00:00 2001 From: Lungan Catalin Date: Mon, 22 Apr 2024 19:04:29 +0300 Subject: [PATCH 02/75] feat(Date Picker): add logic for single and range date picker --- packages/beeq/src/components.d.ts | 32 +++++++++--- .../_storybook/bq-date-picker.stories.tsx | 16 +++++- .../components/date-picker/bq-date-picker.tsx | 51 ++++++++++++++++--- .../beeq/src/components/date-picker/readme.md | 10 ++-- .../date-picker/scss/bq-date-picker.scss | 17 +++++++ 5 files changed, 105 insertions(+), 21 deletions(-) diff --git a/packages/beeq/src/components.d.ts b/packages/beeq/src/components.d.ts index 46de529b5..7ed51b5de 100644 --- a/packages/beeq/src/components.d.ts +++ b/packages/beeq/src/components.d.ts @@ -323,7 +323,7 @@ export namespace Components { } interface BqDatePicker { /** - * If true, the Date picker input will be focused on component render + * If `true`, the Date picker input will be focused on component render */ "autofocus": boolean; /** @@ -337,7 +337,7 @@ export namespace Components { */ "clearButtonLabel"?: string; /** - * If true, the clear button won't be displayed + * If `true`, the clear button won't be displayed */ "disableClear"?: boolean; /** @@ -353,15 +353,19 @@ export namespace Components { */ "form"?: string; /** - * If true, the Date picker panel will remain open after a selection date is made. + * If `true`, the Date picker panel will remain open after a selection date is made. */ "keepOpenOnSelect"?: boolean; + /** + * Number of months to show when range is `true` + */ + "months": number; /** * The Date picker input name. */ "name": string; /** - * If true, the Date picker panel will be visible. + * If `true`, the Date picker panel will be visible. */ "open"?: boolean; /** @@ -376,6 +380,10 @@ export namespace Components { * Position of the Date picker panel */ "placement"?: FloatingUIPlacement; + /** + * If `true`, the Date picker panel will accepts more than 1 month to display + */ + "range": boolean; /** * Indicates whether or not the Date picker input is required to be filled out before submitting the form. */ @@ -2533,7 +2541,7 @@ declare namespace LocalJSX { } interface BqDatePicker { /** - * If true, the Date picker input will be focused on component render + * If `true`, the Date picker input will be focused on component render */ "autofocus"?: boolean; /** @@ -2541,7 +2549,7 @@ declare namespace LocalJSX { */ "clearButtonLabel"?: string; /** - * If true, the clear button won't be displayed + * If `true`, the clear button won't be displayed */ "disableClear"?: boolean; /** @@ -2557,9 +2565,13 @@ declare namespace LocalJSX { */ "form"?: string; /** - * If true, the Date picker panel will remain open after a selection date is made. + * If `true`, the Date picker panel will remain open after a selection date is made. */ "keepOpenOnSelect"?: boolean; + /** + * Number of months to show when range is `true` + */ + "months"?: number; /** * The Date picker input name. */ @@ -2585,7 +2597,7 @@ declare namespace LocalJSX { */ "onBqInput"?: (event: BqDatePickerCustomEvent<{ value: string | number | string[]; el: HTMLBqInputElement }>) => void; /** - * If true, the Date picker panel will be visible. + * If `true`, the Date picker panel will be visible. */ "open"?: boolean; /** @@ -2600,6 +2612,10 @@ declare namespace LocalJSX { * Position of the Date picker panel */ "placement"?: FloatingUIPlacement; + /** + * If `true`, the Date picker panel will accepts more than 1 month to display + */ + "range"?: boolean; /** * Indicates whether or not the Date picker input is required to be filled out before submitting the form. */ 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 cf8fc94b5..e48c24cff 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 @@ -46,6 +46,8 @@ const meta: Meta = { skidding: { control: 'number' }, strategy: { control: 'select', options: ['fixed', 'absolute'] }, 'validation-status': { control: 'select', options: [...INPUT_VALIDATION] }, + range: { control: 'boolean' }, + month: { control: 'number' }, value: { control: 'text' }, // Events bqBlur: { action: 'bqBlur' }, @@ -68,13 +70,15 @@ const meta: Meta = { 'keep-open-on-select': false, name: 'bq-date-picker', open: false, - 'panel-height': undefined, + 'panel-height': 'auto', placement: 'bottom-start', placeholder: 'Enter your date', skidding: 0, strategy: 'absolute', required: false, 'validation-status': 'none', + range: false, + month: 1, value: undefined, }, }; @@ -114,6 +118,8 @@ const Template = (args: Args) => { skidding=${args.skidding} strategy=${args.strategy} validation-status=${args['validation-status']} + range=${args.range} + months=${args.months} value=${ifDefined(args.value)} @bqBlur=${args.bqBlur} @bqChange=${args.bqChange} @@ -132,3 +138,11 @@ const Template = (args: Args) => { export const Default: Story = { render: Template, }; + +export const Range: Story = { + render: Template, + args: { + range: true, + months: 2, + }, +}; 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 c121ec659..8dc45171a 100644 --- a/packages/beeq/src/components/date-picker/bq-date-picker.tsx +++ b/packages/beeq/src/components/date-picker/bq-date-picker.tsx @@ -50,7 +50,7 @@ export class BqDatePicker { // Public Property API // ======================== - /** If true, the Date picker input will be focused on component render */ + /** If `true`, the Date picker input will be focused on component render */ @Prop({ reflect: true }) autofocus: boolean; /** The clear button aria label */ @@ -62,7 +62,7 @@ export class BqDatePicker { */ @Prop({ mutable: true }) disabled?: boolean = false; - /** If true, the clear button won't be displayed */ + /** If `true`, the clear button won't be displayed */ @Prop({ reflect: true }) disableClear? = false; /** Represents the distance (gutter or margin) between the Date picker panel and the input element. */ @@ -71,13 +71,13 @@ export class BqDatePicker { /** The ID of the form that the Date picker input belongs to. */ @Prop({ reflect: true }) form?: string; - /** If true, the Date picker panel will remain open after a selection date is made. */ + /** If `true`, the Date picker panel will remain open after a selection date is made. */ @Prop({ reflect: true }) keepOpenOnSelect?: boolean = false; /** The Date picker input name. */ @Prop({ reflect: true }) name!: string; - /** If true, the Date picker panel will be visible. */ + /** If `true`, the Date picker panel will be visible. */ @Prop({ reflect: true, mutable: true }) open?: boolean = false; /** When set, it will override the height of the Date picker panel. */ @@ -98,6 +98,12 @@ export class BqDatePicker { /** Defines the strategy to position the Date picker panel */ @Prop({ reflect: true }) strategy?: 'fixed' | 'absolute' = 'fixed'; + /** If `true`, the Date picker panel will accepts more than 1 month to display */ + @Prop({ reflect: true }) range: boolean = false; + + /** Number of months to show when range is `true` */ + @Prop({ reflect: true }) months: number; + /** * The validation status of the Select input. * @@ -243,6 +249,30 @@ export class BqDatePicker { this.hasSuffix = hasSlotContent(this.suffixElem); }; + /** + * Generates an array of JSX elements representing calendar months. + * If the 'range' property is true and the 'months' property is defined, + * it generates multiple calendar months with incremental 'offset' values. + * If the 'range' property is false or the 'months' property is undefined, + * it generates a single calendar month without an 'offset'. + * + * @returns An array of JSX elements representing calendar months. + */ + private generateCalendarMonths(): JSX.Element[] { + const months: JSX.Element[] = []; + + if (this.range && this.months) { + for (let i = 0; i < this.months; i++) { + const offset = i > 0 ? i : undefined; + months.push(); + } + } else { + months.push(); + } + + return months; + } + // render() function // Always the last one in the class. // =================================== @@ -250,6 +280,8 @@ export class BqDatePicker { render() { const labelId = `bq-date-picker__label-${this.name || this.fallbackInputId}`; + const CalendarComponentType = this.range ? 'calendar-range' : 'calendar-date'; + return (
{/* Label */} @@ -349,15 +381,18 @@ export class BqDatePicker {
-
- + { this.value = ev.target.value; }} > - - + + + + {this.generateCalendarMonths()} +
diff --git a/packages/beeq/src/components/date-picker/readme.md b/packages/beeq/src/components/date-picker/readme.md index 2d9db098e..4fd1af88d 100644 --- a/packages/beeq/src/components/date-picker/readme.md +++ b/packages/beeq/src/components/date-picker/readme.md @@ -9,18 +9,20 @@ | Property | Attribute | Description | Type | Default | | ------------------- | --------------------- | --------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------- | -| `autofocus` | `autofocus` | If true, the Date picker input will be focused on component render | `boolean` | `undefined` | +| `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` | +| `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` | | `form` | `form` | The ID of the form that the Date picker input belongs to. | `string` | `undefined` | -| `keepOpenOnSelect` | `keep-open-on-select` | If true, the Date picker panel will remain open after a selection date is made. | `boolean` | `false` | +| `keepOpenOnSelect` | `keep-open-on-select` | If `true`, the Date picker panel will remain open after a selection date is made. | `boolean` | `false` | +| `months` | `months` | Number of months to show when range is `true` | `number` | `undefined` | | `name` _(required)_ | `name` | The Date picker input name. | `string` | `undefined` | -| `open` | `open` | If true, the Date picker panel will be visible. | `boolean` | `false` | +| `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-start'` | +| `range` | `range` | If `true`, the Date picker panel will accepts more than 1 month to display | `boolean` | `false` | | `required` | `required` | Indicates whether or not the Date picker input is required to be filled out before submitting the form. | `boolean` | `undefined` | | `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'` | diff --git a/packages/beeq/src/components/date-picker/scss/bq-date-picker.scss b/packages/beeq/src/components/date-picker/scss/bq-date-picker.scss index 627cc6435..0dece59d5 100644 --- a/packages/beeq/src/components/date-picker/scss/bq-date-picker.scss +++ b/packages/beeq/src/components/date-picker/scss/bq-date-picker.scss @@ -139,3 +139,20 @@ bq-icon, ::slotted(bq-icon) { --bq-icon--size: var(--bq-date-picker--icon-size) !important; } + +calendar-date, +calendar-range { + &::part(header) { + @apply justify-center gap-[--bq-spacing-xs]; + } + + &::part(heading) { + @apply px-[--bq-spacing-xs] py-[--bq-spacing-xs2]; + } + + &::part(button) { + background-color: theme('colors.transparent'); + border: none; + padding: theme('spacing.xs2'); + } +} From 03849c6e26f2e272c4020c71a287265a02632329 Mon Sep 17 00:00:00 2001 From: Lungan Catalin Date: Mon, 22 Apr 2024 19:06:48 +0300 Subject: [PATCH 03/75] feat(Date Picker): add some basic style for calendar-month component --- .../date-picker/scss/bq-date-picker.scss | 35 +++++++++++++++++-- 1 file changed, 33 insertions(+), 2 deletions(-) diff --git a/packages/beeq/src/components/date-picker/scss/bq-date-picker.scss b/packages/beeq/src/components/date-picker/scss/bq-date-picker.scss index 0dece59d5..162e6f72e 100644 --- a/packages/beeq/src/components/date-picker/scss/bq-date-picker.scss +++ b/packages/beeq/src/components/date-picker/scss/bq-date-picker.scss @@ -140,6 +140,10 @@ bq-icon, --bq-icon--size: var(--bq-date-picker--icon-size) !important; } +/* -------------------------------------------------------------------------- */ +/* Customize Cally date picker */ +/* -------------------------------------------------------------------------- */ + calendar-date, calendar-range { &::part(header) { @@ -151,8 +155,35 @@ calendar-range { } &::part(button) { + @apply border-0 p-[--bq-spacing-xs]; + background-color: theme('colors.transparent'); - border: none; - padding: theme('spacing.xs2'); + } +} + +calendar-month { + /* stylelint-disable-next-line custom-property-pattern */ + --color-accent: var(--bq-stroke--brand); + + &::part(button) { + @apply h-8 w-8 p-1 font-[--bq-font-family] text-[--bq-text--primary]; + } + + &::part(selected) { + @apply rounded-[--bq-radius--s] text-[color:var(--bq-text--inverse)]; + } + + &::part(range-inner) { + @apply rounded-none; + } + + &::part(range-start) { + border-start-end-radius: 0; + border-end-end-radius: 0; + } + + &::part(range-end) { + border-start-start-radius: 0; + border-end-start-radius: 0; } } From 7ac4edb6bfa3a80b38ec3bbdcdd022b2e2320418 Mon Sep 17 00:00:00 2001 From: Lungan Catalin Date: Mon, 22 Apr 2024 19:12:59 +0300 Subject: [PATCH 04/75] feat(Date Picker): add prop to show days outside the month --- packages/beeq/src/components.d.ts | 12 +++++- .../_storybook/bq-date-picker.stories.tsx | 3 ++ .../components/date-picker/bq-date-picker.tsx | 8 +++- .../beeq/src/components/date-picker/readme.md | 43 ++++++++++--------- 4 files changed, 42 insertions(+), 24 deletions(-) diff --git a/packages/beeq/src/components.d.ts b/packages/beeq/src/components.d.ts index 7ed51b5de..e2840648f 100644 --- a/packages/beeq/src/components.d.ts +++ b/packages/beeq/src/components.d.ts @@ -388,6 +388,10 @@ export namespace Components { * Indicates whether or not the Date picker input is required to be filled out before submitting the form. */ "required"?: boolean; + /** + * Whether to show days outside the month + */ + "showOutsideDays": boolean; /** * Represents the skidding between the Date picker panel and the input element. */ @@ -402,7 +406,7 @@ export namespace Components { */ "validationStatus": TInputValidation; /** - * The select input value, it can be used to reset the field to a previous 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). */ "value": TInputValue; } @@ -2620,6 +2624,10 @@ declare namespace LocalJSX { * Indicates whether or not the Date picker input is required to be filled out before submitting the form. */ "required"?: boolean; + /** + * Whether to show days outside the month + */ + "showOutsideDays"?: boolean; /** * Represents the skidding between the Date picker panel and the input element. */ @@ -2634,7 +2642,7 @@ declare namespace LocalJSX { */ "validationStatus"?: TInputValidation; /** - * The select input value, it can be used to reset the field to a previous 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). */ "value"?: TInputValue; } 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 e48c24cff..e16361ffc 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 @@ -21,6 +21,7 @@ const meta: Meta = { disabled: { control: 'boolean' }, form: { control: 'text' }, 'keep-open-on-select': { control: 'boolean' }, + 'show-outside-days': { control: 'boolean' }, name: { control: 'text' }, open: { control: 'boolean' }, 'panel-height': { control: 'text' }, @@ -68,6 +69,7 @@ const meta: Meta = { disabled: false, form: undefined, 'keep-open-on-select': false, + 'show-outside-days': false, name: 'bq-date-picker', open: false, 'panel-height': 'auto', @@ -109,6 +111,7 @@ const Template = (args: Args) => { ?disabled=${args.disabled} form=${ifDefined(args.form)} ?keep-open-on-select=${args['keep-open-on-select']} + ?show-outside-days=${args['show-outside-days']} name=${ifDefined(args.name)} ?open=${args.open} panel-height=${args['panel-height']} 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 8dc45171a..9a58160b4 100644 --- a/packages/beeq/src/components/date-picker/bq-date-picker.tsx +++ b/packages/beeq/src/components/date-picker/bq-date-picker.tsx @@ -116,9 +116,13 @@ export class BqDatePicker { */ @Prop({ reflect: true }) validationStatus: TInputValidation = 'none'; - /** The select input value, it can be used to reset the field to a previous 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). */ @Prop({ reflect: true, mutable: true }) value: TInputValue; + /** Whether to show days outside the month */ + @Prop({ reflect: true }) showOutsideDays: boolean = false; + // Prop lifecycle events // ======================= @@ -384,6 +388,8 @@ export class BqDatePicker {
{ this.value = ev.target.value; }} diff --git a/packages/beeq/src/components/date-picker/readme.md b/packages/beeq/src/components/date-picker/readme.md index 4fd1af88d..9dcbd75da 100644 --- a/packages/beeq/src/components/date-picker/readme.md +++ b/packages/beeq/src/components/date-picker/readme.md @@ -7,27 +7,28 @@ ## 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` | -| `form` | `form` | The ID of the form that the Date picker input belongs to. | `string` | `undefined` | -| `keepOpenOnSelect` | `keep-open-on-select` | If `true`, the Date picker panel will remain open after a selection date is made. | `boolean` | `false` | -| `months` | `months` | Number of months to show when range is `true` | `number` | `undefined` | -| `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-start'` | -| `range` | `range` | If `true`, the Date picker panel will accepts more than 1 month to display | `boolean` | `false` | -| `required` | `required` | Indicates whether or not the Date picker input is required to be filled out before submitting the form. | `boolean` | `undefined` | -| `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'` | -| `validationStatus` | `validation-status` | The validation status of the Select input. | `"error" \| "none" \| "success" \| "warning"` | `'none'` | -| `value` | `value` | The select input value, it can be used to reset the field to a previous value | `number \| string \| 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` | +| `form` | `form` | The ID of the form that the Date picker input belongs to. | `string` | `undefined` | +| `keepOpenOnSelect` | `keep-open-on-select` | If `true`, the Date picker panel will remain open after a selection date is made. | `boolean` | `false` | +| `months` | `months` | Number of months to show when range is `true` | `number` | `undefined` | +| `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-start'` | +| `range` | `range` | If `true`, the Date picker panel will accepts more than 1 month to display | `boolean` | `false` | +| `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'` | +| `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). | `number \| string \| string[]` | `undefined` | ## Events From b65affcd5c00c9892b718fc8340209c8f1c4e359 Mon Sep 17 00:00:00 2001 From: Lungan Catalin Date: Mon, 22 Apr 2024 19:18:47 +0300 Subject: [PATCH 05/75] feat(Date Picker): add firstDayOfWeek prop for customizable week start in calendar --- packages/beeq/src/components.d.ts | 8 ++++++++ .../date-picker/_storybook/bq-date-picker.stories.tsx | 3 +++ .../beeq/src/components/date-picker/bq-date-picker.tsx | 4 ++++ packages/beeq/src/components/date-picker/readme.md | 1 + 4 files changed, 16 insertions(+) diff --git a/packages/beeq/src/components.d.ts b/packages/beeq/src/components.d.ts index e2840648f..3e0fc6d6f 100644 --- a/packages/beeq/src/components.d.ts +++ b/packages/beeq/src/components.d.ts @@ -348,6 +348,10 @@ export namespace Components { * Represents the distance (gutter or margin) between the Date picker panel and the input element. */ "distance"?: number; + /** + * The first day of the week, where Sunday is 0, Monday is 1, etc + */ + "firstDayOfWeek"?: number; /** * The ID of the form that the Date picker input belongs to. */ @@ -2564,6 +2568,10 @@ declare namespace LocalJSX { * Represents the distance (gutter or margin) between the Date picker panel and the input element. */ "distance"?: number; + /** + * The first day of the week, where Sunday is 0, Monday is 1, etc + */ + "firstDayOfWeek"?: number; /** * The ID of the form that the Date picker input belongs to. */ 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 e16361ffc..54c635901 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 @@ -22,6 +22,7 @@ const meta: Meta = { form: { control: 'text' }, 'keep-open-on-select': { control: 'boolean' }, 'show-outside-days': { control: 'boolean' }, + 'first-day-of-week': { control: 'number' }, name: { control: 'text' }, open: { control: 'boolean' }, 'panel-height': { control: 'text' }, @@ -70,6 +71,7 @@ const meta: Meta = { form: undefined, 'keep-open-on-select': false, 'show-outside-days': false, + 'first-day-of-week': 1, name: 'bq-date-picker', open: false, 'panel-height': 'auto', @@ -112,6 +114,7 @@ const Template = (args: Args) => { form=${ifDefined(args.form)} ?keep-open-on-select=${args['keep-open-on-select']} ?show-outside-days=${args['show-outside-days']} + first-day-of-week=${args['first-day-of-week']} name=${ifDefined(args.name)} ?open=${args.open} panel-height=${args['panel-height']} 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 9a58160b4..059609fe3 100644 --- a/packages/beeq/src/components/date-picker/bq-date-picker.tsx +++ b/packages/beeq/src/components/date-picker/bq-date-picker.tsx @@ -123,6 +123,9 @@ export class BqDatePicker { /** Whether to show days outside the month */ @Prop({ reflect: true }) showOutsideDays: boolean = false; + /** The first day of the week, where Sunday is 0, Monday is 1, etc */ + @Prop({ reflect: true }) firstDayOfWeek?: number = 1; + // Prop lifecycle events // ======================= @@ -389,6 +392,7 @@ export class BqDatePicker { { this.value = ev.target.value; diff --git a/packages/beeq/src/components/date-picker/readme.md b/packages/beeq/src/components/date-picker/readme.md index 9dcbd75da..47c06658d 100644 --- a/packages/beeq/src/components/date-picker/readme.md +++ b/packages/beeq/src/components/date-picker/readme.md @@ -14,6 +14,7 @@ | `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 | `number` | `1` | | `form` | `form` | The ID of the form that the Date picker input belongs to. | `string` | `undefined` | | `keepOpenOnSelect` | `keep-open-on-select` | If `true`, the Date picker panel will remain open after a selection date is made. | `boolean` | `false` | | `months` | `months` | Number of months to show when range is `true` | `number` | `undefined` | From 45e242c82146918ae5d1cdd2320be6a1f416318a Mon Sep 17 00:00:00 2001 From: Lungan Catalin Date: Mon, 22 Apr 2024 19:23:57 +0300 Subject: [PATCH 06/75] feat(Date Picker): add min and max props for defining earliest and latest selectable dates --- packages/beeq/src/components.d.ts | 16 ++++++++++++++++ .../_storybook/bq-date-picker.stories.tsx | 6 ++++++ .../components/date-picker/bq-date-picker.tsx | 8 ++++++++ .../beeq/src/components/date-picker/readme.md | 2 ++ 4 files changed, 32 insertions(+) diff --git a/packages/beeq/src/components.d.ts b/packages/beeq/src/components.d.ts index 3e0fc6d6f..e82d7ce08 100644 --- a/packages/beeq/src/components.d.ts +++ b/packages/beeq/src/components.d.ts @@ -360,6 +360,14 @@ export namespace Components { * If `true`, the Date picker panel will remain open after a selection date is made. */ "keepOpenOnSelect"?: boolean; + /** + * The latest date that can be selected + */ + "max"?: string; + /** + * The earliest date that can be selected + */ + "min"?: string; /** * Number of months to show when range is `true` */ @@ -2580,6 +2588,14 @@ declare namespace LocalJSX { * If `true`, the Date picker panel will remain open after a selection date is made. */ "keepOpenOnSelect"?: boolean; + /** + * The latest date that can be selected + */ + "max"?: string; + /** + * The earliest date that can be selected + */ + "min"?: string; /** * Number of months to show when range is `true` */ 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 54c635901..739ae19b8 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 @@ -20,6 +20,8 @@ const meta: Meta = { distance: { control: 'number' }, disabled: { control: 'boolean' }, form: { control: 'text' }, + min: { control: 'text' }, + max: { control: 'text' }, 'keep-open-on-select': { control: 'boolean' }, 'show-outside-days': { control: 'boolean' }, 'first-day-of-week': { control: 'number' }, @@ -69,6 +71,8 @@ const meta: Meta = { distance: 8, disabled: false, form: undefined, + min: undefined, + max: undefined, 'keep-open-on-select': false, 'show-outside-days': false, 'first-day-of-week': 1, @@ -112,6 +116,8 @@ const Template = (args: Args) => { ?disable-clear=${args['disable-clear']} ?disabled=${args.disabled} form=${ifDefined(args.form)} + min=${ifDefined(args.min)} + max=${ifDefined(args.max)} ?keep-open-on-select=${args['keep-open-on-select']} ?show-outside-days=${args['show-outside-days']} first-day-of-week=${args['first-day-of-week']} 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 059609fe3..032b50122 100644 --- a/packages/beeq/src/components/date-picker/bq-date-picker.tsx +++ b/packages/beeq/src/components/date-picker/bq-date-picker.tsx @@ -126,6 +126,12 @@ export class BqDatePicker { /** The first day of the week, where Sunday is 0, Monday is 1, etc */ @Prop({ reflect: true }) firstDayOfWeek?: number = 1; + /** The earliest date that can be selected */ + @Prop({ reflect: true }) min?: string; + + /** The latest date that can be selected */ + @Prop({ reflect: true }) max?: string; + // Prop lifecycle events // ======================= @@ -391,6 +397,8 @@ export class BqDatePicker {
Date: Mon, 22 Apr 2024 19:27:15 +0300 Subject: [PATCH 07/75] feat(Date Picker): add locale prop, defaults to browser's --- packages/beeq/src/components.d.ts | 8 ++++++++ .../date-picker/_storybook/bq-date-picker.stories.tsx | 3 +++ .../beeq/src/components/date-picker/bq-date-picker.tsx | 4 ++++ packages/beeq/src/components/date-picker/readme.md | 1 + 4 files changed, 16 insertions(+) diff --git a/packages/beeq/src/components.d.ts b/packages/beeq/src/components.d.ts index e82d7ce08..24cfc4f14 100644 --- a/packages/beeq/src/components.d.ts +++ b/packages/beeq/src/components.d.ts @@ -360,6 +360,10 @@ export namespace Components { * If `true`, the Date picker panel will remain open after a selection date is made. */ "keepOpenOnSelect"?: boolean; + /** + * The locale for formatting dates. If not set, will use the browser's locale + */ + "locale"?: string | undefined; /** * The latest date that can be selected */ @@ -2588,6 +2592,10 @@ declare namespace LocalJSX { * If `true`, the Date picker panel will remain open after a selection date is made. */ "keepOpenOnSelect"?: boolean; + /** + * The locale for formatting dates. If not set, will use the browser's locale + */ + "locale"?: string | undefined; /** * The latest date that can be selected */ 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 739ae19b8..86e451b46 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 @@ -22,6 +22,7 @@ const meta: Meta = { form: { control: 'text' }, min: { control: 'text' }, max: { control: 'text' }, + locale: { control: 'text' }, 'keep-open-on-select': { control: 'boolean' }, 'show-outside-days': { control: 'boolean' }, 'first-day-of-week': { control: 'number' }, @@ -73,6 +74,7 @@ const meta: Meta = { form: undefined, min: undefined, max: undefined, + locale: undefined, 'keep-open-on-select': false, 'show-outside-days': false, 'first-day-of-week': 1, @@ -118,6 +120,7 @@ const Template = (args: Args) => { form=${ifDefined(args.form)} min=${ifDefined(args.min)} max=${ifDefined(args.max)} + locale=${ifDefined(args.locale)} ?keep-open-on-select=${args['keep-open-on-select']} ?show-outside-days=${args['show-outside-days']} first-day-of-week=${args['first-day-of-week']} 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 032b50122..c134635db 100644 --- a/packages/beeq/src/components/date-picker/bq-date-picker.tsx +++ b/packages/beeq/src/components/date-picker/bq-date-picker.tsx @@ -132,6 +132,9 @@ export class BqDatePicker { /** The latest date that can be selected */ @Prop({ reflect: true }) max?: string; + /** The locale for formatting dates. If not set, will use the browser's locale */ + @Prop({ reflect: true }) locale?: string | undefined = undefined; + // Prop lifecycle events // ======================= @@ -396,6 +399,7 @@ export class BqDatePicker {
Date: Mon, 22 Apr 2024 19:35:51 +0300 Subject: [PATCH 08/75] feat(Date Picker): add horizontal layout styling for range calendar --- packages/beeq/src/components.d.ts | 2 +- .../date-picker/_storybook/bq-date-picker.stories.tsx | 2 +- .../beeq/src/components/date-picker/bq-date-picker.tsx | 6 +++--- .../src/components/date-picker/scss/bq-date-picker.scss | 8 +++++++- 4 files changed, 12 insertions(+), 6 deletions(-) diff --git a/packages/beeq/src/components.d.ts b/packages/beeq/src/components.d.ts index 24cfc4f14..c58d19762 100644 --- a/packages/beeq/src/components.d.ts +++ b/packages/beeq/src/components.d.ts @@ -363,7 +363,7 @@ export namespace Components { /** * The locale for formatting dates. If not set, will use the browser's locale */ - "locale"?: string | undefined; + "locale": string | undefined; /** * The latest date that can be selected */ 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 86e451b46..b5d3e14d5 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 @@ -110,7 +110,7 @@ const Template = (args: Args) => { `; return html` -
+
{/* Select date picker dropdown */} - {this.generateCalendarMonths()} +
{this.generateCalendarMonths()}
diff --git a/packages/beeq/src/components/date-picker/scss/bq-date-picker.scss b/packages/beeq/src/components/date-picker/scss/bq-date-picker.scss index 162e6f72e..99a0ee464 100644 --- a/packages/beeq/src/components/date-picker/scss/bq-date-picker.scss +++ b/packages/beeq/src/components/date-picker/scss/bq-date-picker.scss @@ -159,6 +159,10 @@ calendar-range { background-color: theme('colors.transparent'); } + + &::part(container) { + @apply px-5 py-2; + } } calendar-month { @@ -166,7 +170,9 @@ calendar-month { --color-accent: var(--bq-stroke--brand); &::part(button) { - @apply h-8 w-8 p-1 font-[--bq-font-family] text-[--bq-text--primary]; + @apply h-8 w-8 p-1 text-[--bq-text--primary]; + + font-family: var(--bq-font-family); } &::part(selected) { From 1de3d92d47e9533ca1b475b53ab4317ba97f0f63 Mon Sep 17 00:00:00 2001 From: Lungan Catalin Date: Mon, 22 Apr 2024 20:15:17 +0300 Subject: [PATCH 09/75] feat(Date Picker): add correct token for arrow color --- packages/beeq/src/components/date-picker/bq-date-picker.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) 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 b058cb3e4..eda5f64a5 100644 --- a/packages/beeq/src/components/date-picker/bq-date-picker.tsx +++ b/packages/beeq/src/components/date-picker/bq-date-picker.tsx @@ -410,8 +410,8 @@ export class BqDatePicker { this.value = ev.target.value; }} > - - + +
{this.generateCalendarMonths()}
From 0cb2e03d201014f683050009d270eae59e4f8660 Mon Sep 17 00:00:00 2001 From: Lungan Catalin Date: Tue, 23 Apr 2024 17:57:41 +0300 Subject: [PATCH 10/75] feat(Date Picker): add listen for bqOpen and style outside days --- packages/beeq/src/components.d.ts | 8 --- .../_storybook/bq-date-picker.stories.tsx | 3 -- .../components/date-picker/bq-date-picker.tsx | 16 +++--- .../beeq/src/components/date-picker/readme.md | 51 +++++++++---------- .../date-picker/scss/bq-date-picker.scss | 4 ++ 5 files changed, 39 insertions(+), 43 deletions(-) diff --git a/packages/beeq/src/components.d.ts b/packages/beeq/src/components.d.ts index c58d19762..483f40660 100644 --- a/packages/beeq/src/components.d.ts +++ b/packages/beeq/src/components.d.ts @@ -356,10 +356,6 @@ export namespace Components { * The ID of the form that the Date picker input belongs to. */ "form"?: string; - /** - * If `true`, the Date picker panel will remain open after a selection date is made. - */ - "keepOpenOnSelect"?: boolean; /** * The locale for formatting dates. If not set, will use the browser's locale */ @@ -2588,10 +2584,6 @@ declare namespace LocalJSX { * The ID of the form that the Date picker input belongs to. */ "form"?: string; - /** - * If `true`, the Date picker panel will remain open after a selection date is made. - */ - "keepOpenOnSelect"?: boolean; /** * The locale for formatting dates. If not set, will use the browser's locale */ 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 b5d3e14d5..b2a238bcc 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 @@ -23,7 +23,6 @@ const meta: Meta = { min: { control: 'text' }, max: { control: 'text' }, locale: { control: 'text' }, - 'keep-open-on-select': { control: 'boolean' }, 'show-outside-days': { control: 'boolean' }, 'first-day-of-week': { control: 'number' }, name: { control: 'text' }, @@ -75,7 +74,6 @@ const meta: Meta = { min: undefined, max: undefined, locale: undefined, - 'keep-open-on-select': false, 'show-outside-days': false, 'first-day-of-week': 1, name: 'bq-date-picker', @@ -121,7 +119,6 @@ const Template = (args: Args) => { min=${ifDefined(args.min)} max=${ifDefined(args.max)} locale=${ifDefined(args.locale)} - ?keep-open-on-select=${args['keep-open-on-select']} ?show-outside-days=${args['show-outside-days']} first-day-of-week=${args['first-day-of-week']} name=${ifDefined(args.name)} 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 eda5f64a5..8b70d1c60 100644 --- a/packages/beeq/src/components/date-picker/bq-date-picker.tsx +++ b/packages/beeq/src/components/date-picker/bq-date-picker.tsx @@ -1,4 +1,4 @@ -import { Component, Element, Event, EventEmitter, h, Method, Prop, State, Watch } from '@stencil/core'; +import { Component, Element, Event, EventEmitter, h, Listen, Method, Prop, State, Watch } from '@stencil/core'; import { FloatingUIPlacement } from '../../services/interfaces'; import { hasSlotContent, isDefined, isHTMLElement } from '../../shared/utils'; @@ -71,9 +71,6 @@ export class BqDatePicker { /** The ID of the form that the Date picker input belongs to. */ @Prop({ reflect: true }) form?: string; - /** If `true`, the Date picker panel will remain open after a selection date is made. */ - @Prop({ reflect: true }) keepOpenOnSelect?: boolean = false; - /** The Date picker input name. */ @Prop({ reflect: true }) name!: string; @@ -184,6 +181,13 @@ export class BqDatePicker { // Listeners // ============== + @Listen('bqOpen', { capture: true }) + handleOpenChange(ev: CustomEvent<{ open: boolean }>) { + if (!ev.composedPath().includes(this.el)) return; + + this.open = ev.detail.open; + } + // Public methods API // These methods are exposed on the host element. // Always use two lines. @@ -312,10 +316,9 @@ export class BqDatePicker { {/* Select date picker dropdown */} { this.value = ev.target.value; + this.open = false; }} > diff --git a/packages/beeq/src/components/date-picker/readme.md b/packages/beeq/src/components/date-picker/readme.md index 231a8c612..6e84570bc 100644 --- a/packages/beeq/src/components/date-picker/readme.md +++ b/packages/beeq/src/components/date-picker/readme.md @@ -7,32 +7,31 @@ ## 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 | `number` | `1` | -| `form` | `form` | The ID of the form that the Date picker input belongs to. | `string` | `undefined` | -| `keepOpenOnSelect` | `keep-open-on-select` | If `true`, the Date picker panel will remain open after a selection date is made. | `boolean` | `false` | -| `locale` | `locale` | The locale for formatting dates. If not set, will use the browser's locale | `string` | `undefined` | -| `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` | -| `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-start'` | -| `range` | `range` | If `true`, the Date picker panel will accepts more than 1 month to display | `boolean` | `false` | -| `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'` | -| `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). | `number \| string \| 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 | `number` | `1` | +| `form` | `form` | The ID of the form that the Date picker input belongs to. | `string` | `undefined` | +| `locale` | `locale` | The locale for formatting dates. If not set, will use the browser's locale | `string` | `undefined` | +| `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` | +| `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-start'` | +| `range` | `range` | If `true`, the Date picker panel will accepts more than 1 month to display | `boolean` | `false` | +| `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'` | +| `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). | `number \| string \| string[]` | `undefined` | ## Events diff --git a/packages/beeq/src/components/date-picker/scss/bq-date-picker.scss b/packages/beeq/src/components/date-picker/scss/bq-date-picker.scss index 99a0ee464..5f4efac1e 100644 --- a/packages/beeq/src/components/date-picker/scss/bq-date-picker.scss +++ b/packages/beeq/src/components/date-picker/scss/bq-date-picker.scss @@ -175,6 +175,10 @@ calendar-month { font-family: var(--bq-font-family); } + &::part(outside) { + @apply text-[--bq-text--secondary] opacity-100; + } + &::part(selected) { @apply rounded-[--bq-radius--s] text-[color:var(--bq-text--inverse)]; } From 492a9ecf54000f4d6e33d5443889f71b8124744d Mon Sep 17 00:00:00 2001 From: Lungan Catalin Date: Tue, 23 Apr 2024 18:32:55 +0300 Subject: [PATCH 11/75] feat(Date Picker): add w-full --- packages/beeq/src/components/date-picker/bq-date-picker.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 8b70d1c60..55205b8e9 100644 --- a/packages/beeq/src/components/date-picker/bq-date-picker.tsx +++ b/packages/beeq/src/components/date-picker/bq-date-picker.tsx @@ -316,7 +316,7 @@ export class BqDatePicker { {/* Select date picker dropdown */} Date: Wed, 24 Apr 2024 13:26:03 +0300 Subject: [PATCH 12/75] feat(Date Picker): optimize calendar range display logic for mobile view --- packages/beeq/src/components/date-picker/bq-date-picker.tsx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) 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 55205b8e9..dfe6e9a66 100644 --- a/packages/beeq/src/components/date-picker/bq-date-picker.tsx +++ b/packages/beeq/src/components/date-picker/bq-date-picker.tsx @@ -284,7 +284,8 @@ export class BqDatePicker { if (this.range && this.months) { for (let i = 0; i < this.months; i++) { const offset = i > 0 ? i : undefined; - months.push(); + const className = offset ? 'hidden sm:block' : ''; + months.push(); } } else { months.push(); From 194d15e1c2d493dabc24325ad822131987d6ebfc Mon Sep 17 00:00:00 2001 From: Lungan Catalin Date: Wed, 24 Apr 2024 18:01:36 +0300 Subject: [PATCH 13/75] feat(Date Picker): add some style to date picker --- .../src/components/date-picker/scss/bq-date-picker.scss | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/packages/beeq/src/components/date-picker/scss/bq-date-picker.scss b/packages/beeq/src/components/date-picker/scss/bq-date-picker.scss index 5f4efac1e..59dcb762c 100644 --- a/packages/beeq/src/components/date-picker/scss/bq-date-picker.scss +++ b/packages/beeq/src/components/date-picker/scss/bq-date-picker.scss @@ -170,9 +170,13 @@ calendar-month { --color-accent: var(--bq-stroke--brand); &::part(button) { - @apply h-8 w-8 p-1 text-[--bq-text--primary]; + @apply h-8 w-8 rounded-[--bq-radius--s] p-1 text-[--bq-text--primary]; font-family: var(--bq-font-family); + + &:hover:not([disabled]) { + @apply bg-[--bq-ui--secondary]; + } } &::part(outside) { From 76911a75538866f9e9023878794e55df2cceed79 Mon Sep 17 00:00:00 2001 From: Lungan Catalin Date: Thu, 25 Apr 2024 13:31:53 +0300 Subject: [PATCH 14/75] feat(Date Picker): add @part docs for calendar components --- .../components/date-picker/bq-date-picker.tsx | 41 +++++++++++++++++- .../beeq/src/components/date-picker/readme.md | 42 ++++++++++++++----- .../date-picker/scss/bq-date-picker.scss | 8 ++-- 3 files changed, 74 insertions(+), 17 deletions(-) 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 dfe6e9a66..509624fe9 100644 --- a/packages/beeq/src/components/date-picker/bq-date-picker.tsx +++ b/packages/beeq/src/components/date-picker/bq-date-picker.tsx @@ -14,6 +14,33 @@ import { TInputValidation, TInputValue } from '../input/bq-input.types'; * @part panel - The date picker panel container * @part prefix - The prefix slot container. * @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. + +// 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 daythat 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. */ @Component({ tag: 'bq-date-picker', @@ -281,14 +308,23 @@ export class BqDatePicker { private generateCalendarMonths(): JSX.Element[] { const months: JSX.Element[] = []; + const commonExportParts = 'heading,table,tr,head,week,th,td'; + const buttonExportParts = 'button,day,selected,today,disallowed,outside,range-start,range-end,range-inner'; + if (this.range && this.months) { for (let i = 0; i < this.months; i++) { const offset = i > 0 ? i : undefined; const className = offset ? 'hidden sm:block' : ''; - months.push(); + months.push( + , + ); } } else { - months.push(); + months.push(); } return months; @@ -414,6 +450,7 @@ export class BqDatePicker { this.value = ev.target.value; this.open = false; }} + exportparts="container,header,button,previous,next,disabled,heading" > diff --git a/packages/beeq/src/components/date-picker/readme.md b/packages/beeq/src/components/date-picker/readme.md index 6e84570bc..1135193ee 100644 --- a/packages/beeq/src/components/date-picker/readme.md +++ b/packages/beeq/src/components/date-picker/readme.md @@ -60,17 +60,37 @@ 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. | -| `"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. | +| 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 daythat 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. | ## Dependencies diff --git a/packages/beeq/src/components/date-picker/scss/bq-date-picker.scss b/packages/beeq/src/components/date-picker/scss/bq-date-picker.scss index 59dcb762c..506da7e8f 100644 --- a/packages/beeq/src/components/date-picker/scss/bq-date-picker.scss +++ b/packages/beeq/src/components/date-picker/scss/bq-date-picker.scss @@ -170,13 +170,13 @@ calendar-month { --color-accent: var(--bq-stroke--brand); &::part(button) { - @apply h-8 w-8 rounded-[--bq-radius--s] p-1 text-[--bq-text--primary]; + @apply h-8 w-8 rounded-[--bq-radius--s] p-1 text-[--bq-text--primary] hover:bg-[--bq-ui--secondary]; font-family: var(--bq-font-family); + } - &:hover:not([disabled]) { - @apply bg-[--bq-ui--secondary]; - } + &::part(button day selected) { + @apply bg-[--bq-ui--brand] hover:bg-hover-ui-brand; } &::part(outside) { From 306337d9118110b79b5ea2f711a595fea626026a Mon Sep 17 00:00:00 2001 From: Lungan Catalin Date: Thu, 25 Apr 2024 17:00:33 +0300 Subject: [PATCH 15/75] feat(Date Picker): add some animation when panel is collapsed --- packages/beeq/src/components/panel/bq-panel.tsx | 6 ++++-- .../beeq/src/components/panel/scss/bq-panel.scss | 4 ++++ .../beeq/src/global/styles/mixins/_keyframes.scss | 15 +++++++++++++++ 3 files changed, 23 insertions(+), 2 deletions(-) diff --git a/packages/beeq/src/components/panel/bq-panel.tsx b/packages/beeq/src/components/panel/bq-panel.tsx index 100026825..42e33fa32 100644 --- a/packages/beeq/src/components/panel/bq-panel.tsx +++ b/packages/beeq/src/components/panel/bq-panel.tsx @@ -138,10 +138,12 @@ export class BqPanel { render() { return (
(this.panel = el)} aria-hidden={!this.open ? 'true' : 'false'} - hidden={!this.open} part="panel" > diff --git a/packages/beeq/src/components/panel/scss/bq-panel.scss b/packages/beeq/src/components/panel/scss/bq-panel.scss index b10fd270d..cf91f76c3 100644 --- a/packages/beeq/src/components/panel/scss/bq-panel.scss +++ b/packages/beeq/src/components/panel/scss/bq-panel.scss @@ -17,3 +17,7 @@ border-style: var(--bq-panel--border-style); } + +.panel-hidden { + @include animation-fade-out; +} diff --git a/packages/beeq/src/global/styles/mixins/_keyframes.scss b/packages/beeq/src/global/styles/mixins/_keyframes.scss index e41751553..4ae6f6140 100644 --- a/packages/beeq/src/global/styles/mixins/_keyframes.scss +++ b/packages/beeq/src/global/styles/mixins/_keyframes.scss @@ -8,6 +8,16 @@ } } +@keyframes fade-out { + from { + opacity: 1; + } + + to { + opacity: 0; + } +} + @keyframes slide-in { from { transform: translateY(10px); @@ -28,6 +38,11 @@ animation: fade-in $duration $timing-function $delay; } +@mixin animation-fade-out($duration: 0.3s, $delay: 0s, $timing-function: ease) { + animation: fade-out $duration $timing-function $delay; + opacity: 0; +} + @mixin animation-slide-in($duration: 0.3s, $delay: 0s, $timing-function: ease) { animation: fade-in $duration $timing-function $delay, From d24ca2a2f981bc7469ebf0198f34dfbd1f0b79ac Mon Sep 17 00:00:00 2001 From: Lungan Catalin Date: Thu, 25 Apr 2024 17:15:15 +0300 Subject: [PATCH 16/75] feat(Date Picker): rename some aria --- packages/beeq/src/components/date-picker/bq-date-picker.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) 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 509624fe9..2b8b23b70 100644 --- a/packages/beeq/src/components/date-picker/bq-date-picker.tsx +++ b/packages/beeq/src/components/date-picker/bq-date-picker.tsx @@ -389,9 +389,9 @@ export class BqDatePicker { autoCapitalize="off" autoFocus={this.autofocus} aria-disabled={this.disabled ? 'true' : 'false'} - aria-controls={`bq-options-${this.name}`} + aria-controls={`${this.name}`} aria-expanded={this.open} - aria-haspopup="listbox" + aria-haspopup="dialog" disabled={this.disabled} form={this.form} name={this.name} From 9aa0bcea29c2a424a0235c86a445a20bba6e647b Mon Sep 17 00:00:00 2001 From: Lungan Catalin Date: Fri, 26 Apr 2024 13:49:08 +0300 Subject: [PATCH 17/75] feat(Date Picker): add focus-visible style --- .../components/date-picker/scss/bq-date-picker.scss | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/packages/beeq/src/components/date-picker/scss/bq-date-picker.scss b/packages/beeq/src/components/date-picker/scss/bq-date-picker.scss index 506da7e8f..b617d4d68 100644 --- a/packages/beeq/src/components/date-picker/scss/bq-date-picker.scss +++ b/packages/beeq/src/components/date-picker/scss/bq-date-picker.scss @@ -160,8 +160,13 @@ calendar-range { background-color: theme('colors.transparent'); } + &::part(button):focus-visible { + @apply rounded-s bg-[--bq-date-picker--background-color] text-[color:--bq-date-picker--border-color-focus]; + @apply focus border-[color:--bq-date-picker--border-color-focus]; + } + &::part(container) { - @apply px-5 py-2; + @apply bg-[--bq-date-picker--background-color] px-5 py-2; } } @@ -169,6 +174,11 @@ calendar-month { /* stylelint-disable-next-line custom-property-pattern */ --color-accent: var(--bq-stroke--brand); + &::part(button):focus-visible { + @apply rounded-s bg-[--bq-date-picker--background-color] text-[color:--bq-date-picker--border-color-focus]; + @apply focus border-[color:--bq-date-picker--border-color-focus]; + } + &::part(button) { @apply h-8 w-8 rounded-[--bq-radius--s] p-1 text-[--bq-text--primary] hover:bg-[--bq-ui--secondary]; From 28000f6067224429a92c643f0ba3fe62818ad08e Mon Sep 17 00:00:00 2001 From: Lungan Catalin Date: Wed, 8 May 2024 13:55:58 +0300 Subject: [PATCH 18/75] feat(Date Picker): update cally library and add external function for date disallowance --- package-lock.json | 6 ++--- package.json | 1 + packages/beeq/src/components.d.ts | 8 ++++++ .../_storybook/bq-date-picker.stories.tsx | 26 +++++++++++++++++-- .../components/date-picker/bq-date-picker.tsx | 5 +++- .../beeq/src/components/date-picker/readme.md | 1 + 6 files changed, 41 insertions(+), 6 deletions(-) diff --git a/package-lock.json b/package-lock.json index a6a1451a0..069d30ede 100644 --- a/package-lock.json +++ b/package-lock.json @@ -16319,9 +16319,9 @@ } }, "node_modules/cally": { - "version": "0.5.2", - "resolved": "https://registry.npmjs.org/cally/-/cally-0.5.2.tgz", - "integrity": "sha512-DoygZJhGp5bPsfiKeCeU+6J555ZkjS+pyyBYnKFeIgjrGncxGfk389zIv8kCHZ2wvH3pW4NlhkSSAf6aknxr2A==", + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/cally/-/cally-0.5.3.tgz", + "integrity": "sha512-WjJgUUw/ToR9qFKir6hK4fS1+Z2J91wOXQefafJ3Ev4HZkx4R8CZXXw15rzo7Ta8Y7KAGlRbI4Mufb5n0GH6jw==", "dependencies": { "atomico": "^1.76.1" } diff --git a/package.json b/package.json index 266863aef..b4ed0a8eb 100644 --- a/package.json +++ b/package.json @@ -41,6 +41,7 @@ "@angular/platform-browser": "17.3.8", "@angular/platform-browser-dynamic": "17.3.8", "@angular/router": "17.3.8", + "cally": "0.5.3", "react": "18.3.1", "react-dom": "18.3.1", "rxjs": "7.8.1", diff --git a/packages/beeq/src/components.d.ts b/packages/beeq/src/components.d.ts index 483f40660..ef3383029 100644 --- a/packages/beeq/src/components.d.ts +++ b/packages/beeq/src/components.d.ts @@ -356,6 +356,10 @@ export namespace Components { * The ID of the form that the Date picker input belongs to. */ "form"?: string; + /** + * A function that takes a date and returns true if the date should not be selectable + */ + "isDateDisallowed"?: (date: Date) => boolean; /** * The locale for formatting dates. If not set, will use the browser's locale */ @@ -2584,6 +2588,10 @@ declare namespace LocalJSX { * The ID of the form that the Date picker input belongs to. */ "form"?: string; + /** + * A function that takes a date and returns true if the date should not be selectable + */ + "isDateDisallowed"?: (date: Date) => boolean; /** * The locale for formatting dates. If not set, will use the browser's locale */ 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 b2a238bcc..88a159e4a 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 @@ -51,7 +51,7 @@ const meta: Meta = { strategy: { control: 'select', options: ['fixed', 'absolute'] }, 'validation-status': { control: 'select', options: [...INPUT_VALIDATION] }, range: { control: 'boolean' }, - month: { control: 'number' }, + months: { control: 'number' }, value: { control: 'text' }, // Events bqBlur: { action: 'bqBlur' }, @@ -63,6 +63,7 @@ const meta: Meta = { noLabel: { control: 'boolean', table: { disable: true } }, prefix: { control: 'boolean', table: { disable: true } }, suffix: { control: 'boolean', table: { disable: true } }, + customDisallowedDate: { control: 'text' }, }, args: { autofocus: false, @@ -86,8 +87,10 @@ const meta: Meta = { required: false, 'validation-status': 'none', range: false, - month: 1, + months: 1, value: undefined, + isDateDisallowed: undefined, + customDisallowedDate: undefined, }, }; export default meta; @@ -107,6 +110,24 @@ const Template = (args: Args) => {
`; + /** + * * Converts a Date object to an ISO 8601 string representation. + * This function is used only for demonstration purposes in Storybook. + */ + + const dateToIsoString = (date: Date): string => { + return date.toISOString().split('T')[0]; + }; + + const isDate = (date: Date): boolean => { + if (!args.customDisallowedDate) { + return false; + } + + const dateString = dateToIsoString(date); + return args.customDisallowedDate.split(',').some((date: string) => date.trim() === dateString); + }; + return html`
{ range=${args.range} months=${args.months} value=${ifDefined(args.value)} + .isDateDisallowed=${isDate} @bqBlur=${args.bqBlur} @bqChange=${args.bqChange} @bqClear=${args.bqClear} 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 2b8b23b70..d10b8b4d2 100644 --- a/packages/beeq/src/components/date-picker/bq-date-picker.tsx +++ b/packages/beeq/src/components/date-picker/bq-date-picker.tsx @@ -128,6 +128,9 @@ export class BqDatePicker { /** Number of months to show when range is `true` */ @Prop({ reflect: true }) months: number; + /** A function that takes a date and returns true if the date should not be selectable */ + @Prop({ reflect: true }) isDateDisallowed?: (date: Date) => boolean; + /** * The validation status of the Select input. * @@ -390,7 +393,6 @@ export class BqDatePicker { autoFocus={this.autofocus} aria-disabled={this.disabled ? 'true' : 'false'} aria-controls={`${this.name}`} - aria-expanded={this.open} aria-haspopup="dialog" disabled={this.disabled} form={this.form} @@ -439,6 +441,7 @@ export class BqDatePicker {
boolean` | `undefined` | | `locale` | `locale` | The locale for formatting dates. If not set, will use the browser's locale | `string` | `undefined` | | `max` | `max` | The latest date that can be selected | `string` | `undefined` | | `min` | `min` | The earliest date that can be selected | `string` | `undefined` | From 9b9fe74713c77ed7a6c1ec976c21ed7774810ddf Mon Sep 17 00:00:00 2001 From: Lungan Catalin Date: Wed, 8 May 2024 16:44:54 +0300 Subject: [PATCH 19/75] feat(Date Picker): add some e2e tests for component --- .../__tests__/bq-date-picker.e2e.ts | 44 +++++++++++++++++++ 1 file changed, 44 insertions(+) diff --git a/packages/beeq/src/components/date-picker/__tests__/bq-date-picker.e2e.ts b/packages/beeq/src/components/date-picker/__tests__/bq-date-picker.e2e.ts index e1d3b2131..0d0fbab3f 100644 --- a/packages/beeq/src/components/date-picker/__tests__/bq-date-picker.e2e.ts +++ b/packages/beeq/src/components/date-picker/__tests__/bq-date-picker.e2e.ts @@ -18,4 +18,48 @@ describe('bq-date-picker', () => { expect(element.shadowRoot).not.toBeNull(); }); + + it('should render with date picker panel opened', async () => { + const page = await newE2EPage({ + html: ` + + `, + }); + const selectPanelElem = await page.find('bq-date-picker >>> .bq-date-picker__dropdown >>> .bq-dropdown__panel'); + + expect(selectPanelElem).toHaveAttribute('open'); + }); + + it('should render single type of date picker', async () => { + const page = await newE2EPage({ + html: ` + + `, + }); + const calendarDefaultElement = await page.find('bq-date-picker >>> calendar-date'); + + expect(calendarDefaultElement).not.toBeNull(); + }); + + it('should render range type of date picker', async () => { + const page = await newE2EPage({ + html: ` + + `, + }); + const calendarRangeElement = await page.find('bq-date-picker >>> calendar-range'); + + expect(calendarRangeElement).not.toBeNull(); + }); + + it('should render multile months for range type of date picker', async () => { + const page = await newE2EPage({ + html: ` + + `, + }); + const calendarMonthElement = await page.findAll('bq-date-picker >>> calendar-month'); + + expect(calendarMonthElement.length).toEqual(4); + }); }); From 94f1d98338c14f830945ef89916ab02c20602d9b Mon Sep 17 00:00:00 2001 From: Lungan Catalin Date: Mon, 13 May 2024 10:29:45 +0300 Subject: [PATCH 20/75] feat(Date Picker): update cally library --- package-lock.json | 10 ++++++---- package.json | 2 +- packages/beeq/package.json | 2 +- 3 files changed, 8 insertions(+), 6 deletions(-) diff --git a/package-lock.json b/package-lock.json index 069d30ede..f819bc33b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -21,6 +21,7 @@ "@angular/platform-browser": "17.3.8", "@angular/platform-browser-dynamic": "17.3.8", "@angular/router": "17.3.8", + "cally": "0.6.0", "react": "18.3.1", "react-dom": "18.3.1", "rxjs": "7.8.1", @@ -16319,9 +16320,9 @@ } }, "node_modules/cally": { - "version": "0.5.3", - "resolved": "https://registry.npmjs.org/cally/-/cally-0.5.3.tgz", - "integrity": "sha512-WjJgUUw/ToR9qFKir6hK4fS1+Z2J91wOXQefafJ3Ev4HZkx4R8CZXXw15rzo7Ta8Y7KAGlRbI4Mufb5n0GH6jw==", + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/cally/-/cally-0.6.0.tgz", + "integrity": "sha512-8tSxilZ71PTGgNggJTmgIXTSIr01AzWfO1vdn8fbCHabYuFO1eYmdGKI47xRReqFUSoQA3ijfAkHYCwgQOVYDQ==", "dependencies": { "atomico": "^1.76.1" } @@ -41358,7 +41359,8 @@ "dependencies": { "@floating-ui/core": "^1.6.2", "@floating-ui/dom": "^1.6.5", - "@stencil/core": "^4.18.1" + "@stencil/core": "^4.18.1", + "cally": "0.6.0" } }, "packages/beeq-angular": { diff --git a/package.json b/package.json index b4ed0a8eb..ca3ff0988 100644 --- a/package.json +++ b/package.json @@ -41,7 +41,7 @@ "@angular/platform-browser": "17.3.8", "@angular/platform-browser-dynamic": "17.3.8", "@angular/router": "17.3.8", - "cally": "0.5.3", + "cally": "0.6.0", "react": "18.3.1", "react-dom": "18.3.1", "rxjs": "7.8.1", diff --git a/packages/beeq/package.json b/packages/beeq/package.json index 022fad9f7..e79b15af2 100644 --- a/packages/beeq/package.json +++ b/packages/beeq/package.json @@ -27,7 +27,7 @@ "@floating-ui/core": "^1.6.2", "@floating-ui/dom": "^1.6.5", "@stencil/core": "^4.18.1", - "cally": "0.5.2" + "cally": "0.6.0" }, "repository": { "type": "git", From bd58d338e134c2728a132541656ccab7740e4d6b Mon Sep 17 00:00:00 2001 From: Lungan Catalin Date: Mon, 13 May 2024 10:31:57 +0300 Subject: [PATCH 21/75] feat(Date Picker): add multi-date feature to date picker --- packages/beeq/src/components.d.ts | 8 ++++++++ .../_storybook/bq-date-picker.stories.tsx | 11 +++++++++++ .../components/date-picker/bq-date-picker.tsx | 16 +++++++++++++--- .../beeq/src/components/date-picker/readme.md | 1 + .../date-picker/scss/bq-date-picker.scss | 5 +++-- 5 files changed, 36 insertions(+), 5 deletions(-) diff --git a/packages/beeq/src/components.d.ts b/packages/beeq/src/components.d.ts index ef3383029..e9d81237f 100644 --- a/packages/beeq/src/components.d.ts +++ b/packages/beeq/src/components.d.ts @@ -376,6 +376,10 @@ export namespace Components { * Number of months to show when range is `true` */ "months": number; + /** + * If `true`, the Date picker panel will accepts to select multiple individual dates + */ + "multi": boolean; /** * The Date picker input name. */ @@ -2608,6 +2612,10 @@ declare namespace LocalJSX { * Number of months to show when range is `true` */ "months"?: number; + /** + * If `true`, the Date picker panel will accepts to select multiple individual dates + */ + "multi"?: boolean; /** * The Date picker input name. */ 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 88a159e4a..fa3aea4c0 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 @@ -51,6 +51,7 @@ const meta: Meta = { strategy: { control: 'select', options: ['fixed', 'absolute'] }, 'validation-status': { control: 'select', options: [...INPUT_VALIDATION] }, range: { control: 'boolean' }, + multi: { control: 'boolean' }, months: { control: 'number' }, value: { control: 'text' }, // Events @@ -87,6 +88,7 @@ const meta: Meta = { required: false, 'validation-status': 'none', range: false, + multi: false, months: 1, value: undefined, isDateDisallowed: undefined, @@ -152,6 +154,7 @@ const Template = (args: Args) => { strategy=${args.strategy} validation-status=${args['validation-status']} range=${args.range} + multi=${args.multi} months=${args.months} value=${ifDefined(args.value)} .isDateDisallowed=${isDate} @@ -180,3 +183,11 @@ export const Range: Story = { months: 2, }, }; + +export const Multi: Story = { + render: Template, + args: { + multi: true, + months: 2, + }, +}; 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 d10b8b4d2..eff226af6 100644 --- a/packages/beeq/src/components/date-picker/bq-date-picker.tsx +++ b/packages/beeq/src/components/date-picker/bq-date-picker.tsx @@ -125,6 +125,9 @@ export class BqDatePicker { /** If `true`, the Date picker panel will accepts more than 1 month to display */ @Prop({ reflect: true }) range: boolean = false; + /** If `true`, the Date picker panel will accepts to select multiple individual dates */ + @Prop({ reflect: true }) multi: boolean = false; + /** Number of months to show when range is `true` */ @Prop({ reflect: true }) months: number; @@ -314,7 +317,7 @@ export class BqDatePicker { const commonExportParts = 'heading,table,tr,head,week,th,td'; const buttonExportParts = 'button,day,selected,today,disallowed,outside,range-start,range-end,range-inner'; - if (this.range && this.months) { + if (this.range || (this.multi && this.months)) { for (let i = 0; i < this.months; i++) { const offset = i > 0 ? i : undefined; const className = offset ? 'hidden sm:block' : ''; @@ -340,7 +343,14 @@ export class BqDatePicker { render() { const labelId = `bq-date-picker__label-${this.name || this.fallbackInputId}`; - const CalendarComponentType = this.range ? 'calendar-range' : 'calendar-date'; + const componentTypes = { + multi: 'calendar-multi', + range: 'calendar-range', + default: 'calendar-date', + }; + + const key = this.multi ? 'multi' : this.range ? 'range' : 'default'; + const CalendarComponentType = componentTypes[key]; return (
@@ -451,7 +461,7 @@ export class BqDatePicker { showOutsideDays={this.showOutsideDays} onChange={(ev: { target: { value: string } }) => { this.value = ev.target.value; - this.open = false; + this.open = !!this.multi; }} exportparts="container,header,button,previous,next,disabled,heading" > diff --git a/packages/beeq/src/components/date-picker/readme.md b/packages/beeq/src/components/date-picker/readme.md index 065993a1e..52368b1d2 100644 --- a/packages/beeq/src/components/date-picker/readme.md +++ b/packages/beeq/src/components/date-picker/readme.md @@ -21,6 +21,7 @@ | `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` | +| `multi` | `multi` | If `true`, the Date picker panel will accepts to select multiple individual dates | `boolean` | `false` | | `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'` | diff --git a/packages/beeq/src/components/date-picker/scss/bq-date-picker.scss b/packages/beeq/src/components/date-picker/scss/bq-date-picker.scss index b617d4d68..fdadf6528 100644 --- a/packages/beeq/src/components/date-picker/scss/bq-date-picker.scss +++ b/packages/beeq/src/components/date-picker/scss/bq-date-picker.scss @@ -145,7 +145,8 @@ bq-icon, /* -------------------------------------------------------------------------- */ calendar-date, -calendar-range { +calendar-range, +calendar-multi { &::part(header) { @apply justify-center gap-[--bq-spacing-xs]; } @@ -180,7 +181,7 @@ calendar-month { } &::part(button) { - @apply h-8 w-8 rounded-[--bq-radius--s] p-1 text-[--bq-text--primary] hover:bg-[--bq-ui--secondary]; + @apply h-8 w-8 rounded-[--bq-radius--s] p-1 text-[--bq-text--primary]; font-family: var(--bq-font-family); } From 6599f889015debf774155a8425e122920ab9397a Mon Sep 17 00:00:00 2001 From: Lungan Catalin Date: Mon, 13 May 2024 10:32:54 +0300 Subject: [PATCH 22/75] feat(Date Picker): add e2e test for calendar-multi --- .../date-picker/__tests__/bq-date-picker.e2e.ts | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/packages/beeq/src/components/date-picker/__tests__/bq-date-picker.e2e.ts b/packages/beeq/src/components/date-picker/__tests__/bq-date-picker.e2e.ts index 0d0fbab3f..6b34fc6a4 100644 --- a/packages/beeq/src/components/date-picker/__tests__/bq-date-picker.e2e.ts +++ b/packages/beeq/src/components/date-picker/__tests__/bq-date-picker.e2e.ts @@ -52,6 +52,17 @@ describe('bq-date-picker', () => { expect(calendarRangeElement).not.toBeNull(); }); + it('should render multi type of date picker', async () => { + const page = await newE2EPage({ + html: ` + + `, + }); + const calendarMultiElement = await page.find('bq-date-picker >>> calendar-multi'); + + expect(calendarMultiElement).not.toBeNull(); + }); + it('should render multile months for range type of date picker', async () => { const page = await newE2EPage({ html: ` From cca53ec8b035cfc0ecd182663aeb7923e2860489 Mon Sep 17 00:00:00 2001 From: Lungan Catalin Date: Mon, 13 May 2024 10:55:03 +0300 Subject: [PATCH 23/75] feat(Date Picker): refactor nested ternary operation --- packages/beeq/src/components/date-picker/bq-date-picker.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 eff226af6..4a9a29510 100644 --- a/packages/beeq/src/components/date-picker/bq-date-picker.tsx +++ b/packages/beeq/src/components/date-picker/bq-date-picker.tsx @@ -349,7 +349,7 @@ export class BqDatePicker { default: 'calendar-date', }; - const key = this.multi ? 'multi' : this.range ? 'range' : 'default'; + const key = (this.multi && 'multi') || (this.range && 'range') || 'default'; const CalendarComponentType = componentTypes[key]; return ( From 7fb0b4ec3facf1288da21c43217ac224cf30e9b4 Mon Sep 17 00:00:00 2001 From: Lungan Catalin Date: Mon, 13 May 2024 11:55:10 +0300 Subject: [PATCH 24/75] feat(Date Picker): add css variable for range bg color --- .../beeq/src/components/date-picker/scss/bq-date-picker.scss | 2 +- .../components/date-picker/scss/bq-date-picker.variables.scss | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/beeq/src/components/date-picker/scss/bq-date-picker.scss b/packages/beeq/src/components/date-picker/scss/bq-date-picker.scss index fdadf6528..276b41330 100644 --- a/packages/beeq/src/components/date-picker/scss/bq-date-picker.scss +++ b/packages/beeq/src/components/date-picker/scss/bq-date-picker.scss @@ -187,7 +187,7 @@ calendar-month { } &::part(button day selected) { - @apply bg-[--bq-ui--brand] hover:bg-hover-ui-brand; + @apply bg-[--bq-date-picker--range-background-color] hover:bg-hover-ui-brand; } &::part(outside) { diff --git a/packages/beeq/src/components/date-picker/scss/bq-date-picker.variables.scss b/packages/beeq/src/components/date-picker/scss/bq-date-picker.variables.scss index 65d1a82a2..776eda218 100644 --- a/packages/beeq/src/components/date-picker/scss/bq-date-picker.variables.scss +++ b/packages/beeq/src/components/date-picker/scss/bq-date-picker.variables.scss @@ -25,6 +25,7 @@ * @prop --bq-date-picker--text-color - Date picker text color * @prop --bq-date-picker--text-size - Date picker text size * @prop --bq-date-picker--text-placeholder-color - Date picker placeholder text color + * @prop --bq-date-picker--range-background-color - Background color for the selected date range in the date picker */ --bq-date-picker--background-color: theme('colors.ui.primary'); @@ -53,4 +54,5 @@ --bq-date-picker--text-color: theme('colors.text.primary'); --bq-date-picker--text-size: theme('fontSize.m'); --bq-date-picker--text-placeholder-color: theme('colors.text.secondary'); + --bq-date-picker--range-background-color: theme('colors.ui.brand'); } From a9ff44b258f2b1af2d130962fef08f7e99577d6b Mon Sep 17 00:00:00 2001 From: Lungan Catalin Date: Mon, 13 May 2024 13:52:24 +0300 Subject: [PATCH 25/75] feat(Date Picker): add missed prop --- packages/beeq/src/components/date-picker/bq-date-picker.tsx | 1 + 1 file changed, 1 insertion(+) 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 4a9a29510..c0c62dd01 100644 --- a/packages/beeq/src/components/date-picker/bq-date-picker.tsx +++ b/packages/beeq/src/components/date-picker/bq-date-picker.tsx @@ -456,6 +456,7 @@ export class BqDatePicker { value={this.value} min={this.min} max={this.max} + months={this.months} focusedDate={this.value} firstDayOfWeek={this.firstDayOfWeek} showOutsideDays={this.showOutsideDays} From 915954b7fd685d3acc78cffe15bf1c213c833a64 Mon Sep 17 00:00:00 2001 From: Lungan Catalin Date: Wed, 15 May 2024 11:25:31 +0300 Subject: [PATCH 26/75] feat(Date Picker): add logic for focused date value --- .../src/components/date-picker/bq-date-picker.tsx | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) 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 c0c62dd01..02330bc4b 100644 --- a/packages/beeq/src/components/date-picker/bq-date-picker.tsx +++ b/packages/beeq/src/components/date-picker/bq-date-picker.tsx @@ -352,6 +352,19 @@ export class BqDatePicker { const key = (this.multi && 'multi') || (this.range && 'range') || 'default'; const CalendarComponentType = componentTypes[key]; + const processFocusedDateValue = (value: TInputValue) => { + if (typeof value === 'string') { + return value.includes('/') ? value.split('/').pop() : value.split(' ').pop(); + } + if (typeof value === 'number') { + return value.toString(); + } + if (Array.isArray(value)) { + return value[value.length - 1]; + } + return null; + }; + return (
{/* Label */} @@ -457,7 +470,7 @@ export class BqDatePicker { min={this.min} max={this.max} months={this.months} - focusedDate={this.value} + focusedDate={processFocusedDateValue(this.value)} firstDayOfWeek={this.firstDayOfWeek} showOutsideDays={this.showOutsideDays} onChange={(ev: { target: { value: string } }) => { From de56f456d5043b4047d91220f921ed0e9d0dcd64 Mon Sep 17 00:00:00 2001 From: Lungan Catalin Date: Wed, 15 May 2024 11:31:14 +0300 Subject: [PATCH 27/75] feat(Date Picker): add some comments --- .../components/date-picker/bq-date-picker.tsx | 31 ++++++++++--------- 1 file changed, 17 insertions(+), 14 deletions(-) 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 02330bc4b..aaf2b15d6 100644 --- a/packages/beeq/src/components/date-picker/bq-date-picker.tsx +++ b/packages/beeq/src/components/date-picker/bq-date-picker.tsx @@ -336,6 +336,22 @@ export class BqDatePicker { return months; } + /** + * Processes the focused date value to extract the relevant part, which is essentially the last selected date. + */ + private processFocusedDateValue = (value: TInputValue) => { + if (typeof value === 'string') { + return value.includes('/') ? value.split('/').pop() : value.split(' ').pop(); + } + if (typeof value === 'number') { + return value.toString(); + } + if (Array.isArray(value)) { + return value[value.length - 1]; + } + return null; + }; + // render() function // Always the last one in the class. // =================================== @@ -352,19 +368,6 @@ export class BqDatePicker { const key = (this.multi && 'multi') || (this.range && 'range') || 'default'; const CalendarComponentType = componentTypes[key]; - const processFocusedDateValue = (value: TInputValue) => { - if (typeof value === 'string') { - return value.includes('/') ? value.split('/').pop() : value.split(' ').pop(); - } - if (typeof value === 'number') { - return value.toString(); - } - if (Array.isArray(value)) { - return value[value.length - 1]; - } - return null; - }; - return (
{/* Label */} @@ -470,7 +473,7 @@ export class BqDatePicker { min={this.min} max={this.max} months={this.months} - focusedDate={processFocusedDateValue(this.value)} + focusedDate={this.processFocusedDateValue(this.value)} firstDayOfWeek={this.firstDayOfWeek} showOutsideDays={this.showOutsideDays} onChange={(ev: { target: { value: string } }) => { From 08a6e7c96a0cb8c2ac5f1f91fa6d9351721fb920 Mon Sep 17 00:00:00 2001 From: Lungan Catalin Date: Wed, 15 May 2024 13:02:14 +0300 Subject: [PATCH 28/75] feat(Date Picker): refactor logic for processFocusedDateValue function --- .../beeq/src/components/date-picker/bq-date-picker.tsx | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) 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 aaf2b15d6..8bb5684a6 100644 --- a/packages/beeq/src/components/date-picker/bq-date-picker.tsx +++ b/packages/beeq/src/components/date-picker/bq-date-picker.tsx @@ -337,11 +337,16 @@ export class BqDatePicker { } /** - * Processes the focused date value to extract the relevant part, which is essentially the last selected date. + * Processes the focused date value to extract the last date portion. + * + * @param value - The value to be processed, can be a string, number, or string array. + * @returns The extracted last date portion of the value. */ private processFocusedDateValue = (value: TInputValue) => { + const dateLength = 10; // Length of a standard date in the format YYYY-MM-DD + if (typeof value === 'string') { - return value.includes('/') ? value.split('/').pop() : value.split(' ').pop(); + return value.slice(-dateLength); } if (typeof value === 'number') { return value.toString(); From 037902d23b8e61650c9b1fa59b3535feef72de38 Mon Sep 17 00:00:00 2001 From: Lungan Catalin Date: Thu, 16 May 2024 15:42:58 +0300 Subject: [PATCH 29/75] feat(Date Picker): add style for current date in picker calendar --- .../date-picker/scss/bq-date-picker.scss | 26 +++++++++++++++++++ .../scss/bq-date-picker.variables.scss | 6 +++++ 2 files changed, 32 insertions(+) diff --git a/packages/beeq/src/components/date-picker/scss/bq-date-picker.scss b/packages/beeq/src/components/date-picker/scss/bq-date-picker.scss index 276b41330..356a68c18 100644 --- a/packages/beeq/src/components/date-picker/scss/bq-date-picker.scss +++ b/packages/beeq/src/components/date-picker/scss/bq-date-picker.scss @@ -202,6 +202,32 @@ calendar-month { @apply rounded-none; } + &::part(today) { + @apply rounded-[--bq-radius--s] border-[length:--bq-date-picker--currentDate-border-width] border-[color:--bq-date-picker--currentDate-border-color] text-[color:--bq-date-picker--currentDate-text-color]; + + border-style: var(--bq-date-picker--border-style); + } + + &::part(today selected) { + @apply rounded-none text-[color:var(--bq-text--inverse)]; + } + + &::part(today range-inner) { + @apply rounded-none; + } + + &::part(today range-start) { + @apply rounded-[--bq-radius--s]; + + border-end-start-radius: 0; + } + + &::part(today range-end) { + @apply rounded-[--bq-radius--s]; + + border-end-end-radius: 0; + } + &::part(range-start) { border-start-end-radius: 0; border-end-end-radius: 0; diff --git a/packages/beeq/src/components/date-picker/scss/bq-date-picker.variables.scss b/packages/beeq/src/components/date-picker/scss/bq-date-picker.variables.scss index 776eda218..38baf82c3 100644 --- a/packages/beeq/src/components/date-picker/scss/bq-date-picker.variables.scss +++ b/packages/beeq/src/components/date-picker/scss/bq-date-picker.variables.scss @@ -10,6 +10,7 @@ * @prop --bq-date-picker--border-color-disabled - Date picker border color when disabled * @prop --bq-date-picker--border-radius - Date picker border radius * @prop --bq-date-picker--border-width - Date picker border width + * @prop --bq-date-picker--currentDate-border-width - Date picker border width for current date * @prop --bq-date-picker--border-style - Date picker border style * @prop --bq-date-picker--gap - Gap between Date picker content and prefix/suffix * @prop --bq-date-picker--helper-margin-top - Helper text margin top @@ -18,6 +19,7 @@ * @prop --bq-date-picker--icon-size - Icon size to use in prefix/suffix and clear button * @prop --bq-date-picker--label-margin-bottom - Date picker label margin bottom * @prop --bq-date-picker--label-text-color - Date picker label text color + * @prop --bq-date-picker--currentDate-text-color - Date picker label text color for currentDate * @prop --bq-date-picker--label-text-size - Date picker label text size * @prop --bq-date-picker--pading-start - Date picker padding start * @prop --bq-date-picker--pading-end - Date picker padding end @@ -26,6 +28,7 @@ * @prop --bq-date-picker--text-size - Date picker text size * @prop --bq-date-picker--text-placeholder-color - Date picker placeholder text color * @prop --bq-date-picker--range-background-color - Background color for the selected date range in the date picker + * @prop --bq-date-picker--currentDate-border-color - Date picker border color for current date */ --bq-date-picker--background-color: theme('colors.ui.primary'); @@ -33,6 +36,7 @@ --bq-date-picker--border-color-focus: theme('colors.stroke.brand'); --bq-date-picker--border-radius: theme('borderRadius.s'); --bq-date-picker--border-width: 1px; + --bq-date-picker--currentDate-border-width: 2px; --bq-date-picker--border-style: solid; --bq-date-picker--gap: theme('spacing.xs'); @@ -46,6 +50,7 @@ --bq-date-picker--label-margin-bottom: theme('spacing.xs'); --bq-date-picker--label-text-size: theme('fontSize.s'); --bq-date-picker--label-text-color: theme('colors.text.primary'); + --bq-date-picker--currentDate-text-color: theme('colors.text.brand'); --bq-date-picker--pading-start: theme('spacing.m'); --bq-date-picker--pading-end: theme('spacing.m'); @@ -55,4 +60,5 @@ --bq-date-picker--text-size: theme('fontSize.m'); --bq-date-picker--text-placeholder-color: theme('colors.text.secondary'); --bq-date-picker--range-background-color: theme('colors.ui.brand'); + --bq-date-picker--currentDate-border-color: theme('colors.stroke.brand'); } From 2e6b6768e419c8358fed950a1727be93dbe08bf0 Mon Sep 17 00:00:00 2001 From: Lungan Catalin Date: Thu, 16 May 2024 16:31:13 +0300 Subject: [PATCH 30/75] chore(deps): sync package-lock.json --- package-lock.json | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/package-lock.json b/package-lock.json index f819bc33b..833239e33 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "beeq", - "version": "1.3.2", + "version": "1.3.3", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "beeq", - "version": "1.3.2", + "version": "1.3.3", "hasInstallScript": true, "license": "Apache-2.0", "workspaces": [ @@ -15048,6 +15048,11 @@ "node": ">= 4.0.0" } }, + "node_modules/atomico": { + "version": "1.79.2", + "resolved": "https://registry.npmjs.org/atomico/-/atomico-1.79.2.tgz", + "integrity": "sha512-mshhLRMeIltNYbnQnqgnrvJ/uDa8XDfTQcjw3ymOygQqwHIQ4Sp0LcNYMCbACkV3DtV+eDXb9szwU4qMUuGwYQ==" + }, "node_modules/autoprefixer": { "version": "10.4.19", "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.19.tgz", @@ -41354,7 +41359,7 @@ }, "packages/beeq": { "name": "@beeq/core", - "version": "1.3.2", + "version": "1.3.3", "license": "Apache-2.0", "dependencies": { "@floating-ui/core": "^1.6.2", @@ -41365,7 +41370,7 @@ }, "packages/beeq-angular": { "name": "@beeq/angular", - "version": "1.3.2", + "version": "1.3.3", "license": "Apache-2.0", "dependencies": { "@beeq/core": "^1.3.2", @@ -41378,7 +41383,7 @@ }, "packages/beeq-react": { "name": "@beeq/react", - "version": "1.3.2", + "version": "1.3.3", "license": "Apache-2.0", "dependencies": { "@beeq/core": "^1.3.2" @@ -41391,7 +41396,7 @@ }, "packages/beeq-tailwindcss": { "name": "@beeq/tailwindcss", - "version": "1.3.2", + "version": "1.3.3", "license": "Apache-2.0", "peerDependencies": { "tailwindcss": "^3.4.1", @@ -41400,7 +41405,7 @@ }, "packages/beeq-vue": { "name": "@beeq/vue", - "version": "1.3.2", + "version": "1.3.3", "license": "Apache-2.0", "dependencies": { "@beeq/core": "^1.3.2", From 791a129ba2e2f00f4c3587a49d1bed2e2d573ab7 Mon Sep 17 00:00:00 2001 From: Lungan Catalin Date: Thu, 16 May 2024 16:53:35 +0300 Subject: [PATCH 31/75] revert: add removed global script --- packages/beeq/stencil.config.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/beeq/stencil.config.ts b/packages/beeq/stencil.config.ts index 0797cfcfa..a21f48a40 100644 --- a/packages/beeq/stencil.config.ts +++ b/packages/beeq/stencil.config.ts @@ -25,6 +25,7 @@ export const config: Config = { taskQueue: 'async', buildDist: true, enableCache: true, + globalScript: resolve(__dirname, './src/global/scripts/global.ts').replace(/\\/g, '/'), globalStyle: resolve(__dirname, './src/global/styles/default.scss').replace(/\\/g, '/'), plugins: [ sass({ From d7a0f3bc25054b47eb7a6492dd44203908d29cb5 Mon Sep 17 00:00:00 2001 From: Lungan Catalin Date: Fri, 17 May 2024 10:49:51 +0300 Subject: [PATCH 32/75] feat(Date Picker): fix typo and remove unused scss variables --- .../date-picker/scss/bq-date-picker.scss | 2 +- .../scss/bq-date-picker.variables.scss | 15 ++++----------- 2 files changed, 5 insertions(+), 12 deletions(-) diff --git a/packages/beeq/src/components/date-picker/scss/bq-date-picker.scss b/packages/beeq/src/components/date-picker/scss/bq-date-picker.scss index 356a68c18..21e373fa0 100644 --- a/packages/beeq/src/components/date-picker/scss/bq-date-picker.scss +++ b/packages/beeq/src/components/date-picker/scss/bq-date-picker.scss @@ -26,7 +26,7 @@ // Border @apply rounded-[--bq-date-picker--border-radius] border-[length:--bq-date-picker--border-width] border-[color:--bq-date-picker--border-color]; // Padding - @apply py-[--bq-date-picker--paddingY] pe-[--bq-date-picker--pading-end] ps-[--bq-date-picker--pading-start]; + @apply py-[--bq-date-picker--paddingY] pe-[--bq-date-picker--padding-end] ps-[--bq-date-picker--padding-start]; // Text @apply select-none text-[length:--bq-date-picker--text-size] text-[color:--bq-date-picker--text-color] placeholder:text-[color:--bq-date-picker--text-placeholder-color]; // Hover diff --git a/packages/beeq/src/components/date-picker/scss/bq-date-picker.variables.scss b/packages/beeq/src/components/date-picker/scss/bq-date-picker.variables.scss index 38baf82c3..c8d1f9f0f 100644 --- a/packages/beeq/src/components/date-picker/scss/bq-date-picker.variables.scss +++ b/packages/beeq/src/components/date-picker/scss/bq-date-picker.variables.scss @@ -13,16 +13,13 @@ * @prop --bq-date-picker--currentDate-border-width - Date picker border width for current date * @prop --bq-date-picker--border-style - Date picker border style * @prop --bq-date-picker--gap - Gap between Date picker content and prefix/suffix - * @prop --bq-date-picker--helper-margin-top - Helper text margin top - * @prop --bq-date-picker--helper-text-color - Helper text color - * @prop --bq-date-picker--helper-text-size - Helper text size * @prop --bq-date-picker--icon-size - Icon size to use in prefix/suffix and clear button * @prop --bq-date-picker--label-margin-bottom - Date picker label margin bottom * @prop --bq-date-picker--label-text-color - Date picker label text color * @prop --bq-date-picker--currentDate-text-color - Date picker label text color for currentDate * @prop --bq-date-picker--label-text-size - Date picker label text size - * @prop --bq-date-picker--pading-start - Date picker padding start - * @prop --bq-date-picker--pading-end - Date picker padding end + * @prop --bq-date-picker--padding-start - Date picker padding start + * @prop --bq-date-picker--padding-end - Date picker padding end * @prop --bq-date-picker--paddingY - Date picker padding top and bottom * @prop --bq-date-picker--text-color - Date picker text color * @prop --bq-date-picker--text-size - Date picker text size @@ -41,10 +38,6 @@ --bq-date-picker--gap: theme('spacing.xs'); - --bq-date-picker--helper-margin-top: theme('spacing.xs'); - --bq-date-picker--helper-text-size: theme('fontSize.s'); - --bq-date-picker--helper-text-color: theme('colors.text.primary'); - --bq-date-picker--icon-size: 24px; --bq-date-picker--label-margin-bottom: theme('spacing.xs'); @@ -52,8 +45,8 @@ --bq-date-picker--label-text-color: theme('colors.text.primary'); --bq-date-picker--currentDate-text-color: theme('colors.text.brand'); - --bq-date-picker--pading-start: theme('spacing.m'); - --bq-date-picker--pading-end: theme('spacing.m'); + --bq-date-picker--padding-start: theme('spacing.m'); + --bq-date-picker--padding-end: theme('spacing.m'); --bq-date-picker--paddingY: theme('spacing.s'); --bq-date-picker--text-color: theme('colors.text.primary'); From 547c16727c70f51eda8e77c9f0d77d6332e548e8 Mon Sep 17 00:00:00 2001 From: Lungan Catalin Date: Fri, 17 May 2024 11:31:05 +0300 Subject: [PATCH 33/75] feat(Date Picker): refactor calendarType method for better type safety and immutability --- .../components/date-picker/bq-date-picker.tsx | 32 ++++++++++++------- .../beeq/src/components/date-picker/readme.md | 2 +- 2 files changed, 22 insertions(+), 12 deletions(-) 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 8bb5684a6..9044e3375 100644 --- a/packages/beeq/src/components/date-picker/bq-date-picker.tsx +++ b/packages/beeq/src/components/date-picker/bq-date-picker.tsx @@ -36,7 +36,7 @@ import { TInputValidation, TInputValue } from '../input/bq-input.types'; * @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 daythat has been disallowed via isDateDisallowed. + * @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. @@ -357,6 +357,23 @@ export class BqDatePicker { return null; }; + private get CalendarType() { + // Define a lookup object to map properties to component types + const componentTypes = { + multi: 'calendar-multi', + range: 'calendar-range', + default: 'calendar-date', + } as const; // Make componentTypes a readonly object + + const types = ['multi', 'range'] as const; // Make types a readonly array + + // Find the first property (multi or range) that is truthy + const type = types.find((t) => this[t]); + + // Return the corresponding component type, or the default type if no truthy property was found + return componentTypes[type] || componentTypes.default; + } + // render() function // Always the last one in the class. // =================================== @@ -364,14 +381,7 @@ export class BqDatePicker { render() { const labelId = `bq-date-picker__label-${this.name || this.fallbackInputId}`; - const componentTypes = { - multi: 'calendar-multi', - range: 'calendar-range', - default: 'calendar-date', - }; - - const key = (this.multi && 'multi') || (this.range && 'range') || 'default'; - const CalendarComponentType = componentTypes[key]; + const CallyCalendar = this.CalendarType; return (
@@ -471,7 +481,7 @@ export class BqDatePicker {
-
{this.generateCalendarMonths()}
-
+
diff --git a/packages/beeq/src/components/date-picker/readme.md b/packages/beeq/src/components/date-picker/readme.md index 52368b1d2..f213b4813 100644 --- a/packages/beeq/src/components/date-picker/readme.md +++ b/packages/beeq/src/components/date-picker/readme.md @@ -71,7 +71,7 @@ Type: `Promise` | `"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 daythat has been disallowed via isDateDisallowed. | +| `"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: | From d408df97c620a8ae9db74291560787f45891bde5 Mon Sep 17 00:00:00 2001 From: Lungan Catalin Date: Fri, 17 May 2024 11:40:43 +0300 Subject: [PATCH 34/75] feat(Date Picker): add private handleCalendarChange method and emit bqChange event on date selection --- .../src/components/date-picker/bq-date-picker.tsx | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) 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 9044e3375..3d3c4f0c8 100644 --- a/packages/beeq/src/components/date-picker/bq-date-picker.tsx +++ b/packages/beeq/src/components/date-picker/bq-date-picker.tsx @@ -374,6 +374,16 @@ export class BqDatePicker { return componentTypes[type] || componentTypes.default; } + private handleCalendarChange = (ev: { target: { value: string } }) => { + const { value } = ev.target; + + this.value = value; + this.inputElem.value = this.value; + this.bqChange.emit({ value: this.value, el: this.el }); + + this.open = !!this.multi; + }; + // render() function // Always the last one in the class. // =================================== @@ -491,10 +501,7 @@ export class BqDatePicker { focusedDate={this.processFocusedDateValue(this.value)} firstDayOfWeek={this.firstDayOfWeek} showOutsideDays={this.showOutsideDays} - onChange={(ev: { target: { value: string } }) => { - this.value = ev.target.value; - this.open = !!this.multi; - }} + onChange={this.handleCalendarChange} exportparts="container,header,button,previous,next,disabled,heading" > From 3adcf8f7aa14037c2954428d6b5722d0c6abf1d3 Mon Sep 17 00:00:00 2001 From: Lungan Catalin Date: Fri, 17 May 2024 14:33:13 +0300 Subject: [PATCH 35/75] feat(Date Picker): fix typo and add dayOfWeek data type --- packages/beeq/src/components.d.ts | 18 ++++++++++-------- .../components/date-picker/bq-date-picker.tsx | 11 ++++++----- .../beeq/src/components/date-picker/readme.md | 18 +++++++++--------- .../date-picker/scss/bq-date-picker.types.ts | 1 + 4 files changed, 26 insertions(+), 22 deletions(-) create mode 100644 packages/beeq/src/components/date-picker/scss/bq-date-picker.types.ts diff --git a/packages/beeq/src/components.d.ts b/packages/beeq/src/components.d.ts index e9d81237f..d44905b9a 100644 --- a/packages/beeq/src/components.d.ts +++ b/packages/beeq/src/components.d.ts @@ -13,6 +13,7 @@ import { TButtonAppearance, TButtonBorderRadius, TButtonSize, TButtonType, TButt import { TCardBorderRadius, TCardType } from "./components/card/bq-card.types"; import { FloatingUIPlacement } from "./services/interfaces"; import { TInputType, TInputValidation, TInputValue } from "./components/input/bq-input.types"; +import { DaysOfWeek } from "./components/date-picker/scss/bq-date-picker.types"; import { TDialogBorderRadius, TDialogFooterAppearance, TDialogSize } from "./components/dialog/bq-dialog.types"; import { TDividerOrientation, TDividerStrokeLinecap, TDividerTitleAlignment } from "./components/divider/bq-divider.types"; import { TDrawerPlacement } from "./components/drawer/bq-drawer.types"; @@ -41,6 +42,7 @@ export { TButtonAppearance, TButtonBorderRadius, TButtonSize, TButtonType, TButt export { TCardBorderRadius, TCardType } from "./components/card/bq-card.types"; export { FloatingUIPlacement } from "./services/interfaces"; export { TInputType, TInputValidation, TInputValue } from "./components/input/bq-input.types"; +export { DaysOfWeek } from "./components/date-picker/scss/bq-date-picker.types"; export { TDialogBorderRadius, TDialogFooterAppearance, TDialogSize } from "./components/dialog/bq-dialog.types"; export { TDividerOrientation, TDividerStrokeLinecap, TDividerTitleAlignment } from "./components/divider/bq-divider.types"; export { TDrawerPlacement } from "./components/drawer/bq-drawer.types"; @@ -351,7 +353,7 @@ export namespace Components { /** * The first day of the week, where Sunday is 0, Monday is 1, etc */ - "firstDayOfWeek"?: number; + "firstDayOfWeek"?: DaysOfWeek; /** * The ID of the form that the Date picker input belongs to. */ @@ -428,7 +430,7 @@ export namespace Components { /** * 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). */ - "value": TInputValue; + "value": string; } interface BqDialog { /** @@ -1708,10 +1710,10 @@ declare global { }; interface HTMLBqDatePickerElementEventMap { "bqBlur": HTMLBqInputElement; - "bqChange": { value: string | number | string[]; el: HTMLBqInputElement }; + "bqChange": { value: string; el: HTMLBqInputElement }; "bqClear": HTMLBqInputElement; "bqFocus": HTMLBqInputElement; - "bqInput": { value: string | number | string[]; el: HTMLBqInputElement }; + "bqInput": { value: string; el: HTMLBqInputElement }; } interface HTMLBqDatePickerElement extends Components.BqDatePicker, HTMLStencilElement { addEventListener(type: K, listener: (this: HTMLBqDatePickerElement, ev: BqDatePickerCustomEvent) => any, options?: boolean | AddEventListenerOptions): void; @@ -2587,7 +2589,7 @@ declare namespace LocalJSX { /** * The first day of the week, where Sunday is 0, Monday is 1, etc */ - "firstDayOfWeek"?: number; + "firstDayOfWeek"?: DaysOfWeek; /** * The ID of the form that the Date picker input belongs to. */ @@ -2627,7 +2629,7 @@ declare namespace LocalJSX { /** * Callback handler emitted when the input value has changed and the input loses focus. This handler is called whenever the user finishes typing or pasting text into the input field and then clicks outside of the input field. */ - "onBqChange"?: (event: BqDatePickerCustomEvent<{ value: string | number | string[]; el: HTMLBqInputElement }>) => void; + "onBqChange"?: (event: BqDatePickerCustomEvent<{ value: string; el: HTMLBqInputElement }>) => void; /** * Callback handler emitted when the input value has been cleared */ @@ -2639,7 +2641,7 @@ declare namespace LocalJSX { /** * Callback handler emitted when the input value changes. This handler is called whenever the user types or pastes text into the input field. */ - "onBqInput"?: (event: BqDatePickerCustomEvent<{ value: string | number | string[]; el: HTMLBqInputElement }>) => void; + "onBqInput"?: (event: BqDatePickerCustomEvent<{ value: string; el: HTMLBqInputElement }>) => void; /** * If `true`, the Date picker panel will be visible. */ @@ -2684,7 +2686,7 @@ declare namespace LocalJSX { /** * 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). */ - "value"?: TInputValue; + "value"?: string; } interface BqDialog { /** 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 3d3c4f0c8..5300bc1fb 100644 --- a/packages/beeq/src/components/date-picker/bq-date-picker.tsx +++ b/packages/beeq/src/components/date-picker/bq-date-picker.tsx @@ -1,5 +1,6 @@ import { Component, Element, Event, EventEmitter, h, Listen, Method, Prop, State, Watch } from '@stencil/core'; +import { DaysOfWeek } from './scss/bq-date-picker.types'; import { FloatingUIPlacement } from '../../services/interfaces'; import { hasSlotContent, isDefined, isHTMLElement } from '../../shared/utils'; import { TInputValidation, TInputValue } from '../input/bq-input.types'; @@ -148,13 +149,13 @@ export class BqDatePicker { /** 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). */ - @Prop({ reflect: true, mutable: true }) value: TInputValue; + @Prop({ reflect: true, mutable: true }) value: string; /** Whether to show days outside the month */ @Prop({ reflect: true }) showOutsideDays: boolean = false; /** The first day of the week, where Sunday is 0, Monday is 1, etc */ - @Prop({ reflect: true }) firstDayOfWeek?: number = 1; + @Prop({ reflect: true }) firstDayOfWeek?: DaysOfWeek = 1; /** The earliest date that can be selected */ @Prop({ reflect: true }) min?: string; @@ -189,7 +190,7 @@ export class BqDatePicker { * Callback handler emitted when the input value has changed and the input loses focus. * This handler is called whenever the user finishes typing or pasting text into the input field and then clicks outside of the input field. */ - @Event() bqChange!: EventEmitter<{ value: string | number | string[]; el: HTMLBqInputElement }>; + @Event() bqChange!: EventEmitter<{ value: string; el: HTMLBqInputElement }>; /** Callback handler emitted when the input value has been cleared */ @Event() bqClear!: EventEmitter; @@ -201,7 +202,7 @@ export class BqDatePicker { * Callback handler emitted when the input value changes. * This handler is called whenever the user types or pastes text into the input field. */ - @Event() bqInput!: EventEmitter<{ value: string | number | string[]; el: HTMLBqInputElement }>; + @Event() bqInput!: EventEmitter<{ value: string; el: HTMLBqInputElement }>; // Component lifecycle events // Ordered by their natural call order @@ -324,7 +325,7 @@ export class BqDatePicker { months.push( , ); diff --git a/packages/beeq/src/components/date-picker/readme.md b/packages/beeq/src/components/date-picker/readme.md index f213b4813..8824d45bc 100644 --- a/packages/beeq/src/components/date-picker/readme.md +++ b/packages/beeq/src/components/date-picker/readme.md @@ -14,7 +14,7 @@ | `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 | `number` | `1` | +| `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` | | `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 | `string` | `undefined` | @@ -33,18 +33,18 @@ | `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'` | | `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). | `number \| string \| string[]` | `undefined` | +| `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 -| Event | Description | Type | -| ---------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------- | -| `bqBlur` | Callback handler emitted when the input loses focus | `CustomEvent` | -| `bqChange` | Callback handler emitted when the input value has changed and the input loses focus. This handler is called whenever the user finishes typing or pasting text into the input field and then clicks outside of the input field. | `CustomEvent<{ value: string \| number \| string[]; el: HTMLBqInputElement; }>` | -| `bqClear` | Callback handler emitted when the input value has been cleared | `CustomEvent` | -| `bqFocus` | Callback handler emitted when the input has received focus | `CustomEvent` | -| `bqInput` | Callback handler emitted when the input value changes. This handler is called whenever the user types or pastes text into the input field. | `CustomEvent<{ value: string \| number \| string[]; el: HTMLBqInputElement; }>` | +| Event | Description | Type | +| ---------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | --------------------------------------------------------- | +| `bqBlur` | Callback handler emitted when the input loses focus | `CustomEvent` | +| `bqChange` | Callback handler emitted when the input value has changed and the input loses focus. This handler is called whenever the user finishes typing or pasting text into the input field and then clicks outside of the input field. | `CustomEvent<{ value: string; el: HTMLBqInputElement; }>` | +| `bqClear` | Callback handler emitted when the input value has been cleared | `CustomEvent` | +| `bqFocus` | Callback handler emitted when the input has received focus | `CustomEvent` | +| `bqInput` | Callback handler emitted when the input value changes. This handler is called whenever the user types or pastes text into the input field. | `CustomEvent<{ value: string; el: HTMLBqInputElement; }>` | ## Methods diff --git a/packages/beeq/src/components/date-picker/scss/bq-date-picker.types.ts b/packages/beeq/src/components/date-picker/scss/bq-date-picker.types.ts new file mode 100644 index 000000000..3c8fba24e --- /dev/null +++ b/packages/beeq/src/components/date-picker/scss/bq-date-picker.types.ts @@ -0,0 +1 @@ +export type DaysOfWeek = 0 | 1 | 2 | 3 | 4 | 5 | 6; From 43fb640f1e93a9ce93d3d732aa136003af88d347 Mon Sep 17 00:00:00 2001 From: Lungan Catalin Date: Fri, 17 May 2024 16:00:07 +0300 Subject: [PATCH 36/75] feat(Date Picker): implement formatDate method to handle single, multi and range date formats --- .../components/date-picker/bq-date-picker.tsx | 41 ++++++++++++++----- 1 file changed, 30 insertions(+), 11 deletions(-) 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 5300bc1fb..650826972 100644 --- a/packages/beeq/src/components/date-picker/bq-date-picker.tsx +++ b/packages/beeq/src/components/date-picker/bq-date-picker.tsx @@ -3,7 +3,7 @@ import { Component, Element, Event, EventEmitter, h, Listen, Method, Prop, State import { DaysOfWeek } from './scss/bq-date-picker.types'; import { FloatingUIPlacement } from '../../services/interfaces'; import { hasSlotContent, isDefined, isHTMLElement } from '../../shared/utils'; -import { TInputValidation, TInputValue } from '../input/bq-input.types'; +import { TInputValidation } from '../input/bq-input.types'; /** * @part base - The component's base wrapper. @@ -340,21 +340,16 @@ export class BqDatePicker { /** * Processes the focused date value to extract the last date portion. * - * @param value - The value to be processed, can be a string, number, or string array. + * @param value - The value to be processed, can be a string. * @returns The extracted last date portion of the value. */ - private processFocusedDateValue = (value: TInputValue) => { + private processFocusedDateValue = (value: string) => { const dateLength = 10; // Length of a standard date in the format YYYY-MM-DD - if (typeof value === 'string') { + if (value) { return value.slice(-dateLength); } - if (typeof value === 'number') { - return value.toString(); - } - if (Array.isArray(value)) { - return value[value.length - 1]; - } + return null; }; @@ -385,6 +380,29 @@ export class BqDatePicker { this.open = !!this.multi; }; + private formatDate = (value: string): string | undefined => { + if (!value) return; + + const formatOptions: Intl.DateTimeFormatOptions = { + day: 'numeric', + month: 'short', + year: 'numeric', + }; + const dateFormatter = new Intl.DateTimeFormat(this.locale, formatOptions); + + if (this.range) { + const [start, end] = value.split('/').map((dateStr) => new Date(dateStr)); + return dateFormatter.formatRange(start, end); + } + + if (this.multi) { + const dates = value.split(' ').map((dateStr) => new Date(dateStr)); + return dates.map((date) => dateFormatter.format(date)).join(', '); + } + + return dateFormatter.format(new Date(value)); + }; + // render() function // Always the last one in the class. // =================================== @@ -394,6 +412,7 @@ export class BqDatePicker { const CallyCalendar = this.CalendarType; + console.log('gggg', this.processFocusedDateValue(this.value)); return (
{/* Label */} @@ -454,7 +473,7 @@ export class BqDatePicker { required={this.required} spellcheck={false} type="text" - value={this.value} + value={this.formatDate(this.value)} part="input" // Events onBlur={this.handleBlur} From f526c5d9b9fdf8048b71b8667dabf6a399fc4321 Mon Sep 17 00:00:00 2001 From: Lungan Catalin Date: Fri, 17 May 2024 16:02:39 +0300 Subject: [PATCH 37/75] feat(Date Picker): remove console.log --- packages/beeq/src/components/date-picker/bq-date-picker.tsx | 1 - 1 file changed, 1 deletion(-) 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 650826972..9f1718688 100644 --- a/packages/beeq/src/components/date-picker/bq-date-picker.tsx +++ b/packages/beeq/src/components/date-picker/bq-date-picker.tsx @@ -412,7 +412,6 @@ export class BqDatePicker { const CallyCalendar = this.CalendarType; - console.log('gggg', this.processFocusedDateValue(this.value)); return (
{/* Label */} From b327748508b416dc0e220d4e9937cd1b889b59e4 Mon Sep 17 00:00:00 2001 From: Lungan Catalin Date: Fri, 17 May 2024 16:37:10 +0300 Subject: [PATCH 38/75] feat(Date Picker): integrate components into JSXBase for improved TS error reporting --- .../src/components/date-picker/bq-date-picker.tsx | 5 +++-- packages/beeq/src/global/scripts/global.ts | 13 +++++++++++++ 2 files changed, 16 insertions(+), 2 deletions(-) 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 9f1718688..3d602e958 100644 --- a/packages/beeq/src/components/date-picker/bq-date-picker.tsx +++ b/packages/beeq/src/components/date-picker/bq-date-picker.tsx @@ -370,8 +370,9 @@ export class BqDatePicker { return componentTypes[type] || componentTypes.default; } - private handleCalendarChange = (ev: { target: { value: string } }) => { - const { value } = ev.target; + private handleCalendarChange = (ev: Event) => { + const target = ev.target as HTMLInputElement; + const value = target.value; this.value = value; this.inputElem.value = this.value; diff --git a/packages/beeq/src/global/scripts/global.ts b/packages/beeq/src/global/scripts/global.ts index 0840a3cca..5f1438f29 100644 --- a/packages/beeq/src/global/scripts/global.ts +++ b/packages/beeq/src/global/scripts/global.ts @@ -1 +1,14 @@ import 'cally'; +import type { JSXBase } from '@stencil/core/internal'; +import type { CalendarDateProps, CalendarMonthProps, CalendarMultiProps, CalendarRangeProps } from 'cally'; +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-date': CalendarDateProps & JSXBase.HTMLAttributes; + 'calendar-month': CalendarMonthProps & JSXBase.HTMLAttributes; + } + } +} From 1af7ced634bc355885521f2bfc3f06455b7f125c Mon Sep 17 00:00:00 2001 From: Lungan Catalin Date: Fri, 17 May 2024 16:57:22 +0300 Subject: [PATCH 39/75] feat(Date Picker): add en-GB as default for locale format dates --- packages/beeq/src/components.d.ts | 8 ++++---- .../beeq/src/components/date-picker/bq-date-picker.tsx | 7 +++++-- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/packages/beeq/src/components.d.ts b/packages/beeq/src/components.d.ts index d44905b9a..01a90e509 100644 --- a/packages/beeq/src/components.d.ts +++ b/packages/beeq/src/components.d.ts @@ -363,9 +363,9 @@ export namespace Components { */ "isDateDisallowed"?: (date: Date) => boolean; /** - * The locale for formatting dates. If not set, will use the browser's 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": string | undefined; + "locale": Intl.LocalesArgument; /** * The latest date that can be selected */ @@ -2599,9 +2599,9 @@ declare namespace LocalJSX { */ "isDateDisallowed"?: (date: Date) => boolean; /** - * The locale for formatting dates. If not set, will use the browser's 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"?: string | undefined; + "locale"?: Intl.LocalesArgument; /** * The latest date that can be selected */ 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 3d602e958..66c3a9dd1 100644 --- a/packages/beeq/src/components/date-picker/bq-date-picker.tsx +++ b/packages/beeq/src/components/date-picker/bq-date-picker.tsx @@ -163,8 +163,11 @@ export class BqDatePicker { /** The latest date that can be selected */ @Prop({ reflect: true }) max?: string; - /** The locale for formatting dates. If not set, will use the browser's locale */ - @Prop({ reflect: true }) locale: string | undefined = undefined; + /** + * 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 + */ + @Prop({ reflect: true }) locale: Intl.LocalesArgument = 'en-GB'; // Prop lifecycle events // ======================= From 553d99ee8c4628c49584c7648c9a85896b47614b Mon Sep 17 00:00:00 2001 From: Lungan Catalin Date: Fri, 17 May 2024 17:29:27 +0300 Subject: [PATCH 40/75] feat(Date Picker): enhance display value formatting flexibility with formatOptions --- packages/beeq/src/components.d.ts | 12 ++++++++++-- .../_storybook/bq-date-picker.stories.tsx | 7 +++++++ .../components/date-picker/bq-date-picker.tsx | 19 ++++++++++++------- .../{scss => }/bq-date-picker.types.ts | 0 4 files changed, 29 insertions(+), 9 deletions(-) rename packages/beeq/src/components/date-picker/{scss => }/bq-date-picker.types.ts (100%) diff --git a/packages/beeq/src/components.d.ts b/packages/beeq/src/components.d.ts index 01a90e509..d7c6c6cf8 100644 --- a/packages/beeq/src/components.d.ts +++ b/packages/beeq/src/components.d.ts @@ -13,7 +13,7 @@ import { TButtonAppearance, TButtonBorderRadius, TButtonSize, TButtonType, TButt import { TCardBorderRadius, TCardType } from "./components/card/bq-card.types"; import { FloatingUIPlacement } from "./services/interfaces"; import { TInputType, TInputValidation, TInputValue } from "./components/input/bq-input.types"; -import { DaysOfWeek } from "./components/date-picker/scss/bq-date-picker.types"; +import { DaysOfWeek } from "./components/date-picker/bq-date-picker.types"; import { TDialogBorderRadius, TDialogFooterAppearance, TDialogSize } from "./components/dialog/bq-dialog.types"; import { TDividerOrientation, TDividerStrokeLinecap, TDividerTitleAlignment } from "./components/divider/bq-divider.types"; import { TDrawerPlacement } from "./components/drawer/bq-drawer.types"; @@ -42,7 +42,7 @@ export { TButtonAppearance, TButtonBorderRadius, TButtonSize, TButtonType, TButt export { TCardBorderRadius, TCardType } from "./components/card/bq-card.types"; export { FloatingUIPlacement } from "./services/interfaces"; export { TInputType, TInputValidation, TInputValue } from "./components/input/bq-input.types"; -export { DaysOfWeek } from "./components/date-picker/scss/bq-date-picker.types"; +export { DaysOfWeek } from "./components/date-picker/bq-date-picker.types"; export { TDialogBorderRadius, TDialogFooterAppearance, TDialogSize } from "./components/dialog/bq-dialog.types"; export { TDividerOrientation, TDividerStrokeLinecap, TDividerTitleAlignment } from "./components/divider/bq-divider.types"; export { TDrawerPlacement } from "./components/drawer/bq-drawer.types"; @@ -358,6 +358,10 @@ export namespace Components { * The ID of the form that the Date picker input belongs to. */ "form"?: string; + /** + * 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 + */ + "formatOptions": Intl.DateTimeFormatOptions; /** * A function that takes a date and returns true if the date should not be selectable */ @@ -2594,6 +2598,10 @@ declare namespace LocalJSX { * The ID of the form that the Date picker input belongs to. */ "form"?: string; + /** + * 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 + */ + "formatOptions"?: Intl.DateTimeFormatOptions; /** * A function that takes a date and returns true if the date should not be selectable */ 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 fa3aea4c0..f3dff1b36 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 @@ -54,6 +54,7 @@ const meta: Meta = { multi: { control: 'boolean' }, months: { control: 'number' }, value: { control: 'text' }, + 'format-options': { control: 'object' }, // Events bqBlur: { action: 'bqBlur' }, bqChange: { action: 'bqChange' }, @@ -91,6 +92,11 @@ const meta: Meta = { multi: false, months: 1, value: undefined, + 'format-options': { + day: 'numeric', + month: 'short', + year: 'numeric', + }, isDateDisallowed: undefined, customDisallowedDate: undefined, }, @@ -157,6 +163,7 @@ const Template = (args: Args) => { multi=${args.multi} months=${args.months} value=${ifDefined(args.value)} + .format-options=${args['format-options']} .isDateDisallowed=${isDate} @bqBlur=${args.bqBlur} @bqChange=${args.bqChange} 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 66c3a9dd1..bc6e29894 100644 --- a/packages/beeq/src/components/date-picker/bq-date-picker.tsx +++ b/packages/beeq/src/components/date-picker/bq-date-picker.tsx @@ -1,6 +1,6 @@ import { Component, Element, Event, EventEmitter, h, Listen, Method, Prop, State, Watch } from '@stencil/core'; -import { DaysOfWeek } from './scss/bq-date-picker.types'; +import { DaysOfWeek } from './bq-date-picker.types'; import { FloatingUIPlacement } from '../../services/interfaces'; import { hasSlotContent, isDefined, isHTMLElement } from '../../shared/utils'; import { TInputValidation } from '../input/bq-input.types'; @@ -169,6 +169,16 @@ export class BqDatePicker { */ @Prop({ reflect: true }) locale: Intl.LocalesArgument = 'en-GB'; + /** + * 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 + */ + @Prop() formatOptions: Intl.DateTimeFormatOptions = { + day: 'numeric', + month: 'short', + year: 'numeric', + }; + // Prop lifecycle events // ======================= @@ -387,12 +397,7 @@ export class BqDatePicker { private formatDate = (value: string): string | undefined => { if (!value) return; - const formatOptions: Intl.DateTimeFormatOptions = { - day: 'numeric', - month: 'short', - year: 'numeric', - }; - const dateFormatter = new Intl.DateTimeFormat(this.locale, formatOptions); + const dateFormatter = new Intl.DateTimeFormat(this.locale, this.formatOptions); if (this.range) { const [start, end] = value.split('/').map((dateStr) => new Date(dateStr)); diff --git a/packages/beeq/src/components/date-picker/scss/bq-date-picker.types.ts b/packages/beeq/src/components/date-picker/bq-date-picker.types.ts similarity index 100% rename from packages/beeq/src/components/date-picker/scss/bq-date-picker.types.ts rename to packages/beeq/src/components/date-picker/bq-date-picker.types.ts From 17c0ffa28ab2255d3f7cbc757636dc2164d64128 Mon Sep 17 00:00:00 2001 From: Lungan Catalin Date: Fri, 17 May 2024 17:49:33 +0300 Subject: [PATCH 41/75] feat(Date Picker): add as string type to locale --- .../components/date-picker/bq-date-picker.tsx | 2 +- .../beeq/src/components/date-picker/readme.md | 55 ++++++++++--------- 2 files changed, 29 insertions(+), 28 deletions(-) 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 bc6e29894..83d35bbdf 100644 --- a/packages/beeq/src/components/date-picker/bq-date-picker.tsx +++ b/packages/beeq/src/components/date-picker/bq-date-picker.tsx @@ -521,7 +521,7 @@ export class BqDatePicker {
boolean` | `undefined` | -| `locale` | `locale` | The locale for formatting dates. If not set, will use the browser's locale | `string` | `undefined` | -| `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` | -| `multi` | `multi` | If `true`, the Date picker panel will accepts to select multiple individual dates | `boolean` | `false` | -| `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-start'` | -| `range` | `range` | If `true`, the Date picker panel will accepts more than 1 month to display | `boolean` | `false` | -| `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'` | -| `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` | +| `multi` | `multi` | If `true`, the Date picker panel will accepts to select multiple individual dates | `boolean` | `false` | +| `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-start'` | +| `range` | `range` | If `true`, the Date picker panel will accepts more than 1 month to display | `boolean` | `false` | +| `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'` | +| `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 From 4127d3d0e1d8896dd6e5ed823d05bd8a2c734ab0 Mon Sep 17 00:00:00 2001 From: Lungan Catalin Date: Fri, 17 May 2024 17:53:59 +0300 Subject: [PATCH 42/75] feat(Date Picker): refactor handleCalendarChange --- packages/beeq/src/components/date-picker/bq-date-picker.tsx | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) 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 83d35bbdf..b5a4894fd 100644 --- a/packages/beeq/src/components/date-picker/bq-date-picker.tsx +++ b/packages/beeq/src/components/date-picker/bq-date-picker.tsx @@ -384,8 +384,7 @@ export class BqDatePicker { } private handleCalendarChange = (ev: Event) => { - const target = ev.target as HTMLInputElement; - const value = target.value; + const { value } = ev.target as unknown as { value: string }; this.value = value; this.inputElem.value = this.value; From e12a8b5205f87950ab954ceb93360cdeea3b9598 Mon Sep 17 00:00:00 2001 From: Lungan Catalin Date: Fri, 17 May 2024 17:58:27 +0300 Subject: [PATCH 43/75] feat(Date Picker): remove unused animation --- packages/beeq/src/components/panel/bq-panel.tsx | 6 ++---- .../beeq/src/components/panel/scss/bq-panel.scss | 4 ---- .../beeq/src/global/styles/mixins/_keyframes.scss | 15 --------------- 3 files changed, 2 insertions(+), 23 deletions(-) diff --git a/packages/beeq/src/components/panel/bq-panel.tsx b/packages/beeq/src/components/panel/bq-panel.tsx index 42e33fa32..100026825 100644 --- a/packages/beeq/src/components/panel/bq-panel.tsx +++ b/packages/beeq/src/components/panel/bq-panel.tsx @@ -138,12 +138,10 @@ export class BqPanel { render() { return (
(this.panel = el)} aria-hidden={!this.open ? 'true' : 'false'} + hidden={!this.open} part="panel" > diff --git a/packages/beeq/src/components/panel/scss/bq-panel.scss b/packages/beeq/src/components/panel/scss/bq-panel.scss index cf91f76c3..b10fd270d 100644 --- a/packages/beeq/src/components/panel/scss/bq-panel.scss +++ b/packages/beeq/src/components/panel/scss/bq-panel.scss @@ -17,7 +17,3 @@ border-style: var(--bq-panel--border-style); } - -.panel-hidden { - @include animation-fade-out; -} diff --git a/packages/beeq/src/global/styles/mixins/_keyframes.scss b/packages/beeq/src/global/styles/mixins/_keyframes.scss index 4ae6f6140..e41751553 100644 --- a/packages/beeq/src/global/styles/mixins/_keyframes.scss +++ b/packages/beeq/src/global/styles/mixins/_keyframes.scss @@ -8,16 +8,6 @@ } } -@keyframes fade-out { - from { - opacity: 1; - } - - to { - opacity: 0; - } -} - @keyframes slide-in { from { transform: translateY(10px); @@ -38,11 +28,6 @@ animation: fade-in $duration $timing-function $delay; } -@mixin animation-fade-out($duration: 0.3s, $delay: 0s, $timing-function: ease) { - animation: fade-out $duration $timing-function $delay; - opacity: 0; -} - @mixin animation-slide-in($duration: 0.3s, $delay: 0s, $timing-function: ease) { animation: fade-in $duration $timing-function $delay, From 45312d1be9951e37c5193b2678a51fdd0b796a49 Mon Sep 17 00:00:00 2001 From: Lungan Catalin Date: Fri, 17 May 2024 18:27:53 +0300 Subject: [PATCH 44/75] feat(Date Picker): consolidate calendar variant selection with single type property --- packages/beeq/src/components.d.ts | 48 ++++++++----------- .../_storybook/bq-date-picker.stories.tsx | 14 +++--- .../components/date-picker/bq-date-picker.tsx | 44 ++++++++--------- .../date-picker/bq-date-picker.types.ts | 3 ++ .../beeq/src/components/date-picker/readme.md | 17 ++++--- 5 files changed, 58 insertions(+), 68 deletions(-) diff --git a/packages/beeq/src/components.d.ts b/packages/beeq/src/components.d.ts index d7c6c6cf8..898171314 100644 --- a/packages/beeq/src/components.d.ts +++ b/packages/beeq/src/components.d.ts @@ -12,8 +12,8 @@ import { TBadgeSize } from "./components/badge/bq-badge.types"; import { TButtonAppearance, TButtonBorderRadius, TButtonSize, TButtonType, TButtonVariant } from "./components/button/bq-button.types"; import { TCardBorderRadius, TCardType } from "./components/card/bq-card.types"; import { FloatingUIPlacement } from "./services/interfaces"; +import { DaysOfWeek, TDatePickerType } from "./components/date-picker/bq-date-picker.types"; import { TInputType, TInputValidation, TInputValue } from "./components/input/bq-input.types"; -import { DaysOfWeek } from "./components/date-picker/bq-date-picker.types"; import { TDialogBorderRadius, TDialogFooterAppearance, TDialogSize } from "./components/dialog/bq-dialog.types"; import { TDividerOrientation, TDividerStrokeLinecap, TDividerTitleAlignment } from "./components/divider/bq-divider.types"; import { TDrawerPlacement } from "./components/drawer/bq-drawer.types"; @@ -41,8 +41,8 @@ export { TBadgeSize } from "./components/badge/bq-badge.types"; export { TButtonAppearance, TButtonBorderRadius, TButtonSize, TButtonType, TButtonVariant } from "./components/button/bq-button.types"; export { TCardBorderRadius, TCardType } from "./components/card/bq-card.types"; export { FloatingUIPlacement } from "./services/interfaces"; +export { DaysOfWeek, TDatePickerType } from "./components/date-picker/bq-date-picker.types"; export { TInputType, TInputValidation, TInputValue } from "./components/input/bq-input.types"; -export { DaysOfWeek } from "./components/date-picker/bq-date-picker.types"; export { TDialogBorderRadius, TDialogFooterAppearance, TDialogSize } from "./components/dialog/bq-dialog.types"; export { TDividerOrientation, TDividerStrokeLinecap, TDividerTitleAlignment } from "./components/divider/bq-divider.types"; export { TDrawerPlacement } from "./components/drawer/bq-drawer.types"; @@ -382,10 +382,6 @@ export namespace Components { * Number of months to show when range is `true` */ "months": number; - /** - * If `true`, the Date picker panel will accepts to select multiple individual dates - */ - "multi": boolean; /** * The Date picker input name. */ @@ -406,10 +402,6 @@ export namespace Components { * Position of the Date picker panel */ "placement"?: FloatingUIPlacement; - /** - * If `true`, the Date picker panel will accepts more than 1 month to display - */ - "range": boolean; /** * Indicates whether or not the Date picker input is required to be filled out before submitting the form. */ @@ -426,6 +418,10 @@ export namespace Components { * Defines the strategy to position the Date picker panel */ "strategy"?: 'fixed' | 'absolute'; + /** + * It defines how the calendar will behave, allowing single date selection, range selection, or multiple date selection + */ + "type": TDatePickerType; /** * The validation status of the Select input. * @remarks This property is used to indicate the validation status of the select input. It can be set to one of the following values: - `'none'`: No validation status is set. - `'error'`: The input has a validation error. - `'warning'`: The input has a validation warning. - `'success'`: The input has passed validation. @@ -1713,11 +1709,11 @@ declare global { new (): HTMLBqCheckboxElement; }; interface HTMLBqDatePickerElementEventMap { - "bqBlur": HTMLBqInputElement; - "bqChange": { value: string; el: HTMLBqInputElement }; - "bqClear": HTMLBqInputElement; - "bqFocus": HTMLBqInputElement; - "bqInput": { value: string; el: HTMLBqInputElement }; + "bqBlur": HTMLBqDatePickerElement; + "bqChange": { value: string; el: HTMLBqDatePickerElement }; + "bqClear": HTMLBqDatePickerElement; + "bqFocus": HTMLBqDatePickerElement; + "bqInput": { value: string; el: HTMLBqDatePickerElement }; } interface HTMLBqDatePickerElement extends Components.BqDatePicker, HTMLStencilElement { addEventListener(type: K, listener: (this: HTMLBqDatePickerElement, ev: BqDatePickerCustomEvent) => any, options?: boolean | AddEventListenerOptions): void; @@ -2622,10 +2618,6 @@ declare namespace LocalJSX { * Number of months to show when range is `true` */ "months"?: number; - /** - * If `true`, the Date picker panel will accepts to select multiple individual dates - */ - "multi"?: boolean; /** * The Date picker input name. */ @@ -2633,23 +2625,23 @@ declare namespace LocalJSX { /** * Callback handler emitted when the input loses focus */ - "onBqBlur"?: (event: BqDatePickerCustomEvent) => void; + "onBqBlur"?: (event: BqDatePickerCustomEvent) => void; /** * Callback handler emitted when the input value has changed and the input loses focus. This handler is called whenever the user finishes typing or pasting text into the input field and then clicks outside of the input field. */ - "onBqChange"?: (event: BqDatePickerCustomEvent<{ value: string; el: HTMLBqInputElement }>) => void; + "onBqChange"?: (event: BqDatePickerCustomEvent<{ value: string; el: HTMLBqDatePickerElement }>) => void; /** * Callback handler emitted when the input value has been cleared */ - "onBqClear"?: (event: BqDatePickerCustomEvent) => void; + "onBqClear"?: (event: BqDatePickerCustomEvent) => void; /** * Callback handler emitted when the input has received focus */ - "onBqFocus"?: (event: BqDatePickerCustomEvent) => void; + "onBqFocus"?: (event: BqDatePickerCustomEvent) => void; /** * Callback handler emitted when the input value changes. This handler is called whenever the user types or pastes text into the input field. */ - "onBqInput"?: (event: BqDatePickerCustomEvent<{ value: string; el: HTMLBqInputElement }>) => void; + "onBqInput"?: (event: BqDatePickerCustomEvent<{ value: string; el: HTMLBqDatePickerElement }>) => void; /** * If `true`, the Date picker panel will be visible. */ @@ -2666,10 +2658,6 @@ declare namespace LocalJSX { * Position of the Date picker panel */ "placement"?: FloatingUIPlacement; - /** - * If `true`, the Date picker panel will accepts more than 1 month to display - */ - "range"?: boolean; /** * Indicates whether or not the Date picker input is required to be filled out before submitting the form. */ @@ -2686,6 +2674,10 @@ declare namespace LocalJSX { * Defines the strategy to position the Date picker panel */ "strategy"?: 'fixed' | 'absolute'; + /** + * It defines how the calendar will behave, allowing single date selection, range selection, or multiple date selection + */ + "type"?: TDatePickerType; /** * The validation status of the Select input. * @remarks This property is used to indicate the validation status of the select input. It can be set to one of the following values: - `'none'`: No validation status is set. - `'error'`: The input has a validation error. - `'warning'`: The input has a validation warning. - `'success'`: The input has passed validation. 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 f3dff1b36..ff5eaf5dd 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 @@ -4,6 +4,7 @@ import { ifDefined } from 'lit-html/directives/if-defined.js'; import mdx from './bq-date-picker.mdx'; import { INPUT_VALIDATION } from '../../input/bq-input.types'; +import { DATE_PICKER_TYPE } from '../bq-date-picker.types'; const meta: Meta = { title: 'Components/Date picker', @@ -50,8 +51,7 @@ const meta: Meta = { skidding: { control: 'number' }, strategy: { control: 'select', options: ['fixed', 'absolute'] }, 'validation-status': { control: 'select', options: [...INPUT_VALIDATION] }, - range: { control: 'boolean' }, - multi: { control: 'boolean' }, + type: { control: 'select', options: [...DATE_PICKER_TYPE] }, months: { control: 'number' }, value: { control: 'text' }, 'format-options': { control: 'object' }, @@ -88,8 +88,7 @@ const meta: Meta = { strategy: 'absolute', required: false, 'validation-status': 'none', - range: false, - multi: false, + type: 'single', months: 1, value: undefined, 'format-options': { @@ -159,8 +158,7 @@ const Template = (args: Args) => { skidding=${args.skidding} strategy=${args.strategy} validation-status=${args['validation-status']} - range=${args.range} - multi=${args.multi} + type=${args.type} months=${args.months} value=${ifDefined(args.value)} .format-options=${args['format-options']} @@ -186,7 +184,7 @@ export const Default: Story = { export const Range: Story = { render: Template, args: { - range: true, + type: 'range', months: 2, }, }; @@ -194,7 +192,7 @@ export const Range: Story = { export const Multi: Story = { render: Template, args: { - multi: true, + type: 'multi', months: 2, }, }; 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 b5a4894fd..6f6a309f9 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,8 @@ import { Component, Element, Event, EventEmitter, h, Listen, Method, Prop, State, Watch } from '@stencil/core'; -import { DaysOfWeek } from './bq-date-picker.types'; +import { DATE_PICKER_TYPE, DaysOfWeek, TDatePickerType } from './bq-date-picker.types'; import { FloatingUIPlacement } from '../../services/interfaces'; -import { hasSlotContent, isDefined, isHTMLElement } from '../../shared/utils'; +import { hasSlotContent, isDefined, isHTMLElement, validatePropValue } from '../../shared/utils'; import { TInputValidation } from '../input/bq-input.types'; /** @@ -64,7 +64,7 @@ export class BqDatePicker { // Reference to host HTML element // =================================== - @Element() el!: HTMLBqInputElement; + @Element() el!: HTMLBqDatePickerElement; // State() variables // Inlined decorator, alphabetical order @@ -123,11 +123,8 @@ export class BqDatePicker { /** Defines the strategy to position the Date picker panel */ @Prop({ reflect: true }) strategy?: 'fixed' | 'absolute' = 'fixed'; - /** If `true`, the Date picker panel will accepts more than 1 month to display */ - @Prop({ reflect: true }) range: boolean = false; - - /** If `true`, the Date picker panel will accepts to select multiple individual dates */ - @Prop({ reflect: true }) multi: boolean = false; + /** It defines how the calendar will behave, allowing single date selection, range selection, or multiple date selection */ + @Prop({ reflect: true }) type: TDatePickerType = 'single'; /** Number of months to show when range is `true` */ @Prop({ reflect: true }) months: number; @@ -192,30 +189,35 @@ export class BqDatePicker { this.hasValue = isDefined(this.value); } + @Watch('type') + checkPropValues() { + validatePropValue(DATE_PICKER_TYPE, 'single', this.el, 'type'); + } + // Events section // Requires JSDocs for public API documentation // ============================================== /** Callback handler emitted when the input loses focus */ - @Event() bqBlur!: EventEmitter; + @Event() bqBlur!: EventEmitter; /** * Callback handler emitted when the input value has changed and the input loses focus. * This handler is called whenever the user finishes typing or pasting text into the input field and then clicks outside of the input field. */ - @Event() bqChange!: EventEmitter<{ value: string; el: HTMLBqInputElement }>; + @Event() bqChange!: EventEmitter<{ value: string; el: HTMLBqDatePickerElement }>; /** Callback handler emitted when the input value has been cleared */ - @Event() bqClear!: EventEmitter; + @Event() bqClear!: EventEmitter; /** Callback handler emitted when the input has received focus */ - @Event() bqFocus!: EventEmitter; + @Event() bqFocus!: EventEmitter; /** * Callback handler emitted when the input value changes. * This handler is called whenever the user types or pastes text into the input field. */ - @Event() bqInput!: EventEmitter<{ value: string; el: HTMLBqInputElement }>; + @Event() bqInput!: EventEmitter<{ value: string; el: HTMLBqDatePickerElement }>; // Component lifecycle events // Ordered by their natural call order @@ -331,7 +333,7 @@ export class BqDatePicker { const commonExportParts = 'heading,table,tr,head,week,th,td'; const buttonExportParts = 'button,day,selected,today,disallowed,outside,range-start,range-end,range-inner'; - if (this.range || (this.multi && this.months)) { + if (this.type === 'range' || (this.type === 'multi' && this.months)) { for (let i = 0; i < this.months; i++) { const offset = i > 0 ? i : undefined; const className = offset ? 'hidden sm:block' : ''; @@ -374,13 +376,8 @@ export class BqDatePicker { default: 'calendar-date', } as const; // Make componentTypes a readonly object - const types = ['multi', 'range'] as const; // Make types a readonly array - - // Find the first property (multi or range) that is truthy - const type = types.find((t) => this[t]); - // Return the corresponding component type, or the default type if no truthy property was found - return componentTypes[type] || componentTypes.default; + return componentTypes[this.type] || componentTypes.default; } private handleCalendarChange = (ev: Event) => { @@ -388,9 +385,10 @@ export class BqDatePicker { this.value = value; this.inputElem.value = this.value; + this.bqChange.emit({ value: this.value, el: this.el }); - this.open = !!this.multi; + this.open = this.type !== 'single'; }; private formatDate = (value: string): string | undefined => { @@ -398,12 +396,12 @@ export class BqDatePicker { const dateFormatter = new Intl.DateTimeFormat(this.locale, this.formatOptions); - if (this.range) { + if (this.type === 'range') { const [start, end] = value.split('/').map((dateStr) => new Date(dateStr)); return dateFormatter.formatRange(start, end); } - if (this.multi) { + if (this.type === 'multi') { const dates = value.split(' ').map((dateStr) => new Date(dateStr)); return dates.map((date) => dateFormatter.format(date)).join(', '); } diff --git a/packages/beeq/src/components/date-picker/bq-date-picker.types.ts b/packages/beeq/src/components/date-picker/bq-date-picker.types.ts index 3c8fba24e..410a1f142 100644 --- a/packages/beeq/src/components/date-picker/bq-date-picker.types.ts +++ b/packages/beeq/src/components/date-picker/bq-date-picker.types.ts @@ -1 +1,4 @@ export type DaysOfWeek = 0 | 1 | 2 | 3 | 4 | 5 | 6; + +export const DATE_PICKER_TYPE = ['single', 'multi', 'range'] as const; +export type TDatePickerType = (typeof DATE_PICKER_TYPE)[number]; diff --git a/packages/beeq/src/components/date-picker/readme.md b/packages/beeq/src/components/date-picker/readme.md index 5b2424a45..345b2ffde 100644 --- a/packages/beeq/src/components/date-picker/readme.md +++ b/packages/beeq/src/components/date-picker/readme.md @@ -22,30 +22,29 @@ | `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` | -| `multi` | `multi` | If `true`, the Date picker panel will accepts to select multiple individual dates | `boolean` | `false` | | `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-start'` | -| `range` | `range` | If `true`, the Date picker panel will accepts more than 1 month to display | `boolean` | `false` | | `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` | ## Events -| Event | Description | Type | -| ---------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | --------------------------------------------------------- | -| `bqBlur` | Callback handler emitted when the input loses focus | `CustomEvent` | -| `bqChange` | Callback handler emitted when the input value has changed and the input loses focus. This handler is called whenever the user finishes typing or pasting text into the input field and then clicks outside of the input field. | `CustomEvent<{ value: string; el: HTMLBqInputElement; }>` | -| `bqClear` | Callback handler emitted when the input value has been cleared | `CustomEvent` | -| `bqFocus` | Callback handler emitted when the input has received focus | `CustomEvent` | -| `bqInput` | Callback handler emitted when the input value changes. This handler is called whenever the user types or pastes text into the input field. | `CustomEvent<{ value: string; el: HTMLBqInputElement; }>` | +| Event | Description | Type | +| ---------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | -------------------------------------------------------------- | +| `bqBlur` | Callback handler emitted when the input loses focus | `CustomEvent` | +| `bqChange` | Callback handler emitted when the input value has changed and the input loses focus. This handler is called whenever the user finishes typing or pasting text into the input field and then clicks outside of the input field. | `CustomEvent<{ value: string; el: HTMLBqDatePickerElement; }>` | +| `bqClear` | Callback handler emitted when the input value has been cleared | `CustomEvent` | +| `bqFocus` | Callback handler emitted when the input has received focus | `CustomEvent` | +| `bqInput` | Callback handler emitted when the input value changes. This handler is called whenever the user types or pastes text into the input field. | `CustomEvent<{ value: string; el: HTMLBqDatePickerElement; }>` | ## Methods From 4be6a189f3f8d5493fc05d8502b016c3b1618d22 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dabiel=20Gonz=C3=A1lez=20Ramos?= Date: Fri, 17 May 2024 19:01:54 +0300 Subject: [PATCH 45/75] test(e2e): update e2e tests after the `type` property addition --- .../date-picker/__tests__/bq-date-picker.e2e.ts | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/packages/beeq/src/components/date-picker/__tests__/bq-date-picker.e2e.ts b/packages/beeq/src/components/date-picker/__tests__/bq-date-picker.e2e.ts index 6b34fc6a4..fec45c9e6 100644 --- a/packages/beeq/src/components/date-picker/__tests__/bq-date-picker.e2e.ts +++ b/packages/beeq/src/components/date-picker/__tests__/bq-date-picker.e2e.ts @@ -33,7 +33,7 @@ describe('bq-date-picker', () => { it('should render single type of date picker', async () => { const page = await newE2EPage({ html: ` - + `, }); const calendarDefaultElement = await page.find('bq-date-picker >>> calendar-date'); @@ -44,7 +44,7 @@ describe('bq-date-picker', () => { it('should render range type of date picker', async () => { const page = await newE2EPage({ html: ` - + `, }); const calendarRangeElement = await page.find('bq-date-picker >>> calendar-range'); @@ -55,7 +55,7 @@ describe('bq-date-picker', () => { it('should render multi type of date picker', async () => { const page = await newE2EPage({ html: ` - + `, }); const calendarMultiElement = await page.find('bq-date-picker >>> calendar-multi'); @@ -63,10 +63,10 @@ describe('bq-date-picker', () => { expect(calendarMultiElement).not.toBeNull(); }); - it('should render multile months for range type of date picker', async () => { + it('should render multiple months for range type of date picker', async () => { const page = await newE2EPage({ html: ` - + `, }); const calendarMonthElement = await page.findAll('bq-date-picker >>> calendar-month'); From 4ae835d7ecd31e8c413a7ad82df1a4188efaba14 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dabiel=20Gonz=C3=A1lez=20Ramos?= Date: Fri, 17 May 2024 19:32:21 +0300 Subject: [PATCH 46/75] style(Slider): sort `@Prop` decorators in alphabetical order --- .../components/date-picker/bq-date-picker.tsx | 82 +++++++++---------- 1 file changed, 40 insertions(+), 42 deletions(-) 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 6f6a309f9..5adf0fa4a 100644 --- a/packages/beeq/src/components/date-picker/bq-date-picker.tsx +++ b/packages/beeq/src/components/date-picker/bq-date-picker.tsx @@ -15,8 +15,8 @@ import { TInputValidation } from '../input/bq-input.types'; * @part panel - The date picker panel container * @part prefix - The prefix slot container. * @part suffix - The suffix slot container. - -// Parts from the Cally library for calendar-date and calendar-range components: + +// 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. @@ -24,7 +24,7 @@ import { TInputValidation } from '../input/bq-input.types'; * @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. - + // Parts specific to the calendar-month component: * @part heading - The heading that labels the month. * @part table - The
element. @@ -35,13 +35,13 @@ import { TInputValidation } from '../input/bq-input.types'; * @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 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 range-inner - Any days between the start and end of a date range. */ @Component({ tag: 'bq-date-picker', @@ -84,21 +84,50 @@ export class BqDatePicker { /** The clear button aria label */ @Prop({ reflect: true }) clearButtonLabel? = 'Clear value'; + /** If `true`, the clear button won't be displayed */ + @Prop({ reflect: true }) disableClear? = false; + /** * Indicates whether the Date picker input is disabled or not. * If `true`, the Date picker is disabled and cannot be interacted with. */ @Prop({ mutable: true }) disabled?: boolean = false; - /** If `true`, the clear button won't be displayed */ - @Prop({ reflect: true }) disableClear? = false; - /** Represents the distance (gutter or margin) between the Date picker panel and the input element. */ @Prop({ reflect: true }) distance?: number = 8; + /** The first day of the week, where Sunday is 0, Monday is 1, etc */ + @Prop({ reflect: true }) firstDayOfWeek?: DaysOfWeek = 1; + + /** 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 + */ + @Prop() formatOptions: Intl.DateTimeFormatOptions = { + day: 'numeric', + month: 'short', + year: 'numeric', + }; + /** The ID of the form that the Date picker input belongs to. */ @Prop({ reflect: true }) form?: string; + /** A function that takes a date and returns true if the date should not be selectable */ + @Prop({ reflect: true }) isDateDisallowed?: (date: Date) => boolean; + + /** 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 + */ + @Prop({ reflect: true }) locale: Intl.LocalesArgument = 'en-GB'; + + /** The latest date that can be selected */ + @Prop({ reflect: true }) max?: string; + + /** The earliest date that can be selected */ + @Prop({ reflect: true }) min?: string; + + /** Number of months to show when range is `true` */ + @Prop({ reflect: true }) months: number; + /** The Date picker input name. */ @Prop({ reflect: true }) name!: string; @@ -120,18 +149,15 @@ export class BqDatePicker { /** Represents the skidding between the Date picker panel and the input element. */ @Prop({ reflect: true }) skidding?: number = 0; + /** Whether to show days outside the month */ + @Prop({ reflect: true }) showOutsideDays: boolean = false; + /** Defines the strategy to position the Date picker panel */ @Prop({ reflect: true }) strategy?: 'fixed' | 'absolute' = 'fixed'; /** It defines how the calendar will behave, allowing single date selection, range selection, or multiple date selection */ @Prop({ reflect: true }) type: TDatePickerType = 'single'; - /** Number of months to show when range is `true` */ - @Prop({ reflect: true }) months: number; - - /** A function that takes a date and returns true if the date should not be selectable */ - @Prop({ reflect: true }) isDateDisallowed?: (date: Date) => boolean; - /** * The validation status of the Select input. * @@ -148,34 +174,6 @@ export class BqDatePicker { * All dates are expected in ISO-8601 format (YYYY-MM-DD). */ @Prop({ reflect: true, mutable: true }) value: string; - /** Whether to show days outside the month */ - @Prop({ reflect: true }) showOutsideDays: boolean = false; - - /** The first day of the week, where Sunday is 0, Monday is 1, etc */ - @Prop({ reflect: true }) firstDayOfWeek?: DaysOfWeek = 1; - - /** The earliest date that can be selected */ - @Prop({ reflect: true }) min?: string; - - /** The latest date that can be selected */ - @Prop({ reflect: true }) max?: string; - - /** - * 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 - */ - @Prop({ reflect: true }) locale: Intl.LocalesArgument = 'en-GB'; - - /** - * 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 - */ - @Prop() formatOptions: Intl.DateTimeFormatOptions = { - day: 'numeric', - month: 'short', - year: 'numeric', - }; - // Prop lifecycle events // ======================= From 83702f454543eb54e26ebf53f0db91b28c818533 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dabiel=20Gonz=C3=A1lez=20Ramos?= Date: Fri, 17 May 2024 19:34:42 +0300 Subject: [PATCH 47/75] style(Slider): move `handleCalendarChange()` after `handleChange()` --- .../components/date-picker/bq-date-picker.tsx | 22 +++++++++---------- 1 file changed, 11 insertions(+), 11 deletions(-) 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 5adf0fa4a..4ee0590a4 100644 --- a/packages/beeq/src/components/date-picker/bq-date-picker.tsx +++ b/packages/beeq/src/components/date-picker/bq-date-picker.tsx @@ -290,6 +290,17 @@ export class BqDatePicker { this.bqChange.emit({ value: this.value, el: this.el }); }; + private handleCalendarChange = (ev: Event) => { + const { value } = ev.target as unknown as { value: string }; + + this.value = value; + this.inputElem.value = this.value; + + this.bqChange.emit({ value: this.value, el: this.el }); + + this.open = this.type !== 'single'; + }; + private handleClearClick = (ev: CustomEvent) => { if (this.disabled) return; @@ -378,17 +389,6 @@ export class BqDatePicker { return componentTypes[this.type] || componentTypes.default; } - private handleCalendarChange = (ev: Event) => { - const { value } = ev.target as unknown as { value: string }; - - this.value = value; - this.inputElem.value = this.value; - - this.bqChange.emit({ value: this.value, el: this.el }); - - this.open = this.type !== 'single'; - }; - private formatDate = (value: string): string | undefined => { if (!value) return; From 067834706d8b8d00ac40f131382d782b9e5eb7c7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dabiel=20Gonz=C3=A1lez=20Ramos?= Date: Fri, 17 May 2024 19:51:21 +0300 Subject: [PATCH 48/75] refactor(Slider): split `generateCalendarMonths()` to improve readability --- packages/beeq/src/components.d.ts | 4 +- .../components/date-picker/bq-date-picker.tsx | 56 ++++++++++--------- 2 files changed, 33 insertions(+), 27 deletions(-) diff --git a/packages/beeq/src/components.d.ts b/packages/beeq/src/components.d.ts index 898171314..f17c01254 100644 --- a/packages/beeq/src/components.d.ts +++ b/packages/beeq/src/components.d.ts @@ -11,8 +11,8 @@ import { TAvatarShape, TAvatarSize } from "./components/avatar/bq-avatar.types"; import { TBadgeSize } from "./components/badge/bq-badge.types"; import { TButtonAppearance, TButtonBorderRadius, TButtonSize, TButtonType, TButtonVariant } from "./components/button/bq-button.types"; import { TCardBorderRadius, TCardType } from "./components/card/bq-card.types"; -import { FloatingUIPlacement } from "./services/interfaces"; import { DaysOfWeek, TDatePickerType } from "./components/date-picker/bq-date-picker.types"; +import { FloatingUIPlacement } from "./services/interfaces"; import { TInputType, TInputValidation, TInputValue } from "./components/input/bq-input.types"; import { TDialogBorderRadius, TDialogFooterAppearance, TDialogSize } from "./components/dialog/bq-dialog.types"; import { TDividerOrientation, TDividerStrokeLinecap, TDividerTitleAlignment } from "./components/divider/bq-divider.types"; @@ -40,8 +40,8 @@ export { TAvatarShape, TAvatarSize } from "./components/avatar/bq-avatar.types"; export { TBadgeSize } from "./components/badge/bq-badge.types"; export { TButtonAppearance, TButtonBorderRadius, TButtonSize, TButtonType, TButtonVariant } from "./components/button/bq-button.types"; export { TCardBorderRadius, TCardType } from "./components/card/bq-card.types"; -export { FloatingUIPlacement } from "./services/interfaces"; export { DaysOfWeek, TDatePickerType } from "./components/date-picker/bq-date-picker.types"; +export { FloatingUIPlacement } from "./services/interfaces"; export { TInputType, TInputValidation, TInputValue } from "./components/input/bq-input.types"; export { TDialogBorderRadius, TDialogFooterAppearance, TDialogSize } from "./components/dialog/bq-dialog.types"; export { TDividerOrientation, TDividerStrokeLinecap, TDividerTitleAlignment } from "./components/divider/bq-divider.types"; 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 4ee0590a4..0bfff4a62 100644 --- a/packages/beeq/src/components/date-picker/bq-date-picker.tsx +++ b/packages/beeq/src/components/date-picker/bq-date-picker.tsx @@ -61,6 +61,11 @@ 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 BUTTON_EXPORT_PARTS = + 'button,day,selected,today,disallowed,outside,range-start,range-end,range-inner'; + // Reference to host HTML element // =================================== @@ -327,39 +332,40 @@ export class BqDatePicker { this.hasSuffix = hasSlotContent(this.suffixElem); }; + private generateCalendarMonth = (offset?: number, className = ''): JSX.Element => { + return ( + + ); + }; + /** - * Generates an array of JSX elements representing calendar months. - * If the 'range' property is true and the 'months' property is defined, - * it generates multiple calendar months with incremental 'offset' values. - * If the 'range' property is false or the 'months' property is undefined, - * it generates a single calendar month without an 'offset'. + * Generates an array of JSX.Element representing calendar months. + * + * If the type of the date picker is 'range' or 'multi' and the number of months is specified, + * it generates an array of calendar months with the specified length. Each month will have an offset + * and a class name based on its position in the array. The offset is used to determine the month to display, + * and the class name is used for responsive design. * - * @returns An array of JSX elements representing calendar months. + * If the type of the date picker is not 'range' or 'multi', or if the number of months is not specified, + * it generates an array with a single calendar month. + * + * @returns {JSX.Element[]} An array of JSX.Element representing calendar months. */ - private generateCalendarMonths(): JSX.Element[] { - const months: JSX.Element[] = []; - - const commonExportParts = 'heading,table,tr,head,week,th,td'; - const buttonExportParts = 'button,day,selected,today,disallowed,outside,range-start,range-end,range-inner'; - + private generateCalendarMonths = (): JSX.Element[] => { if (this.type === 'range' || (this.type === 'multi' && this.months)) { - for (let i = 0; i < this.months; i++) { + return Array.from({ length: this.months }, (_, i) => { const offset = i > 0 ? i : undefined; const className = offset ? 'hidden sm:block' : ''; - months.push( - , - ); - } - } else { - months.push(); + return this.generateCalendarMonth(offset, className); + }); } - return months; - } + return [this.generateCalendarMonth()]; + }; /** * Processes the focused date value to extract the last date portion. From 01ee5111b8d7a7e4dd2768dcd8d37c148b48be60 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dabiel=20Gonz=C3=A1lez=20Ramos?= Date: Fri, 17 May 2024 20:08:42 +0300 Subject: [PATCH 49/75] refactor(Slider): simplify `processFocusedDateValue()` method with early return --- .../components/date-picker/bq-date-picker.tsx | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) 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 0bfff4a62..1c2e16a0b 100644 --- a/packages/beeq/src/components/date-picker/bq-date-picker.tsx +++ b/packages/beeq/src/components/date-picker/bq-date-picker.tsx @@ -368,19 +368,18 @@ export class BqDatePicker { }; /** - * Processes the focused date value to extract the last date portion. + * Extracts and returns the last date part from a given string. + * When the type of the date picker is 'range' or 'multi', the last date part of the value + * should be the focused date in the calendar. * * @param value - The value to be processed, can be a string. * @returns The extracted last date portion of the value. */ - private processFocusedDateValue = (value: string) => { - const dateLength = 10; // Length of a standard date in the format YYYY-MM-DD - - if (value) { - return value.slice(-dateLength); - } + private focusedDate = (value: string) => { + if (!value) return; - return null; + const dateLength = 10; // Length of a standard date in the format YYYY-MM-DD + return value.slice(-dateLength); }; private get CalendarType() { @@ -527,7 +526,7 @@ export class BqDatePicker { min={this.min} max={this.max} months={this.months} - focusedDate={this.processFocusedDateValue(this.value)} + focusedDate={this.focusedDate(this.value)} firstDayOfWeek={this.firstDayOfWeek} showOutsideDays={this.showOutsideDays} onChange={this.handleCalendarChange} From 795fba0c10869a26fec5f9f33cec066ddd770442 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dabiel=20Gonz=C3=A1lez=20Ramos?= Date: Fri, 17 May 2024 20:13:49 +0300 Subject: [PATCH 50/75] style(Slider): move getter `CalendarType()` to be the last method --- .../components/date-picker/bq-date-picker.tsx | 23 +++++++++---------- 1 file changed, 11 insertions(+), 12 deletions(-) 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 1c2e16a0b..7415d834c 100644 --- a/packages/beeq/src/components/date-picker/bq-date-picker.tsx +++ b/packages/beeq/src/components/date-picker/bq-date-picker.tsx @@ -382,18 +382,6 @@ export class BqDatePicker { return value.slice(-dateLength); }; - private get CalendarType() { - // Define a lookup object to map properties to component types - const componentTypes = { - multi: 'calendar-multi', - range: 'calendar-range', - default: 'calendar-date', - } as const; // Make componentTypes a readonly object - - // Return the corresponding component type, or the default type if no truthy property was found - return componentTypes[this.type] || componentTypes.default; - } - private formatDate = (value: string): string | undefined => { if (!value) return; @@ -412,6 +400,17 @@ export class BqDatePicker { return dateFormatter.format(new Date(value)); }; + private get CalendarType() { + const componentTypes = { + single: 'calendar-date', + multi: 'calendar-multi', + range: 'calendar-range', + } as const; + + // Return the corresponding component type, based on the type prop value + return componentTypes[this.type] || componentTypes.single; + } + // render() function // Always the last one in the class. // =================================== From 18b454d7f93daa072405539acd085e1daa15c18c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dabiel=20Gonz=C3=A1lez=20Ramos?= Date: Fri, 17 May 2024 20:16:18 +0300 Subject: [PATCH 51/75] style(Slider): remove empty line between const declaration --- packages/beeq/src/components/date-picker/bq-date-picker.tsx | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) 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 7415d834c..f7aad91d9 100644 --- a/packages/beeq/src/components/date-picker/bq-date-picker.tsx +++ b/packages/beeq/src/components/date-picker/bq-date-picker.tsx @@ -416,9 +416,8 @@ export class BqDatePicker { // =================================== render() { - const labelId = `bq-date-picker__label-${this.name || this.fallbackInputId}`; - const CallyCalendar = this.CalendarType; + const labelId = `bq-date-picker__label-${this.name || this.fallbackInputId}`; return (
From 5fbdc2bb575aa89fa569306138b0d74530c6b47b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dabiel=20Gonz=C3=A1lez=20Ramos?= Date: Fri, 17 May 2024 20:17:34 +0300 Subject: [PATCH 52/75] fix(Slider): keep the calendar open only for `multi` --- packages/beeq/src/components/date-picker/bq-date-picker.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 f7aad91d9..35ba25b4a 100644 --- a/packages/beeq/src/components/date-picker/bq-date-picker.tsx +++ b/packages/beeq/src/components/date-picker/bq-date-picker.tsx @@ -303,7 +303,7 @@ export class BqDatePicker { this.bqChange.emit({ value: this.value, el: this.el }); - this.open = this.type !== 'single'; + this.open = this.type === 'multi'; }; private handleClearClick = (ev: CustomEvent) => { From a992cfaeef8bd575717a19d7b59c15ec75f37429 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dabiel=20Gonz=C3=A1lez=20Ramos?= Date: Fri, 17 May 2024 20:19:59 +0300 Subject: [PATCH 53/75] refactor(Slider): remove bqInput event emitter We don't want to trigger input changes while the date value is invalid --- packages/beeq/src/components.d.ts | 5 ----- .../date-picker/_storybook/bq-date-picker.stories.tsx | 2 -- .../beeq/src/components/date-picker/bq-date-picker.tsx | 7 ------- packages/beeq/src/components/date-picker/readme.md | 1 - 4 files changed, 15 deletions(-) diff --git a/packages/beeq/src/components.d.ts b/packages/beeq/src/components.d.ts index f17c01254..b561b4cc2 100644 --- a/packages/beeq/src/components.d.ts +++ b/packages/beeq/src/components.d.ts @@ -1713,7 +1713,6 @@ declare global { "bqChange": { value: string; el: HTMLBqDatePickerElement }; "bqClear": HTMLBqDatePickerElement; "bqFocus": HTMLBqDatePickerElement; - "bqInput": { value: string; el: HTMLBqDatePickerElement }; } interface HTMLBqDatePickerElement extends Components.BqDatePicker, HTMLStencilElement { addEventListener(type: K, listener: (this: HTMLBqDatePickerElement, ev: BqDatePickerCustomEvent) => any, options?: boolean | AddEventListenerOptions): void; @@ -2638,10 +2637,6 @@ declare namespace LocalJSX { * Callback handler emitted when the input has received focus */ "onBqFocus"?: (event: BqDatePickerCustomEvent) => void; - /** - * Callback handler emitted when the input value changes. This handler is called whenever the user types or pastes text into the input field. - */ - "onBqInput"?: (event: BqDatePickerCustomEvent<{ value: string; el: HTMLBqDatePickerElement }>) => void; /** * If `true`, the Date picker panel will be visible. */ 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 ff5eaf5dd..5b26fd853 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 @@ -60,7 +60,6 @@ const meta: Meta = { bqChange: { action: 'bqChange' }, bqClear: { action: 'bqClear' }, bqFocus: { action: 'bqFocus' }, - bqInput: { action: 'bqInput' }, // Not part of the public API, so we don't want to expose it in the docs noLabel: { control: 'boolean', table: { disable: true } }, prefix: { control: 'boolean', table: { disable: true } }, @@ -167,7 +166,6 @@ const Template = (args: Args) => { @bqChange=${args.bqChange} @bqClear=${args.bqClear} @bqFocus=${args.bqFocus} - @bqInput=${args.bqInput} > ${!args.noLabel ? label : nothing} ${args.prefix ? html`` : nothing} 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 35ba25b4a..2c5d967f4 100644 --- a/packages/beeq/src/components/date-picker/bq-date-picker.tsx +++ b/packages/beeq/src/components/date-picker/bq-date-picker.tsx @@ -216,12 +216,6 @@ export class BqDatePicker { /** Callback handler emitted when the input has received focus */ @Event() bqFocus!: EventEmitter; - /** - * Callback handler emitted when the input value changes. - * This handler is called whenever the user types or pastes text into the input field. - */ - @Event() bqInput!: EventEmitter<{ value: string; el: HTMLBqDatePickerElement }>; - // Component lifecycle events // Ordered by their natural call order // ===================================== @@ -313,7 +307,6 @@ export class BqDatePicker { this.value = this.inputElem.value; this.bqClear.emit(this.el); - this.bqInput.emit({ value: this.value, el: this.el }); this.bqChange.emit({ value: this.value, el: this.el }); this.inputElem.focus(); diff --git a/packages/beeq/src/components/date-picker/readme.md b/packages/beeq/src/components/date-picker/readme.md index 345b2ffde..8ead0d987 100644 --- a/packages/beeq/src/components/date-picker/readme.md +++ b/packages/beeq/src/components/date-picker/readme.md @@ -44,7 +44,6 @@ | `bqChange` | Callback handler emitted when the input value has changed and the input loses focus. This handler is called whenever the user finishes typing or pasting text into the input field and then clicks outside of the input field. | `CustomEvent<{ value: string; el: HTMLBqDatePickerElement; }>` | | `bqClear` | Callback handler emitted when the input value has been cleared | `CustomEvent` | | `bqFocus` | Callback handler emitted when the input has received focus | `CustomEvent` | -| `bqInput` | Callback handler emitted when the input value changes. This handler is called whenever the user types or pastes text into the input field. | `CustomEvent<{ value: string; el: HTMLBqDatePickerElement; }>` | ## Methods From ce9b2a9a6082cc40077e0f68f5eb762b5b330bb7 Mon Sep 17 00:00:00 2001 From: Lungan Catalin Date: Mon, 20 May 2024 11:07:22 +0300 Subject: [PATCH 54/75] feat(Date Picker): add logic for formatted date and input readonly for range and multi picker --- .../components/date-picker/bq-date-picker.tsx | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) 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 2c5d967f4..33080fef0 100644 --- a/packages/beeq/src/components/date-picker/bq-date-picker.tsx +++ b/packages/beeq/src/components/date-picker/bq-date-picker.tsx @@ -75,6 +75,7 @@ export class BqDatePicker { // Inlined decorator, alphabetical order // ======================================= + @State() formattedDate: string; @State() hasLabel = false; @State() hasPrefix = false; @State() hasSuffix = false; @@ -284,16 +285,23 @@ export class BqDatePicker { if (this.disabled) return; if (!isHTMLElement(ev.target, 'input')) return; - this.value = ev.target.value; - this.bqChange.emit({ value: this.value, el: this.el }); + const dateValue = new Date(ev.target.value); + if (!isNaN(dateValue.getTime())) { + this.value = new Intl.DateTimeFormat('fr-CA', { year: 'numeric', month: '2-digit', day: '2-digit' }).format( + dateValue, + ); + this.formattedDate = this.formatDate(this.value); + this.bqChange.emit({ value: this.value, el: this.el }); + } }; private handleCalendarChange = (ev: Event) => { const { value } = ev.target as unknown as { value: string }; this.value = value; - this.inputElem.value = this.value; + this.formattedDate = this.formatDate(this.value); + this.inputElem.value = this.formattedDate; this.bqChange.emit({ value: this.value, el: this.el }); @@ -468,11 +476,12 @@ export class BqDatePicker { form={this.form} name={this.name} placeholder={this.placeholder} + readonly={this.type !== 'single'} ref={(inputElem: HTMLInputElement) => (this.inputElem = inputElem)} required={this.required} spellcheck={false} type="text" - value={this.formatDate(this.value)} + value={this.formattedDate} part="input" // Events onBlur={this.handleBlur} From 1553335d73cd8f8168ca65bbc1d01f1e758128df Mon Sep 17 00:00:00 2001 From: Lungan Catalin Date: Mon, 20 May 2024 11:28:30 +0300 Subject: [PATCH 55/75] feat(Date Picker): add text to mdx file --- .../date-picker/_storybook/bq-date-picker.mdx | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/packages/beeq/src/components/date-picker/_storybook/bq-date-picker.mdx b/packages/beeq/src/components/date-picker/_storybook/bq-date-picker.mdx index f7cd5c1e1..f8da19b87 100644 --- a/packages/beeq/src/components/date-picker/_storybook/bq-date-picker.mdx +++ b/packages/beeq/src/components/date-picker/_storybook/bq-date-picker.mdx @@ -4,10 +4,24 @@ import { ArgTypes, Title, Subtitle } from '@storybook/addon-docs';
Date picker + The Date Picker is a intuitive UI element component allows users to select dates from a visual calendar interface, providing an intuitive way to input date information. + It offers a simple and efficient way to pick dates and/or time by minimizing errors and improving clarity. + Usage + - Use the Date Picker to allow users to select dates for scheduling appointments or events. + - Use the Date Picker to enable users to choose dates for travel bookings or reservations. + - Use the Date Picker to specify due dates or deadlines in project management tools. + - Use the Date Picker to filter records by date range in data analysis or reporting tools. + 👍 When to use + - When you need to collect precise date input, such as for booking systems, event scheduling, or project timelines. + - When providing a calendar view can enhance the user experience and reduce errors in date selection. + - When requiring users to select date ranges for filtering data, such as in reports or search functions. + - When simplifying the process of entering dates, reducing the likelihood of format errors, and improving overall data integrity. + - When offering users a convenient way to pick dates for reminders, deadlines, or other time-sensitive tasks. + Properties From 5c5698fe00d75cee66e7ef9de0d8638d24e784a9 Mon Sep 17 00:00:00 2001 From: Lungan Catalin Date: Mon, 20 May 2024 11:49:06 +0300 Subject: [PATCH 56/75] feat(Date Picker): add additional comment --- packages/beeq/src/components/date-picker/bq-date-picker.tsx | 3 +++ 1 file changed, 3 insertions(+) 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 33080fef0..2d2f3ed09 100644 --- a/packages/beeq/src/components/date-picker/bq-date-picker.tsx +++ b/packages/beeq/src/components/date-picker/bq-date-picker.tsx @@ -288,6 +288,7 @@ export class BqDatePicker { const dateValue = new Date(ev.target.value); if (!isNaN(dateValue.getTime())) { + // We need to force the value to respect the format: yyyy-mm-dd, hence the hardcoded locale this.value = new Intl.DateTimeFormat('fr-CA', { year: 'numeric', month: '2-digit', day: '2-digit' }).format( dateValue, ); @@ -420,6 +421,8 @@ export class BqDatePicker { const CallyCalendar = this.CalendarType; const labelId = `bq-date-picker__label-${this.name || this.fallbackInputId}`; + console.log('this.locale', this.locale); + return (
{/* Label */} From 296a63249af4e3dcb3c9c0b0e485cdf009ff59a1 Mon Sep 17 00:00:00 2001 From: Lungan Catalin Date: Mon, 20 May 2024 13:32:54 +0300 Subject: [PATCH 57/75] feat(Date Picker): fix typo and add more stories for date picker --- .../_storybook/bq-date-picker.stories.tsx | 102 ++++++++++++++++-- .../input/_storybook/bq-input.stories.tsx | 14 +-- 2 files changed, 101 insertions(+), 15 deletions(-) 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 5b26fd853..d46c5a4a9 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 @@ -62,6 +62,7 @@ const meta: Meta = { bqFocus: { action: 'bqFocus' }, // Not part of the public API, so we don't want to expose it in the docs noLabel: { control: 'boolean', table: { disable: true } }, + hasLabelTooltip: { control: 'boolean', table: { disable: true } }, prefix: { control: 'boolean', table: { disable: true } }, suffix: { control: 'boolean', table: { disable: true } }, customDisallowedDate: { control: 'text' }, @@ -104,8 +105,18 @@ export default meta; type Story = StoryObj; const Template = (args: Args) => { + const tooltipTemplate = args.hasLabelTooltip + ? html` + + + You can provide more context detail by adding a tooltip to the label. + + ` + : nothing; const labelTemplate = html` - + `; const label = !args.optionalLabel ? labelTemplate @@ -115,6 +126,15 @@ const Template = (args: Args) => { Optional
`; + const style = args.hasLabelTooltip + ? html` + + ` + : nothing; /** * * Converts a Date object to an ISO 8601 string representation. @@ -135,6 +155,7 @@ const Template = (args: Args) => { }; return html` + ${style}
{ `; }; -export const Default: Story = { +export const InitialValue: Story = { + render: (args) => html` +
+ +
+

Default date picker

+ ${Template({ ...args, name: 'bq-date-picker-default', noLabel: 'true' })} +
+ +
+

Range date picker

+ ${Template({ ...args, name: 'bq-date-picker-range', type: 'range', months: 2, noLabel: 'true' })} +
+ +
+

Multi date picker

+ ${Template({ ...args, name: 'bq-date-picker-multi', type: 'multi', months: 2, noLabel: 'true' })} +
+
+ `, +}; + +export const MixMax: Story = { + name: 'Min and Max allowed dates', + render: Template, + args: { + min: '2024-06-06', + max: '2024-06-16', + }, +}; + +export const Disabled: Story = { + render: Template, + args: { + disabled: true, + }, +}; + +export const ValidationStatus: Story = { + name: 'Validation', + render: (args) => html` +
+ +
+

Error date picker

+ ${Template({ ...args, name: 'bq-date-picker-error', 'validation-status': 'error', noLabel: 'true' })} +
+ +
+

Success date picker

+ ${Template({ ...args, name: 'bq-date-picker-success', 'validation-status': 'success', noLabel: 'true' })} +
+ +
+

Warning date picker

+ ${Template({ ...args, name: 'bq-date-picker-warning', 'validation-status': 'warning', noLabel: 'true' })} +
+
+ `, +}; + +export const Optional: Story = { + name: 'Label with "Optional"', render: Template, + args: { + optionalLabel: true, + }, }; -export const Range: Story = { +export const Tooltip: Story = { + name: 'Label with "Info tooltip"', render: Template, args: { - type: 'range', - months: 2, + hasLabelTooltip: true, }, }; -export const Multi: Story = { +export const NoLabel: Story = { + name: 'With no Label', render: Template, args: { - type: 'multi', - months: 2, + noLabel: true, }, }; diff --git a/packages/beeq/src/components/input/_storybook/bq-input.stories.tsx b/packages/beeq/src/components/input/_storybook/bq-input.stories.tsx index 32abf0f0a..6f74b7f45 100644 --- a/packages/beeq/src/components/input/_storybook/bq-input.stories.tsx +++ b/packages/beeq/src/components/input/_storybook/bq-input.stories.tsx @@ -42,12 +42,12 @@ const meta: Meta = { bqFocus: { action: 'bqFocus' }, bqInput: { action: 'bqInput' }, // Not part of the public API, so we don't want to expose it in the docs - noLabel: { control: 'bolean', table: { disable: true } }, - hasLabelTooltip: { control: 'bolean', table: { disable: true } }, - noHelperText: { control: 'bolean', table: { disable: true } }, - optionalLabel: { control: 'bolean', table: { disable: true } }, - prefix: { control: 'bolean', table: { disable: true } }, - suffix: { control: 'bolean', table: { disable: true } }, + noLabel: { control: 'boolean', table: { disable: true } }, + hasLabelTooltip: { control: 'boolean', table: { disable: true } }, + noHelperText: { control: 'boolean', table: { disable: true } }, + optionalLabel: { control: 'boolean', table: { disable: true } }, + prefix: { control: 'boolean', table: { disable: true } }, + suffix: { control: 'boolean', table: { disable: true } }, }, args: { autocapitalize: 'off', @@ -207,7 +207,7 @@ export const ValidationStatus: Story = {
${Template({ ...args, name: 'bq-input-error', 'validation-status': 'error' })} - + ${Template({ ...args, name: 'bq-input-success', 'validation-status': 'success' })} ${Template({ ...args, name: 'bq-input-warning', 'validation-status': 'warning' })} From f7ea9ad0384d8b7d341661e40ce11d068fe43c39 Mon Sep 17 00:00:00 2001 From: Lungan Catalin Date: Mon, 20 May 2024 13:36:56 +0300 Subject: [PATCH 58/75] feat(Date Picker): refactor formattedDate logic --- packages/beeq/src/components/date-picker/bq-date-picker.tsx | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) 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 2d2f3ed09..d4fb82123 100644 --- a/packages/beeq/src/components/date-picker/bq-date-picker.tsx +++ b/packages/beeq/src/components/date-picker/bq-date-picker.tsx @@ -289,9 +289,7 @@ export class BqDatePicker { const dateValue = new Date(ev.target.value); if (!isNaN(dateValue.getTime())) { // We need to force the value to respect the format: yyyy-mm-dd, hence the hardcoded locale - this.value = new Intl.DateTimeFormat('fr-CA', { year: 'numeric', month: '2-digit', day: '2-digit' }).format( - dateValue, - ); + this.value = dateValue.toLocaleDateString('fr-CA'); this.formattedDate = this.formatDate(this.value); this.bqChange.emit({ value: this.value, el: this.el }); } From c1c5fe1ca0c8490ea73576225d99f892707cc15a Mon Sep 17 00:00:00 2001 From: Lungan Catalin Date: Mon, 20 May 2024 13:48:49 +0300 Subject: [PATCH 59/75] feat(Date Picker): remove forgotten console.log --- packages/beeq/src/components/date-picker/bq-date-picker.tsx | 2 -- 1 file changed, 2 deletions(-) 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 d4fb82123..36b5ad34a 100644 --- a/packages/beeq/src/components/date-picker/bq-date-picker.tsx +++ b/packages/beeq/src/components/date-picker/bq-date-picker.tsx @@ -419,8 +419,6 @@ export class BqDatePicker { const CallyCalendar = this.CalendarType; const labelId = `bq-date-picker__label-${this.name || this.fallbackInputId}`; - console.log('this.locale', this.locale); - return (
{/* Label */} From 7a375331e57f6dd90d47a5d0b0c1ca39b894b913 Mon Sep 17 00:00:00 2001 From: Lungan Catalin Date: Mon, 20 May 2024 14:47:29 +0300 Subject: [PATCH 60/75] feat(Date Picker): add initial value in Storybook --- .../_storybook/bq-date-picker.stories.tsx | 24 +++++++++++++++---- 1 file changed, 19 insertions(+), 5 deletions(-) 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 d46c5a4a9..801d27b5f 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 @@ -202,17 +202,31 @@ export const InitialValue: Story = {

Default date picker

- ${Template({ ...args, name: 'bq-date-picker-default', noLabel: 'true' })} + ${Template({ ...args, value: '2024-05-25', name: 'bq-date-picker-default', noLabel: 'true' })}

Range date picker

- ${Template({ ...args, name: 'bq-date-picker-range', type: 'range', months: 2, noLabel: 'true' })} + ${Template({ + ...args, + value: '2024-06-04/2024-06-15', + name: 'bq-date-picker-range', + type: 'range', + months: 2, + noLabel: 'true', + })}

Multi date picker

- ${Template({ ...args, name: 'bq-date-picker-multi', type: 'multi', months: 2, noLabel: 'true' })} + ${Template({ + ...args, + value: '2024-05-08 2024-05-09 2024-05-10', + name: 'bq-date-picker-multi', + type: 'multi', + months: 2, + noLabel: 'true', + })}
`, @@ -222,8 +236,8 @@ export const MixMax: Story = { name: 'Min and Max allowed dates', render: Template, args: { - min: '2024-06-06', - max: '2024-06-16', + min: '2024-06-05', + max: '2024-06-15', }, }; From 359a8fd07241fd8a15c7cc9a62a55eb078c1f2e9 Mon Sep 17 00:00:00 2001 From: Lungan Catalin Date: Mon, 20 May 2024 15:34:16 +0300 Subject: [PATCH 61/75] feat(Date Picker): enable displaying predefined value --- packages/beeq/src/components/date-picker/bq-date-picker.tsx | 1 + 1 file changed, 1 insertion(+) 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 36b5ad34a..53c3226e3 100644 --- a/packages/beeq/src/components/date-picker/bq-date-picker.tsx +++ b/packages/beeq/src/components/date-picker/bq-date-picker.tsx @@ -190,6 +190,7 @@ export class BqDatePicker { return; } + this.formattedDate = this.formatDate(this.value); this.hasValue = isDefined(this.value); } From 8e08109ec9eddd4180ebc9b9c6a25f2e7ee673b9 Mon Sep 17 00:00:00 2001 From: Lungan Catalin Date: Mon, 20 May 2024 15:42:16 +0300 Subject: [PATCH 62/75] feat(Date Picker): resolve some left comments --- .../_storybook/bq-date-picker.stories.tsx | 14 +++----------- .../src/components/date-picker/bq-date-picker.tsx | 7 ------- 2 files changed, 3 insertions(+), 18 deletions(-) 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 801d27b5f..1147a6ee2 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 @@ -126,16 +126,6 @@ const Template = (args: Args) => { Optional
`; - const style = args.hasLabelTooltip - ? html` - - ` - : nothing; - /** * * Converts a Date object to an ISO 8601 string representation. * This function is used only for demonstration purposes in Storybook. @@ -155,7 +145,6 @@ const Template = (args: Args) => { }; return html` - ${style}
{ - if (this.disabled) return; - - if (!isHTMLElement(ev.target, 'input')) return; - this.value = ev.target.value; - }; - private handleChange = (ev: Event) => { if (this.disabled) return; From 0fed282b16015dd564a48431a179546159fff42b Mon Sep 17 00:00:00 2001 From: Lungan Catalin Date: Mon, 20 May 2024 15:46:20 +0300 Subject: [PATCH 63/75] feat(Date Picker): remove forgotten onInput --- packages/beeq/src/components/date-picker/bq-date-picker.tsx | 1 - 1 file changed, 1 deletion(-) 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 4cae7b5bc..d5715482f 100644 --- a/packages/beeq/src/components/date-picker/bq-date-picker.tsx +++ b/packages/beeq/src/components/date-picker/bq-date-picker.tsx @@ -479,7 +479,6 @@ export class BqDatePicker { // Events onBlur={this.handleBlur} onFocus={this.handleFocus} - onInput={this.handleInput} onChange={this.handleChange} /> {/* Clear Button */} From 0a295e3c4f757839ae6d861b693f8afeb6511b6f Mon Sep 17 00:00:00 2001 From: Lungan Catalin Date: Mon, 20 May 2024 16:03:19 +0300 Subject: [PATCH 64/75] feat(Date Picker): add more stories to Storybook --- .../_storybook/bq-date-picker.stories.tsx | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) 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 1147a6ee2..80359df2c 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 @@ -185,6 +185,26 @@ const Template = (args: Args) => { `; }; +export const Default: Story = { + render: Template, +}; + +export const Range: Story = { + render: Template, + args: { + type: 'range', + months: 2, + }, +}; + +export const Multi: Story = { + render: Template, + args: { + type: 'multi', + months: 2, + }, +}; + export const InitialValue: Story = { render: (args) => html`
@@ -234,6 +254,7 @@ export const Disabled: Story = { render: Template, args: { disabled: true, + value: '2024-06-20', }, }; From 07672078ca45eecdf9e4ef00855121cb4245af46 Mon Sep 17 00:00:00 2001 From: Lungan Catalin Date: Mon, 20 May 2024 16:58:32 +0300 Subject: [PATCH 65/75] feat(Date Picker): resolve left comments --- .../_storybook/bq-date-picker.stories.tsx | 126 +++++++++++------- .../components/date-picker/bq-date-picker.tsx | 2 +- .../beeq/src/components/date-picker/readme.md | 2 +- 3 files changed, 83 insertions(+), 47 deletions(-) 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 80359df2c..5892f1ced 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 @@ -82,7 +82,7 @@ const meta: Meta = { name: 'bq-date-picker', open: false, 'panel-height': 'auto', - placement: 'bottom-start', + placement: 'bottom-end', placeholder: 'Enter your date', skidding: 0, strategy: 'absolute', @@ -144,49 +144,61 @@ const Template = (args: Args) => { return args.customDisallowedDate.split(',').some((date: string) => date.trim() === dateString); }; + const style = args.hasLabelTooltip + ? html` + + ` + : nothing; + return html` -
- - ${!args.noLabel ? label : nothing} - ${args.prefix ? html`` : nothing} - ${args.suffix ? html`` : nothing} - -
+ ${style} + + ${!args.noLabel ? label : nothing} + ${args.prefix ? html`` : nothing} + ${args.suffix ? html`` : nothing} + `; }; export const Default: Story = { render: Template, + args: { + value: '2024-07-08', + }, }; export const Range: Story = { @@ -194,6 +206,7 @@ export const Range: Story = { args: { type: 'range', months: 2, + value: '2024-12-20/2025-01-10', }, }; @@ -202,12 +215,13 @@ export const Multi: Story = { args: { type: 'multi', months: 2, + value: '2024-05-08 2024-05-22 2024-06-04 2024-06-18 2024-05-16 2024-05-30 2024-06-12 2024-06-26', }, }; export const InitialValue: Story = { render: (args) => html` -
+

Default date picker

@@ -218,7 +232,7 @@ export const InitialValue: Story = {

Range date picker

${Template({ ...args, - value: '2024-06-04/2024-06-15', + value: '2024-12-20/2025-01-10', name: 'bq-date-picker-range', type: 'range', months: 2, @@ -230,7 +244,7 @@ export const InitialValue: Story = {

Multi date picker

${Template({ ...args, - value: '2024-05-08 2024-05-09 2024-05-10', + value: '2024-05-08 2024-05-22 2024-06-04 2024-06-18 2024-05-16 2024-05-30 2024-06-12 2024-06-26', name: 'bq-date-picker-multi', type: 'multi', months: 2, @@ -247,6 +261,7 @@ export const MixMax: Story = { args: { min: '2024-06-05', max: '2024-06-15', + value: '2024-06-10', }, }; @@ -261,21 +276,39 @@ export const Disabled: Story = { export const ValidationStatus: Story = { name: 'Validation', render: (args) => html` -
+

Error date picker

- ${Template({ ...args, name: 'bq-date-picker-error', 'validation-status': 'error', noLabel: 'true' })} + ${Template({ + ...args, + value: '2024-05-25', + name: 'bq-date-picker-error', + 'validation-status': 'error', + noLabel: 'true', + })}

Success date picker

- ${Template({ ...args, name: 'bq-date-picker-success', 'validation-status': 'success', noLabel: 'true' })} + ${Template({ + ...args, + value: '2024-06-25', + name: 'bq-date-picker-success', + 'validation-status': 'success', + noLabel: 'true', + })}

Warning date picker

- ${Template({ ...args, name: 'bq-date-picker-warning', 'validation-status': 'warning', noLabel: 'true' })} + ${Template({ + ...args, + value: '2024-07-25', + name: 'bq-date-picker-warning', + 'validation-status': 'warning', + noLabel: 'true', + })}
`, @@ -286,6 +319,7 @@ export const Optional: Story = { render: Template, args: { optionalLabel: true, + value: '2024-10-10', }, }; @@ -294,6 +328,7 @@ export const Tooltip: Story = { render: Template, args: { hasLabelTooltip: true, + value: '2024-09-11', }, parameters: { layout: 'centered', @@ -305,5 +340,6 @@ export const NoLabel: Story = { render: Template, args: { noLabel: true, + value: '2024-10-13', }, }; 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 d5715482f..3f002487a 100644 --- a/packages/beeq/src/components/date-picker/bq-date-picker.tsx +++ b/packages/beeq/src/components/date-picker/bq-date-picker.tsx @@ -147,7 +147,7 @@ export class BqDatePicker { @Prop({ reflect: true }) placeholder?: string; /** Position of the Date picker panel */ - @Prop({ reflect: true }) placement?: FloatingUIPlacement = 'bottom-start'; + @Prop({ reflect: true }) placement?: FloatingUIPlacement = 'bottom-end'; /** Indicates whether or not the Date picker input is required to be filled out before submitting the form. */ @Prop({ reflect: true }) required?: boolean; diff --git a/packages/beeq/src/components/date-picker/readme.md b/packages/beeq/src/components/date-picker/readme.md index 8ead0d987..88c096ec9 100644 --- a/packages/beeq/src/components/date-picker/readme.md +++ b/packages/beeq/src/components/date-picker/readme.md @@ -26,7 +26,7 @@ | `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-start'` | +| `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` | From fc1f6e4b5fabc3a9b2cb3a6ad51ac09733729538 Mon Sep 17 00:00:00 2001 From: Lungan Catalin Date: Mon, 20 May 2024 18:48:00 +0300 Subject: [PATCH 66/75] feat(Date Picker): refactor style for date picker --- .../date-picker/_storybook/bq-date-picker.stories.tsx | 8 ++------ .../beeq/src/components/date-picker/bq-date-picker.tsx | 2 +- .../src/components/date-picker/scss/bq-date-picker.scss | 6 +++--- 3 files changed, 6 insertions(+), 10 deletions(-) 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 5892f1ced..47bb67a81 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 @@ -147,7 +147,8 @@ const Template = (args: Args) => { const style = args.hasLabelTooltip ? html` @@ -196,9 +197,6 @@ const Template = (args: Args) => { export const Default: Story = { render: Template, - args: { - value: '2024-07-08', - }, }; export const Range: Story = { @@ -206,7 +204,6 @@ export const Range: Story = { args: { type: 'range', months: 2, - value: '2024-12-20/2025-01-10', }, }; @@ -215,7 +212,6 @@ export const Multi: Story = { args: { type: 'multi', months: 2, - value: '2024-05-08 2024-05-22 2024-06-04 2024-06-18 2024-05-16 2024-05-30 2024-06-12 2024-06-26', }, }; 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 3f002487a..500df9cd7 100644 --- a/packages/beeq/src/components/date-picker/bq-date-picker.tsx +++ b/packages/beeq/src/components/date-picker/bq-date-picker.tsx @@ -427,7 +427,7 @@ export class BqDatePicker { {/* Select date picker dropdown */} Date: Mon, 20 May 2024 19:02:07 +0300 Subject: [PATCH 67/75] feat(Date Picker): refactor formatDate with regex --- packages/beeq/src/components/date-picker/bq-date-picker.tsx | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) 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 500df9cd7..2f5806178 100644 --- a/packages/beeq/src/components/date-picker/bq-date-picker.tsx +++ b/packages/beeq/src/components/date-picker/bq-date-picker.tsx @@ -372,8 +372,9 @@ export class BqDatePicker { private focusedDate = (value: string) => { if (!value) return; - const dateLength = 10; // Length of a standard date in the format YYYY-MM-DD - return value.slice(-dateLength); + const dateRegex = /\b\d{4}-\d{2}-\d{2}\b/; + const match = dateRegex.exec(value); + return match ? match[0] : null; }; private formatDate = (value: string): string | undefined => { From c8c21f08d041a4e8a1cb35571084bd062bdbe4e6 Mon Sep 17 00:00:00 2001 From: Lungan Catalin Date: Mon, 20 May 2024 19:24:26 +0300 Subject: [PATCH 68/75] feat(Date Picker): add monthsPerView prop --- packages/beeq/src/components.d.ts | 8 ++++++++ .../date-picker/_storybook/bq-date-picker.stories.tsx | 3 +++ .../beeq/src/components/date-picker/bq-date-picker.tsx | 7 ++++++- packages/beeq/src/components/date-picker/readme.md | 1 + 4 files changed, 18 insertions(+), 1 deletion(-) diff --git a/packages/beeq/src/components.d.ts b/packages/beeq/src/components.d.ts index b561b4cc2..21f4aa26f 100644 --- a/packages/beeq/src/components.d.ts +++ b/packages/beeq/src/components.d.ts @@ -382,6 +382,10 @@ export namespace Components { * Number of months to show when range is `true` */ "months": number; + /** + * The number of months to display per page when using next/previous buttons. + */ + "monthsPerView": number; /** * The Date picker input name. */ @@ -2617,6 +2621,10 @@ declare namespace LocalJSX { * Number of months to show when range is `true` */ "months"?: number; + /** + * The number of months to display per page when using next/previous buttons. + */ + "monthsPerView"?: number; /** * The Date picker input name. */ 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 47bb67a81..8c04c53ba 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 @@ -53,6 +53,7 @@ const meta: Meta = { 'validation-status': { control: 'select', options: [...INPUT_VALIDATION] }, type: { control: 'select', options: [...DATE_PICKER_TYPE] }, months: { control: 'number' }, + monthsPerView: { control: 'number' }, value: { control: 'text' }, 'format-options': { control: 'object' }, // Events @@ -90,6 +91,7 @@ const meta: Meta = { 'validation-status': 'none', type: 'single', months: 1, + monthsPerView: 1, value: undefined, 'format-options': { day: 'numeric', @@ -180,6 +182,7 @@ const Template = (args: Args) => { validation-status=${args['validation-status']} type=${args.type} months=${args.months} + .monthsPerView=${args.monthsPerView} value=${ifDefined(args.value)} .format-options=${args['format-options']} .isDateDisallowed=${isDate} 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 2f5806178..1cdb3069f 100644 --- a/packages/beeq/src/components/date-picker/bq-date-picker.tsx +++ b/packages/beeq/src/components/date-picker/bq-date-picker.tsx @@ -134,6 +134,9 @@ 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; + /** The Date picker input name. */ @Prop({ reflect: true }) name!: string; @@ -414,6 +417,8 @@ export class BqDatePicker { const CallyCalendar = this.CalendarType; const labelId = `bq-date-picker__label-${this.name || this.fallbackInputId}`; + console.log('monthsPerView', this.monthsPerView); + console.log('months', this.months); return (
{/* Label */} @@ -518,7 +523,7 @@ export class BqDatePicker { value={this.value} min={this.min} max={this.max} - months={this.months} + months={this.monthsPerView} focusedDate={this.focusedDate(this.value)} firstDayOfWeek={this.firstDayOfWeek} showOutsideDays={this.showOutsideDays} diff --git a/packages/beeq/src/components/date-picker/readme.md b/packages/beeq/src/components/date-picker/readme.md index 88c096ec9..cdee3559b 100644 --- a/packages/beeq/src/components/date-picker/readme.md +++ b/packages/beeq/src/components/date-picker/readme.md @@ -22,6 +22,7 @@ | `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'` | From 1e245e4e3a484fdcea17523fdfb1a7158727df09 Mon Sep 17 00:00:00 2001 From: Lungan Catalin Date: Mon, 20 May 2024 19:26:00 +0300 Subject: [PATCH 69/75] feat(Date Picker): clean code --- packages/beeq/src/components/date-picker/bq-date-picker.tsx | 2 -- 1 file changed, 2 deletions(-) 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 1cdb3069f..ef3228bca 100644 --- a/packages/beeq/src/components/date-picker/bq-date-picker.tsx +++ b/packages/beeq/src/components/date-picker/bq-date-picker.tsx @@ -417,8 +417,6 @@ export class BqDatePicker { const CallyCalendar = this.CalendarType; const labelId = `bq-date-picker__label-${this.name || this.fallbackInputId}`; - console.log('monthsPerView', this.monthsPerView); - console.log('months', this.months); return (
{/* Label */} From 323da044ced0451835ed5dd79e74345444ad041f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dabiel=20Gonz=C3=A1lez=20Ramos?= Date: Mon, 20 May 2024 21:13:27 +0300 Subject: [PATCH 70/75] docs: fix JSDoc after `focusedDate` method changes --- packages/beeq/src/components/date-picker/bq-date-picker.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) 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 ef3228bca..52b8b385c 100644 --- a/packages/beeq/src/components/date-picker/bq-date-picker.tsx +++ b/packages/beeq/src/components/date-picker/bq-date-picker.tsx @@ -365,8 +365,8 @@ export class BqDatePicker { }; /** - * Extracts and returns the last date part from a given string. - * When the type of the date picker is 'range' or 'multi', the last date part of the value + * Extracts and returns the first date part from a given string. + * When the type of the date picker is 'range' or 'multi', the first or initial date part of the value * should be the focused date in the calendar. * * @param value - The value to be processed, can be a string. From 0240585e5a07c8617b5bffd67112cc87941a7d41 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dabiel=20Gonz=C3=A1lez=20Ramos?= Date: Mon, 20 May 2024 21:16:43 +0300 Subject: [PATCH 71/75] refactor: improve calendar day button styles, use `--bq-focus` instead --- .../date-picker/scss/bq-date-picker.scss | 24 +++++-------------- 1 file changed, 6 insertions(+), 18 deletions(-) diff --git a/packages/beeq/src/components/date-picker/scss/bq-date-picker.scss b/packages/beeq/src/components/date-picker/scss/bq-date-picker.scss index a7479a4ea..82a3906cd 100644 --- a/packages/beeq/src/components/date-picker/scss/bq-date-picker.scss +++ b/packages/beeq/src/components/date-picker/scss/bq-date-picker.scss @@ -38,9 +38,8 @@ &:not(.disabled):focus-within { --bq-ring-width: 1px; --bq-ring-offset-width: 0; - --bq-ring-color-focus: var(--bq-date-picker--border-color-focus); - @apply focus border-[color:--bq-date-picker--border-color-focus]; + @apply focus border-[color:--bq-focus]; } // Enable clear button whenever the input group control is hovered or has focus @@ -156,14 +155,8 @@ calendar-multi { } &::part(button) { - @apply border-0 p-[--bq-spacing-xs]; - - background-color: theme('colors.transparent'); - } - - &::part(button):focus-visible { - @apply rounded-s bg-[--bq-date-picker--background-color] text-[color:--bq-date-picker--border-color-focus]; - @apply focus border-[color:--bq-date-picker--border-color-focus]; + @apply rounded-s border-0 bg-transparent p-[--bq-spacing-xs]; + @apply focus-visible:focus focus-visible:border-[color:--bq-focus]; } &::part(container) { @@ -175,15 +168,10 @@ calendar-month { /* stylelint-disable-next-line custom-property-pattern */ --color-accent: var(--bq-stroke--brand); - &::part(button):focus-visible { - @apply rounded-s bg-[--bq-date-picker--background-color] text-[color:--bq-date-picker--border-color-focus]; - @apply focus border-[color:--bq-date-picker--border-color-focus]; - } - &::part(button) { - @apply h-8 w-8 rounded-[--bq-radius--s] p-1 text-[--bq-text--primary]; - - font-family: var(--bq-font-family); + @apply h-8 w-8 rounded-[--bq-radius--s] bg-transparent p-xs2 font-default text-[--bq-text--primary] transition-colors duration-200 ease-in-out; + @apply hover:bg-hover-bg-secondary; + @apply focus-visible:focus focus-visible:border-[color:--bq-focus]; } &::part(button day selected) { From edd68b266a5924806075176f95d464cba67a8acc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dabiel=20Gonz=C3=A1lez=20Ramos?= Date: Mon, 20 May 2024 21:19:51 +0300 Subject: [PATCH 72/75] refactor: remove useless CSS variable --- .../components/date-picker/scss/bq-date-picker.variables.scss | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/beeq/src/components/date-picker/scss/bq-date-picker.variables.scss b/packages/beeq/src/components/date-picker/scss/bq-date-picker.variables.scss index c8d1f9f0f..42d4afa65 100644 --- a/packages/beeq/src/components/date-picker/scss/bq-date-picker.variables.scss +++ b/packages/beeq/src/components/date-picker/scss/bq-date-picker.variables.scss @@ -30,7 +30,6 @@ --bq-date-picker--background-color: theme('colors.ui.primary'); --bq-date-picker--border-color: theme('colors.stroke.tertiary'); - --bq-date-picker--border-color-focus: theme('colors.stroke.brand'); --bq-date-picker--border-radius: theme('borderRadius.s'); --bq-date-picker--border-width: 1px; --bq-date-picker--currentDate-border-width: 2px; From 673dcb5f9ff820240ac1d84d7032799148ca1aed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dabiel=20Gonz=C3=A1lez=20Ramos?= Date: Tue, 21 May 2024 14:25:07 +0300 Subject: [PATCH 73/75] fix: focus the input element after user selection --- packages/beeq/src/components/date-picker/bq-date-picker.tsx | 1 + 1 file changed, 1 insertion(+) 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 52b8b385c..8af188512 100644 --- a/packages/beeq/src/components/date-picker/bq-date-picker.tsx +++ b/packages/beeq/src/components/date-picker/bq-date-picker.tsx @@ -298,6 +298,7 @@ export class BqDatePicker { this.value = value; this.formattedDate = this.formatDate(this.value); this.inputElem.value = this.formattedDate; + this.inputElem.focus(); this.bqChange.emit({ value: this.value, el: this.el }); From 9402aadaecd592a5847f212128140fba76520668 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dabiel=20Gonz=C3=A1lez=20Ramos?= Date: Tue, 21 May 2024 14:26:33 +0300 Subject: [PATCH 74/75] refactor: more tweaks and style polish --- .../date-picker/scss/bq-date-picker.scss | 42 ++++++++----------- .../scss/bq-date-picker.variables.scss | 1 + 2 files changed, 19 insertions(+), 24 deletions(-) diff --git a/packages/beeq/src/components/date-picker/scss/bq-date-picker.scss b/packages/beeq/src/components/date-picker/scss/bq-date-picker.scss index 82a3906cd..bab9e53d1 100644 --- a/packages/beeq/src/components/date-picker/scss/bq-date-picker.scss +++ b/packages/beeq/src/components/date-picker/scss/bq-date-picker.scss @@ -94,9 +94,6 @@ .bq-date-picker__control--input { @apply flex-auto cursor-[inherit] select-none appearance-none bg-[inherit] font-[inherit] text-[length:inherit] text-[color:inherit]; @apply m-0 min-h-[--bq-date-picker--icon-size] min-w-[0] border-none p-0 focus:outline-none focus-visible:outline-none; - - box-shadow: none; - font-weight: inherit; } /* -------------------------------------------------------------------------- */ @@ -119,7 +116,7 @@ .bq-date-picker__control--prefix, .bq-date-picker__control--suffix { - @apply pointer-events-none flex items-center text-[color:var(--bq-date-picker--text-color)]; + @apply pointer-events-none flex items-center text-[color:--bq-date-picker--text-color]; } .bq-date-picker__control--prefix { @@ -147,16 +144,16 @@ calendar-date, calendar-range, calendar-multi { &::part(header) { - @apply justify-center gap-[--bq-spacing-xs]; + @apply justify-center gap-s; } &::part(heading) { - @apply px-[--bq-spacing-xs] py-[--bq-spacing-xs2]; + @apply px-xs py-xs2; } &::part(button) { - @apply rounded-s border-0 bg-transparent p-[--bq-spacing-xs]; - @apply focus-visible:focus focus-visible:border-[color:--bq-focus]; + @apply rounded-s border-0 bg-transparent p-xs2 transition-colors duration-200; + @apply focus-visible:focus hover:bg-hover-ui-primary; } &::part(container) { @@ -166,12 +163,11 @@ calendar-multi { calendar-month { /* stylelint-disable-next-line custom-property-pattern */ - --color-accent: var(--bq-stroke--brand); + --color-accent: var(--bq-ui--brand); &::part(button) { - @apply h-8 w-8 rounded-[--bq-radius--s] bg-transparent p-xs2 font-default text-[--bq-text--primary] transition-colors duration-200 ease-in-out; - @apply hover:bg-hover-bg-secondary; - @apply focus-visible:focus focus-visible:border-[color:--bq-focus]; + @apply flex items-center justify-center rounded-s bg-transparent p-0 font-default text-text-primary transition-colors duration-200 ease-in-out; + @apply size-[--bq-date-picker--day-size] focus-visible:focus hover:bg-hover-bg-secondary; } &::part(button day selected) { @@ -183,7 +179,7 @@ calendar-month { } &::part(selected) { - @apply rounded-[--bq-radius--s] text-[color:var(--bq-text--alt)]; + @apply rounded-s text-[color:var(--bq-text--alt)]; } &::part(range-inner) { @@ -191,7 +187,7 @@ calendar-month { } &::part(today) { - @apply rounded-[--bq-radius--s] border-[length:--bq-date-picker--currentDate-border-width] border-[color:--bq-date-picker--currentDate-border-color] text-[color:--bq-date-picker--currentDate-text-color]; + @apply rounded-s border-[length:--bq-date-picker--currentDate-border-width] border-[color:--bq-date-picker--currentDate-border-color] text-[color:--bq-date-picker--currentDate-text-color]; border-style: var(--bq-date-picker--border-style); } @@ -205,24 +201,22 @@ calendar-month { } &::part(today range-start) { - @apply rounded-[--bq-radius--s]; - - border-end-start-radius: 0; + @apply rounded-s rounded-es-none; } &::part(today range-end) { - @apply rounded-[--bq-radius--s]; - - border-end-end-radius: 0; + @apply rounded-s rounded-ee-none; } &::part(range-start) { - border-start-end-radius: 0; - border-end-end-radius: 0; + @apply rounded-ee-none rounded-se-none; } &::part(range-end) { - border-start-start-radius: 0; - border-end-start-radius: 0; + @apply rounded-es-none rounded-ss-none; + } + + &::part(range-start range-end) { + @apply rounded-s; } } diff --git a/packages/beeq/src/components/date-picker/scss/bq-date-picker.variables.scss b/packages/beeq/src/components/date-picker/scss/bq-date-picker.variables.scss index 42d4afa65..443c5de44 100644 --- a/packages/beeq/src/components/date-picker/scss/bq-date-picker.variables.scss +++ b/packages/beeq/src/components/date-picker/scss/bq-date-picker.variables.scss @@ -48,6 +48,7 @@ --bq-date-picker--padding-end: theme('spacing.m'); --bq-date-picker--paddingY: theme('spacing.s'); + --bq-date-picker--day-size: theme(spacing.xl); --bq-date-picker--text-color: theme('colors.text.primary'); --bq-date-picker--text-size: theme('fontSize.m'); --bq-date-picker--text-placeholder-color: theme('colors.text.secondary'); From b0aa37af2b72f816a13822a45ab281de08262b32 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dabiel=20Gonz=C3=A1lez=20Ramos?= Date: Tue, 21 May 2024 16:33:34 +0300 Subject: [PATCH 75/75] style: remove quotes from variables.scss file --- .../scss/bq-date-picker.variables.scss | 33 ++++++++++--------- 1 file changed, 17 insertions(+), 16 deletions(-) diff --git a/packages/beeq/src/components/date-picker/scss/bq-date-picker.variables.scss b/packages/beeq/src/components/date-picker/scss/bq-date-picker.variables.scss index 443c5de44..beca8dae5 100644 --- a/packages/beeq/src/components/date-picker/scss/bq-date-picker.variables.scss +++ b/packages/beeq/src/components/date-picker/scss/bq-date-picker.variables.scss @@ -21,37 +21,38 @@ * @prop --bq-date-picker--padding-start - Date picker padding start * @prop --bq-date-picker--padding-end - Date picker padding end * @prop --bq-date-picker--paddingY - Date picker padding top and bottom + * @prop --bq-date-picker--day-size - Date picker button day size * @prop --bq-date-picker--text-color - Date picker text color * @prop --bq-date-picker--text-size - Date picker text size * @prop --bq-date-picker--text-placeholder-color - Date picker placeholder text color * @prop --bq-date-picker--range-background-color - Background color for the selected date range in the date picker * @prop --bq-date-picker--currentDate-border-color - Date picker border color for current date */ - --bq-date-picker--background-color: theme('colors.ui.primary'); + --bq-date-picker--background-color: theme(colors.ui.primary); - --bq-date-picker--border-color: theme('colors.stroke.tertiary'); - --bq-date-picker--border-radius: theme('borderRadius.s'); + --bq-date-picker--border-color: theme(colors.stroke.tertiary); + --bq-date-picker--border-radius: theme(borderRadius.s); --bq-date-picker--border-width: 1px; --bq-date-picker--currentDate-border-width: 2px; --bq-date-picker--border-style: solid; - --bq-date-picker--gap: theme('spacing.xs'); + --bq-date-picker--gap: theme(spacing.xs); --bq-date-picker--icon-size: 24px; - --bq-date-picker--label-margin-bottom: theme('spacing.xs'); - --bq-date-picker--label-text-size: theme('fontSize.s'); - --bq-date-picker--label-text-color: theme('colors.text.primary'); - --bq-date-picker--currentDate-text-color: theme('colors.text.brand'); + --bq-date-picker--label-margin-bottom: theme(spacing.xs); + --bq-date-picker--label-text-size: theme(fontSize.s); + --bq-date-picker--label-text-color: theme(colors.text.primary); + --bq-date-picker--currentDate-text-color: theme(colors.text.brand); - --bq-date-picker--padding-start: theme('spacing.m'); - --bq-date-picker--padding-end: theme('spacing.m'); - --bq-date-picker--paddingY: theme('spacing.s'); + --bq-date-picker--padding-start: theme(spacing.m); + --bq-date-picker--padding-end: theme(spacing.m); + --bq-date-picker--paddingY: theme(spacing.s); --bq-date-picker--day-size: theme(spacing.xl); - --bq-date-picker--text-color: theme('colors.text.primary'); - --bq-date-picker--text-size: theme('fontSize.m'); - --bq-date-picker--text-placeholder-color: theme('colors.text.secondary'); - --bq-date-picker--range-background-color: theme('colors.ui.brand'); - --bq-date-picker--currentDate-border-color: theme('colors.stroke.brand'); + --bq-date-picker--text-color: theme(colors.text.primary); + --bq-date-picker--text-size: theme(fontSize.m); + --bq-date-picker--text-placeholder-color: theme(colors.text.secondary); + --bq-date-picker--range-background-color: theme(colors.ui.brand); + --bq-date-picker--currentDate-border-color: theme(colors.stroke.brand); }