@justeattakeaway/pie-icon-button 0.19.0 → 0.21.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
@@ -94,7 +94,8 @@ Then, in your markup, you would implement the component like this:
94
94
  |-------------|-----------|-----------------|----------------------------------------------------------------------|
95
95
  | size | `String` | `medium` | Size of the Icon Button, one of `sizes` – `xsmall`, `small`, `medium`, `large` |
96
96
  | variant | `String` | `primary` | Variant of the button, one of `variants` – `primary`, `secondary`, `outline`, `ghost`, `ghost-secondary` |
97
- | disabled | `Boolean` | `false` | If `true`, disables the button. |
97
+ | disabled | `Boolean` | `false`| If `true`, disables the button.|
98
+ | isLoading | `Boolean` | `false` | If `true`, displays a loading indicator inside the icon button. |
98
99
 
99
100
  In your HTML markup or JSX, you can then use these to set the properties for the `pie-icon-button` component, like so:
100
101
 
package/dist/index.d.ts CHANGED
@@ -1,38 +1,50 @@
1
1
  import type { CSSResult } from 'lit';
2
2
  import type { LitElement } from 'lit';
3
- import type { TemplateResult } from 'lit-html';
3
+ import type { TemplateResult } from 'lit';
4
4
 
5
5
  export declare interface IconButtonProps {
6
6
  /**
7
7
  * (Optional) What size the button should be.
8
8
  * @default "medium"
9
9
  */
10
- size: typeof sizes[number];
10
+ size?: typeof sizes[number];
11
11
  /**
12
12
  * (Optional) What style variant the button should be such as primary, outline or ghost.
13
13
  * @default "primary"
14
14
  */
15
- variant: typeof variants[number];
15
+ variant?: typeof variants[number];
16
16
  /**
17
17
  * (Optional) When true, the button element is disabled.
18
18
  * @default false
19
19
  */
20
- disabled: boolean;
20
+ disabled?: boolean;
21
+ /**
22
+ * (Optional) When true, a loading spinner is rendered.
23
+ * @default false
24
+ */
25
+ isLoading?: boolean;
21
26
  }
22
27
 
23
28
  /**
24
29
  * @tagname pie-icon-button
25
30
  */
26
31
  export declare class PieIconButton extends LitElement implements IconButtonProps {
27
- size: IconButtonProps['size'];
28
- variant: IconButtonProps['variant'];
29
- disabled: boolean;
32
+ size?: IconButtonProps['size'];
33
+ variant?: IconButtonProps['variant'];
34
+ disabled?: boolean | undefined;
35
+ isLoading?: boolean | undefined;
36
+ /**
37
+ * Template for the loading state
38
+ *
39
+ * @private
40
+ */
41
+ private renderSpinner;
30
42
  render(): TemplateResult<1>;
31
43
  static styles: CSSResult;
32
44
  }
33
45
 
34
46
  export declare const sizes: readonly ["xsmall", "small", "medium", "large"];
35
47
 
36
- export declare const variants: readonly ["primary", "secondary", "outline", "ghost", "ghost-secondary"];
48
+ export declare const variants: readonly ["primary", "secondary", "outline", "ghost", "ghost-secondary", "inverse", "ghost-inverse"];
37
49
 
38
50
  export { }
