@justeattakeaway/pie-spinner 0.1.0 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -60,7 +60,9 @@ import { PieSpinner } from '@justeattakeaway/pie-spinner/dist/react';
60
60
 
61
61
  | Property | Type | Default | Description |
62
62
  |---|---|---|---|
63
- | - | - | - | - |
63
+ | size | `String` | `m` | Size of the spinner, one of `sizes` – `xs`, `s`, `m`, `l`, `xl` |
64
+ | variant | `String` | `brand` | Variant of the spinner, one of `variants` – `brand`, `secondary`, `inverse` |
65
+ | aria | `Object` | `undefined` | An object representing the aria attributes such as label;
64
66
 
65
67
  In your markup or JSX, you can then use these to set the properties for the `pie-spinner` component:
66
68
 
package/dist/index.d.ts CHANGED
@@ -2,15 +2,38 @@ import type { CSSResult } from 'lit';
2
2
  import type { LitElement } from 'lit';
3
3
  import type { TemplateResult } from 'lit-html';
4
4
 
5
+ export declare type AriaProps = {
6
+ label?: string;
7
+ };
8
+
5
9
  /**
6
10
  * @tagname pie-spinner
7
11
  */
8
12
  export declare class PieSpinner extends LitElement implements SpinnerProps {
13
+ aria?: AriaProps;
14
+ size?: SpinnerProps['size'];
15
+ variant?: SpinnerProps['variant'];
9
16
  render(): TemplateResult<1>;
10
17
  static styles: CSSResult;
11
18
  }
12
19
 
20
+ export declare const sizes: readonly ["xs", "s", "m", "l", "xl"];
21
+
13
22
  export declare interface SpinnerProps {
23
+ /**
24
+ * The ARIA labels used for the spinner component.
25
+ */
26
+ aria?: AriaProps;
27
+ /**
28
+ * What size the spinner should be.
29
+ */
30
+ size?: typeof sizes[number];
31
+ /**
32
+ * What style variant the spinner should be such as brand, secondary or inverse.
33
+ */
34
+ variant?: typeof variants[number];
14
35
  }
15
36
 
37
+ export declare const variants: readonly ["brand", "secondary", "inverse"];
38
+
16
39
  export { }
