@esri/calcite-components
Version:
Web Components for Esri's Calcite Design System.
118 lines (117 loc) • 9.17 kB
JavaScript
/*! All material copyright ESRI, All Rights Reserved, unless otherwise specified.
See https://github.com/Esri/calcite-design-system/blob/dev/LICENSE.md for details.
v3.2.1 */
import { c as customElement } from "../../chunks/runtime.js";
import { html, nothing, svg } from "lit";
import { LitElement, setAttribute, safeClassMap, safeStyleMap } from "@arcgis/lumina";
import { g as guid } from "../../chunks/guid.js";
import { u as useT9n } from "../../chunks/useT9n.js";
import { css } from "@lit/reactive-element/css-tag.js";
const CSS = {
percentage: "percentage",
progressRing: "ring--progress",
ring: "ring",
rings: "rings",
text: "text",
trackRing: "ring--track"
};
const styles = css`:host{position:relative;margin-inline:auto;display:flex;align-items:center;justify-content:center;opacity:1;flex-direction:column;min-block-size:var(--calcite-loader-size);font-size:var(--calcite-loader-font-size);stroke-width:var(--calcite-internal-stroke-width);fill:none;transform:scale(1);padding-block:var(--calcite-loader-spacing, 4rem)}:host([scale=s]){--calcite-internal-stroke-width: 3;--calcite-internal-text-offset: var(--calcite-spacing-xxs);--calcite-internal-loader-font-size: var(--calcite-font-size--3);--calcite-internal-loader-size: 2rem;--calcite-internal-loader-size-inline: .75rem;--calcite-internal-loader-value-line-height: .625rem}:host([scale=m]){--calcite-internal-stroke-width: 6;--calcite-internal-text-offset: var(--calcite-spacing-sm);--calcite-internal-loader-font-size: var(--calcite-font-size-0);--calcite-internal-loader-size: 4rem;--calcite-internal-loader-size-inline: 1rem;--calcite-internal-loader-value-line-height: 1.375rem}:host([scale=l]){--calcite-internal-stroke-width: 8;--calcite-internal-text-offset: var(--calcite-spacing-md);--calcite-internal-loader-font-size: var(--calcite-font-size-2);--calcite-internal-loader-size: 6rem;--calcite-internal-loader-size-inline: 1.5rem;--calcite-internal-loader-value-line-height: 1.71875rem}.text{display:block;text-align:center;font-size:var(--calcite-font-size--2);line-height:1rem;margin-block-start:var(--calcite-loader-text-spacing, var(--calcite-internal-text-offset));font-weight:var(--calcite-loader-text-weight, var(--calcite-font-weight-normal));color:var(--calcite-loader-text-color, var(--calcite-color-text-1))}.percentage{display:block;text-align:center;font-size:var(--calcite-loader-font-size);inline-size:var(--calcite-loader-size, var(--calcite-internal-loader-size));line-height:var(--calcite-internal-loader-value-line-height);align-self:center;color:var(--calcite-loader-text-color, var(--calcite-color-text-1))}.rings{position:relative;display:flex;overflow:visible;opacity:1;inline-size:var(--calcite-loader-size, var(--calcite-internal-loader-size));block-size:var(--calcite-loader-size, var(--calcite-internal-loader-size))}.ring{position:absolute;inset-block-start:0px;transform-origin:center;overflow:visible;inset-inline-start:0;inline-size:var(--calcite-loader-size, var(--calcite-internal-loader-size));block-size:var(--calcite-loader-size, var(--calcite-internal-loader-size))}.ring--track{stroke:var(--calcite-loader-track-color, var(--calcite-color-transparent-press))}.ring--progress{stroke:var(--calcite-loader-progress-color, var(--calcite-color-brand));transform:rotate(-90deg);transition:all var(--calcite-internal-animation-timing-fast) linear}:host([type=indeterminate]) .ring--progress{animation:loader-clockwise calc(var(--calcite-internal-animation-timing-slow) / var(--calcite-internal-duration-factor) * 2 / var(--calcite-internal-duration-factor)) linear infinite}:host([inline]){--calcite-internal-stroke-width: 2;position:relative;margin:0;stroke:currentColor;stroke-width:2;padding-block:0px;block-size:var(--calcite-loader-size, var(--calcite-loader-size-inline, var(--calcite-internal-loader-size-inline)));min-block-size:var(--calcite-loader-size, var(--calcite-loader-size-inline, var(--calcite-internal-loader-size-inline)));inline-size:var(--calcite-loader-size, var(--calcite-loader-size-inline, var(--calcite-internal-loader-size-inline)));vertical-align:calc(var(--calcite-loader-size, var(--calcite-loader-size-inline, var(--calcite-internal-loader-size-inline))) * -1 * .2)}:host([inline]) .rings{inset-block-start:0px;margin:0;inset-inline-start:0;inline-size:var(--calcite-loader-size, var(--calcite-loader-size-inline, var(--calcite-internal-loader-size-inline)));block-size:var(--calcite-loader-size, var(--calcite-loader-size-inline, var(--calcite-internal-loader-size-inline)))}:host([inline]) .ring{inline-size:var(--calcite-loader-size, var(--calcite-loader-size-inline, var(--calcite-internal-loader-size-inline)));block-size:var(--calcite-loader-size, var(--calcite-loader-size-inline, var(--calcite-internal-loader-size-inline)))}:host([inline]) .ring--progress{stroke:var(--calcite-loader-progress-color-inline, currentColor)}:host([complete]){opacity:0;transform:scale(.75);transform-origin:center;transition:opacity var(--calcite-internal-animation-timing-medium) linear 1s,transform var(--calcite-internal-animation-timing-medium) linear 1s}:host([complete]) .rings{opacity:0;transform:scale(.75);transform-origin:center;transition:opacity calc(.18s * var(--calcite-internal-duration-factor)) linear .8s,transform calc(.18s * var(--calcite-internal-duration-factor)) linear .8s}:host([complete]) .percentage{color:var(--calcite-color-brand);transform:scale(1.05);transform-origin:center;transition:color var(--calcite-internal-animation-timing-medium) linear,transform var(--calcite-internal-animation-timing-medium) linear}@keyframes loader-clockwise{0%{transform:rotate(0)}to{transform:rotate(360deg)}}:host([hidden]){display:none}[hidden]{display:none}`;
class Loader extends LitElement {
constructor() {
super(...arguments);
this.messages = useT9n({ name: null });
this.complete = false;
this.inline = false;
this.scale = "m";
this.text = "";
this.type = "indeterminate";
this.value = 0;
}
static {
this.properties = { complete: [7, {}, { reflect: true, type: Boolean }], inline: [7, {}, { reflect: true, type: Boolean }], label: 1, scale: [3, {}, { reflect: true }], text: 1, type: [3, {}, { reflect: true }], value: [9, {}, { type: Number }] };
}
static {
this.styles = styles;
}
connectedCallback() {
super.connectedCallback();
this.updateFormatter();
}
load() {
requestAnimationFrame(() => this.valueChangeHandler());
}
willUpdate(changes) {
if (changes.has("value") && (this.hasUpdated || this.value !== 0)) {
this.valueChangeHandler();
}
if (changes.has("type") && (this.hasUpdated || this.type !== "indeterminate") || changes.has("messages")) {
this.updateFormatter();
}
}
valueChangeHandler() {
this.complete = this.type.startsWith("determinate") && this.value === 100;
}
formatValue() {
if (this.type !== "determinate-value") {
return `${this.value}`;
}
return this.formatter.format(this.value / 100);
}
getSize(scale) {
return {
s: 32,
m: 64,
l: 96
}[scale];
}
getInlineSize(scale) {
return {
s: 12,
m: 16,
l: 24
}[scale];
}
updateFormatter() {
if (this.type !== "determinate-value" || this.formatter?.resolvedOptions().locale === this.messages._lang) {
return;
}
this.formatter = new Intl.NumberFormat(this.messages._lang, {
style: "percent"
});
}
render() {
const { el, inline, label, text, type, value } = this;
const id = el.id || guid();
const isDeterminate = type !== "indeterminate";
const valueNow = Math.floor(value);
this.el.ariaLabel = label;
this.el.ariaValueMax = isDeterminate ? "100" : void 0;
this.el.ariaValueMin = isDeterminate ? "0" : void 0;
this.el.ariaValueNow = isDeterminate ? valueNow.toString() : void 0;
setAttribute(this.el, "id", id);
this.el.role = "progressbar";
return html`<div class=${safeClassMap(CSS.rings)}>${this.renderRing("track")}${this.renderRing("progress")}${!inline && isDeterminate && html`<div class=${safeClassMap(CSS.percentage)}>${this.formatValue()}</div>` || ""}</div>${!inline && text && html`<div class=${safeClassMap(CSS.text)}>${text}</div>` || ""}`;
}
renderRing(type) {
const { inline, scale, value } = this;
const size = inline ? this.getInlineSize(scale) : this.getSize(scale);
const radiusRatio = 0.45;
const radius = size * radiusRatio;
let style;
if (type === "progress") {
const circumference = 2 * radius * Math.PI;
const progress = (this.type.startsWith("determinate") ? value : 24) / 100 * circumference;
const remaining = circumference - progress;
style = { "stroke-dasharray": `${progress} ${remaining}` };
}
return html`<svg aria-hidden=true class=${safeClassMap({
[CSS.ring]: true,
[CSS.trackRing]: type === "track",
[CSS.progressRing]: type === "progress"
})} style=${safeStyleMap(style)} viewBox=${`0 0 ${size} ${size}`}>${svg`<circle cx=${size / 2} cy=${size / 2} r=${radius ?? nothing} />`}</svg>`;
}
}
customElement("calcite-loader", Loader);
export {
Loader
};