From 4e2cf2e9de90b67932fc7670fac0307111514e4a Mon Sep 17 00:00:00 2001 From: Cory LaViska Date: Mon, 9 Nov 2020 09:38:30 -0500 Subject: [PATCH] Add format number component --- docs/_sidebar.md | 1 + docs/components/format-number.md | 61 +++++++++++ docs/getting-started/changelog.md | 3 +- src/components.d.ts | 101 ++++++++++++++++++ .../format-number/format-number.tsx | 65 +++++++++++ 5 files changed, 230 insertions(+), 1 deletion(-) create mode 100644 docs/components/format-number.md create mode 100644 src/components/format-number/format-number.tsx diff --git a/docs/_sidebar.md b/docs/_sidebar.md index a4cfb1b1..58d94001 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 Number](/components/format-number.md) - [Include](/components/include.md) - [Resize Observer](/components/resize-observer.md) - [Theme](/components/theme.md) diff --git a/docs/components/format-number.md b/docs/components/format-number.md new file mode 100644 index 00000000..bcfd1899 --- /dev/null +++ b/docs/components/format-number.md @@ -0,0 +1,61 @@ +# Format Number + +[component-header:sl-format-number] + +Formats a number using the specified locale and options. + +Localization is handled by the browser's built-in [Intl: NumberFormat API](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/NumberFormat/NumberFormat). As such, there's no need to load language packs or omit those you don't plan on using. + +```html preview +
+ +