package/dist/index.js CHANGED
@@ -1,67 +1,151 @@
1
- import { unsafeCSS as h, LitElement as f, html as p } from "lit";
2
- import { property as d } from "lit/decorators.js";
3
- const b = (t, o, r) => function(n, a) {
4
- const e = `#${a}`;
5
- Object.defineProperty(n, a, {
1
+ import { unsafeCSS as m, LitElement as g, html as d, nothing as z } from "lit";
2
+ import { property as c } from "lit/decorators.js";
3
+ const u = (n, o, t) => function(r, i) {
4
+ const a = `#${i}`;
5
+ Object.defineProperty(r, i, {
6
6
  get() {
7
- return this[e];
7
+ return this[a];
8
8
  },
9
9
  set(l) {
10
- const u = this[e];
11
- o.includes(l) ? this[e] = l : (console.error(
12
- `<${t}> Invalid value "${l}" provided for property "${a}".`,
10
+ const B = this[a];
11
+ o.includes(l) ? this[a] = l : (console.error(
12
+ `<${n}> Invalid value "${l}" provided for property "${i}".`,
13
13
  `Must be one of: ${o.join(" | ")}.`,
14
- `Falling back to default value: "${r}"`
15
- ), this[e] = r), this.requestUpdate(a, u);
14
+ `Falling back to default value: "${t}"`
15
+ ), this[a] = t), this.requestUpdate(i, B);
16
16
  }
17
17
  });
18
18
  };
19
- function g(t, o) {
20
- customElements.get(t) ? console.warn(`PIE Web Component: "${t}" has already been defined. Please ensure the component is only being defined once in your application.`) : customElements.define(t, o);
19
+ function x(n, o) {
20
+ customElements.get(n) ? console.warn(`PIE Web Component: "${n}" has already been defined. Please ensure the component is only being defined once in your application.`) : customElements.define(n, o);
21
21
  }
22
- const m = `:host{--btn-dimension: 48px;--btn-icon-size: 24px}.o-iconBtn{--btn-border-radius: var(--dt-radius-rounded-e);--btn-bg-color: var(--dt-color-interactive-brand);--btn-icon-fill: var(--dt-color-content-interactive-primary);--btn-focus: var(--dt-color-focus-outer);min-block-size:var(--btn-dimension);aspect-ratio:1/1;border:none;border-radius:var(--btn-border-radius);outline:none;background-color:var(--btn-bg-color);color:var(--btn-icon-fill);cursor:pointer;user-select:none;display:flex;align-items:center;justify-content:center}@supports not (aspect-ratio: 1/1){.o-iconBtn{min-inline-size:var(--btn-dimension)}}.o-iconBtn:focus-visible{box-shadow:0 0 0 2px var(--dt-color-focus-inner),0 0 0 4px var(--dt-color-focus-outer);outline:none}.o-iconBtn svg{height:var(--btn-icon-size);width:var(--btn-icon-size)}.o-iconBtn[variant=primary]:hover:not(:disabled){background-color:hsl(var(--dt-color-interactive-brand-h),var(--dt-color-interactive-brand-s),calc(var(--dt-color-interactive-brand-l) - var(--dt-color-hover-01)))}.o-iconBtn[variant=primary]:active:not(:disabled){background-color:hsl(var(--dt-color-interactive-brand-h),var(--dt-color-interactive-brand-s),calc(var(--dt-color-interactive-brand-l) - var(--dt-color-active-01)))}.o-iconBtn[variant=secondary]{--btn-bg-color: var(--dt-color-interactive-secondary);--btn-icon-fill: var(--dt-color-content-interactive-secondary)}.o-iconBtn[variant=secondary]:hover:not(:disabled){background-color:hsl(var(--dt-color-interactive-secondary-h),var(--dt-color-interactive-secondary-s),calc(var(--dt-color-interactive-secondary-l) - var(--dt-color-hover-01)))}.o-iconBtn[variant=secondary]:active:not(:disabled){background-color:hsl(var(--dt-color-interactive-secondary-h),var(--dt-color-interactive-secondary-s),calc(var(--dt-color-interactive-secondary-l) - var(--dt-color-active-01)))}.o-iconBtn[variant=outline]{--btn-bg-color: var(--dt-color-container-default);--btn-icon-fill: var(--dt-color-content-interactive-brand)}.o-iconBtn[variant=outline] .o-iconBtn{border:1px solid var(--dt-color-border-strong)}.o-iconBtn[variant=outline]:hover:not(:disabled){background-color:hsl(var(--dt-color-container-default-h),var(--dt-color-container-default-s),calc(var(--dt-color-container-default-l) - var(--dt-color-hover-01)))}.o-iconBtn[variant=outline]:active:not(:disabled){background-color:hsl(var(--dt-color-container-default-h),var(--dt-color-container-default-s),calc(var(--dt-color-container-default-l) - var(--dt-color-active-01)))}.o-iconBtn[variant=ghost]{--btn-bg-color: var(--dt-color-container-default);--btn-icon-fill: var(--dt-color-content-interactive-brand)}.o-iconBtn[variant=ghost]:hover:not(:disabled){background-color:hsl(var(--dt-color-container-default-h),var(--dt-color-container-default-s),calc(var(--dt-color-container-default-l) - var(--dt-color-hover-01)))}.o-iconBtn[variant=ghost]:active:not(:disabled){background-color:hsl(var(--dt-color-container-default-h),var(--dt-color-container-default-s),calc(var(--dt-color-container-default-l) - var(--dt-color-active-01)))}.o-iconBtn[variant=ghost-secondary]{--btn-bg-color: var(--dt-color-container-default);--btn-icon-fill: var(--dt-color-content-interactive-secondary)}.o-iconBtn[variant=ghost-secondary]:hover:not(:disabled){background-color:hsl(var(--dt-color-container-default-h),var(--dt-color-container-default-s),calc(var(--dt-color-container-default-l) - var(--dt-color-hover-01)))}.o-iconBtn[variant=ghost-secondary]:active:not(:disabled){background-color:hsl(var(--dt-color-container-default-h),var(--dt-color-container-default-s),calc(var(--dt-color-container-default-l) - var(--dt-color-active-01)))}.o-iconBtn[disabled]{--btn-bg-color: var(--dt-color-disabled-01) !important;--btn-icon-fill: var(--dt-color-content-disabled) !important}.o-iconBtn[disabled] .o-iconBtn{border:1px solid var(--dt-color-disabled-01);cursor:not-allowed}.o-iconBtn[disabled][variant=outline] .o-iconBtn{outline:none}.o-iconBtn[disabled][variant=ghost],.o-iconBtn[disabled][variant=ghost-secondary]{--btn-bg-color: transparent;--btn-icon-fill: var(--dt-color-content-default)}.o-iconBtn[disabled][variant=ghost] .o-iconBtn,.o-iconBtn[disabled][variant=ghost-secondary] .o-iconBtn{outline:none;border:none}.o-iconBtn[size=xsmall]{--btn-dimension: 32px}.o-iconBtn[size=small]{--btn-dimension: 40px}.o-iconBtn[size=large]{--btn-dimension: 56px;--btn-icon-size: 28px}
23
- `, y = ["xsmall", "small", "medium", "large"], B = ["primary", "secondary", "outline", "ghost", "ghost-secondary"];
24
- var x = Object.defineProperty, z = Object.getOwnPropertyDescriptor, s = (t, o, r, i) => {
25
- for (var n = i > 1 ? void 0 : i ? z(o, r) : o, a = t.length - 1, e; a >= 0; a--)
26
- (e = t[a]) && (n = (i ? e(o, r, n) : e(n)) || n);
27
- return i && n && x(o, r, n), n;
22
+ const $ = `:host{--btn-dimension: 48px;--btn-icon-size: 24px}.o-iconBtn{--btn-border-radius: var(--dt-radius-rounded-e);--btn-bg-color: var(--dt-color-interactive-brand);--btn-icon-fill: var(--dt-color-content-interactive-primary);block-size:var(--btn-dimension);inline-size:var(--btn-dimension);border-color:var(--btn-border-color);border-radius:var(--btn-border-radius);background-color:var(--btn-bg-color);color:var(--btn-icon-fill);cursor:pointer;user-select:none;outline:none;border:none;display:flex;align-items:center;justify-content:center}.o-iconBtn:focus-visible{box-shadow:0 0 0 2px var(--dt-color-focus-inner),0 0 0 4px var(--dt-color-focus-outer);outline:none}.o-iconBtn svg{height:var(--btn-icon-size);width:var(--btn-icon-size)}.o-iconBtn[variant=primary]:hover:not(:disabled){--hover-modifier: calc(-1 * var(--dt-color-hover-01));--btn-bg-color: hsl(var(--dt-color-interactive-brand-h), var(--dt-color-interactive-brand-s), calc(var(--dt-color-interactive-brand-l) + var(--hover-modifier)))}.o-iconBtn[variant=primary]:active:not(:disabled),.o-iconBtn[variant=primary][isLoading]:not(:disabled){--active-modifier: calc(-1 * var(--dt-color-active-01));--btn-bg-color: hsl(var(--dt-color-interactive-brand-h), var(--dt-color-interactive-brand-s), calc(var(--dt-color-interactive-brand-l) + var(--active-modifier)))}.o-iconBtn[variant=secondary]{--btn-bg-color: var(--dt-color-interactive-secondary);--btn-icon-fill: var(--dt-color-content-interactive-secondary)}.o-iconBtn[variant=secondary]:hover:not(:disabled){--hover-modifier: calc(-1 * var(--dt-color-hover-01));--btn-bg-color: hsl(var(--dt-color-interactive-secondary-h), var(--dt-color-interactive-secondary-s), calc(var(--dt-color-interactive-secondary-l) + var(--hover-modifier)))}.o-iconBtn[variant=secondary]:active:not(:disabled),.o-iconBtn[variant=secondary][isLoading]:not(:disabled){--active-modifier: calc(-1 * var(--dt-color-active-01));--btn-bg-color: hsl(var(--dt-color-interactive-secondary-h), var(--dt-color-interactive-secondary-s), calc(var(--dt-color-interactive-secondary-l) + var(--active-modifier)))}.o-iconBtn[variant=outline]{--btn-bg-color: transparent;--btn-icon-fill: var(--dt-color-content-interactive-brand);border:1px solid var(--dt-color-border-strong)}.o-iconBtn[variant=outline]:hover:not(:disabled){--hover-modifier: calc(-1 * var(--dt-color-hover-01));--hover-modifier: var(--dt-color-hover-01);--btn-bg-color: hsl(var(--dt-color-black-h), var(--dt-color-black-s), var(--dt-color-black-l), var(--hover-modifier))}.o-iconBtn[variant=outline]:active:not(:disabled),.o-iconBtn[variant=outline][isLoading]:not(:disabled){--active-modifier: calc(-1 * var(--dt-color-active-01));--active-modifier: var(--dt-color-active-01);--btn-bg-color: hsl(var(--dt-color-black-h), var(--dt-color-black-s), var(--dt-color-black-l), var(--active-modifier))}.o-iconBtn[variant=ghost]{--btn-bg-color: transparent;--btn-icon-fill: var(--dt-color-content-interactive-brand)}.o-iconBtn[variant=ghost]:hover:not(:disabled){--hover-modifier: calc(-1 * var(--dt-color-hover-01));--hover-modifier: var(--dt-color-hover-01);--btn-bg-color: hsl(var(--dt-color-black-h), var(--dt-color-black-s), var(--dt-color-black-l), var(--hover-modifier))}.o-iconBtn[variant=ghost]:active:not(:disabled),.o-iconBtn[variant=ghost][isLoading]:not(:disabled){--active-modifier: calc(-1 * var(--dt-color-active-01));--active-modifier: var(--dt-color-active-01);--btn-bg-color: hsl(var(--dt-color-black-h), var(--dt-color-black-s), var(--dt-color-black-l), var(--active-modifier))}.o-iconBtn[variant=ghost-secondary]{--btn-bg-color: transparent;--btn-icon-fill: var(--dt-color-content-interactive-secondary)}.o-iconBtn[variant=ghost-secondary]:hover:not(:disabled){--hover-modifier: calc(-1 * var(--dt-color-hover-01));--hover-modifier: var(--dt-color-hover-01);--btn-bg-color: hsl(var(--dt-color-black-h), var(--dt-color-black-s), var(--dt-color-black-l), var(--hover-modifier))}.o-iconBtn[variant=ghost-secondary]:active:not(:disabled),.o-iconBtn[variant=ghost-secondary][isLoading]:not(:disabled){--active-modifier: calc(-1 * var(--dt-color-active-01));--active-modifier: var(--dt-color-active-01);--btn-bg-color: hsl(var(--dt-color-black-h), var(--dt-color-black-s), var(--dt-color-black-l), var(--active-modifier))}.o-iconBtn[variant=inverse]{--btn-bg-color: var(--dt-color-interactive-inverse);--btn-icon-fill: var(--dt-color-content-interactive-brand)}.o-iconBtn[variant=inverse]:hover:not(:disabled){--hover-modifier: calc(-1 * var(--dt-color-hover-01));--btn-bg-color: hsl(var(--dt-color-interactive-inverse-h), var(--dt-color-interactive-inverse-s), calc(var(--dt-color-interactive-inverse-l) + var(--hover-modifier)))}.o-iconBtn[variant=inverse]:active:not(:disabled),.o-iconBtn[variant=inverse][isLoading]:not(:disabled){--active-modifier: calc(-1 * var(--dt-color-active-01));--btn-bg-color: hsl(var(--dt-color-interactive-inverse-h), var(--dt-color-interactive-inverse-s), calc(var(--dt-color-interactive-inverse-l) + var(--active-modifier)))}.o-iconBtn[variant=ghost-inverse]{--btn-bg-color: transparent;--btn-icon-fill: var(--dt-color-content-inverse)}.o-iconBtn[variant=ghost-inverse]:hover:not(:disabled){--hover-modifier: calc(-1 * var(--dt-color-hover-01));--hover-modifier: var(--dt-color-hover-01);--btn-bg-color: hsl(var(--dt-color-container-default-h), var(--dt-color-container-default-s), var(--dt-color-container-default-l), var(--hover-modifier))}.o-iconBtn[variant=ghost-inverse]:active:not(:disabled),.o-iconBtn[variant=ghost-inverse][isLoading]:not(:disabled){--active-modifier: calc(-1 * var(--dt-color-active-01));--active-modifier: var(--dt-color-active-01);--btn-bg-color: hsl(var(--dt-color-container-default-h), var(--dt-color-container-default-s), var(--dt-color-container-default-l), var(--active-modifier))}.o-iconBtn[disabled]{--btn-icon-fill: var(--dt-color-content-disabled);cursor:not-allowed}.o-iconBtn[disabled]:not([variant=ghost],[variant=ghost-secondary],[variant=ghost-inverse]){--btn-bg-color: var(--dt-color-disabled-01)}.o-iconBtn[disabled][variant=outline]{border-color:var(--dt-color-disabled-01)}.o-iconBtn[size=xsmall]{--btn-dimension: 32px}.o-iconBtn[size=small]{--btn-dimension: 40px}.o-iconBtn[size=large]{--btn-dimension: 56px;--btn-icon-size: 28px}
23
+ `, k = ["xsmall", "small", "medium", "large"], P = [
24
+ "primary",
25
+ "secondary",
26
+ "outline",
27
+ "ghost",
28
+ "ghost-secondary",
29
+ "inverse",
30
+ "ghost-inverse"
31
+ ], y = (n, o, t) => function(e, r) {
32
+ const i = `#${r}`;
33
+ Object.defineProperty(e, r, {
34
+ get() {
35
+ return this[i];
36
+ },
37
+ set(a) {
38
+ const l = this[i];
39
+ o.includes(a) ? this[i] = a : (console.error(
40
+ `<${n}> Invalid value "${a}" provided for property "${r}".`,
41
+ `Must be one of: ${o.join(" | ")}.`,
42
+ `Falling back to default value: "${t}"`
43
+ ), this[i] = t), this.requestUpdate(r, l);
44
+ }
45
+ });
46
+ };
47
+ function w(n, o) {
48
+ customElements.get(n) ? console.warn(`PIE Web Component: "${n}" has already been defined. Please ensure the component is only being defined once in your application.`) : customElements.define(n, o);
49
+ }
50
+ const L = `*,*: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}
51
+ `, j = ["xs", "s", "m", "l", "xl"], O = ["brand", "secondary", "inverse"];
52
+ var E = Object.defineProperty, _ = Object.getOwnPropertyDescriptor, p = (n, o, t, e) => {
53
+ for (var r = e > 1 ? void 0 : e ? _(o, t) : o, i = n.length - 1, a; i >= 0; i--)
54
+ (a = n[i]) && (r = (e ? a(o, t, r) : a(r)) || r);
55
+ return e && r && E(o, t, r), r;
28
56
  };
29
- const v = "pie-icon-button";
30
- class c extends f {
57
+ const h = "pie-spinner";
58
+ class v extends g {
31
59
  constructor() {
32
- super(...arguments), this.size = "medium", this.variant = "primary", this.disabled = !1;
60
+ super(...arguments), this.size = "m", this.variant = "brand";
61
+ }
62
+ render() {
63
+ const { variant: o, size: t, aria: e } = this;
64
+ return d`
65
+ <div
66
+ data-test-id="pie-spinner"
67
+ class="c-spinner"
68
+ role="status"
69
+ aria-live="polite"
70
+ size="${t}"
71
+ variant="${o}">
72
+ ${e != null && e.label ? d`<span class="c-spinner-label">${e.label}</span>` : z}
73
+ </div>`;
74
+ }
75
+ }
76
+ v.styles = m(L);
77
+ p([
78
+ c({ type: Object })
79
+ ], v.prototype, "aria", 2);
80
+ p([
81
+ c(),
82
+ y(h, j, "m")
83
+ ], v.prototype, "size", 2);
84
+ p([
85
+ c(),
86
+ y(h, O, "brand")
87
+ ], v.prototype, "variant", 2);
88
+ w(h, v);
89
+ var C = Object.defineProperty, I = Object.getOwnPropertyDescriptor, b = (n, o, t, e) => {
90
+ for (var r = e > 1 ? void 0 : e ? I(o, t) : o, i = n.length - 1, a; i >= 0; i--)
91
+ (a = n[i]) && (r = (e ? a(o, t, r) : a(r)) || r);
92
+ return e && r && C(o, t, r), r;
93
+ };
94
+ const f = "pie-icon-button";
95
+ class s extends g {
96
+ constructor() {
97
+ super(...arguments), this.size = "medium", this.variant = "primary", this.disabled = !1, this.isLoading = !1;
98
+ }
99
+ /**
100
+ * Template for the loading state
101
+ *
102
+ * @private
103
+ */
104
+ renderSpinner() {
105
+ const { variant: o, size: t } = this, e = t === "xsmall" ? "s" : "m";
106
+ let r = "brand";
107
+ return o != null && o.includes("secondary") && (r = "secondary"), (o === "primary" || o === "ghost-inverse") && (r = "inverse"), d`
108
+ <pie-spinner
109
+ size="${e}"
110
+ variant="${r}"
111
+ </pie-spinner>`;
33
112
  }
34
113
  render() {
35
114
  const {
36
115
  disabled: o,
37
- size: r,
38
- variant: i
116
+ size: t,
117
+ variant: e,
118
+ isLoading: r
39
119
  } = this;
40
- return p`
120
+ return d`
41
121
  <button
42
122
  class="o-iconBtn"
43
- size=${r}
44
- variant=${i}
45
- ?disabled=${o}>
46
- <slot></slot>
123
+ size="${t}"
124
+ variant="${e}"
125
+ ?disabled="${o}"
126
+ ?isLoading="${r}">
127
+ ${r ? this.renderSpinner() : d`<slot></slot>`}
47
128
  </button>`;
48
129
  }
49
130
  }
50
- c.styles = h(m);
51
- s([
52
- d(),
53
- b(v, y, "medium")
54
- ], c.prototype, "size", 2);
55
- s([
56
- d(),
57
- b(v, B, "primary")
58
- ], c.prototype, "variant", 2);
59
- s([
60
- d({ type: Boolean })
61
- ], c.prototype, "disabled", 2);
62
- g(v, c);
131
+ s.styles = m($);
132
+ b([
133
+ c(),
134
+ u(f, k, "medium")
135
+ ], s.prototype, "size", 2);
136
+ b([
137
+ c(),
138
+ u(f, P, "primary")
139
+ ], s.prototype, "variant", 2);
140
+ b([
141
+ c({ type: Boolean })
142
+ ], s.prototype, "disabled", 2);
143
+ b([
144
+ c({ type: Boolean })
145
+ ], s.prototype, "isLoading", 2);
146
+ x(f, s);
63
147
  export {
64
- c as PieIconButton,
65
- y as sizes,
66
- B as variants
148
+ s as PieIconButton,
149
+ k as sizes,
150
+ P as variants
67
151
  };
package/dist/react.d.ts CHANGED
@@ -1,24 +1,29 @@
1
1
  import type { CSSResult } from 'lit';
2
2
  import type { LitElement } from 'lit';
3
3
  import type { ReactWebComponent } from '@lit-labs/react';
4
- import type { TemplateResult } from 'lit-html';
4
+ import type { TemplateResult } from 'lit';
5
5
 
6
6
  export declare interface IconButtonProps {
7
7
  /**
8
8
  * (Optional) What size the button should be.
9
9
  * @default "medium"
10
10
  */
11
- size: typeof sizes[number];
11
+ size?: typeof sizes[number];
12
12
  /**
13
13
  * (Optional) What style variant the button should be such as primary, outline or ghost.
14
14
  * @default "primary"
15
15
  */
16
- variant: typeof variants[number];
16
+ variant?: typeof variants[number];
17
17
  /**
18
18
  * (Optional) When true, the button element is disabled.
19
19
  * @default false
20
20
  */
21
- disabled: boolean;
21
+ disabled?: boolean;
22
+ /**
23
+ * (Optional) When true, a loading spinner is rendered.
24
+ * @default false
25
+ */
26
+ isLoading?: boolean;
22
27
  }
23
28
 
24
29
  export declare const PieIconButton: ReactWebComponent<PieIconButton_2, {}>;
@@ -27,15 +32,22 @@ export declare const PieIconButton: ReactWebComponent<PieIconButton_2, {}>;
27
32
  * @tagname pie-icon-button
28
33
  */
29
34
  declare class PieIconButton_2 extends LitElement implements IconButtonProps {
30
- size: IconButtonProps['size'];
31
- variant: IconButtonProps['variant'];
32
- disabled: boolean;
35
+ size?: IconButtonProps['size'];
36
+ variant?: IconButtonProps['variant'];
37
+ disabled?: boolean | undefined;
38
+ isLoading?: boolean | undefined;
39
+ /**
40
+ * Template for the loading state
41
+ *
42
+ * @private
43
+ */
44
+ private renderSpinner;
33
45
  render(): TemplateResult<1>;
34
46
  static styles: CSSResult;
35
47
  }
36
48
 
37
49
  export declare const sizes: readonly ["xsmall", "small", "medium", "large"];
38
50
 
39
- export declare const variants: readonly ["primary", "secondary", "outline", "ghost", "ghost-secondary"];
51
+ export declare const variants: readonly ["primary", "secondary", "outline", "ghost", "ghost-secondary", "inverse", "ghost-inverse"];
40
52
 
41
53
  export { }
package/dist/react.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import * as g from "react";
2
- import { PieIconButton as b } from "./index.js";
2
+ import { PieIconButton as E } from "./index.js";
3
3
  import { sizes as j, variants as k } from "./index.js";
4
4
  import "lit";
5
5
  import "lit/decorators.js";
@@ -8,58 +8,59 @@ import "lit/decorators.js";
8
8
  * Copyright 2018 Google LLC
9
9
  * SPDX-License-Identifier: BSD-3-Clause
10
10
  */
11
- const B = /* @__PURE__ */ new Set(["children", "localName", "ref", "style", "className"]), E = /* @__PURE__ */ new WeakMap(), I = (d, l, m, p, u) => {
12
- const o = u == null ? void 0 : u[l];
13
- o === void 0 || m === p ? m == null && l in HTMLElement.prototype ? d.removeAttribute(l) : d[l] = m : ((i, t, h) => {
14
- let s = E.get(i);
15
- s === void 0 && E.set(i, s = /* @__PURE__ */ new Map());
16
- let a = s.get(t);
17
- h !== void 0 ? a === void 0 ? (s.set(t, a = { handleEvent: h }), i.addEventListener(t, a)) : a.handleEvent = h : a !== void 0 && (s.delete(t), i.removeEventListener(t, a));
18
- })(d, o, m);
11
+ const b = /* @__PURE__ */ new Set(["children", "localName", "ref", "style", "className"]), w = /* @__PURE__ */ new WeakMap(), B = (t, n, d, m, p) => {
12
+ const s = p == null ? void 0 : p[n];
13
+ s === void 0 || d === m ? d == null && n in HTMLElement.prototype ? t.removeAttribute(n) : t[n] = d : ((r, o, u) => {
14
+ let a = w.get(r);
15
+ a === void 0 && w.set(r, a = /* @__PURE__ */ new Map());
16
+ let l = a.get(o);
17
+ u !== void 0 ? l === void 0 ? (a.set(o, l = { handleEvent: u }), r.addEventListener(o, l)) : l.handleEvent = u : l !== void 0 && (a.delete(o), r.removeEventListener(o, l));
18
+ })(t, s, d);
19
+ }, I = (t, n) => {
20
+ typeof t == "function" ? t(n) : t.current = n;
19
21
  };
20
- function M(d = window.React, l, m, p, u) {
21
- let o, i, t;
22
- if (l === void 0) {
23
- const r = d;
24
- ({ tagName: i, elementClass: t, events: p, displayName: u } = r), o = r.react;
22
+ function M(t = window.React, n, d, m, p) {
23
+ let s, r, o;
24
+ if (n === void 0) {
25
+ const c = t;
26
+ ({ tagName: r, elementClass: o, events: m, displayName: p } = c), s = c.react;
25
27
  } else
26
- o = d, t = m, i = l;
27
- const h = o.Component, s = o.createElement, a = new Set(Object.keys(p ?? {}));
28
- class f extends h {
28
+ s = t, o = d, r = n;
29
+ const u = s.Component, a = s.createElement, l = new Set(Object.keys(m ?? {}));
30
+ class f extends u {
29
31
  constructor() {
30
32
  super(...arguments), this.o = null;
31
33
  }
32
34
  t(e) {
33
35
  if (this.o !== null)
34
- for (const v in this.i)
35
- I(this.o, v, this.props[v], e ? e[v] : void 0, p);
36
+ for (const h in this.i)
37
+ B(this.o, h, this.props[h], e ? e[h] : void 0, m);
36
38
  }
37
39
  componentDidMount() {
38
- this.t();
40
+ var e;
41
+ this.t(), (e = this.o) === null || e === void 0 || e.removeAttribute("defer-hydration");
39
42
  }
40
43
  componentDidUpdate(e) {
41
44
  this.t(e);
42
45
  }
43
46
  render() {
44
- const { _$Gl: e, ...v } = this.props;
45
- this.h !== e && (this.u = (n) => {
46
- e !== null && ((c, w) => {
47
- typeof c == "function" ? c(w) : c.current = w;
48
- })(e, n), this.o = n, this.h = e;
47
+ const { _$Gl: e, ...h } = this.props;
48
+ this.h !== e && (this.u = (i) => {
49
+ e !== null && I(e, i), this.o = i, this.h = e;
49
50
  }), this.i = {};
50
- const y = { ref: this.u };
51
- for (const [n, c] of Object.entries(v))
52
- B.has(n) ? y[n === "className" ? "class" : n] = c : a.has(n) || n in t.prototype ? this.i[n] = c : y[n] = c;
53
- return s(i, y);
51
+ const v = { ref: this.u };
52
+ for (const [i, y] of Object.entries(h))
53
+ b.has(i) ? v[i === "className" ? "class" : i] = y : l.has(i) || i in o.prototype ? this.i[i] = y : v[i] = y;
54
+ return v.suppressHydrationWarning = !0, a(r, v);
54
55
  }
55
56
  }
56
- f.displayName = u ?? t.name;
57
- const N = o.forwardRef((r, e) => s(f, { ...r, _$Gl: e }, r == null ? void 0 : r.children));
57
+ f.displayName = p ?? o.name;
58
+ const N = s.forwardRef((c, e) => a(f, { ...c, _$Gl: e }, c == null ? void 0 : c.children));
58
59
  return N.displayName = f.displayName, N;
59
60
  }
60
61
  const L = M({
61
62
  displayName: "PieIconButton",
62
- elementClass: b,
63
+ elementClass: E,
63
64
  react: g,
64
65
  tagName: "pie-icon-button",
65
66
  events: {}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@justeattakeaway/pie-icon-button",
3
- "version": "0.19.0",
3
+ "version": "0.21.0",
4
4
  "description": "PIE Design System Icon Button built using Web Components",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -25,13 +25,11 @@
25
25
  },
26
26
  "author": "Just Eat Takeaway.com - Design System Team",
27
27
  "license": "Apache-2.0",
28
- "devDependencies": {
28
+ "dependencies": {
29
29
  "@justeattakeaway/pie-icons-webc": "0.11.1",
30
+ "@justeattakeaway/pie-spinner": "0.2.0",
30
31
  "@justeattakeaway/pie-webc-core": "0.11.0"
31
32
  },
32
- "peerDependencies": {
33
- "@justeat/pie-design-tokens": "^5.8.2"
34
- },
35
33
  "volta": {
36
34
  "extends": "../../../package.json"
37
35
  },
package/src/defs.ts CHANGED
@@ -1,20 +1,26 @@
1
1
  export const sizes = ['xsmall', 'small', 'medium', 'large'] as const;
2
- export const variants = ['primary', 'secondary', 'outline', 'ghost', 'ghost-secondary'] as const;
2
+ export const variants = ['primary', 'secondary', 'outline', 'ghost',
3
+ 'ghost-secondary', 'inverse', 'ghost-inverse'] as const;
3
4
 
4
5
  export interface IconButtonProps {
5
6
  /**
6
7
  * (Optional) What size the button should be.
7
8
  * @default "medium"
8
9
  */
9
- size: typeof sizes[number];
10
+ size?: typeof sizes[number];
10
11
  /**
11
12
  * (Optional) What style variant the button should be such as primary, outline or ghost.
12
13
  * @default "primary"
13
14
  */
14
- variant: typeof variants[number];
15
+ variant?: typeof variants[number];
15
16
  /**
16
17
  * (Optional) When true, the button element is disabled.
17
18
  * @default false
18
19
  */
19
- disabled: boolean;
20
+ disabled?: boolean;
21
+ /**
22
+ * (Optional) When true, a loading spinner is rendered.
23
+ * @default false
24
+ */
25
+ isLoading?: boolean;
20
26
  }
@@ -1,15 +1,5 @@
1
1
  @use '@justeattakeaway/pie-css/scss' as p;
2
2
 
3
- @mixin button-interactive-states($bg-color) {
4
- &:hover:not(:disabled) {
5
- background-color: hsl(var(#{$bg-color}-h), var(#{$bg-color}-s), calc(var(#{$bg-color}-l) - var(--dt-color-hover-01)));
6
- }
7
-
8
- &:active:not(:disabled) {
9
- background-color: hsl(var(#{$bg-color}-h), var(#{$bg-color}-s), calc(var(#{$bg-color}-l) - var(--dt-color-active-01)));
10
- }
11
- }
12
-
13
3
  // Normally we don't expect consumers to override these, but there are situations where it may be necessary
14
4
  :host {
15
5
  // The base values are set to the size default, which is for the medium button size
@@ -22,27 +12,20 @@
22
12
  // Base button styles
23
13
  .o-iconBtn {
24
14
  --btn-border-radius: var(--dt-radius-rounded-e);
25
-
26
- // The following values set to default background and color
27
- // currently this sets the primary button styles
28
15
  --btn-bg-color: var(--dt-color-interactive-brand);
29
16
  --btn-icon-fill: var(--dt-color-content-interactive-primary);
30
- --btn-focus: var(--dt-color-focus-outer);
31
17
 
32
- min-block-size: var(--btn-dimension);
33
- aspect-ratio: 1 / 1;
34
-
35
- @supports not (aspect-ratio: 1 / 1) {
36
- min-inline-size: var(--btn-dimension);
37
- }
18
+ block-size: var(--btn-dimension);
19
+ inline-size: var(--btn-dimension);
38
20
 
39
- border: none;
21
+ border-color: var(--btn-border-color);
40
22
  border-radius: var(--btn-border-radius);
41
- outline: none;
42
23
  background-color: var(--btn-bg-color);
43
24
  color: var(--btn-icon-fill);
44
25
  cursor: pointer;
45
26
  user-select: none;
27
+ outline: none;
28
+ border: none;
46
29
 
47
30
  display: flex;
48
31
  align-items: center;
@@ -58,65 +41,68 @@
58
41
  }
59
42
 
60
43
  &[variant='primary'] {
61
- @include button-interactive-states('--dt-color-interactive-brand');
44
+ /* Same as default styles */
45
+
46
+ @include p.button-interactive-states('--dt-color-interactive-brand');
62
47
  }
63
48
 
64
49
  &[variant='secondary'] {
65
50
  --btn-bg-color: var(--dt-color-interactive-secondary);
66
51
  --btn-icon-fill: var(--dt-color-content-interactive-secondary);
67
52
 
68
- @include button-interactive-states('--dt-color-interactive-secondary');
53
+ @include p.button-interactive-states('--dt-color-interactive-secondary');
69
54
  }
70
55
 
71
56
  &[variant='outline'] {
72
- --btn-bg-color: var(--dt-color-container-default);
57
+ --btn-bg-color: transparent;
73
58
  --btn-icon-fill: var(--dt-color-content-interactive-brand);
74
59
 
75
- & .o-iconBtn {
76
- border: 1px solid var(--dt-color-border-strong);
77
- }
60
+ border: 1px solid var(--dt-color-border-strong);
78
61
 
79
- @include button-interactive-states('--dt-color-container-default');
62
+ @include p.button-interactive-states('--dt-color-black', 'transparent');
80
63
  }
81
64
 
82
65
  &[variant='ghost'] {
83
- --btn-bg-color: var(--dt-color-container-default);
66
+ --btn-bg-color: transparent;
84
67
  --btn-icon-fill: var(--dt-color-content-interactive-brand);
85
68
 
86
- @include button-interactive-states('--dt-color-container-default');
69
+ @include p.button-interactive-states('--dt-color-black', 'transparent');
87
70
  }
88
71
 
89
72
  &[variant='ghost-secondary'] {
90
- --btn-bg-color: var(--dt-color-container-default);
73
+ --btn-bg-color: transparent;
91
74
  --btn-icon-fill: var(--dt-color-content-interactive-secondary);
92
75
 
93
- @include button-interactive-states('--dt-color-container-default');
76
+ @include p.button-interactive-states('--dt-color-black', 'transparent');
94
77
  }
95
78
 
96
- &[disabled] {
97
- --btn-bg-color: var(--dt-color-disabled-01) !important;
98
- --btn-icon-fill: var(--dt-color-content-disabled) !important;
79
+ &[variant='inverse'] {
80
+ --btn-bg-color: var(--dt-color-interactive-inverse);
81
+ --btn-icon-fill: var(--dt-color-content-interactive-brand);
99
82
 
100
- & .o-iconBtn {
101
- border: 1px solid var(--dt-color-disabled-01);
102
- cursor: not-allowed;
103
- }
83
+ @include p.button-interactive-states('--dt-color-interactive-inverse');
104
84
  }
105
85
 
106
- &[disabled][variant='outline'] {
107
- & .o-iconBtn {
108
- outline: none;
109
- }
86
+ &[variant='ghost-inverse'] {
87
+ --btn-bg-color: transparent;
88
+ --btn-icon-fill: var(--dt-color-content-inverse);
89
+
90
+ @include p.button-interactive-states('--dt-color-container-default', 'transparent');
110
91
  }
111
92
 
112
- &[disabled][variant='ghost'],
113
- &[disabled][variant='ghost-secondary'] {
114
- --btn-bg-color: transparent;
115
- --btn-icon-fill: var(--dt-color-content-default);
93
+ &[disabled] {
94
+ --btn-icon-fill: var(--dt-color-content-disabled);
95
+
96
+ cursor: not-allowed;
97
+
98
+ // For every variant (except ghost variants) set the disabled background color
99
+ &:not([variant='ghost'], [variant='ghost-secondary'], [variant='ghost-inverse']) {
100
+ --btn-bg-color: var(--dt-color-disabled-01);
101
+ }
116
102
 
117
- & .o-iconBtn {
118
- outline: none;
119
- border: none;
103
+ // For outline variants, set the border to the disabled color
104
+ &[variant='outline'] {
105
+ border-color: var(--dt-color-disabled-01);
120
106
  }
121
107
  }
122
108
 
package/src/index.ts CHANGED
@@ -1,11 +1,13 @@
1
- import { LitElement, html, unsafeCSS } from 'lit';
1
+ import {
2
+ LitElement, TemplateResult, html, unsafeCSS,
3
+ } from 'lit';
2
4
  import { property } from 'lit/decorators.js';
3
5
  import { validPropertyValues, defineCustomElement } from '@justeattakeaway/pie-webc-core';
4
-
5
6
  import styles from './iconButton.scss?inline';
6
7
  import {
7
8
  IconButtonProps, sizes, variants,
8
9
  } from './defs';
10
+ import '@justeattakeaway/pie-spinner';
9
11
 
10
12
  // Valid values available to consumers
11
13
  export * from './defs';
@@ -18,28 +20,51 @@ const componentSelector = 'pie-icon-button';
18
20
  export class PieIconButton extends LitElement implements IconButtonProps {
19
21
  @property()
20
22
  @validPropertyValues(componentSelector, sizes, 'medium')
21
- public size: IconButtonProps['size'] = 'medium';
23
+ public size?: IconButtonProps['size'] = 'medium';
22
24
 
23
25
  @property()
24
26
  @validPropertyValues(componentSelector, variants, 'primary')
25
- public variant: IconButtonProps['variant'] = 'primary';
27
+ public variant?: IconButtonProps['variant'] = 'primary';
28
+
29
+ @property({ type: Boolean })
30
+ public disabled? = false;
26
31
 
27
32
  @property({ type: Boolean })
28
- public disabled = false;
33
+ public isLoading? = false;
34
+
35
+ /**
36
+ * Template for the loading state
37
+ *
38
+ * @private
39
+ */
40
+ private renderSpinner (): TemplateResult {
41
+ const { variant, size } = this;
42
+ const spinnerSize = size === 'xsmall' ? 's' : 'm';
43
+ let spinnerVariant = 'brand';
44
+ if (variant?.includes('secondary')) spinnerVariant = 'secondary';
45
+ if (variant === 'primary' || variant === 'ghost-inverse') spinnerVariant = 'inverse';
46
+
47
+ return html`
48
+ <pie-spinner
49
+ size="${spinnerSize}"
50
+ variant="${spinnerVariant}"
51
+ </pie-spinner>`;
52
+ }
29
53
 
30
54
  render () {
31
55
  const {
32
- disabled, size, variant,
56
+ disabled, size, variant, isLoading,
33
57
  } = this;
34
58
 
35
59
  // The inline SVG is temporary until we have a proper icon integration
36
60
  return html`
37
61
  <button
38
62
  class="o-iconBtn"
39
- size=${size}
40
- variant=${variant}
41
- ?disabled=${disabled}>
42
- <slot></slot>
63
+ size="${size}"
64
+ variant="${variant}"
65
+ ?disabled="${disabled}"
66
+ ?isLoading="${isLoading}">
67
+ ${isLoading ? this.renderSpinner() : html`<slot></slot>`}
43
68
  </button>`;
44
69
  }
45
70