package/dist/index.js CHANGED
@@ -1,15 +1,65 @@
1
- import { unsafeCSS as t, LitElement as o, html as i } from "lit";
2
- function l(e, s) {
3
- customElements.get(e) ? console.warn(`PIE Web Component: "${e}" has already been defined. Please ensure the component is only being defined once in your application.`) : customElements.define(e, s);
1
+ import { unsafeCSS as f, LitElement as u, html as v, nothing as m } from "lit";
2
+ import { property as c } from "lit/decorators.js";
3
+ const b = (r, e, o) => function(s, i) {
4
+ const t = `#${i}`;
5
+ Object.defineProperty(s, i, {
6
+ get() {
7
+ return this[t];
8
+ },
9
+ set(l) {
10
+ const h = this[t];
11
+ e.includes(l) ? this[t] = l : (console.error(
12
+ `<${r}> Invalid value "${l}" provided for property "${i}".`,
13
+ `Must be one of: ${e.join(" | ")}.`,
14
+ `Falling back to default value: "${o}"`
15
+ ), this[t] = o), this.requestUpdate(i, h);
16
+ }
17
+ });
18
+ };
19
+ function z(r, e) {
20
+ customElements.get(r) ? console.warn(`PIE Web Component: "${r}" has already been defined. Please ensure the component is only being defined once in your application.`) : customElements.define(r, e);
4
21
  }
5
- const r = "", d = "pie-spinner";
6
- class n extends o {
22
+ const y = `*,*:before,*:after{box-sizing:border-box}@keyframes rotate360{0%{transform:rotate(0)}to{transform:rotate(360deg)}}.c-spinner{--spinner-size: 24px;--spinner-left-color: hsl(var(--spinner-base-color-h), var(--spinner-base-color-s), var(--spinner-base-color-l), 1);--spinner-right-color: hsl(var(--spinner-base-color-h), var(--spinner-base-color-s), var(--spinner-base-color-l), .35);block-size:var(--spinner-size);inline-size:var(--spinner-size);border-radius:var(--dt-radius-rounded-e);border-width:calc(var(--spinner-size) / 8);border-style:solid;border-color:var(--spinner-left-color) var(--spinner-right-color) var(--spinner-right-color) var(--spinner-left-color);will-change:transform;animation:rotate360 1.15s linear infinite;--spinner-base-color-h: var(--dt-color-content-brand-h);--spinner-base-color-s: var(--dt-color-content-brand-s);--spinner-base-color-l: var(--dt-color-content-brand-l)}.c-spinner[variant=secondary]{--spinner-base-color-h: var(--dt-color-content-interactive-secondary-h);--spinner-base-color-s: var(--dt-color-content-interactive-secondary-s);--spinner-base-color-l: var(--dt-color-content-interactive-secondary-l)}.c-spinner[variant=inverse]{--spinner-base-color-h: var(--dt-color-content-inverse-h);--spinner-base-color-s: var(--dt-color-content-inverse-s);--spinner-base-color-l: var(--dt-color-content-inverse-l)}.c-spinner[size=xs]{--spinner-size: 16px}.c-spinner[size=s]{--spinner-size: 20px}.c-spinner[size=l]{--spinner-size: 32px}.c-spinner[size=xl]{--spinner-size: 48px}.c-spinner-label{position:absolute;display:block;height:1px;width:1px;overflow:hidden;padding:1px;white-space:nowrap}
23
+ `, x = ["xs", "s", "m", "l", "xl"], g = ["brand", "secondary", "inverse"];
24
+ var P = Object.defineProperty, $ = Object.getOwnPropertyDescriptor, p = (r, e, o, n) => {
25
+ for (var s = n > 1 ? void 0 : n ? $(e, o) : e, i = r.length - 1, t; i >= 0; i--)
26
+ (t = r[i]) && (s = (n ? t(e, o, s) : t(s)) || s);
27
+ return n && s && P(e, o, s), s;
28
+ };
29
+ const d = "pie-spinner";
30
+ class a extends u {
31
+ constructor() {
32
+ super(...arguments), this.size = "m", this.variant = "brand";
33
+ }
7
34
  render() {
8
- return i`<h1 data-test-id="pie-spinner">Hello world!</h1>`;
35
+ const { variant: e, size: o, aria: n } = this;
36
+ return v`
37
+ <div
38
+ data-test-id="pie-spinner"
39
+ class="c-spinner"
40
+ role="status"
41
+ aria-live="polite"
42
+ size="${o}"
43
+ variant="${e}">
44
+ ${n != null && n.label ? v`<span class="c-spinner-label">${n.label}</span>` : m}
45
+ </div>`;
9
46
  }
10
47
  }
11
- n.styles = t(r);
12
- l(d, n);
48
+ a.styles = f(y);
49
+ p([
50
+ c({ type: Object })
51
+ ], a.prototype, "aria", 2);
52
+ p([
53
+ c(),
54
+ b(d, x, "m")
55
+ ], a.prototype, "size", 2);
56
+ p([
57
+ c(),
58
+ b(d, g, "brand")
59
+ ], a.prototype, "variant", 2);
60
+ z(d, a);
13
61
  export {
14
- n as PieSpinner
62
+ a as PieSpinner,
63
+ x as sizes,
64
+ g as variants
15
65
  };
package/dist/react.d.ts CHANGED
@@ -3,17 +3,40 @@ import type { LitElement } from 'lit';
3
3
  import type { ReactWebComponent } from '@lit-labs/react';
4
4
  import type { TemplateResult } from 'lit-html';
5
5
 
6
+ export declare type AriaProps = {
7
+ label?: string;
8
+ };
9
+
6
10
  export declare const PieSpinner: ReactWebComponent<PieSpinner_2, {}>;
7
11
 
8
12
  /**
9
13
  * @tagname pie-spinner
10
14
  */
11
15
  declare class PieSpinner_2 extends LitElement implements SpinnerProps {
16
+ aria?: AriaProps;
17
+ size?: SpinnerProps['size'];
18
+ variant?: SpinnerProps['variant'];
12
19
  render(): TemplateResult<1>;
13
20
  static styles: CSSResult;
14
21
  }
15
22
 
23
+ export declare const sizes: readonly ["xs", "s", "m", "l", "xl"];
24
+
16
25
  export declare interface SpinnerProps {
26
+ /**
27
+ * The ARIA labels used for the spinner component.
28
+ */
29
+ aria?: AriaProps;
30
+ /**
31
+ * What size the spinner should be.
32
+ */
33
+ size?: typeof sizes[number];
34
+ /**
35
+ * What style variant the spinner should be such as brand, secondary or inverse.
36
+ */
37
+ variant?: typeof variants[number];
17
38
  }
18
39
 
40
+ export declare const variants: readonly ["brand", "secondary", "inverse"];
41
+
19
42
  export { }
package/dist/react.js CHANGED
@@ -1,67 +1,72 @@
1
- import * as S from "react";
2
- import { PieSpinner as g } from "./index.js";
1
+ import * as g from "react";
2
+ import { PieSpinner as E } from "./index.js";
3
+ import { sizes as k, variants as A } from "./index.js";
3
4
  import "lit";
5
+ import "lit/decorators.js";
4
6
  /**
5
7
  * @license
6
8
  * Copyright 2018 Google LLC
7
9
  * SPDX-License-Identifier: BSD-3-Clause
8
10
  */
9
- const M = /* @__PURE__ */ new Set(["children", "localName", "ref", "style", "className"]), E = /* @__PURE__ */ new WeakMap(), P = (p, a, d, m, h) => {
10
- const i = h == null ? void 0 : h[a];
11
- i === void 0 || d === m ? d == null && a in HTMLElement.prototype ? p.removeAttribute(a) : p[a] = d : ((s, t, u) => {
12
- let o = E.get(s);
13
- o === void 0 && E.set(s, o = /* @__PURE__ */ new Map());
14
- let r = o.get(t);
15
- u !== void 0 ? r === void 0 ? (o.set(t, r = { handleEvent: u }), s.addEventListener(t, r)) : r.handleEvent = u : r !== void 0 && (o.delete(t), s.removeEventListener(t, r));
16
- })(p, i, d);
11
+ const S = /* @__PURE__ */ new Set(["children", "localName", "ref", "style", "className"]), w = /* @__PURE__ */ new WeakMap(), b = (t, n, c, d, m) => {
12
+ const o = m == null ? void 0 : m[n];
13
+ o === void 0 || c === d ? c == null && n in HTMLElement.prototype ? t.removeAttribute(n) : t[n] = c : ((r, i, h) => {
14
+ let a = w.get(r);
15
+ a === void 0 && w.set(r, a = /* @__PURE__ */ new Map());
16
+ let l = a.get(i);
17
+ h !== void 0 ? l === void 0 ? (a.set(i, l = { handleEvent: h }), r.addEventListener(i, l)) : l.handleEvent = h : l !== void 0 && (a.delete(i), r.removeEventListener(i, l));
18
+ })(t, o, c);
19
+ }, M = (t, n) => {
20
+ typeof t == "function" ? t(n) : t.current = n;
17
21
  };
18
- function b(p = window.React, a, d, m, h) {
19
- let i, s, t;
20
- if (a === void 0) {
21
- const l = p;
22
- ({ tagName: s, elementClass: t, events: m, displayName: h } = l), i = l.react;
22
+ function P(t = window.React, n, c, d, m) {
23
+ let o, r, i;
24
+ if (n === void 0) {
25
+ const p = t;
26
+ ({ tagName: r, elementClass: i, events: d, displayName: m } = p), o = p.react;
23
27
  } else
24
- i = p, t = d, s = a;
25
- const u = i.Component, o = i.createElement, r = new Set(Object.keys(m ?? {}));
26
- class f extends u {
28
+ o = t, i = c, r = n;
29
+ const h = o.Component, a = o.createElement, l = new Set(Object.keys(d ?? {}));
30
+ class f extends h {
27
31
  constructor() {
28
32
  super(...arguments), this.o = null;
29
33
  }
30
34
  t(e) {
31
35
  if (this.o !== null)
32
- for (const v in this.i)
33
- P(this.o, v, this.props[v], e ? e[v] : void 0, m);
36
+ for (const u in this.i)
37
+ b(this.o, u, this.props[u], e ? e[u] : void 0, d);
34
38
  }
35
39
  componentDidMount() {
36
- this.t();
40
+ var e;
41
+ this.t(), (e = this.o) === null || e === void 0 || e.removeAttribute("defer-hydration");
37
42
  }
38
43
  componentDidUpdate(e) {
39
44
  this.t(e);
40
45
  }
41
46
  render() {
42
- const { _$Gl: e, ...v } = this.props;
43
- this.h !== e && (this.u = (n) => {
44
- e !== null && ((c, w) => {
45
- typeof c == "function" ? c(w) : c.current = w;
46
- })(e, n), this.o = n, this.h = e;
47
+ const { _$Gl: e, ...u } = this.props;
48
+ this.h !== e && (this.u = (s) => {
49
+ e !== null && M(e, s), this.o = s, this.h = e;
47
50
  }), this.i = {};
48
- const y = { ref: this.u };
49
- for (const [n, c] of Object.entries(v))
50
- M.has(n) ? y[n === "className" ? "class" : n] = c : r.has(n) || n in t.prototype ? this.i[n] = c : y[n] = c;
51
- return o(s, y);
51
+ const v = { ref: this.u };
52
+ for (const [s, y] of Object.entries(u))
53
+ S.has(s) ? v[s === "className" ? "class" : s] = y : l.has(s) || s in i.prototype ? this.i[s] = y : v[s] = y;
54
+ return v.suppressHydrationWarning = !0, a(r, v);
52
55
  }
53
56
  }
54
- f.displayName = h ?? t.name;
55
- const N = i.forwardRef((l, e) => o(f, { ...l, _$Gl: e }, l == null ? void 0 : l.children));
57
+ f.displayName = m ?? i.name;
58
+ const N = o.forwardRef((p, e) => a(f, { ...p, _$Gl: e }, p == null ? void 0 : p.children));
56
59
  return N.displayName = f.displayName, N;
57
60
  }
58
- const R = b({
61
+ const R = P({
59
62
  displayName: "PieSpinner",
60
- elementClass: g,
61
- react: S,
63
+ elementClass: E,
64
+ react: g,
62
65
  tagName: "pie-spinner",
63
66
  events: {}
64
67
  });
65
68
  export {
66
- R as PieSpinner
69
+ R as PieSpinner,
70
+ k as sizes,
71
+ A as variants
67
72
  };
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@justeattakeaway/pie-spinner",
3
3
  "description": "PIE Design System Spinner built using Web Components",
4
- "version": "0.1.0",
4
+ "version": "0.2.0",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
7
7
  "module": "dist/index.js",
package/src/defs.ts CHANGED
@@ -1,3 +1,21 @@
1
- // TODO - please remove the eslint disable comment below when you add props to this interface
2
- // eslint-disable-next-line @typescript-eslint/no-empty-interface
3
- export interface SpinnerProps {}
1
+ export const sizes = ['xs', 's', 'm', 'l', 'xl'] as const;
2
+ export const variants = ['brand', 'secondary', 'inverse'] as const;
3
+
4
+ export type AriaProps = {
5
+ label?: string;
6
+ };
7
+
8
+ export interface SpinnerProps {
9
+ /**
10
+ * The ARIA labels used for the spinner component.
11
+ */
12
+ aria?: AriaProps;
13
+ /**
14
+ * What size the spinner should be.
15
+ */
16
+ size?: typeof sizes[number];
17
+ /**
18
+ * What style variant the spinner should be such as brand, secondary or inverse.
19
+ */
20
+ variant?: typeof variants[number];
21
+ }
package/src/index.ts CHANGED
@@ -1,8 +1,15 @@
1
- import { LitElement, html, unsafeCSS } from 'lit';
2
-
3
- import { defineCustomElement } from '@justeattakeaway/pie-webc-core';
1
+ import {
2
+ LitElement, html, nothing, unsafeCSS,
3
+ } from 'lit';
4
+ import { property } from 'lit/decorators.js';
5
+ import { validPropertyValues, defineCustomElement } from '@justeattakeaway/pie-webc-core';
4
6
  import styles from './spinner.scss?inline';
5
- import { SpinnerProps } from './defs';
7
+ import {
8
+ SpinnerProps,
9
+ sizes,
10
+ variants,
11
+ type AriaProps,
12
+ } from './defs';
6
13
 
7
14
  // Valid values available to consumers
8
15
  export * from './defs';
@@ -13,8 +20,30 @@ const componentSelector = 'pie-spinner';
13
20
  * @tagname pie-spinner
14
21
  */
15
22
  export class PieSpinner extends LitElement implements SpinnerProps {
23
+ @property({ type: Object })
24
+ public aria?: AriaProps;
25
+
26
+ @property()
27
+ @validPropertyValues(componentSelector, sizes, 'm')
28
+ public size?: SpinnerProps['size'] = 'm';
29
+
30
+ @property()
31
+ @validPropertyValues(componentSelector, variants, 'brand')
32
+ public variant?: SpinnerProps['variant'] = 'brand';
33
+
16
34
  render () {
17
- return html`<h1 data-test-id="pie-spinner">Hello world!</h1>`;
35
+ const { variant, size, aria } = this;
36
+
37
+ return html`
38
+ <div
39
+ data-test-id="pie-spinner"
40
+ class="c-spinner"
41
+ role="status"
42
+ aria-live="polite"
43
+ size="${size}"
44
+ variant="${variant}">
45
+ ${aria?.label ? html`<span class="c-spinner-label">${aria.label}</span>` : nothing}
46
+ </div>`;
18
47
  }
19
48
 
20
49
  // Renders a `CSSResult` generated from SCSS by Vite
package/src/spinner.scss CHANGED
@@ -1 +1,82 @@
1
1
  @use '@justeattakeaway/pie-css/scss' as p;
2
+
3
+ *,
4
+ *:before,
5
+ *:after {
6
+ box-sizing: border-box;
7
+ }
8
+
9
+ /**
10
+ * Shorthand mixin for updating the HSL custom properties for the loading spinner.
11
+ * Takes in the name of the color to be split into its HSL components.
12
+ */
13
+ @mixin spinner-base-colors($color) {
14
+ --spinner-base-color-h: var(#{$color}-h);
15
+ --spinner-base-color-s: var(#{$color}-s);
16
+ --spinner-base-color-l: var(#{$color}-l);
17
+ }
18
+
19
+ // Spin animation for loading state
20
+ @keyframes rotate360 {
21
+ from {
22
+ transform: rotate(0deg);
23
+ }
24
+
25
+ to {
26
+ transform: rotate(360deg);
27
+ }
28
+ }
29
+
30
+ .c-spinner {
31
+ --spinner-size: 24px;
32
+ --spinner-left-color: hsl(var(--spinner-base-color-h), var(--spinner-base-color-s), var(--spinner-base-color-l), 1);
33
+ --spinner-right-color: hsl(var(--spinner-base-color-h), var(--spinner-base-color-s), var(--spinner-base-color-l), 0.35);
34
+
35
+ block-size: var(--spinner-size);
36
+ inline-size: var(--spinner-size);
37
+ border-radius: var(--dt-radius-rounded-e);
38
+ border-width: calc(var(--spinner-size) / 8);
39
+ border-style: solid;
40
+ border-color: var(--spinner-left-color) var(--spinner-right-color) var(--spinner-right-color) var(--spinner-left-color);
41
+ will-change: transform;
42
+ animation: rotate360 1.15s linear infinite;
43
+
44
+ @include spinner-base-colors('--dt-color-content-brand');
45
+
46
+ &[variant='brand'] {
47
+ /* Same as default styles */
48
+ }
49
+
50
+ &[variant='secondary'] {
51
+ @include spinner-base-colors('--dt-color-content-interactive-secondary');
52
+ }
53
+
54
+ &[variant='inverse'] {
55
+ @include spinner-base-colors('--dt-color-content-inverse');
56
+ }
57
+
58
+ &[size='xs'] {
59
+ --spinner-size: 16px;
60
+ }
61
+
62
+ &[size='s'] {
63
+ --spinner-size: 20px;
64
+ }
65
+
66
+ &[size='m'] {
67
+ /* Same as default styles */
68
+ }
69
+
70
+ &[size='l'] {
71
+ --spinner-size: 32px;
72
+ }
73
+
74
+ &[size='xl'] {
75
+ --spinner-size: 48px;
76
+ }
77
+ }
78
+
79
+ // The label is only required for screen readers so we need to visually hide it
80
+ .c-spinner-label {
81
+ @include p.visually-hidden;
82
+ }