@justeattakeaway/pie-card 0.14.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 ADDED
@@ -0,0 +1,85 @@
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-card">
7
+ <img alt="GitHub Workflow Status" src="https://img.shields.io/npm/v/@justeattakeaway/pie-card.svg">
8
+ </a>
9
+ </p>
10
+
11
+ # Table of Contents
12
+
13
+ 1. [Introduction](#pie-card)
14
+ 2. [Installation](#installation)
15
+ 3. [Importing the component](#importing-the-component)
16
+ 4. [Peer Dependencies](#peer-dependencies)
17
+ 5. [Props](#props)
18
+ 6. [Contributing](#contributing)
19
+
20
+ ## pie-card
21
+
22
+ `pie-card` is a Web Component built using the Lit library.
23
+
24
+ This component can be easily integrated into various frontend frameworks and customized through a set of properties.
25
+
26
+
27
+ ## Installation
28
+
29
+ To install `pie-card` in your application, run the following on your command line:
30
+
31
+ ```bash
32
+ # npm
33
+ $ npm i @justeattakeaway/pie-card
34
+
35
+ # yarn
36
+ $ yarn add @justeattakeaway/pie-card
37
+ ```
38
+
39
+ 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).
40
+
41
+
42
+ ### Importing the component
43
+
44
+ ```js
45
+ // default
46
+ import { PieCard } from '@justeattakeaway/pie-card';
47
+
48
+ // react
49
+ import { PieCard } from '@justeattakeaway/pie-card/dist/react';
50
+ ```
51
+
52
+
53
+ ## Peer Dependencies
54
+
55
+ > [!IMPORTANT]
56
+ > When using `pie-card`, 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.
57
+
58
+ ## Props
59
+
60
+ | Property | Type | Default | Description |
61
+ |---|---|-------------|------------------------------------------------------------------------------------------------------------------------------|
62
+ | tag | `String` | `button` | What HTML element the card should be such as a or button
63
+ | variant | `string` | `default` | What style variant the card should be such as default, outline, inverse or outline-inverse |
64
+ | disabled | `boolean` | `false` | When true, the card is disabled. |
65
+ | href | `string` | `undefined` | The URL that the card should point to (this will not take effect unless the card is a link). |
66
+ | target | `string` | `undefined` | Where to display the linked URL such as _self, _blank, _parent or _top (this will not take effect unless the card is a link). |
67
+ | rel | `string` | `undefined` | What the relationship of the linked URL is (this will not take effect unless the card is a link). |
68
+ | aria | `object` | `undefined` | The ARIA labels used for various parts of the card. |
69
+ | isDraggable | `boolean` | `false` | Sets a grab/grabbing cursor when set to true. **Note:** the actual dragging capabilities should be implemented by the consuming application. |
70
+ | padding | `String` | `undefined` | Sets the padding of the card. Can be either a single value or two values separated by commas. Setting a single value adds padding to all sides of the card, whereas setting two values will set the "topBottom, leftRight" padding. e.g `'a'` or `'a, b'` |
71
+
72
+
73
+ In your markup or JSX, you can then use these to set the properties for the `pie-card` component:
74
+
75
+ ```html
76
+ <!-- Native HTML -->
77
+ <pie-card disabled href="/foo/bar" rel="noopener" target="_blank"></pie-card>
78
+
79
+ <!-- JSX -->
80
+ <PieCard disabled href="/foo/bar" rel="noopener" target="_blank"></PieCard>
81
+ ```
82
+
83
+ ## Contributing
84
+
85
+ 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,94 @@
1
+ import type { CSSResult } from 'lit';
2
+ import type { LitElement } from 'lit';
3
+ import type { TemplateResult } from 'lit';
4
+
5
+ export declare type AriaProps = {
6
+ label?: string;
7
+ };
8
+
9
+ export declare interface CardProps {
10
+ /**
11
+ * The ARIA labels used for various parts of the card.
12
+ */
13
+ aria?: AriaProps;
14
+ /**
15
+ * When true, the card is disabled.
16
+ */
17
+ disabled: boolean;
18
+ /**
19
+ * The URL that the card should point to (this will not take effect unless the card is a link).
20
+ */
21
+ href?: string;
22
+ /**
23
+ * Where to display the linked URL such as _self, _blank, _parent or _top (this will not take effect unless the card is a link).
24
+ */
25
+ target?: string;
26
+ /**
27
+ * What the relationship of the linked URL is (this will not take effect unless the card is a link).
28
+ */
29
+ rel?: string;
30
+ /**
31
+ * What style variant the card should be such as default or inverse.
32
+ */
33
+ variant: typeof variants[number];
34
+ /**
35
+ * Allows the consumer to set draggable css styles (grab/grabbing cursor styles).
36
+ */
37
+ isDraggable: boolean;
38
+ /**
39
+ * What HTML element the card should be such as `a` or `button`.
40
+ */
41
+ tag?: typeof tags[number];
42
+ /**
43
+ * Sets the padding of the card. Can be either a single value or two values
44
+ * separated by a comma. Setting a single value adds padding to all sides of the card,
45
+ * whereas setting two values will set the "paddingX, paddingY" padding. e.g `'a'` or `'a, b'`
46
+ */
47
+ padding?: PaddingValue | `${PaddingValue},${PaddingValue}`;
48
+ }
49
+
50
+ declare type PaddingValue = typeof spacingTokens[number];
51
+
52
+ export declare const paddingValues: string[];
53
+
54
+ /**
55
+ * @tagname pie-card
56
+ */
57
+ export declare class PieCard extends LitElement implements CardProps {
58
+ tag: CardProps['tag'];
59
+ variant: CardProps['variant'];
60
+ href?: string;
61
+ target?: string;
62
+ rel?: string;
63
+ disabled: boolean;
64
+ aria: CardProps['aria'];
65
+ isDraggable: boolean;
66
+ padding?: CardProps['padding'];
67
+ /**
68
+ * Renders the card as an anchor element.
69
+ *
70
+ * @private
71
+ */
72
+ private renderAnchor;
73
+ /**
74
+ * Generates padding for the component based on `padding` values passed
75
+ * by the consumer.
76
+ *
77
+ *
78
+ * Example: 'a' or 'a, b'
79
+ * Single values i.e `'a'` applies to all sides and `'a, b'` applies to: top & bottom, left & right
80
+ *
81
+ * @private
82
+ */
83
+ private generatePaddingCSS;
84
+ render(): TemplateResult;
85
+ static styles: CSSResult;
86
+ }
87
+
88
+ declare const spacingTokens: readonly ["a", "b", "c", "d", "e", "f", "g"];
89
+
90
+ export declare const tags: readonly ["a", "button"];
91
+
92
+ export declare const variants: readonly ["default", "outline", "inverse", "outline-inverse"];
93
+
94
+ export { }
package/dist/index.js ADDED
@@ -0,0 +1,142 @@
1
+ import { unsafeCSS as p, LitElement as m, html as g, nothing as s } from "lit";
2
+ import { property as n } from "lit/decorators.js";
3
+ const u = (t, r, a) => function(e, c) {
4
+ const i = `#${c}`;
5
+ Object.defineProperty(e, c, {
6
+ get() {
7
+ return this[i];
8
+ },
9
+ set(b) {
10
+ const h = this[i];
11
+ r.includes(b) ? this[i] = b : (console.error(
12
+ `<${t}> Invalid value "${b}" provided for property "${c}".`,
13
+ `Must be one of: ${r.join(" | ")}.`,
14
+ `Falling back to default value: "${a}"`
15
+ ), this[i] = a), this.requestUpdate(c, h);
16
+ }
17
+ });
18
+ };
19
+ function $(t, r) {
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, r);
21
+ }
22
+ const y = `.c-card[isdraggable]{cursor:grab}.c-card[isdraggable]:active{cursor:grabbing}*,*:before,*:after{box-sizing:border-box}.c-card{--card-bg-color: var(--dt-color-container-default);--card-color: var(--dt-color-content-default);--card-radius: var(--dt-radius-rounded-c);--card-border-color: transparent;display:block;position:relative;color:var(--card-color);background-color:var(--card-bg-color);border:1px solid var(--card-border-color);border-radius:var(--card-radius);cursor:pointer;user-select:none;outline:none;text-decoration:none}.c-card[variant=default]{box-shadow:var(--dt-elevation-card)}.c-card[variant=default]:hover:not([disabled]){--hover-modifier: calc(-1 * var(--dt-color-hover-01));--card-bg-color: hsl(var(--dt-color-container-default-h), var(--dt-color-container-default-s), calc(var(--dt-color-container-default-l) + var(--hover-modifier)))}.c-card[variant=default]:active:not([disabled]){--active-modifier: calc(-1 * var(--dt-color-active-01));--card-bg-color: hsl(var(--dt-color-container-default-h), var(--dt-color-container-default-s), calc(var(--dt-color-container-default-l) + var(--active-modifier)))}.c-card[variant=outline]{border-color:var(--dt-color-border-strong)}.c-card[variant=outline]:hover:not([disabled]){--hover-modifier: calc(-1 * var(--dt-color-hover-01));--card-bg-color: hsl(var(--dt-color-container-default-h), var(--dt-color-container-default-s), calc(var(--dt-color-container-default-l) + var(--hover-modifier)))}.c-card[variant=outline]:active:not([disabled]){--active-modifier: calc(-1 * var(--dt-color-active-01));--card-bg-color: hsl(var(--dt-color-container-default-h), var(--dt-color-container-default-s), calc(var(--dt-color-container-default-l) + var(--active-modifier)))}.c-card[variant=inverse]{--card-bg-color: var(--dt-color-container-dark);--card-color: var(--dt-color-content-inverse);box-shadow:var(--dt-elevation-dark-card)}.c-card[variant=inverse]:hover:not([disabled]){--hover-modifier: var(--dt-color-hover-01);--card-bg-color: hsl(var(--dt-color-container-dark-h), var(--dt-color-container-dark-s), calc(var(--dt-color-container-dark-l) + var(--hover-modifier)))}.c-card[variant=inverse]:active:not([disabled]){--active-modifier: var(--dt-color-active-01);--card-bg-color: hsl(var(--dt-color-container-dark-h), var(--dt-color-container-dark-s), calc(var(--dt-color-container-dark-l) + var(--active-modifier)))}.c-card[variant=outline-inverse]{--card-bg-color: var(--dt-color-container-dark);--card-color: var(--dt-color-content-inverse);border-color:var(--dt-color-border-inverse)}.c-card[variant=outline-inverse]:hover:not([disabled]){--hover-modifier: var(--dt-color-hover-01);--card-bg-color: hsl(var(--dt-color-container-dark-h), var(--dt-color-container-dark-s), calc(var(--dt-color-container-dark-l) + var(--hover-modifier)))}.c-card[variant=outline-inverse]:active:not([disabled]){--active-modifier: var(--dt-color-active-01);--card-bg-color: hsl(var(--dt-color-container-dark-h), var(--dt-color-container-dark-s), calc(var(--dt-color-container-dark-l) + var(--active-modifier)))}.c-card[disabled]{--card-bg-color: var(--dt-color-disabled-01);cursor:not-allowed}.c-card[disabled] ::slotted(*){color:var(--dt-color-content-disabled)}.c-card[disabled] img{opacity:.5}.c-card[disabled][variant=inverse],.c-card[disabled][variant=outline-inverse]{--card-bg-color: var(--dt-color-disabled-01-inverse)}.c-card:focus-visible{box-shadow:0 0 0 2px var(--dt-color-focus-inner),0 0 0 4px var(--dt-color-focus-outer);outline:none}
23
+ `, S = ["default", "outline", "inverse", "outline-inverse"], k = ["a", "button"], f = ["a", "b", "c", "d", "e", "f", "g"], P = f.flatMap((t) => [t, ...f.map((r) => `${t},${r}`)]);
24
+ var x = Object.defineProperty, C = Object.getOwnPropertyDescriptor, l = (t, r, a, o) => {
25
+ for (var e = o > 1 ? void 0 : o ? C(r, a) : r, c = t.length - 1, i; c >= 0; c--)
26
+ (i = t[c]) && (e = (o ? i(r, a, e) : i(e)) || e);
27
+ return o && e && x(r, a, e), e;
28
+ };
29
+ const v = "pie-card";
30
+ class d extends m {
31
+ constructor() {
32
+ super(...arguments), this.tag = "button", this.variant = "default", this.disabled = !1, this.isDraggable = !1;
33
+ }
34
+ /**
35
+ * Renders the card as an anchor element.
36
+ *
37
+ * @private
38
+ */
39
+ renderAnchor() {
40
+ var a;
41
+ const r = this.generatePaddingCSS();
42
+ return g`
43
+ <a
44
+ class="c-card"
45
+ data-test-id="pie-card"
46
+ tag=${this.tag}
47
+ ?isDraggable="${this.isDraggable}"
48
+ variant=${this.variant}
49
+ ?disabled=${this.disabled}
50
+ href=${this.href || s}
51
+ target=${this.target || s}
52
+ rel=${this.rel || s}
53
+ role="link"
54
+ aria-label=${((a = this.aria) == null ? void 0 : a.label) || s}
55
+ aria-disabled=${this.disabled ? "true" : "false"}
56
+ style=${r || s}>
57
+ <slot></slot>
58
+ </div>
59
+ </a>`;
60
+ }
61
+ /**
62
+ * Generates padding for the component based on `padding` values passed
63
+ * by the consumer.
64
+ *
65
+ *
66
+ * Example: 'a' or 'a, b'
67
+ * Single values i.e `'a'` applies to all sides and `'a, b'` applies to: top & bottom, left & right
68
+ *
69
+ * @private
70
+ */
71
+ generatePaddingCSS() {
72
+ const { padding: r } = this;
73
+ let a = "";
74
+ if (!r)
75
+ return "";
76
+ const o = r.split(",").map((e) => e.trim()).filter((e) => /^[a-g]$/.test(e));
77
+ return o.length > 0 && o.length <= 2 && (a += `var(--dt-spacing-${o[0]})`, o.length > 1 && (a += ` var(--dt-spacing-${o[1]})`)), a ? `padding: ${a}` : "";
78
+ }
79
+ render() {
80
+ const {
81
+ variant: r,
82
+ disabled: a,
83
+ tag: o,
84
+ aria: e,
85
+ isDraggable: c
86
+ } = this, i = this.generatePaddingCSS();
87
+ return o === "a" ? this.renderAnchor() : g`
88
+ <div
89
+ class="c-card"
90
+ data-test-id="pie-card"
91
+ tag=${o}
92
+ ?isDraggable="${c}"
93
+ variant=${r}
94
+ ?disabled=${a}
95
+ role="button"
96
+ tabindex="0"
97
+ aria-label=${(e == null ? void 0 : e.label) || s}
98
+ aria-disabled=${a ? "true" : "false"}
99
+ style=${i || s}>
100
+ <slot></slot>
101
+ </div>
102
+ </div>`;
103
+ }
104
+ }
105
+ d.styles = p(y);
106
+ l([
107
+ n(),
108
+ u(v, k, "button")
109
+ ], d.prototype, "tag", 2);
110
+ l([
111
+ n(),
112
+ u(v, S, "default")
113
+ ], d.prototype, "variant", 2);
114
+ l([
115
+ n({ type: String, reflect: !0 })
116
+ ], d.prototype, "href", 2);
117
+ l([
118
+ n({ type: String, reflect: !0 })
119
+ ], d.prototype, "target", 2);
120
+ l([
121
+ n({ type: String, reflect: !0 })
122
+ ], d.prototype, "rel", 2);
123
+ l([
124
+ n({ type: Boolean })
125
+ ], d.prototype, "disabled", 2);
126
+ l([
127
+ n({ type: Object })
128
+ ], d.prototype, "aria", 2);
129
+ l([
130
+ n({ type: Boolean })
131
+ ], d.prototype, "isDraggable", 2);
132
+ l([
133
+ n({ type: String }),
134
+ u(v, P, void 0)
135
+ ], d.prototype, "padding", 2);
136
+ $(v, d);
137
+ export {
138
+ d as PieCard,
139
+ P as paddingValues,
140
+ k as tags,
141
+ S as variants
142
+ };
@@ -0,0 +1,97 @@
1
+ import type { CSSResult } from 'lit';
2
+ import type { LitElement } from 'lit';
3
+ import type { ReactWebComponent } from '@lit-labs/react';
4
+ import type { TemplateResult } from 'lit';
5
+
6
+ export declare type AriaProps = {
7
+ label?: string;
8
+ };
9
+
10
+ export declare interface CardProps {
11
+ /**
12
+ * The ARIA labels used for various parts of the card.
13
+ */
14
+ aria?: AriaProps;
15
+ /**
16
+ * When true, the card is disabled.
17
+ */
18
+ disabled: boolean;
19
+ /**
20
+ * The URL that the card should point to (this will not take effect unless the card is a link).
21
+ */
22
+ href?: string;
23
+ /**
24
+ * Where to display the linked URL such as _self, _blank, _parent or _top (this will not take effect unless the card is a link).
25
+ */
26
+ target?: string;
27
+ /**
28
+ * What the relationship of the linked URL is (this will not take effect unless the card is a link).
29
+ */
30
+ rel?: string;
31
+ /**
32
+ * What style variant the card should be such as default or inverse.
33
+ */
34
+ variant: typeof variants[number];
35
+ /**
36
+ * Allows the consumer to set draggable css styles (grab/grabbing cursor styles).
37
+ */
38
+ isDraggable: boolean;
39
+ /**
40
+ * What HTML element the card should be such as `a` or `button`.
41
+ */
42
+ tag?: typeof tags[number];
43
+ /**
44
+ * Sets the padding of the card. Can be either a single value or two values
45
+ * separated by a comma. Setting a single value adds padding to all sides of the card,
46
+ * whereas setting two values will set the "paddingX, paddingY" padding. e.g `'a'` or `'a, b'`
47
+ */
48
+ padding?: PaddingValue | `${PaddingValue},${PaddingValue}`;
49
+ }
50
+
51
+ declare type PaddingValue = typeof spacingTokens[number];
52
+
53
+ export declare const paddingValues: string[];
54
+
55
+ export declare const PieCard: ReactWebComponent<PieCard_2, {}>;
56
+
57
+ /**
58
+ * @tagname pie-card
59
+ */
60
+ declare class PieCard_2 extends LitElement implements CardProps {
61
+ tag: CardProps['tag'];
62
+ variant: CardProps['variant'];
63
+ href?: string;
64
+ target?: string;
65
+ rel?: string;
66
+ disabled: boolean;
67
+ aria: CardProps['aria'];
68
+ isDraggable: boolean;
69
+ padding?: CardProps['padding'];
70
+ /**
71
+ * Renders the card as an anchor element.
72
+ *
73
+ * @private
74
+ */
75
+ private renderAnchor;
76
+ /**
77
+ * Generates padding for the component based on `padding` values passed
78
+ * by the consumer.
79
+ *
80
+ *
81
+ * Example: 'a' or 'a, b'
82
+ * Single values i.e `'a'` applies to all sides and `'a, b'` applies to: top & bottom, left & right
83
+ *
84
+ * @private
85
+ */
86
+ private generatePaddingCSS;
87
+ render(): TemplateResult;
88
+ static styles: CSSResult;
89
+ }
90
+
91
+ declare const spacingTokens: readonly ["a", "b", "c", "d", "e", "f", "g"];
92
+
93
+ export declare const tags: readonly ["a", "button"];
94
+
95
+ export declare const variants: readonly ["default", "outline", "inverse", "outline-inverse"];
96
+
97
+ export { }
package/dist/react.js ADDED
@@ -0,0 +1,72 @@
1
+ import * as C from "react";
2
+ import { PieCard as E } from "./index.js";
3
+ import { paddingValues as D, tags as G, variants as O } from "./index.js";
4
+ import "lit";
5
+ import "lit/decorators.js";
6
+ /**
7
+ * @license
8
+ * Copyright 2018 Google LLC
9
+ * SPDX-License-Identifier: BSD-3-Clause
10
+ */
11
+ const M = /* @__PURE__ */ new Set(["children", "localName", "ref", "style", "className"]), w = /* @__PURE__ */ new WeakMap(), P = (c, r, p, m, h) => {
12
+ const s = h == null ? void 0 : h[r];
13
+ s === void 0 || p === m ? p == null && r in HTMLElement.prototype ? c.removeAttribute(r) : c[r] = p : ((n, t, u) => {
14
+ let o = w.get(n);
15
+ o === void 0 && w.set(n, o = /* @__PURE__ */ new Map());
16
+ let a = o.get(t);
17
+ u !== void 0 ? a === void 0 ? (o.set(t, a = { handleEvent: u }), n.addEventListener(t, a)) : a.handleEvent = u : a !== void 0 && (o.delete(t), n.removeEventListener(t, a));
18
+ })(c, s, p);
19
+ };
20
+ function b(c = window.React, r, p, m, h) {
21
+ let s, n, t;
22
+ if (r === void 0) {
23
+ const l = c;
24
+ ({ tagName: n, elementClass: t, events: m, displayName: h } = l), s = l.react;
25
+ } else
26
+ s = c, t = p, n = r;
27
+ const u = s.Component, o = s.createElement, a = new Set(Object.keys(m ?? {}));
28
+ class f extends u {
29
+ constructor() {
30
+ super(...arguments), this.o = null;
31
+ }
32
+ t(e) {
33
+ if (this.o !== null)
34
+ for (const v in this.i)
35
+ P(this.o, v, this.props[v], e ? e[v] : void 0, m);
36
+ }
37
+ componentDidMount() {
38
+ this.t();
39
+ }
40
+ componentDidUpdate(e) {
41
+ this.t(e);
42
+ }
43
+ render() {
44
+ const { _$Gl: e, ...v } = this.props;
45
+ this.h !== e && (this.u = (i) => {
46
+ e !== null && ((d, g) => {
47
+ typeof d == "function" ? d(g) : d.current = g;
48
+ })(e, i), this.o = i, this.h = e;
49
+ }), this.i = {};
50
+ const y = { ref: this.u };
51
+ for (const [i, d] of Object.entries(v))
52
+ M.has(i) ? y[i === "className" ? "class" : i] = d : a.has(i) || i in t.prototype ? this.i[i] = d : y[i] = d;
53
+ return o(n, y);
54
+ }
55
+ }
56
+ f.displayName = h ?? t.name;
57
+ const N = s.forwardRef((l, e) => o(f, { ...l, _$Gl: e }, l == null ? void 0 : l.children));
58
+ return N.displayName = f.displayName, N;
59
+ }
60
+ const $ = b({
61
+ displayName: "PieCard",
62
+ elementClass: E,
63
+ react: C,
64
+ tagName: "pie-card",
65
+ events: {}
66
+ });
67
+ export {
68
+ $ as PieCard,
69
+ D as paddingValues,
70
+ G as tags,
71
+ O as variants
72
+ };
package/package.json ADDED
@@ -0,0 +1,42 @@
1
+ {
2
+ "name": "@justeattakeaway/pie-card",
3
+ "version": "0.14.0",
4
+ "description": "PIE Design System Card 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-card && run -T vite build",
16
+ "lint:scripts": "run -T eslint .",
17
+ "lint:scripts:fix": "yarn lint:scripts --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:browsers": "npx playwright test -c ./playwright-lit.config.ts",
24
+ "test:browsers:ci": "yarn test:browsers",
25
+ "test:visual": "run -T cross-env-shell PERCY_TOKEN=${PERCY_TOKEN_PIE_CARD} percy exec --allowed-hostname cloudfront.net -- npx playwright test -c ./playwright-lit-visual.config.ts",
26
+ "test:visual:ci": "yarn test:visual"
27
+ },
28
+ "author": "Just Eat Takeaway.com - Design System Team",
29
+ "license": "Apache-2.0",
30
+ "devDependencies": {
31
+ "@justeattakeaway/pie-components-config": "0.4.0"
32
+ },
33
+ "dependencies": {
34
+ "@justeattakeaway/pie-webc-core": "0.11.0"
35
+ },
36
+ "volta": {
37
+ "extends": "../../../package.json"
38
+ },
39
+ "sideEffects": [
40
+ "dist/*.js"
41
+ ]
42
+ }
package/src/card.scss ADDED
@@ -0,0 +1,104 @@
1
+ @use '@justeattakeaway/pie-css/scss' as p;
2
+
3
+ *,
4
+ *:before,
5
+ *:after {
6
+ box-sizing: border-box;
7
+ }
8
+
9
+ @mixin card-interactive-states($bg-color, $mode: 'default') {
10
+ &:hover:not([disabled]) {
11
+ @if $mode == 'inverse' {
12
+ --hover-modifier: var(--dt-color-hover-01);
13
+ } @else {
14
+ --hover-modifier: calc(-1 * var(--dt-color-hover-01));
15
+ }
16
+
17
+ --card-bg-color: hsl(var(#{$bg-color}-h), var(#{$bg-color}-s), calc(var(#{$bg-color}-l) + var(--hover-modifier)));
18
+ }
19
+
20
+ &:active:not([disabled]) {
21
+ @if $mode == 'inverse' {
22
+ --active-modifier: var(--dt-color-active-01);
23
+ } @else {
24
+ --active-modifier: calc(-1 * var(--dt-color-active-01));
25
+ }
26
+
27
+ --card-bg-color: hsl(var(#{$bg-color}-h), var(#{$bg-color}-s), calc(var(#{$bg-color}-l) + var(--active-modifier)));
28
+ }
29
+ }
30
+
31
+ .c-card {
32
+ --card-bg-color: var(--dt-color-container-default);
33
+ --card-color: var(--dt-color-content-default);
34
+ --card-radius: var(--dt-radius-rounded-c);
35
+ --card-border-color: transparent;
36
+
37
+ display: block;
38
+ position: relative;
39
+ color: var(--card-color);
40
+ background-color: var(--card-bg-color);
41
+ border: 1px solid var(--card-border-color);
42
+ border-radius: var(--card-radius);
43
+ cursor: pointer;
44
+ user-select: none;
45
+ outline: none;
46
+ text-decoration: none;
47
+
48
+ &[variant='default'] {
49
+ box-shadow: var(--dt-elevation-card);
50
+
51
+ @include card-interactive-states('--dt-color-container-default');
52
+ }
53
+
54
+ &[variant='outline'] {
55
+ border-color: var(--dt-color-border-strong);
56
+
57
+ @include card-interactive-states('--dt-color-container-default');
58
+ }
59
+
60
+ &[variant='inverse'] {
61
+ --card-bg-color: var(--dt-color-container-dark);
62
+ --card-color: var(--dt-color-content-inverse);
63
+
64
+ box-shadow: var(--dt-elevation-dark-card);
65
+
66
+ @include card-interactive-states('--dt-color-container-dark', 'inverse');
67
+ }
68
+
69
+ &[variant='outline-inverse'] {
70
+ --card-bg-color: var(--dt-color-container-dark);
71
+ --card-color: var(--dt-color-content-inverse);
72
+
73
+ border-color: var(--dt-color-border-inverse);
74
+
75
+ @include card-interactive-states('--dt-color-container-dark', 'inverse');
76
+ }
77
+
78
+ &[disabled] {
79
+ --card-bg-color: var(--dt-color-disabled-01);
80
+
81
+ cursor: not-allowed;
82
+
83
+ ::slotted(*) {
84
+ color: var(--dt-color-content-disabled);
85
+ }
86
+
87
+ img {
88
+ opacity: 0.5;
89
+ }
90
+
91
+ &[variant='inverse'],
92
+ &[variant='outline-inverse'] {
93
+ --card-bg-color: var(--dt-color-disabled-01-inverse);
94
+ }
95
+ }
96
+
97
+ &:focus-visible {
98
+ @include p.focus;
99
+ }
100
+
101
+ &[isdraggable] {
102
+ @extend %has-grab-cursor;
103
+ }
104
+ }
package/src/defs.ts ADDED
@@ -0,0 +1,60 @@
1
+ export const variants = ['default', 'outline', 'inverse', 'outline-inverse'] as const;
2
+ export const tags = ['a', 'button'] as const;
3
+
4
+ const spacingTokens = ['a', 'b', 'c', 'd', 'e', 'f', 'g'] as const;
5
+ export const paddingValues = spacingTokens.flatMap((first) => [first, ...spacingTokens.map((second) => `${first},${second}`)]);
6
+
7
+ type PaddingValue = typeof spacingTokens[number];
8
+
9
+ export type AriaProps = {
10
+ label?: string;
11
+ };
12
+
13
+ export interface CardProps {
14
+ /**
15
+ * The ARIA labels used for various parts of the card.
16
+ */
17
+ aria?: AriaProps;
18
+
19
+ /**
20
+ * When true, the card is disabled.
21
+ */
22
+ disabled: boolean;
23
+
24
+ /**
25
+ * The URL that the card should point to (this will not take effect unless the card is a link).
26
+ */
27
+ href?: string;
28
+
29
+ /**
30
+ * Where to display the linked URL such as _self, _blank, _parent or _top (this will not take effect unless the card is a link).
31
+ */
32
+ target?: string;
33
+
34
+ /**
35
+ * What the relationship of the linked URL is (this will not take effect unless the card is a link).
36
+ */
37
+ rel?: string;
38
+
39
+ /**
40
+ * What style variant the card should be such as default or inverse.
41
+ */
42
+ variant: typeof variants[number];
43
+
44
+ /**
45
+ * Allows the consumer to set draggable css styles (grab/grabbing cursor styles).
46
+ */
47
+ isDraggable: boolean;
48
+
49
+ /**
50
+ * What HTML element the card should be such as `a` or `button`.
51
+ */
52
+ tag?: typeof tags[number];
53
+
54
+ /**
55
+ * Sets the padding of the card. Can be either a single value or two values
56
+ * separated by a comma. Setting a single value adds padding to all sides of the card,
57
+ * whereas setting two values will set the "paddingX, paddingY" padding. e.g `'a'` or `'a, b'`
58
+ */
59
+ padding?: PaddingValue | `${PaddingValue},${PaddingValue}`;
60
+ }
package/src/index.ts ADDED
@@ -0,0 +1,161 @@
1
+ import {
2
+ html, LitElement, unsafeCSS, nothing, TemplateResult,
3
+ } from 'lit';
4
+ import { property } from 'lit/decorators.js';
5
+ import { validPropertyValues, defineCustomElement } from '@justeattakeaway/pie-webc-core';
6
+ import styles from './card.scss?inline';
7
+ import {
8
+ variants,
9
+ tags,
10
+ CardProps,
11
+ paddingValues,
12
+ } from './defs';
13
+
14
+ // Valid values available to consumers
15
+ export * from './defs';
16
+
17
+ const componentSelector = 'pie-card';
18
+
19
+ /**
20
+ * @tagname pie-card
21
+ */
22
+ export class PieCard extends LitElement implements CardProps {
23
+ @property()
24
+ @validPropertyValues(componentSelector, tags, 'button')
25
+ public tag: CardProps['tag'] = 'button';
26
+
27
+ @property()
28
+ @validPropertyValues(componentSelector, variants, 'default')
29
+ public variant: CardProps['variant'] = 'default';
30
+
31
+ @property({ type: String, reflect: true })
32
+ public href?: string;
33
+
34
+ @property({ type: String, reflect: true })
35
+ public target?: string;
36
+
37
+ @property({ type: String, reflect: true })
38
+ public rel?: string;
39
+
40
+ @property({ type: Boolean })
41
+ public disabled = false;
42
+
43
+ @property({ type: Object })
44
+ public aria: CardProps['aria'];
45
+
46
+ @property({ type: Boolean })
47
+ public isDraggable = false;
48
+
49
+ @property({ type: String })
50
+ @validPropertyValues(componentSelector, paddingValues, undefined)
51
+ public padding?: CardProps['padding'];
52
+
53
+ /**
54
+ * Renders the card as an anchor element.
55
+ *
56
+ * @private
57
+ */
58
+ private renderAnchor (): TemplateResult {
59
+ const paddingCSS = this.generatePaddingCSS();
60
+
61
+ return html`
62
+ <a
63
+ class="c-card"
64
+ data-test-id="pie-card"
65
+ tag=${this.tag}
66
+ ?isDraggable="${this.isDraggable}"
67
+ variant=${this.variant}
68
+ ?disabled=${this.disabled}
69
+ href=${this.href || nothing}
70
+ target=${this.target || nothing}
71
+ rel=${this.rel || nothing}
72
+ role="link"
73
+ aria-label=${this.aria?.label || nothing}
74
+ aria-disabled=${this.disabled ? 'true' : 'false'}
75
+ style=${paddingCSS || nothing}>
76
+ <slot></slot>
77
+ </div>
78
+ </a>`;
79
+ }
80
+
81
+ /**
82
+ * Generates padding for the component based on `padding` values passed
83
+ * by the consumer.
84
+ *
85
+ *
86
+ * Example: 'a' or 'a, b'
87
+ * Single values i.e `'a'` applies to all sides and `'a, b'` applies to: top & bottom, left & right
88
+ *
89
+ * @private
90
+ */
91
+ private generatePaddingCSS (): string {
92
+ const { padding } = this;
93
+ let paddingCSS = '';
94
+
95
+ // Check if padding is empty (null, undefined, or an empty string)
96
+ if (!padding) {
97
+ return '';
98
+ }
99
+
100
+ const paddingArray = padding
101
+ .split(',')
102
+ .map((item) => item.trim())
103
+ .filter((value) => /^[a-g]$/.test(value));
104
+
105
+ if (paddingArray.length > 0 && paddingArray.length <= 2) {
106
+ paddingCSS += `var(--dt-spacing-${paddingArray[0]})`;
107
+
108
+ if (paddingArray.length > 1) {
109
+ paddingCSS += ` var(--dt-spacing-${paddingArray[1]})`;
110
+ }
111
+ }
112
+
113
+ if (!paddingCSS) {
114
+ return '';
115
+ }
116
+
117
+ return `padding: ${paddingCSS}`;
118
+ }
119
+
120
+ render () {
121
+ const {
122
+ variant,
123
+ disabled,
124
+ tag,
125
+ aria,
126
+ isDraggable,
127
+ } = this;
128
+
129
+ const paddingCSS = this.generatePaddingCSS();
130
+
131
+ if (tag === 'a') return this.renderAnchor();
132
+
133
+ return html`
134
+ <div
135
+ class="c-card"
136
+ data-test-id="pie-card"
137
+ tag=${tag}
138
+ ?isDraggable="${isDraggable}"
139
+ variant=${variant}
140
+ ?disabled=${disabled}
141
+ role="button"
142
+ tabindex="0"
143
+ aria-label=${aria?.label || nothing}
144
+ aria-disabled=${disabled ? 'true' : 'false'}
145
+ style=${paddingCSS || nothing}>
146
+ <slot></slot>
147
+ </div>
148
+ </div>`;
149
+ }
150
+
151
+ // Renders a `CSSResult` generated from SCSS by Vite
152
+ static styles = unsafeCSS(styles);
153
+ }
154
+
155
+ defineCustomElement(componentSelector, PieCard);
156
+
157
+ declare global {
158
+ interface HTMLElementTagNameMap {
159
+ [componentSelector]: PieCard;
160
+ }
161
+ }