From b7f70fcf8a47b7b3759b7361af91f961e8bb7a86 Mon Sep 17 00:00:00 2001 From: Cory LaViska Date: Wed, 25 Nov 2020 16:18:07 -0500 Subject: [PATCH] Add sl-format-date component --- docs/_sidebar.md | 1 + docs/components/format-date.md | 64 +++++++++++ src/components.d.ts | 121 +++++++++++++++++++++ src/components/format-date/format-date.tsx | 75 +++++++++++++ 4 files changed, 261 insertions(+) create mode 100644 docs/components/format-date.md create mode 100644 src/components/format-date/format-date.tsx diff --git a/docs/_sidebar.md b/docs/_sidebar.md index 7f71c10e..568902b8 100644 --- a/docs/_sidebar.md +++ b/docs/_sidebar.md @@ -50,6 +50,7 @@ - Utility Components - [Animation](/components/animation.md) - [Format Bytes](/components/format-bytes.md) + - [Format Date](/components/format-date.md) - [Format Number](/components/format-number.md) - [Include](/components/include.md) - [Relative Time](/components/relative-time.md) diff --git a/docs/components/format-date.md b/docs/components/format-date.md new file mode 100644 index 00000000..39cf5f90 --- /dev/null +++ b/docs/components/format-date.md @@ -0,0 +1,64 @@ +# Format Date + +[component-header:sl-format-date] + +Formats a date/time using the specified locale and options. + +Localization is handled by the browser's [`Intl.DateTimeFormat` API](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/DateTimeFormat). No language packs are required. + +```html preview + + +``` + +The `date` prop determines the date/time to use when formatting. It must be a string that [`Date.parse()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/parse) can interpret or a [`Date`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date) object set via JavaScript. If omitted, the current date/time will be assumed. + +?> When using strings, avoid ambiguous dates such as `03/04/2020` which can be interpreted as March 4 or April 3 depending on the user's browser and locale. Instead, always use a valid [ISO 8601 date time string](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/parse#Date_Time_String_Format) to ensure the date will be parsed properly by all clients. + + +## Examples + +### Date & Time Formatting + +Formatting options are based on those found in the [`Intl.DateTimeFormat` API](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/DateTimeFormat). When formatting options are provided, the date/time will be formatted according to those values. When no formatting options are provided, a localized, numeric date will be displayed instead. + +```html preview + +
+ + +
+ + +
+ + +
+ + +
+ + + +``` + +### Hour Formatting + +By default, the browser will determine whether to use 12-hour or 24-hour time. To force one or the other, set the `hourFormat` prop to `12` or `24`. + +```html preview +
+ +``` + +### Localization + +Use the `locale` attribute to set the date/time formatting locale. + +```html preview +English:
+French:
+Russian:
+``` + +[component-metadata:sl-format-date] diff --git a/src/components.d.ts b/src/components.d.ts index 63ee7713..9ea5473f 100644 --- a/src/components.d.ts +++ b/src/components.d.ts @@ -468,6 +468,60 @@ export namespace Components { */ "value": number; } + interface SlFormatDate { + /** + * The date/time to format. If not set, the current date and time will be used. + */ + "date": Date | string; + /** + * The format for displaying the day. + */ + "day": 'numeric' | '2-digit'; + /** + * The format for displaying the era. + */ + "era": 'narrow' | 'short' | 'long'; + /** + * The format for displaying the hour. + */ + "hour": 'numeric' | '2-digit'; + /** + * When set, 24 hour time will always be used. + */ + "hourFormat": 'auto' | '12' | '24'; + /** + * The locale to use when formatting the date/time. + */ + "locale": string; + /** + * The format for displaying the minute. + */ + "minute": 'numeric' | '2-digit'; + /** + * The format for displaying the month. + */ + "month": 'numeric' | '2-digit' | 'narrow' | 'short' | 'long'; + /** + * The format for displaying the second. + */ + "second": 'numeric' | '2-digit'; + /** + * The time zone to express the time in. + */ + "timeZone": string; + /** + * The format for displaying the time. + */ + "timeZoneName": 'short' | 'long'; + /** + * The format for displaying the weekday. + */ + "weekday": 'narrow' | 'short' | 'long'; + /** + * The format for displaying the year. + */ + "year": 'numeric' | '2-digit'; + } interface SlFormatNumber { /** * The currency to use when formatting. Must be an ISO 4217 currency code such as `USD` or `EUR`. @@ -1360,6 +1414,12 @@ declare global { prototype: HTMLSlFormatBytesElement; new (): HTMLSlFormatBytesElement; }; + interface HTMLSlFormatDateElement extends Components.SlFormatDate, HTMLStencilElement { + } + var HTMLSlFormatDateElement: { + prototype: HTMLSlFormatDateElement; + new (): HTMLSlFormatDateElement; + }; interface HTMLSlFormatNumberElement extends Components.SlFormatNumber, HTMLStencilElement { } var HTMLSlFormatNumberElement: { @@ -1556,6 +1616,7 @@ declare global { "sl-dropdown": HTMLSlDropdownElement; "sl-form": HTMLSlFormElement; "sl-format-bytes": HTMLSlFormatBytesElement; + "sl-format-date": HTMLSlFormatDateElement; "sl-format-number": HTMLSlFormatNumberElement; "sl-icon": HTMLSlIconElement; "sl-icon-button": HTMLSlIconButtonElement; @@ -2082,6 +2143,60 @@ declare namespace LocalJSX { */ "value"?: number; } + interface SlFormatDate { + /** + * The date/time to format. If not set, the current date and time will be used. + */ + "date"?: Date | string; + /** + * The format for displaying the day. + */ + "day"?: 'numeric' | '2-digit'; + /** + * The format for displaying the era. + */ + "era"?: 'narrow' | 'short' | 'long'; + /** + * The format for displaying the hour. + */ + "hour"?: 'numeric' | '2-digit'; + /** + * When set, 24 hour time will always be used. + */ + "hourFormat"?: 'auto' | '12' | '24'; + /** + * The locale to use when formatting the date/time. + */ + "locale"?: string; + /** + * The format for displaying the minute. + */ + "minute"?: 'numeric' | '2-digit'; + /** + * The format for displaying the month. + */ + "month"?: 'numeric' | '2-digit' | 'narrow' | 'short' | 'long'; + /** + * The format for displaying the second. + */ + "second"?: 'numeric' | '2-digit'; + /** + * The time zone to express the time in. + */ + "timeZone"?: string; + /** + * The format for displaying the time. + */ + "timeZoneName"?: 'short' | 'long'; + /** + * The format for displaying the weekday. + */ + "weekday"?: 'narrow' | 'short' | 'long'; + /** + * The format for displaying the year. + */ + "year"?: 'numeric' | '2-digit'; + } interface SlFormatNumber { /** * The currency to use when formatting. Must be an ISO 4217 currency code such as `USD` or `EUR`. @@ -2373,6 +2488,10 @@ declare namespace LocalJSX { interface SlMenuLabel { } interface SlProgressBar { + /** + * When true, percentage is ignored, the label is hidden, and the progress bar is drawn in an indeterminate state. + */ + "indeterminate"?: boolean; /** * The progress bar's percentage, 0 to 100. */ @@ -2897,6 +3016,7 @@ declare namespace LocalJSX { "sl-dropdown": SlDropdown; "sl-form": SlForm; "sl-format-bytes": SlFormatBytes; + "sl-format-date": SlFormatDate; "sl-format-number": SlFormatNumber; "sl-icon": SlIcon; "sl-icon-button": SlIconButton; @@ -2948,6 +3068,7 @@ declare module "@stencil/core" { "sl-dropdown": LocalJSX.SlDropdown & JSXBase.HTMLAttributes; "sl-form": LocalJSX.SlForm & JSXBase.HTMLAttributes; "sl-format-bytes": LocalJSX.SlFormatBytes & JSXBase.HTMLAttributes; + "sl-format-date": LocalJSX.SlFormatDate & JSXBase.HTMLAttributes; "sl-format-number": LocalJSX.SlFormatNumber & JSXBase.HTMLAttributes; "sl-icon": LocalJSX.SlIcon & JSXBase.HTMLAttributes; "sl-icon-button": LocalJSX.SlIconButton & JSXBase.HTMLAttributes; diff --git a/src/components/format-date/format-date.tsx b/src/components/format-date/format-date.tsx new file mode 100644 index 00000000..bfc14897 --- /dev/null +++ b/src/components/format-date/format-date.tsx @@ -0,0 +1,75 @@ +import { Component, Prop } from '@stencil/core'; + +/** + * @since 2.0 + * @status stable + */ + +@Component({ + tag: 'sl-format-date', + shadow: true +}) +export class FormatBytes { + /** The date/time to format. If not set, the current date and time will be used. */ + @Prop() date: Date | string = new Date(); + + /** The locale to use when formatting the date/time. */ + @Prop() locale: string; + + /** The format for displaying the weekday. */ + @Prop() weekday: 'narrow' | 'short' | 'long'; + + /** The format for displaying the era. */ + @Prop() era: 'narrow' | 'short' | 'long'; + + /** The format for displaying the year. */ + @Prop() year: 'numeric' | '2-digit'; + + /** The format for displaying the month. */ + @Prop() month: 'numeric' | '2-digit' | 'narrow' | 'short' | 'long'; + + /** The format for displaying the day. */ + @Prop() day: 'numeric' | '2-digit'; + + /** The format for displaying the hour. */ + @Prop() hour: 'numeric' | '2-digit'; + + /** The format for displaying the minute. */ + @Prop() minute: 'numeric' | '2-digit'; + + /** The format for displaying the second. */ + @Prop() second: 'numeric' | '2-digit'; + + /** The format for displaying the time. */ + @Prop() timeZoneName: 'short' | 'long'; + + /** The time zone to express the time in. */ + @Prop() timeZone: string; + + /** When set, 24 hour time will always be used. */ + @Prop() hourFormat: 'auto' | '12' | '24' = 'auto'; + + render() { + const date = new Date(this.date); + const hour12 = this.hourFormat === 'auto' ? undefined : this.hourFormat === '12'; + + // Check for an invalid date + if (isNaN(date.getMilliseconds())) { + return; + } + + return new Intl.DateTimeFormat(this.locale, { + weekday: this.weekday, + era: this.era, + year: this.year, + month: this.month, + day: this.day, + hour: this.hour, + minute: this.minute, + second: this.second, + timeZoneName: this.timeZoneName, + timeZone: this.timeZone, + hour12: hour12 + }).format(date); + } +}