@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 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).
@@ -0,0 +1,9 @@
1
+ declare module '*.scss' {
2
+ const content: Record<string, string>;
3
+ export default content;
4
+ }
5
+
6
+ declare module '*.scss?inline' {
7
+ const content: Record<string, string>;
8
+ export default content;
9
+ }
@@ -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
+ };
@@ -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
+ }