@justeattakeaway/pie-icon-button 0.0.0-snapshot-release-20231129145325
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 +153 -0
- package/declaration.d.ts +9 -0
- package/dist/index.d.ts +50 -0
- package/dist/index.js +77 -0
- package/dist/react.d.ts +53 -0
- package/dist/react.js +20 -0
- package/package.json +39 -0
- package/src/defs.ts +26 -0
- package/src/iconButton.scss +127 -0
- package/src/index.ts +81 -0
package/README.md
ADDED
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
<p align="center">
|
|
2
|
+
<img align="center" src="../../../readme_image.png" height="200" alt="">
|
|
3
|
+
</p>
|
|
4
|
+
|
|
5
|
+
<p align="center">
|
|
6
|
+
<a href="https://www.npmjs.com/@justeattakeaway/pie-icon-button">
|
|
7
|
+
<img alt="GitHub Workflow Status" src="https://img.shields.io/npm/v/@justeattakeaway/pie-icon-button.svg">
|
|
8
|
+
</a>
|
|
9
|
+
</p>
|
|
10
|
+
|
|
11
|
+
# Table of Contents
|
|
12
|
+
|
|
13
|
+
1. [Introduction](#pie-icon-button)
|
|
14
|
+
2. [Installation](#installation)
|
|
15
|
+
3. [Importing the component](#importing-the-component)
|
|
16
|
+
4. [Peer Dependencies](#peer-dependencies)
|
|
17
|
+
5. [Props](#props)
|
|
18
|
+
6. [Events](#events)
|
|
19
|
+
- [HTML example](#html)
|
|
20
|
+
- [Vue example (using Nuxt 3)](#vue-templates-using-nuxt-3)
|
|
21
|
+
- [React example (using Next 13)](#react-templates-using-next-13)
|
|
22
|
+
7. [Contributing](#contributing)
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
## `pie-icon-button`
|
|
26
|
+
|
|
27
|
+
`pie-icon-button` is a Web Component built using the Lit library. It offers a simple and accessible icon button component for web applications.
|
|
28
|
+
|
|
29
|
+
This component can be easily integrated into various frontend frameworks and customized through a set of properties.
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
## Installation
|
|
33
|
+
|
|
34
|
+
To install `pie-icon-button` in your application, run the following on your command line:
|
|
35
|
+
|
|
36
|
+
```bash
|
|
37
|
+
# npm
|
|
38
|
+
$ npm i @justeattakeaway/pie-icon-button
|
|
39
|
+
|
|
40
|
+
# yarn
|
|
41
|
+
$ yarn add @justeattakeaway/pie-icon-button
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
For full information on using PIE components as part of an application, check out the [Getting Started Guide](https://github.com/justeattakeaway/pie/wiki/Getting-started-with-PIE-Web-Components).
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
### Importing the component
|
|
48
|
+
|
|
49
|
+
#### JavaScript
|
|
50
|
+
```js
|
|
51
|
+
// Default – for Native JS Applications, Vue, Angular, Svelte, etc.
|
|
52
|
+
import { PieIconButton } from '@justeattakeaway/pie-icon-button';
|
|
53
|
+
|
|
54
|
+
// If you don't need to reference the imported object, you can simply
|
|
55
|
+
// import the module which registers the component as a custom element.
|
|
56
|
+
import '@justeattakeaway/pie-icon-button';
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
#### React
|
|
60
|
+
```js
|
|
61
|
+
// React
|
|
62
|
+
// For React, you will need to import our React-specific component build
|
|
63
|
+
// which wraps the web component using @lit/react
|
|
64
|
+
import { PieIconButton } from '@justeattakeaway/pie-icon-button/dist/react';
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
> [!NOTE]
|
|
68
|
+
> When using the React version of the component, please make sure to also
|
|
69
|
+
> include React as a [peer dependency](#peer-dependencies) in your project.
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
## Peer Dependencies
|
|
73
|
+
|
|
74
|
+
> [!IMPORTANT]
|
|
75
|
+
> When using `pie-icon-button`, you will also need to include a couple of dependencies to ensure the component renders as expected. See [the PIE Wiki](https://github.com/justeattakeaway/pie/wiki/Getting-started-with-PIE-Web-Components#expected-dependencies) for more information and how to include these in your application.
|
|
76
|
+
|
|
77
|
+
## Importing Icons
|
|
78
|
+
|
|
79
|
+
We recommend using the `pie-icon-button` component alongside the `pie-icons-webc` package. This package contains all of the PIE icons as importable web components and are built to work alongside our other PIE components.
|
|
80
|
+
|
|
81
|
+
`pie-icon-button` provides a slot into which you can pass your chosen icon, and it will automatically size it to the correct dimensions depending on the `size` of the `pie-icon-button` component.
|
|
82
|
+
|
|
83
|
+
### Importing an icon with `pie-icons-webc`
|
|
84
|
+
|
|
85
|
+
To import an icon using `pie-icons-webc`, you should import the icon that you would like to use alongside the `pie-icon-button` component:
|
|
86
|
+
|
|
87
|
+
```js
|
|
88
|
+
import { PieIconButton } from '@justeattakeaway/pie-icon-button';
|
|
89
|
+
import '@justeattakeaway/pie-icons-webc/icons/IconClose';
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
Then, in your markup, you would implement the component like this:
|
|
93
|
+
|
|
94
|
+
```html
|
|
95
|
+
<pie-icon-button><icon-close></icon-close></pie-icon-button>
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
> [!WARNING]
|
|
99
|
+
> Usually, icons imported from `pie-icons-webc` can be resized by specifying the `size` prop (such as `<icon-close size="xl"></icon-close>`).
|
|
100
|
+
> These size props will have no effect when used alongside the `pie-icon-button` component, as the icon is resized with respect to the size of the `pie-icon-button`.
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
## Props
|
|
104
|
+
|
|
105
|
+
| Property | Type | Default | Description |
|
|
106
|
+
|-------------|-----------|-----------------|----------------------------------------------------------------------|
|
|
107
|
+
| size | `String` | `medium` | Size of the Icon Button, one of `sizes` – `xsmall`, `small`, `medium`, `large` |
|
|
108
|
+
| variant | `String` | `primary` | Variant of the button, one of `variants` – `primary`, `secondary`, `outline`, `ghost`, `ghost-secondary` |
|
|
109
|
+
| disabled | `Boolean` | `false`| If `true`, disables the button.|
|
|
110
|
+
| isLoading | `Boolean` | `false` | If `true`, displays a loading indicator inside the icon button. |
|
|
111
|
+
|
|
112
|
+
In your HTML markup or JSX, you can then use these to set the properties for the `pie-icon-button` component, like so:
|
|
113
|
+
|
|
114
|
+
```html
|
|
115
|
+
<!-- Native HTML -->
|
|
116
|
+
<pie-icon-button size='small' type='button' variant='secondary'><icon-close></icon-close></pie-icon-button>
|
|
117
|
+
|
|
118
|
+
<!-- JSX -->
|
|
119
|
+
<PieIconButton size='small' type='button' variant='secondary'><icon-close></icon-close></PieIconButton>
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
## Events
|
|
123
|
+
|
|
124
|
+
This component does not use any custom event handlers. In order to add event listening to this component, you can treat it like a native HTML element in your application.
|
|
125
|
+
|
|
126
|
+
For example, to add a click handler in various templates:
|
|
127
|
+
|
|
128
|
+
|
|
129
|
+
### HTML
|
|
130
|
+
|
|
131
|
+
```html
|
|
132
|
+
<!-- Other attributes omitted for clarity -->
|
|
133
|
+
<pie-icon-button onclick="e => console.log(e)"><icon-close></icon-close></pie-icon-button>
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
### Vue templates (using Nuxt 3)
|
|
137
|
+
|
|
138
|
+
```html
|
|
139
|
+
<!-- Other attributes omitted for clarity -->
|
|
140
|
+
<pie-icon-button @click="handleClick"><icon-close></icon-close></pie-icon-button>
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
### React templates (using Next 13)
|
|
144
|
+
|
|
145
|
+
```html
|
|
146
|
+
<!-- Other attributes omitted for clarity -->
|
|
147
|
+
<PieIconButton onClick={handleClick}><icon-close></icon-close></PieIconButton>
|
|
148
|
+
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
## Contributing
|
|
152
|
+
|
|
153
|
+
Check out our [contributing guide](https://github.com/justeattakeaway/pie/wiki/Contributing-Guide) for more information on [local development](https://github.com/justeattakeaway/pie/wiki/Contributing-Guide#local-development) and how to run specific [component tests](https://github.com/justeattakeaway/pie/wiki/Contributing-Guide#testing).
|
package/declaration.d.ts
ADDED
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import type { CSSResult } from 'lit';
|
|
2
|
+
import type { LitElement } from 'lit';
|
|
3
|
+
import type { TemplateResult } from 'lit';
|
|
4
|
+
|
|
5
|
+
export declare interface IconButtonProps {
|
|
6
|
+
/**
|
|
7
|
+
* (Optional) What size the button should be.
|
|
8
|
+
* @default "medium"
|
|
9
|
+
*/
|
|
10
|
+
size?: typeof sizes[number];
|
|
11
|
+
/**
|
|
12
|
+
* (Optional) What style variant the button should be such as primary, outline or ghost.
|
|
13
|
+
* @default "primary"
|
|
14
|
+
*/
|
|
15
|
+
variant?: typeof variants[number];
|
|
16
|
+
/**
|
|
17
|
+
* (Optional) When true, the button element is disabled.
|
|
18
|
+
* @default false
|
|
19
|
+
*/
|
|
20
|
+
disabled?: boolean;
|
|
21
|
+
/**
|
|
22
|
+
* (Optional) When true, a loading spinner is rendered.
|
|
23
|
+
* @default false
|
|
24
|
+
*/
|
|
25
|
+
isLoading?: boolean;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* @tagname pie-icon-button
|
|
30
|
+
*/
|
|
31
|
+
export declare class PieIconButton extends LitElement implements IconButtonProps {
|
|
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;
|
|
42
|
+
render(): TemplateResult<1>;
|
|
43
|
+
static styles: CSSResult;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export declare const sizes: readonly ["xsmall", "small", "medium", "large"];
|
|
47
|
+
|
|
48
|
+
export declare const variants: readonly ["primary", "secondary", "outline", "ghost", "ghost-secondary", "inverse", "ghost-inverse"];
|
|
49
|
+
|
|
50
|
+
export { }
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import { unsafeCSS as h, LitElement as m, html as d } from "lit";
|
|
2
|
+
import { property as n } from "lit/decorators.js";
|
|
3
|
+
import { validPropertyValues as b, defineCustomElement as f } from "@justeattakeaway/pie-webc-core";
|
|
4
|
+
import "@justeattakeaway/pie-spinner";
|
|
5
|
+
const g = `: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;--btn-icon-size: 20px}.o-iconBtn[size=small]{--btn-dimension: 40px}.o-iconBtn[size=large]{--btn-dimension: 56px;--btn-icon-size: 28px}
|
|
6
|
+
`, p = ["xsmall", "small", "medium", "large"], u = [
|
|
7
|
+
"primary",
|
|
8
|
+
"secondary",
|
|
9
|
+
"outline",
|
|
10
|
+
"ghost",
|
|
11
|
+
"ghost-secondary",
|
|
12
|
+
"inverse",
|
|
13
|
+
"ghost-inverse"
|
|
14
|
+
];
|
|
15
|
+
var y = Object.defineProperty, B = Object.getOwnPropertyDescriptor, c = (l, o, i, t) => {
|
|
16
|
+
for (var r = t > 1 ? void 0 : t ? B(o, i) : o, a = l.length - 1, v; a >= 0; a--)
|
|
17
|
+
(v = l[a]) && (r = (t ? v(o, i, r) : v(r)) || r);
|
|
18
|
+
return t && r && y(o, i, r), r;
|
|
19
|
+
};
|
|
20
|
+
const s = "pie-icon-button";
|
|
21
|
+
class e extends m {
|
|
22
|
+
constructor() {
|
|
23
|
+
super(...arguments), this.size = "medium", this.variant = "primary", this.disabled = !1, this.isLoading = !1;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Template for the loading state
|
|
27
|
+
*
|
|
28
|
+
* @private
|
|
29
|
+
*/
|
|
30
|
+
renderSpinner() {
|
|
31
|
+
const { variant: o, size: i, disabled: t } = this, r = i === "xsmall" ? "small" : "medium";
|
|
32
|
+
let a = "brand";
|
|
33
|
+
return o != null && o.includes("secondary") && (a = "secondary"), (o === "primary" && !t || o === "ghost-inverse") && (a = "inverse"), d`
|
|
34
|
+
<pie-spinner
|
|
35
|
+
size="${r}"
|
|
36
|
+
variant="${a}"
|
|
37
|
+
</pie-spinner>`;
|
|
38
|
+
}
|
|
39
|
+
render() {
|
|
40
|
+
const {
|
|
41
|
+
disabled: o,
|
|
42
|
+
size: i,
|
|
43
|
+
variant: t,
|
|
44
|
+
isLoading: r
|
|
45
|
+
} = this;
|
|
46
|
+
return d`
|
|
47
|
+
<button
|
|
48
|
+
class="o-iconBtn"
|
|
49
|
+
size="${i}"
|
|
50
|
+
variant="${t}"
|
|
51
|
+
?disabled="${o}"
|
|
52
|
+
?isLoading="${r}">
|
|
53
|
+
${r ? this.renderSpinner() : d`<slot></slot>`}
|
|
54
|
+
</button>`;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
e.styles = h(g);
|
|
58
|
+
c([
|
|
59
|
+
n(),
|
|
60
|
+
b(s, p, "medium")
|
|
61
|
+
], e.prototype, "size", 2);
|
|
62
|
+
c([
|
|
63
|
+
n(),
|
|
64
|
+
b(s, u, "primary")
|
|
65
|
+
], e.prototype, "variant", 2);
|
|
66
|
+
c([
|
|
67
|
+
n({ type: Boolean })
|
|
68
|
+
], e.prototype, "disabled", 2);
|
|
69
|
+
c([
|
|
70
|
+
n({ type: Boolean })
|
|
71
|
+
], e.prototype, "isLoading", 2);
|
|
72
|
+
f(s, e);
|
|
73
|
+
export {
|
|
74
|
+
e as PieIconButton,
|
|
75
|
+
p as sizes,
|
|
76
|
+
u as variants
|
|
77
|
+
};
|
package/dist/react.d.ts
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import type { CSSResult } from 'lit';
|
|
2
|
+
import type { LitElement } from 'lit';
|
|
3
|
+
import type { ReactWebComponent } from '@lit/react';
|
|
4
|
+
import type { TemplateResult } from 'lit';
|
|
5
|
+
|
|
6
|
+
export declare interface IconButtonProps {
|
|
7
|
+
/**
|
|
8
|
+
* (Optional) What size the button should be.
|
|
9
|
+
* @default "medium"
|
|
10
|
+
*/
|
|
11
|
+
size?: typeof sizes[number];
|
|
12
|
+
/**
|
|
13
|
+
* (Optional) What style variant the button should be such as primary, outline or ghost.
|
|
14
|
+
* @default "primary"
|
|
15
|
+
*/
|
|
16
|
+
variant?: typeof variants[number];
|
|
17
|
+
/**
|
|
18
|
+
* (Optional) When true, the button element is disabled.
|
|
19
|
+
* @default false
|
|
20
|
+
*/
|
|
21
|
+
disabled?: boolean;
|
|
22
|
+
/**
|
|
23
|
+
* (Optional) When true, a loading spinner is rendered.
|
|
24
|
+
* @default false
|
|
25
|
+
*/
|
|
26
|
+
isLoading?: boolean;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export declare const PieIconButton: ReactWebComponent<PieIconButton_2, {}>;
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* @tagname pie-icon-button
|
|
33
|
+
*/
|
|
34
|
+
declare class PieIconButton_2 extends LitElement implements IconButtonProps {
|
|
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;
|
|
45
|
+
render(): TemplateResult<1>;
|
|
46
|
+
static styles: CSSResult;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export declare const sizes: readonly ["xsmall", "small", "medium", "large"];
|
|
50
|
+
|
|
51
|
+
export declare const variants: readonly ["primary", "secondary", "outline", "ghost", "ghost-secondary", "inverse", "ghost-inverse"];
|
|
52
|
+
|
|
53
|
+
export { }
|
package/dist/react.js
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import * as t from "react";
|
|
2
|
+
import { createComponent as o } from "@lit/react";
|
|
3
|
+
import { PieIconButton as e } from "./index.js";
|
|
4
|
+
import { sizes as f, variants as B } from "./index.js";
|
|
5
|
+
import "lit";
|
|
6
|
+
import "lit/decorators.js";
|
|
7
|
+
import "@justeattakeaway/pie-webc-core";
|
|
8
|
+
import "@justeattakeaway/pie-spinner";
|
|
9
|
+
const s = o({
|
|
10
|
+
displayName: "PieIconButton",
|
|
11
|
+
elementClass: e,
|
|
12
|
+
react: t,
|
|
13
|
+
tagName: "pie-icon-button",
|
|
14
|
+
events: {}
|
|
15
|
+
});
|
|
16
|
+
export {
|
|
17
|
+
s as PieIconButton,
|
|
18
|
+
f as sizes,
|
|
19
|
+
B as variants
|
|
20
|
+
};
|
package/package.json
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@justeattakeaway/pie-icon-button",
|
|
3
|
+
"version": "0.0.0-snapshot-release-20231129145325",
|
|
4
|
+
"description": "PIE Design System Icon Button built using Web Components",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "dist/index.js",
|
|
7
|
+
"module": "dist/index.js",
|
|
8
|
+
"types": "dist/index.d.ts",
|
|
9
|
+
"files": [
|
|
10
|
+
"src",
|
|
11
|
+
"dist",
|
|
12
|
+
"**/*.d.ts"
|
|
13
|
+
],
|
|
14
|
+
"scripts": {
|
|
15
|
+
"build": "yarn build:wrapper pie-icon-button && run -T vite build",
|
|
16
|
+
"lint:scripts": "run -T eslint .",
|
|
17
|
+
"lint:scripts:fix": "run -T eslint . --fix",
|
|
18
|
+
"lint:style": "run -T stylelint ./src/**/*.{css,scss}",
|
|
19
|
+
"lint:style:fix": "yarn lint:style --fix",
|
|
20
|
+
"watch": "run -T vite build --watch",
|
|
21
|
+
"test": "echo \"Error: no test specified\" && exit 0",
|
|
22
|
+
"test:ci": "yarn test",
|
|
23
|
+
"test:visual": "run -T cross-env-shell PERCY_TOKEN=${PERCY_TOKEN_PIE_ICON_BUTTON} percy exec --allowed-hostname cloudfront.net -- npx playwright test -c ./playwright-lit-visual.config.ts",
|
|
24
|
+
"test:visual:ci": "yarn test:visual"
|
|
25
|
+
},
|
|
26
|
+
"author": "Just Eat Takeaway.com - Design System Team",
|
|
27
|
+
"license": "Apache-2.0",
|
|
28
|
+
"dependencies": {
|
|
29
|
+
"@justeattakeaway/pie-icons-webc": "0.0.0-snapshot-release-20231129145325",
|
|
30
|
+
"@justeattakeaway/pie-spinner": "0.3.1",
|
|
31
|
+
"@justeattakeaway/pie-webc-core": "0.13.0"
|
|
32
|
+
},
|
|
33
|
+
"volta": {
|
|
34
|
+
"extends": "../../../package.json"
|
|
35
|
+
},
|
|
36
|
+
"sideEffects": [
|
|
37
|
+
"dist/*.js"
|
|
38
|
+
]
|
|
39
|
+
}
|
package/src/defs.ts
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
export const sizes = ['xsmall', 'small', 'medium', 'large'] as const;
|
|
2
|
+
export const variants = ['primary', 'secondary', 'outline', 'ghost',
|
|
3
|
+
'ghost-secondary', 'inverse', 'ghost-inverse'] as const;
|
|
4
|
+
|
|
5
|
+
export interface IconButtonProps {
|
|
6
|
+
/**
|
|
7
|
+
* (Optional) What size the button should be.
|
|
8
|
+
* @default "medium"
|
|
9
|
+
*/
|
|
10
|
+
size?: typeof sizes[number];
|
|
11
|
+
/**
|
|
12
|
+
* (Optional) What style variant the button should be such as primary, outline or ghost.
|
|
13
|
+
* @default "primary"
|
|
14
|
+
*/
|
|
15
|
+
variant?: typeof variants[number];
|
|
16
|
+
/**
|
|
17
|
+
* (Optional) When true, the button element is disabled.
|
|
18
|
+
* @default false
|
|
19
|
+
*/
|
|
20
|
+
disabled?: boolean;
|
|
21
|
+
/**
|
|
22
|
+
* (Optional) When true, a loading spinner is rendered.
|
|
23
|
+
* @default false
|
|
24
|
+
*/
|
|
25
|
+
isLoading?: boolean;
|
|
26
|
+
}
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
@use '@justeattakeaway/pie-css/scss' as p;
|
|
2
|
+
|
|
3
|
+
// Normally we don't expect consumers to override these, but there are situations where it may be necessary
|
|
4
|
+
:host {
|
|
5
|
+
// The base values are set to the size default, which is for the medium button size
|
|
6
|
+
--btn-dimension: 48px;
|
|
7
|
+
|
|
8
|
+
// Sizing is set to Medium button icon size, as that is the default
|
|
9
|
+
--btn-icon-size: 24px;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
// Base button styles
|
|
13
|
+
.o-iconBtn {
|
|
14
|
+
--btn-border-radius: var(--dt-radius-rounded-e);
|
|
15
|
+
--btn-bg-color: var(--dt-color-interactive-brand);
|
|
16
|
+
--btn-icon-fill: var(--dt-color-content-interactive-primary);
|
|
17
|
+
|
|
18
|
+
block-size: var(--btn-dimension);
|
|
19
|
+
inline-size: var(--btn-dimension);
|
|
20
|
+
|
|
21
|
+
border-color: var(--btn-border-color);
|
|
22
|
+
border-radius: var(--btn-border-radius);
|
|
23
|
+
background-color: var(--btn-bg-color);
|
|
24
|
+
color: var(--btn-icon-fill);
|
|
25
|
+
cursor: pointer;
|
|
26
|
+
user-select: none;
|
|
27
|
+
outline: none;
|
|
28
|
+
border: none;
|
|
29
|
+
|
|
30
|
+
display: flex;
|
|
31
|
+
align-items: center;
|
|
32
|
+
justify-content: center;
|
|
33
|
+
|
|
34
|
+
&:focus-visible {
|
|
35
|
+
@include p.focus;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
svg {
|
|
39
|
+
height: var(--btn-icon-size);
|
|
40
|
+
width: var(--btn-icon-size);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
&[variant='primary'] {
|
|
44
|
+
/* Same as default styles */
|
|
45
|
+
|
|
46
|
+
@include p.button-interactive-states('--dt-color-interactive-brand');
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
&[variant='secondary'] {
|
|
50
|
+
--btn-bg-color: var(--dt-color-interactive-secondary);
|
|
51
|
+
--btn-icon-fill: var(--dt-color-content-interactive-secondary);
|
|
52
|
+
|
|
53
|
+
@include p.button-interactive-states('--dt-color-interactive-secondary');
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
&[variant='outline'] {
|
|
57
|
+
--btn-bg-color: transparent;
|
|
58
|
+
--btn-icon-fill: var(--dt-color-content-interactive-brand);
|
|
59
|
+
|
|
60
|
+
border: 1px solid var(--dt-color-border-strong);
|
|
61
|
+
|
|
62
|
+
@include p.button-interactive-states('--dt-color-black', 'transparent');
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
&[variant='ghost'] {
|
|
66
|
+
--btn-bg-color: transparent;
|
|
67
|
+
--btn-icon-fill: var(--dt-color-content-interactive-brand);
|
|
68
|
+
|
|
69
|
+
@include p.button-interactive-states('--dt-color-black', 'transparent');
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
&[variant='ghost-secondary'] {
|
|
73
|
+
--btn-bg-color: transparent;
|
|
74
|
+
--btn-icon-fill: var(--dt-color-content-interactive-secondary);
|
|
75
|
+
|
|
76
|
+
@include p.button-interactive-states('--dt-color-black', 'transparent');
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
&[variant='inverse'] {
|
|
80
|
+
--btn-bg-color: var(--dt-color-interactive-inverse);
|
|
81
|
+
--btn-icon-fill: var(--dt-color-content-interactive-brand);
|
|
82
|
+
|
|
83
|
+
@include p.button-interactive-states('--dt-color-interactive-inverse');
|
|
84
|
+
}
|
|
85
|
+
|
|
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');
|
|
91
|
+
}
|
|
92
|
+
|
|
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
|
+
}
|
|
102
|
+
|
|
103
|
+
// For outline variants, set the border to the disabled color
|
|
104
|
+
&[variant='outline'] {
|
|
105
|
+
border-color: var(--dt-color-disabled-01);
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
&[size='xsmall'] {
|
|
110
|
+
--btn-dimension: 32px;
|
|
111
|
+
--btn-icon-size: 20px;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
&[size='small'] {
|
|
115
|
+
--btn-dimension: 40px;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
&[size='medium'] {
|
|
119
|
+
/* Same as default styles */
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
&[size='large'] {
|
|
123
|
+
--btn-dimension: 56px;
|
|
124
|
+
--btn-icon-size: 28px;
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import {
|
|
2
|
+
LitElement, TemplateResult, html, unsafeCSS,
|
|
3
|
+
} from 'lit';
|
|
4
|
+
import { property } from 'lit/decorators.js';
|
|
5
|
+
import { validPropertyValues, defineCustomElement } from '@justeattakeaway/pie-webc-core';
|
|
6
|
+
import styles from './iconButton.scss?inline';
|
|
7
|
+
import {
|
|
8
|
+
IconButtonProps, sizes, variants,
|
|
9
|
+
} from './defs';
|
|
10
|
+
import '@justeattakeaway/pie-spinner';
|
|
11
|
+
|
|
12
|
+
// Valid values available to consumers
|
|
13
|
+
export * from './defs';
|
|
14
|
+
|
|
15
|
+
const componentSelector = 'pie-icon-button';
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* @tagname pie-icon-button
|
|
19
|
+
*/
|
|
20
|
+
export class PieIconButton extends LitElement implements IconButtonProps {
|
|
21
|
+
@property()
|
|
22
|
+
@validPropertyValues(componentSelector, sizes, 'medium')
|
|
23
|
+
public size?: IconButtonProps['size'] = 'medium';
|
|
24
|
+
|
|
25
|
+
@property()
|
|
26
|
+
@validPropertyValues(componentSelector, variants, 'primary')
|
|
27
|
+
public variant?: IconButtonProps['variant'] = 'primary';
|
|
28
|
+
|
|
29
|
+
@property({ type: Boolean })
|
|
30
|
+
public disabled? = false;
|
|
31
|
+
|
|
32
|
+
@property({ type: Boolean })
|
|
33
|
+
public isLoading? = false;
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Template for the loading state
|
|
37
|
+
*
|
|
38
|
+
* @private
|
|
39
|
+
*/
|
|
40
|
+
private renderSpinner (): TemplateResult {
|
|
41
|
+
const { variant, size, disabled } = this;
|
|
42
|
+
const spinnerSize = size === 'xsmall' ? 'small' : 'medium';
|
|
43
|
+
let spinnerVariant = 'brand';
|
|
44
|
+
if (variant?.includes('secondary')) spinnerVariant = 'secondary';
|
|
45
|
+
if ((variant === 'primary' && !disabled) || variant === 'ghost-inverse') spinnerVariant = 'inverse';
|
|
46
|
+
|
|
47
|
+
return html`
|
|
48
|
+
<pie-spinner
|
|
49
|
+
size="${spinnerSize}"
|
|
50
|
+
variant="${spinnerVariant}"
|
|
51
|
+
</pie-spinner>`;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
render () {
|
|
55
|
+
const {
|
|
56
|
+
disabled, size, variant, isLoading,
|
|
57
|
+
} = this;
|
|
58
|
+
|
|
59
|
+
// The inline SVG is temporary until we have a proper icon integration
|
|
60
|
+
return html`
|
|
61
|
+
<button
|
|
62
|
+
class="o-iconBtn"
|
|
63
|
+
size="${size}"
|
|
64
|
+
variant="${variant}"
|
|
65
|
+
?disabled="${disabled}"
|
|
66
|
+
?isLoading="${isLoading}">
|
|
67
|
+
${isLoading ? this.renderSpinner() : html`<slot></slot>`}
|
|
68
|
+
</button>`;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
// Renders a `CSSResult` generated from SCSS by Vite
|
|
72
|
+
static styles = unsafeCSS(styles);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
defineCustomElement(componentSelector, PieIconButton);
|
|
76
|
+
|
|
77
|
+
declare global {
|
|
78
|
+
interface HTMLElementTagNameMap {
|
|
79
|
+
[componentSelector]: PieIconButton;
|
|
80
|
+
}
|
|
81
|
+
}
|