+ +
+ + +``` + +## Examples + +### Percentages + +To get the value as a percent, set the `type` attribute to `percent`. + +```html preview +
+
+
+
+ +``` + +### Localization + +Use the `locale` attribute to set the number formatting locale. + +```html preview +English:
+German:
+Russian:
+``` + +### Currency + +To format a number as a monetary value, set the `type` attribute to `currency` and set the `currency` attribute to the desired ISO 4217 currency code. You should also specify `locale` to ensure the the number is formatted correctly for the target locale. + +```html preview +
+
+
+
+ +``` + +[component-metadata:sl-format-number] diff --git a/docs/getting-started/changelog.md b/docs/getting-started/changelog.md index d16bf759..664cea8c 100644 --- a/docs/getting-started/changelog.md +++ b/docs/getting-started/changelog.md @@ -8,9 +8,10 @@ _During the beta period, these restrictions may be relaxed in the event of a mis ## Next +- Added `sl-format-number` component +- Added `closable` prop to `sl-tab` - Added experimental `sl-resize-observer` utility - Added experimental `sl-theme` utility and updated theming documentation -- Added `closable` prop to `sl-tab` - Fixed a bug where `sl-menu-item` wouldn't render properly in the dark theme - Fixed a bug where `sl-select` would show an autocomplete menu - Improved placeholder contrast in dark theme diff --git a/src/components.d.ts b/src/components.d.ts index db418df2..716a355c 100644 --- a/src/components.d.ts +++ b/src/components.d.ts @@ -468,6 +468,52 @@ export namespace Components { */ "value": number; } + interface SlFormatNumber { + /** + * The currency to use when formatting. Must be an ISO 4217 currency code such as `USD` or `EUR`. + */ + "currency": string; + /** + * How to display the currency. + */ + "currencyDisplay": 'symbol' | 'narrowSymbol' | 'code' | 'name'; + /** + * The locale to use when formatting the number. + */ + "locale": string; + /** + * The maximum number of fraction digits to use. Possible values are 0 - 20. + */ + "maximumFractionDigits": number; + /** + * The maximum number of significant digits to use,. Possible values are 1 - 21. + */ + "maximumSignificantDigits": number; + /** + * The minimum number of fraction digits to use. Possible values are 0 - 20. + */ + "minimumFractionDigits": number; + /** + * The minimum number of integer digits to use. Possible values are 1 - 21. + */ + "minimumIntegerDigits": number; + /** + * The minimum number of significant digits to use. Possible values are 1 - 21. + */ + "minimumSignificantDigits": number; + /** + * Turns off grouping separators. + */ + "noGrouping": boolean; + /** + * The formatting style to use. + */ + "type": 'currency' | 'decimal' | 'percent'; + /** + * The number to format in bytes. + */ + "value": number; + } interface SlIcon { /** * An alternative description to use for accessibility. If omitted, the name or src will be used to generate it. @@ -1292,6 +1338,12 @@ declare global { prototype: HTMLSlFormatBytesElement; new (): HTMLSlFormatBytesElement; }; + interface HTMLSlFormatNumberElement extends Components.SlFormatNumber, HTMLStencilElement { + } + var HTMLSlFormatNumberElement: { + prototype: HTMLSlFormatNumberElement; + new (): HTMLSlFormatNumberElement; + }; interface HTMLSlIconElement extends Components.SlIcon, HTMLStencilElement { } var HTMLSlIconElement: { @@ -1476,6 +1528,7 @@ declare global { "sl-dropdown": HTMLSlDropdownElement; "sl-form": HTMLSlFormElement; "sl-format-bytes": HTMLSlFormatBytesElement; + "sl-format-number": HTMLSlFormatNumberElement; "sl-icon": HTMLSlIconElement; "sl-icon-button": HTMLSlIconButtonElement; "sl-icon-library": HTMLSlIconLibraryElement; @@ -2000,6 +2053,52 @@ declare namespace LocalJSX { */ "value"?: number; } + interface SlFormatNumber { + /** + * The currency to use when formatting. Must be an ISO 4217 currency code such as `USD` or `EUR`. + */ + "currency"?: string; + /** + * How to display the currency. + */ + "currencyDisplay"?: 'symbol' | 'narrowSymbol' | 'code' | 'name'; + /** + * The locale to use when formatting the number. + */ + "locale"?: string; + /** + * The maximum number of fraction digits to use. Possible values are 0 - 20. + */ + "maximumFractionDigits"?: number; + /** + * The maximum number of significant digits to use,. Possible values are 1 - 21. + */ + "maximumSignificantDigits"?: number; + /** + * The minimum number of fraction digits to use. Possible values are 0 - 20. + */ + "minimumFractionDigits"?: number; + /** + * The minimum number of integer digits to use. Possible values are 1 - 21. + */ + "minimumIntegerDigits"?: number; + /** + * The minimum number of significant digits to use. Possible values are 1 - 21. + */ + "minimumSignificantDigits"?: number; + /** + * Turns off grouping separators. + */ + "noGrouping"?: boolean; + /** + * The formatting style to use. + */ + "type"?: 'currency' | 'decimal' | 'percent'; + /** + * The number to format in bytes. + */ + "value"?: number; + } interface SlIcon { /** * An alternative description to use for accessibility. If omitted, the name or src will be used to generate it. @@ -2747,6 +2846,7 @@ declare namespace LocalJSX { "sl-dropdown": SlDropdown; "sl-form": SlForm; "sl-format-bytes": SlFormatBytes; + "sl-format-number": SlFormatNumber; "sl-icon": SlIcon; "sl-icon-button": SlIconButton; "sl-icon-library": SlIconLibrary; @@ -2796,6 +2896,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-number": LocalJSX.SlFormatNumber & JSXBase.HTMLAttributes; "sl-icon": LocalJSX.SlIcon & JSXBase.HTMLAttributes; "sl-icon-button": LocalJSX.SlIconButton & JSXBase.HTMLAttributes; "sl-icon-library": LocalJSX.SlIconLibrary & JSXBase.HTMLAttributes; diff --git a/src/components/format-number/format-number.tsx b/src/components/format-number/format-number.tsx new file mode 100644 index 00000000..d5609ec6 --- /dev/null +++ b/src/components/format-number/format-number.tsx @@ -0,0 +1,65 @@ +import { Component, Prop } from '@stencil/core'; + +/** + * @since 2.0 + * @status stable + */ + +@Component({ + tag: 'sl-format-number', + shadow: true +}) +export class FormatBytes { + /** The number to format in bytes. */ + @Prop() value = 0; + + /** The locale to use when formatting the number. */ + @Prop() locale: string; + + /** The formatting style to use. */ + @Prop() type: 'currency' | 'decimal' | 'percent' = 'decimal'; + + /** Turns off grouping separators. */ + @Prop() noGrouping = false; + + /** The currency to use when formatting. Must be an ISO 4217 currency code such as `USD` or `EUR`. */ + @Prop() currency = 'USD'; + + /** How to display the currency. */ + @Prop() currencyDisplay: 'symbol' | 'narrowSymbol' | 'code' | 'name' = 'symbol'; + + /** The minimum number of integer digits to use. Possible values are 1 - 21. */ + @Prop() minimumIntegerDigits: number; + + /** The minimum number of fraction digits to use. Possible values are 0 - 20. */ + @Prop() minimumFractionDigits: number; + + /** The maximum number of fraction digits to use. Possible values are 0 - 20. */ + @Prop() maximumFractionDigits: number; + + /** The minimum number of significant digits to use. Possible values are 1 - 21. */ + @Prop() minimumSignificantDigits: number; + + /** The maximum number of significant digits to use,. Possible values are 1 - 21. */ + @Prop() maximumSignificantDigits: number; + + render() { + const number = Number(this.value); + + if (isNaN(number)) { + return ''; + } + + return new Intl.NumberFormat(this.locale, { + style: this.type, + currency: this.currency, + currencyDisplay: this.currencyDisplay, + useGrouping: !this.noGrouping, + minimumIntegerDigits: this.minimumIntegerDigits, + minimumFractionDigits: this.minimumFractionDigits, + maximumFractionDigits: this.maximumFractionDigits, + minimumSignificantDigits: this.minimumSignificantDigits, + maximumSignificantDigits: this.maximumSignificantDigits + }).format(number); + } +}