@justeattakeaway/pie-list 0.1.0 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +40 -0
- package/custom-elements.json +139 -1
- package/dist/{PieElement-BsEd8lGj.js → PieElement-B3g_8vKy.js} +1 -1
- package/dist/index-KnN5fPmj.js +265 -0
- package/dist/index.js +13 -13
- package/dist/pie-list-item/defs.d.ts +24 -0
- package/dist/pie-list-item/defs.d.ts.map +1 -1
- package/dist/pie-list-item/index.d.ts +34 -0
- package/dist/pie-list-item/index.d.ts.map +1 -1
- package/dist/pie-list-item/index.js +3 -3
- package/dist/pie-list-item/react.js +5 -4
- package/package.json +5 -4
- package/src/list.scss +1 -5
- package/src/pie-list-item/defs.ts +30 -0
- package/src/pie-list-item/index.ts +128 -10
- package/src/pie-list-item/list-item.scss +28 -1
- package/dist/index-C0_lfUTv.js +0 -79
package/README.md
CHANGED
|
@@ -55,6 +55,8 @@ Ideally, you should install the component using the **`@justeattakeaway/pie-webc
|
|
|
55
55
|
| `isCompact` | `true`, `false` | Decreases the item height to save vertical space. See the [rules](#usage-notes-and-rules) below. | `false` |
|
|
56
56
|
| `isBold` | `true`, `false` | Sets the primary text to a bold font-weight. | `false` |
|
|
57
57
|
| `hasMedia` | `true`, `false` | **Required whenever you slot a media element (e.g. `pie-thumbnail`) into the item.** Reduces the block padding so single-line media sits correctly (this padding adjustment has no effect when `secondaryText` is set, but you should still set `hasMedia`). | `false` |
|
|
58
|
+
| `selectionType` | `"none"`, `"radio"`, `"checkbox"`, `"switch"` | Declares that the item hosts an interactive control in its `leading`/`trailing` slot, making the **whole row** a selectable target. Set it on each selectable row. Inside a `pie-radio-group`, the group lays the rows out as a divided list automatically. See [Selectable lists](#selectable-lists). | `"none"` |
|
|
59
|
+
| `disabled` | `true`, `false` | Marks the row as disabled: it takes the disabled styling and stops forwarding row clicks to its control. Set it alongside the slotted control's own `disabled` (the control still governs its own interactivity). No visible effect on a non-selectable (static) item. | `false` |
|
|
58
60
|
|
|
59
61
|
### Slots
|
|
60
62
|
|
|
@@ -68,6 +70,9 @@ Slots are provided by `pie-list-item`.
|
|
|
68
70
|
The permitted slotted elements are: a PIE WEBC icon, `pie-tag`, `pie-thumbnail`, `pie-avatar`*, `pie-switch`, and native HTML radio/checkbox inputs.
|
|
69
71
|
Some slotted content is designed with specific properties being used. So please read the entire readme to understand correct slot usage.
|
|
70
72
|
|
|
73
|
+
> [!NOTE]
|
|
74
|
+
> `pie-list` is a **static** container: it has no selection state or keyboard behaviour. For a **selectable** list, do not slot the controls into `pie-list`. Place `pie-list-item`s inside a [`pie-radio-group`](https://webc.pie.design/?path=/docs/components-radio-group--overview) (single-select) or a [`pie-checkbox-group`](https://webc.pie.design/?path=/docs/components-checkbox-group--overview) (multi-select) instead. See [Selectable lists](#selectable-lists) below.
|
|
75
|
+
|
|
71
76
|
> Slotted PIE icons are always sized by `pie-list-item` (24px). Consumers cannot override this size.
|
|
72
77
|
|
|
73
78
|
> \* `pie-avatar` is a permitted slot element but is not covered by usage examples here yet, as it is not ready for use in lists.
|
|
@@ -241,6 +246,40 @@ import '@justeattakeaway/pie-webc/components/thumbnail.js';
|
|
|
241
246
|
</pie-list>
|
|
242
247
|
```
|
|
243
248
|
|
|
249
|
+
### Selectable lists
|
|
250
|
+
|
|
251
|
+
`pie-list` itself is a static container with no selection or keyboard behaviour. To build a **selectable** list, do **not** put the controls in `pie-list`. Instead, place `pie-list-item`s inside a [`pie-radio-group`](https://webc.pie.design/?path=/docs/components-radio-group--overview) (single-select) with `selection-type="radio"`, and slot the control into each item's `leading` (or `trailing`) slot. The group lays the rows out as a divided list automatically.
|
|
252
|
+
|
|
253
|
+
`selection-type` on each **item** makes that row selectable:
|
|
254
|
+
|
|
255
|
+
- takes the correct **role** — `presentation` for `radio`/`checkbox` (so the group owns the controls directly), `listitem` for `switch` and `none`;
|
|
256
|
+
- provides its `primaryText`, `secondaryText` and `metaText` as the slotted control's **accessible name and description** (and `aria-hidden`s the now-duplicated visible text);
|
|
257
|
+
- **forwards a click** anywhere on the row to the control, so the whole row is a hit target;
|
|
258
|
+
- shows **hover and active** states on the row (suppressed when the item's `disabled` is set, or the group is disabled).
|
|
259
|
+
|
|
260
|
+
Provide the label through the item's `primaryText` — not as the control's own content. The group still owns the group-level semantics (its own role, shared `name`, selection coordination and group-disable).
|
|
261
|
+
|
|
262
|
+
Single-select (radios):
|
|
263
|
+
|
|
264
|
+
```js
|
|
265
|
+
import '@justeattakeaway/pie-webc/components/radio-group.js';
|
|
266
|
+
import '@justeattakeaway/pie-webc/components/radio.js';
|
|
267
|
+
import '@justeattakeaway/pie-webc/components/list-item.js';
|
|
268
|
+
```
|
|
269
|
+
|
|
270
|
+
```html
|
|
271
|
+
<!-- `selection-type="radio"` makes each row selectable and the group lays them out as a divided
|
|
272
|
+
list. `value` on the group selects the matching radio (here, Express). -->
|
|
273
|
+
<pie-radio-group name="delivery" value="express">
|
|
274
|
+
<pie-list-item selection-type="radio" primaryText="Standard delivery" secondaryText="3 to 5 working days" metaText="Free">
|
|
275
|
+
<pie-radio slot="leading" value="standard"></pie-radio>
|
|
276
|
+
</pie-list-item>
|
|
277
|
+
<pie-list-item selection-type="radio" primaryText="Express delivery" secondaryText="Next working day" metaText="£4.99">
|
|
278
|
+
<pie-radio slot="leading" value="express"></pie-radio>
|
|
279
|
+
</pie-list-item>
|
|
280
|
+
</pie-radio-group>
|
|
281
|
+
```
|
|
282
|
+
|
|
244
283
|
**For Native JS Applications, Vue, Angular, Svelte etc.:**
|
|
245
284
|
|
|
246
285
|
```js
|
|
@@ -272,6 +311,7 @@ To keep lists consistent and correct, follow these rules:
|
|
|
272
311
|
|
|
273
312
|
- **Always give `pie-list` an accessible name** with `aria-label` or `aria-labelledby` (use `aria-labelledby` when a visible heading exists). This is required for screen reader users to understand the list. See [Accessibility](#accessibility).
|
|
274
313
|
- **Provide `primaryText`** on every `pie-list-item`; it is the item's main line of content.
|
|
314
|
+
- **For selectable lists, use `pie-list-item` inside `pie-radio-group` or `pie-checkbox-group`, not `pie-list`.** `pie-list` is a static container with no selection or keyboard behaviour. See [Selectable lists](#selectable-lists).
|
|
275
315
|
- **`metaText` and the `trailing` slot are mutually exclusive.** If `metaText` is set, any `trailing` slot content is ignored. Choose one.
|
|
276
316
|
- **Slotted `pie-thumbnail` must use `size="40"`.** This is the only size that fits the list-item layout correctly.
|
|
277
317
|
- **Always set `hasMedia` when slotting media** (`pie-thumbnail`, and `pie-avatar` in future), whether or not the item has `secondaryText`. This guarantees the item has the correct block padding.
|
package/custom-elements.json
CHANGED
|
@@ -66,16 +66,32 @@
|
|
|
66
66
|
"kind": "javascript-module",
|
|
67
67
|
"path": "src/pie-list-item/defs.js",
|
|
68
68
|
"declarations": [
|
|
69
|
+
{
|
|
70
|
+
"kind": "variable",
|
|
71
|
+
"name": "selectionTypes",
|
|
72
|
+
"type": {
|
|
73
|
+
"text": "['none', 'radio', 'checkbox', 'switch']"
|
|
74
|
+
},
|
|
75
|
+
"default": "['none', 'radio', 'checkbox', 'switch']"
|
|
76
|
+
},
|
|
69
77
|
{
|
|
70
78
|
"kind": "variable",
|
|
71
79
|
"name": "defaultProps",
|
|
72
80
|
"type": {
|
|
73
81
|
"text": "DefaultProps"
|
|
74
82
|
},
|
|
75
|
-
"default": "{ isCompact: false, isBold: false, hasMedia: false, }"
|
|
83
|
+
"default": "{ isCompact: false, isBold: false, hasMedia: false, selectionType: 'none', disabled: false, }"
|
|
76
84
|
}
|
|
77
85
|
],
|
|
78
86
|
"exports": [
|
|
87
|
+
{
|
|
88
|
+
"kind": "js",
|
|
89
|
+
"name": "selectionTypes",
|
|
90
|
+
"declaration": {
|
|
91
|
+
"name": "selectionTypes",
|
|
92
|
+
"module": "src/pie-list-item/defs.js"
|
|
93
|
+
}
|
|
94
|
+
},
|
|
79
95
|
{
|
|
80
96
|
"kind": "js",
|
|
81
97
|
"name": "defaultProps",
|
|
@@ -94,6 +110,16 @@
|
|
|
94
110
|
"kind": "class",
|
|
95
111
|
"description": "",
|
|
96
112
|
"name": "PieListItem",
|
|
113
|
+
"slots": [
|
|
114
|
+
{
|
|
115
|
+
"description": "Content shown at the start of the item (for example an icon, avatar, or a slotted radio/checkbox).",
|
|
116
|
+
"name": "leading"
|
|
117
|
+
},
|
|
118
|
+
{
|
|
119
|
+
"description": "Content shown at the end of the item. Mutually exclusive with `metaText`.",
|
|
120
|
+
"name": "trailing"
|
|
121
|
+
}
|
|
122
|
+
],
|
|
97
123
|
"members": [
|
|
98
124
|
{
|
|
99
125
|
"kind": "field",
|
|
@@ -134,6 +160,110 @@
|
|
|
134
160
|
"name": "hasMedia",
|
|
135
161
|
"attribute": "hasMedia"
|
|
136
162
|
},
|
|
163
|
+
{
|
|
164
|
+
"kind": "field",
|
|
165
|
+
"name": "selectionType",
|
|
166
|
+
"attribute": "selection-type"
|
|
167
|
+
},
|
|
168
|
+
{
|
|
169
|
+
"kind": "field",
|
|
170
|
+
"name": "disabled",
|
|
171
|
+
"attribute": "disabled"
|
|
172
|
+
},
|
|
173
|
+
{
|
|
174
|
+
"kind": "field",
|
|
175
|
+
"name": "_parentDisabled",
|
|
176
|
+
"type": {
|
|
177
|
+
"text": "boolean"
|
|
178
|
+
},
|
|
179
|
+
"privacy": "private",
|
|
180
|
+
"default": "false"
|
|
181
|
+
},
|
|
182
|
+
{
|
|
183
|
+
"kind": "field",
|
|
184
|
+
"name": "_ariaProvider",
|
|
185
|
+
"privacy": "private"
|
|
186
|
+
},
|
|
187
|
+
{
|
|
188
|
+
"kind": "field",
|
|
189
|
+
"name": "_abortController",
|
|
190
|
+
"type": {
|
|
191
|
+
"text": "AbortController"
|
|
192
|
+
},
|
|
193
|
+
"privacy": "private"
|
|
194
|
+
},
|
|
195
|
+
{
|
|
196
|
+
"kind": "field",
|
|
197
|
+
"name": "_hasExplicitRole",
|
|
198
|
+
"type": {
|
|
199
|
+
"text": "boolean"
|
|
200
|
+
},
|
|
201
|
+
"privacy": "private",
|
|
202
|
+
"default": "false"
|
|
203
|
+
},
|
|
204
|
+
{
|
|
205
|
+
"kind": "field",
|
|
206
|
+
"name": "_isSelectable",
|
|
207
|
+
"type": {
|
|
208
|
+
"text": "boolean"
|
|
209
|
+
},
|
|
210
|
+
"privacy": "private",
|
|
211
|
+
"readonly": true
|
|
212
|
+
},
|
|
213
|
+
{
|
|
214
|
+
"kind": "field",
|
|
215
|
+
"name": "_ownedByGroup",
|
|
216
|
+
"type": {
|
|
217
|
+
"text": "boolean"
|
|
218
|
+
},
|
|
219
|
+
"privacy": "private",
|
|
220
|
+
"readonly": true
|
|
221
|
+
},
|
|
222
|
+
{
|
|
223
|
+
"kind": "field",
|
|
224
|
+
"name": "_isDisabled",
|
|
225
|
+
"type": {
|
|
226
|
+
"text": "boolean"
|
|
227
|
+
},
|
|
228
|
+
"privacy": "private",
|
|
229
|
+
"readonly": true
|
|
230
|
+
},
|
|
231
|
+
{
|
|
232
|
+
"kind": "field",
|
|
233
|
+
"name": "_control",
|
|
234
|
+
"type": {
|
|
235
|
+
"text": "HTMLElement | null"
|
|
236
|
+
},
|
|
237
|
+
"privacy": "private",
|
|
238
|
+
"readonly": true
|
|
239
|
+
},
|
|
240
|
+
{
|
|
241
|
+
"kind": "method",
|
|
242
|
+
"name": "_applyRole",
|
|
243
|
+
"privacy": "private",
|
|
244
|
+
"return": {
|
|
245
|
+
"type": {
|
|
246
|
+
"text": "void"
|
|
247
|
+
}
|
|
248
|
+
},
|
|
249
|
+
"description": "Sets the item's role from `selectionType`: `presentation` for radio/checkbox (so the group\nowns those controls directly), otherwise `listitem` (static items and switches). A role set\nexplicitly by the consumer is left untouched."
|
|
250
|
+
},
|
|
251
|
+
{
|
|
252
|
+
"kind": "field",
|
|
253
|
+
"name": "_providedAria",
|
|
254
|
+
"type": {
|
|
255
|
+
"text": "ContextualAria | undefined"
|
|
256
|
+
},
|
|
257
|
+
"privacy": "private",
|
|
258
|
+
"description": "The accessible name and description this item provides to its slotted control, stitched from\nits text. Only provided in a selectable list. Each control consumes this via `ariaContext`\nand decides how to apply it: `pie-radio` names its host (which carries `role=\"radio\"`),\nwhile `pie-checkbox` / `pie-switch` name their internal input (their host is role-less, so\n`aria-label` there would be invalid). Context reaches across the shadow boundary that\n`aria-labelledby` cannot.",
|
|
259
|
+
"readonly": true
|
|
260
|
+
},
|
|
261
|
+
{
|
|
262
|
+
"kind": "field",
|
|
263
|
+
"name": "_handleHostClick",
|
|
264
|
+
"privacy": "private",
|
|
265
|
+
"description": "Forwards a click anywhere on the row to the slotted control, so the whole item is a hit\ntarget. Skips clicks that already landed on the control, to avoid a double toggle."
|
|
266
|
+
},
|
|
137
267
|
{
|
|
138
268
|
"kind": "method",
|
|
139
269
|
"name": "_renderSecondaryText"
|
|
@@ -176,6 +306,14 @@
|
|
|
176
306
|
{
|
|
177
307
|
"name": "hasMedia",
|
|
178
308
|
"fieldName": "hasMedia"
|
|
309
|
+
},
|
|
310
|
+
{
|
|
311
|
+
"name": "selection-type",
|
|
312
|
+
"fieldName": "selectionType"
|
|
313
|
+
},
|
|
314
|
+
{
|
|
315
|
+
"name": "disabled",
|
|
316
|
+
"fieldName": "disabled"
|
|
179
317
|
}
|
|
180
318
|
],
|
|
181
319
|
"superclass": {
|
|
@@ -0,0 +1,265 @@
|
|
|
1
|
+
import { unsafeCSS as x, isServer as f, html as p, nothing as m } from "lit";
|
|
2
|
+
import { property as c, state as y } from "lit/decorators.js";
|
|
3
|
+
import { classMap as k } from "lit/directives/class-map.js";
|
|
4
|
+
import { validPropertyValues as _, safeCustomElement as T, ariaContext as I, parentDisabledContext as C } from "@justeattakeaway/pie-webc-core";
|
|
5
|
+
import { P as w } from "./PieElement-B3g_8vKy.js";
|
|
6
|
+
/**
|
|
7
|
+
* @license
|
|
8
|
+
* Copyright 2021 Google LLC
|
|
9
|
+
* SPDX-License-Identifier: BSD-3-Clause
|
|
10
|
+
*/
|
|
11
|
+
let g = class extends Event {
|
|
12
|
+
constructor(t, e, o, s) {
|
|
13
|
+
super("context-request", { bubbles: !0, composed: !0 }), this.context = t, this.contextTarget = e, this.callback = o, this.subscribe = s ?? !1;
|
|
14
|
+
}
|
|
15
|
+
};
|
|
16
|
+
/**
|
|
17
|
+
* @license
|
|
18
|
+
* Copyright 2021 Google LLC
|
|
19
|
+
* SPDX-License-Identifier: BSD-3-Clause
|
|
20
|
+
*/
|
|
21
|
+
let v = class {
|
|
22
|
+
constructor(t, e, o, s) {
|
|
23
|
+
if (this.subscribe = !1, this.provided = !1, this.value = void 0, this.t = (r, a) => {
|
|
24
|
+
this.unsubscribe && (this.unsubscribe !== a && (this.provided = !1, this.unsubscribe()), this.subscribe || this.unsubscribe()), this.value = r, this.host.requestUpdate(), this.provided && !this.subscribe || (this.provided = !0, this.callback && this.callback(r, a)), this.unsubscribe = a;
|
|
25
|
+
}, this.host = t, e.context !== void 0) {
|
|
26
|
+
const r = e;
|
|
27
|
+
this.context = r.context, this.callback = r.callback, this.subscribe = r.subscribe ?? !1;
|
|
28
|
+
} else this.context = e, this.callback = o, this.subscribe = s ?? !1;
|
|
29
|
+
this.host.addController(this);
|
|
30
|
+
}
|
|
31
|
+
hostConnected() {
|
|
32
|
+
this.dispatchRequest();
|
|
33
|
+
}
|
|
34
|
+
hostDisconnected() {
|
|
35
|
+
this.unsubscribe && (this.unsubscribe(), this.unsubscribe = void 0);
|
|
36
|
+
}
|
|
37
|
+
dispatchRequest() {
|
|
38
|
+
this.host.dispatchEvent(new g(this.context, this.host, this.t, this.subscribe));
|
|
39
|
+
}
|
|
40
|
+
};
|
|
41
|
+
/**
|
|
42
|
+
* @license
|
|
43
|
+
* Copyright 2021 Google LLC
|
|
44
|
+
* SPDX-License-Identifier: BSD-3-Clause
|
|
45
|
+
*/
|
|
46
|
+
class P {
|
|
47
|
+
get value() {
|
|
48
|
+
return this.o;
|
|
49
|
+
}
|
|
50
|
+
set value(t) {
|
|
51
|
+
this.setValue(t);
|
|
52
|
+
}
|
|
53
|
+
setValue(t, e = !1) {
|
|
54
|
+
const o = e || !Object.is(t, this.o);
|
|
55
|
+
this.o = t, o && this.updateObservers();
|
|
56
|
+
}
|
|
57
|
+
constructor(t) {
|
|
58
|
+
this.subscriptions = /* @__PURE__ */ new Map(), this.updateObservers = () => {
|
|
59
|
+
for (const [e, { disposer: o }] of this.subscriptions) e(this.o, o);
|
|
60
|
+
}, t !== void 0 && (this.value = t);
|
|
61
|
+
}
|
|
62
|
+
addCallback(t, e, o) {
|
|
63
|
+
if (!o) return void t(this.value);
|
|
64
|
+
this.subscriptions.has(t) || this.subscriptions.set(t, { disposer: () => {
|
|
65
|
+
this.subscriptions.delete(t);
|
|
66
|
+
}, consumerHost: e });
|
|
67
|
+
const { disposer: s } = this.subscriptions.get(t);
|
|
68
|
+
t(this.value, s);
|
|
69
|
+
}
|
|
70
|
+
clearCallbacks() {
|
|
71
|
+
this.subscriptions.clear();
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* @license
|
|
76
|
+
* Copyright 2021 Google LLC
|
|
77
|
+
* SPDX-License-Identifier: BSD-3-Clause
|
|
78
|
+
*/
|
|
79
|
+
class S extends Event {
|
|
80
|
+
constructor(t, e) {
|
|
81
|
+
super("context-provider", { bubbles: !0, composed: !0 }), this.context = t, this.contextTarget = e;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
class E extends P {
|
|
85
|
+
constructor(t, e, o) {
|
|
86
|
+
var s, r;
|
|
87
|
+
super(e.context !== void 0 ? e.initialValue : o), this.onContextRequest = (a) => {
|
|
88
|
+
if (a.context !== this.context) return;
|
|
89
|
+
const h = a.contextTarget ?? a.composedPath()[0];
|
|
90
|
+
h !== this.host && (a.stopPropagation(), this.addCallback(a.callback, h, a.subscribe));
|
|
91
|
+
}, this.onProviderRequest = (a) => {
|
|
92
|
+
if (a.context !== this.context || (a.contextTarget ?? a.composedPath()[0]) === this.host) return;
|
|
93
|
+
const h = /* @__PURE__ */ new Set();
|
|
94
|
+
for (const [b, { consumerHost: u }] of this.subscriptions) h.has(b) || (h.add(b), u.dispatchEvent(new g(this.context, u, b, !0)));
|
|
95
|
+
a.stopPropagation();
|
|
96
|
+
}, this.host = t, e.context !== void 0 ? this.context = e.context : this.context = e, this.attachListeners(), (r = (s = this.host).addController) == null || r.call(s, this);
|
|
97
|
+
}
|
|
98
|
+
attachListeners() {
|
|
99
|
+
this.host.addEventListener("context-request", this.onContextRequest), this.host.addEventListener("context-provider", this.onProviderRequest);
|
|
100
|
+
}
|
|
101
|
+
hostConnected() {
|
|
102
|
+
this.host.dispatchEvent(new S(this.context, this.host));
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
106
|
+
* @license
|
|
107
|
+
* Copyright 2022 Google LLC
|
|
108
|
+
* SPDX-License-Identifier: BSD-3-Clause
|
|
109
|
+
*/
|
|
110
|
+
function B({ context: i, subscribe: t }) {
|
|
111
|
+
return (e, o) => {
|
|
112
|
+
typeof o == "object" ? o.addInitializer((function() {
|
|
113
|
+
new v(this, { context: i, callback: (s) => {
|
|
114
|
+
e.set.call(this, s);
|
|
115
|
+
}, subscribe: t });
|
|
116
|
+
})) : e.constructor.addInitializer(((s) => {
|
|
117
|
+
new v(s, { context: i, callback: (r) => {
|
|
118
|
+
s[o] = r;
|
|
119
|
+
}, subscribe: t });
|
|
120
|
+
}));
|
|
121
|
+
};
|
|
122
|
+
}
|
|
123
|
+
const z = ["none", "radio", "checkbox", "switch"], d = {
|
|
124
|
+
isCompact: !1,
|
|
125
|
+
isBold: !1,
|
|
126
|
+
hasMedia: !1,
|
|
127
|
+
selectionType: "none",
|
|
128
|
+
disabled: !1
|
|
129
|
+
}, R = "*,*:after,*:before{box-sizing:inherit}:host{--list-item-inline-padding: var(--dt-spacing-d);--list-item-alignment: flex-start;--list-item-border: none;display:block}.c-listItem-container{--list-item-block-padding: var(--dt-spacing-d);--list-item-block-end-padding: calc(var(--list-item-block-padding) - var(--list-item-size-modifier));padding-inline-start:var(--list-item-inline-padding);padding-inline-end:var(--list-item-inline-padding);padding-block-start:var(--list-item-block-padding);padding-block-end:var(--list-item-block-end-padding, var(--list-item-block-padding));display:flex;align-items:var(--list-item-alignment);gap:var(--dt-spacing-c);min-height:56px;border-bottom:var(--list-item-border)}.c-listItem-container:has(.c-listItem-secondaryText){align-items:var(--list-item-alignment);min-height:76px}.c-listItem-container.is-compact{--list-item-block-padding: var(--dt-spacing-c);--list-item-alignment: center;align-items:var(--list-item-alignment);min-height:48px}.c-listItem-container.is-selectable:not(.is-disabled){--list-item-hover-bg: hsl(var(--dt-color-black-h), var(--dt-color-black-s), var(--dt-color-black-l), var(--dt-color-hover-01));--list-item-active-bg: hsl(var(--dt-color-black-h), var(--dt-color-black-s), var(--dt-color-black-l), var(--dt-color-active-01))}@supports (background-color: color-mix(in srgb,black,white)){.c-listItem-container.is-selectable:not(.is-disabled){--list-item-hover-bg: color-mix(in srgb, var(--dt-color-hover-01-bg) var(--dt-color-hover-01), transparent);--list-item-active-bg: color-mix(in srgb, var(--dt-color-active-01-bg) var(--dt-color-active-01), transparent)}}.c-listItem-container.is-selectable:not(.is-disabled){cursor:pointer}.c-listItem-container.is-selectable:not(.is-disabled):hover{background-color:var(--list-item-hover-bg)}.c-listItem-container.is-selectable:not(.is-disabled):active{background-color:var(--list-item-active-bg)}.c-listItem-container.has-media:has(.c-listItem-primaryText:only-child){--list-item-block-padding: var(--dt-spacing-b)}.c-listItem-text{flex:1}slot[name=trailing]::slotted(*),.c-listItem-metaText{padding-inline-start:var(--dt-spacing-a)}.c-listItem-leading,slot[name=leading],.c-listItem-trailing,slot[name=trailing]{display:contents}.c-listItem-text>*{display:block}.c-listItem-trailing{margin-inline-start:auto}.c-listItem-metaText{display:block;max-width:33.3333333333%}::slotted(.c-pieIcon){--icon-size-override: 24px }.c-listItem-primaryText{font-family:var(--dt-font-body-l-family);font-weight:var(--dt-font-body-l-weight);font-size:calc(var(--dt-font-body-l-size) * 1px);line-height:calc(var(--dt-font-body-l-line-height) * 1px);color:var(--dt-color-content-default)}.c-listItem-container.is-bold .c-listItem-primaryText{font-family:var(--dt-font-body-strong-l-family);font-weight:var(--dt-font-body-strong-l-weight);font-size:calc(var(--dt-font-body-strong-l-size) * 1px);line-height:calc(var(--dt-font-body-strong-l-line-height) * 1px)}.c-listItem-secondaryText,.c-listItem-metaText{font-family:var(--dt-font-body-s-family);font-weight:var(--dt-font-body-s-weight);font-size:calc(var(--dt-font-body-s-size) * 1px);line-height:calc(var(--dt-font-body-s-line-height) * 1px);color:var(--dt-color-content-subdued)}";
|
|
130
|
+
var q = Object.defineProperty, D = Object.getOwnPropertyDescriptor, l = (i, t, e, o) => {
|
|
131
|
+
for (var s = o > 1 ? void 0 : o ? D(t, e) : t, r = i.length - 1, a; r >= 0; r--)
|
|
132
|
+
(a = i[r]) && (s = (o ? a(t, e, s) : a(s)) || s);
|
|
133
|
+
return o && s && q(t, e, s), s;
|
|
134
|
+
};
|
|
135
|
+
const $ = "pie-list-item";
|
|
136
|
+
let n = class extends w {
|
|
137
|
+
constructor() {
|
|
138
|
+
super(...arguments), this.isCompact = d.isCompact, this.isBold = d.isBold, this.hasMedia = d.hasMedia, this.selectionType = d.selectionType, this.disabled = d.disabled, this._parentDisabled = !1, this._ariaProvider = f ? void 0 : new E(this, { context: I }), this._hasExplicitRole = !1, this._handleHostClick = (i) => {
|
|
139
|
+
if (!this._isSelectable || this._isDisabled) return;
|
|
140
|
+
const t = this._control;
|
|
141
|
+
!t || i.composedPath().includes(t) || (t.click(), t.focus());
|
|
142
|
+
};
|
|
143
|
+
}
|
|
144
|
+
get _isSelectable() {
|
|
145
|
+
return this.selectionType !== "none";
|
|
146
|
+
}
|
|
147
|
+
// radio/checkbox are owned by a selection group, which is why the item becomes `presentation`
|
|
148
|
+
// (so the group owns the controls directly) and the radio is named on its host. A switch has
|
|
149
|
+
// no group, so the item stays a `listitem`.
|
|
150
|
+
get _ownedByGroup() {
|
|
151
|
+
return this.selectionType === "radio" || this.selectionType === "checkbox";
|
|
152
|
+
}
|
|
153
|
+
// True when the row should be treated as disabled: either its own `disabled` prop is set, or the
|
|
154
|
+
// containing group is disabled (provided via context). Declarative and reactive, so the styling
|
|
155
|
+
// and row-click guard react without observing the slotted control.
|
|
156
|
+
get _isDisabled() {
|
|
157
|
+
return this.disabled || this._parentDisabled;
|
|
158
|
+
}
|
|
159
|
+
// The interactive control (radio/checkbox/switch) slotted into this item, if any. Used only by
|
|
160
|
+
// the client-side row-click handler.
|
|
161
|
+
get _control() {
|
|
162
|
+
return this.querySelector("pie-radio, pie-checkbox, pie-switch");
|
|
163
|
+
}
|
|
164
|
+
connectedCallback() {
|
|
165
|
+
super.connectedCallback(), this._hasExplicitRole = this.hasAttribute("role"), this._abortController = new AbortController(), this.addEventListener("click", this._handleHostClick, { signal: this._abortController.signal });
|
|
166
|
+
}
|
|
167
|
+
disconnectedCallback() {
|
|
168
|
+
super.disconnectedCallback(), this._abortController.abort();
|
|
169
|
+
}
|
|
170
|
+
updated() {
|
|
171
|
+
var i;
|
|
172
|
+
this._applyRole(), (i = this._ariaProvider) == null || i.setValue(this._providedAria);
|
|
173
|
+
}
|
|
174
|
+
/**
|
|
175
|
+
* Sets the item's role from `selectionType`: `presentation` for radio/checkbox (so the group
|
|
176
|
+
* owns those controls directly), otherwise `listitem` (static items and switches). A role set
|
|
177
|
+
* explicitly by the consumer is left untouched.
|
|
178
|
+
*/
|
|
179
|
+
_applyRole() {
|
|
180
|
+
this._hasExplicitRole || this.setAttribute("role", this._ownedByGroup ? "presentation" : "listitem");
|
|
181
|
+
}
|
|
182
|
+
/**
|
|
183
|
+
* The accessible name and description this item provides to its slotted control, stitched from
|
|
184
|
+
* its text. Only provided in a selectable list. Each control consumes this via `ariaContext`
|
|
185
|
+
* and decides how to apply it: `pie-radio` names its host (which carries `role="radio"`),
|
|
186
|
+
* while `pie-checkbox` / `pie-switch` name their internal input (their host is role-less, so
|
|
187
|
+
* `aria-label` there would be invalid). Context reaches across the shadow boundary that
|
|
188
|
+
* `aria-labelledby` cannot.
|
|
189
|
+
*/
|
|
190
|
+
get _providedAria() {
|
|
191
|
+
if (!this._isSelectable) return;
|
|
192
|
+
const i = [this.secondaryText, this.metaText].filter(Boolean).join(". ");
|
|
193
|
+
return { label: this.primaryText, description: i || void 0 };
|
|
194
|
+
}
|
|
195
|
+
_renderSecondaryText() {
|
|
196
|
+
const { secondaryText: i } = this;
|
|
197
|
+
return i ? p`<span class="c-listItem-secondaryText">${i}</span>` : m;
|
|
198
|
+
}
|
|
199
|
+
// metaText is another form of trailing content. The component can only ever display either slotted trailing content or the metaText string
|
|
200
|
+
_renderTrailingContent() {
|
|
201
|
+
const { metaText: i } = this;
|
|
202
|
+
return i ? p`<span class="c-listItem-metaText c-listItem-trailing" aria-hidden=${this._isSelectable ? "true" : m}>${i}</span>` : p`<div class="c-listItem-trailing"><slot name="trailing"></slot></div>`;
|
|
203
|
+
}
|
|
204
|
+
render() {
|
|
205
|
+
const { primaryText: i } = this, t = {
|
|
206
|
+
"c-listItem-container": !0,
|
|
207
|
+
"is-compact": this.isCompact,
|
|
208
|
+
"is-bold": this.isBold,
|
|
209
|
+
"has-media": this.hasMedia,
|
|
210
|
+
"is-selectable": this._isSelectable,
|
|
211
|
+
"is-disabled": this._isDisabled
|
|
212
|
+
};
|
|
213
|
+
return p`
|
|
214
|
+
<div class=${k(t)}>
|
|
215
|
+
<div class="c-listItem-leading">
|
|
216
|
+
<slot name="leading"></slot>
|
|
217
|
+
</div>
|
|
218
|
+
|
|
219
|
+
<div class="c-listItem-text" aria-hidden=${this._isSelectable ? "true" : m}>
|
|
220
|
+
<span class="c-listItem-primaryText">${i}</span>
|
|
221
|
+
${this._renderSecondaryText()}
|
|
222
|
+
</div>
|
|
223
|
+
|
|
224
|
+
${this._renderTrailingContent()}
|
|
225
|
+
</div>`;
|
|
226
|
+
}
|
|
227
|
+
};
|
|
228
|
+
n.styles = x(R);
|
|
229
|
+
l([
|
|
230
|
+
c({ type: String })
|
|
231
|
+
], n.prototype, "primaryText", 2);
|
|
232
|
+
l([
|
|
233
|
+
c({ type: String })
|
|
234
|
+
], n.prototype, "secondaryText", 2);
|
|
235
|
+
l([
|
|
236
|
+
c({ type: String })
|
|
237
|
+
], n.prototype, "metaText", 2);
|
|
238
|
+
l([
|
|
239
|
+
c({ type: Boolean })
|
|
240
|
+
], n.prototype, "isCompact", 2);
|
|
241
|
+
l([
|
|
242
|
+
c({ type: Boolean })
|
|
243
|
+
], n.prototype, "isBold", 2);
|
|
244
|
+
l([
|
|
245
|
+
c({ type: Boolean })
|
|
246
|
+
], n.prototype, "hasMedia", 2);
|
|
247
|
+
l([
|
|
248
|
+
c({ type: String, attribute: "selection-type" }),
|
|
249
|
+
_($, z, d.selectionType)
|
|
250
|
+
], n.prototype, "selectionType", 2);
|
|
251
|
+
l([
|
|
252
|
+
c({ type: Boolean })
|
|
253
|
+
], n.prototype, "disabled", 2);
|
|
254
|
+
l([
|
|
255
|
+
B({ context: C, subscribe: !0 }),
|
|
256
|
+
y()
|
|
257
|
+
], n.prototype, "_parentDisabled", 2);
|
|
258
|
+
n = l([
|
|
259
|
+
T("pie-list-item")
|
|
260
|
+
], n);
|
|
261
|
+
export {
|
|
262
|
+
n as P,
|
|
263
|
+
d,
|
|
264
|
+
z as s
|
|
265
|
+
};
|
package/dist/index.js
CHANGED
|
@@ -1,23 +1,23 @@
|
|
|
1
|
-
import { html as
|
|
2
|
-
import { P as
|
|
3
|
-
import { RtlMixin as
|
|
4
|
-
const
|
|
5
|
-
var
|
|
6
|
-
for (var
|
|
7
|
-
(o =
|
|
8
|
-
return
|
|
1
|
+
import { html as n, unsafeCSS as m } from "lit";
|
|
2
|
+
import { P as f } from "./PieElement-B3g_8vKy.js";
|
|
3
|
+
import { RtlMixin as d, safeCustomElement as p } from "@justeattakeaway/pie-webc-core";
|
|
4
|
+
const c = "*,*:after,*:before{box-sizing:inherit}:host{display:block}:host ::slotted(pie-list-item:not(:last-of-type)){--list-item-size-modifier: 1px;--list-item-border: var(--list-item-size-modifier) solid var(--dt-color-divider-default)}";
|
|
5
|
+
var b = Object.getOwnPropertyDescriptor, u = (s, r, a, l) => {
|
|
6
|
+
for (var t = l > 1 ? void 0 : l ? b(r, a) : r, e = s.length - 1, o; e >= 0; e--)
|
|
7
|
+
(o = s[e]) && (t = o(t) || t);
|
|
8
|
+
return t;
|
|
9
9
|
};
|
|
10
|
-
let i = class extends
|
|
10
|
+
let i = class extends d(f) {
|
|
11
11
|
connectedCallback() {
|
|
12
12
|
super.connectedCallback(), this.hasAttribute("role") || this.setAttribute("role", "list");
|
|
13
13
|
}
|
|
14
14
|
render() {
|
|
15
|
-
return
|
|
15
|
+
return n`<slot></slot>`;
|
|
16
16
|
}
|
|
17
17
|
};
|
|
18
|
-
i.styles =
|
|
19
|
-
i =
|
|
20
|
-
|
|
18
|
+
i.styles = m(c);
|
|
19
|
+
i = u([
|
|
20
|
+
p("pie-list")
|
|
21
21
|
], i);
|
|
22
22
|
export {
|
|
23
23
|
i as PieList
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import { ComponentDefaultProps } from '@justeattakeaway/pie-webc-core';
|
|
2
|
+
export declare const selectionTypes: readonly ["none", "radio", "checkbox", "switch"];
|
|
3
|
+
export type SelectionType = typeof selectionTypes[number];
|
|
2
4
|
export interface ListItemProps {
|
|
3
5
|
/**
|
|
4
6
|
* **Required:** Provides an overview of the content.
|
|
@@ -28,6 +30,28 @@ export interface ListItemProps {
|
|
|
28
30
|
* **Note**: This has no effect when `secondaryText` is set, and should not be combined with `isCompact`.
|
|
29
31
|
*/
|
|
30
32
|
hasMedia?: boolean;
|
|
33
|
+
/**
|
|
34
|
+
* The kind of interactive control this item hosts in its `leading` or `trailing` slot. This
|
|
35
|
+
* makes the whole row a selectable target: the item takes the appropriate role, provides its
|
|
36
|
+
* text as the control's accessible name/description, hides the duplicated visible text, and
|
|
37
|
+
* forwards row clicks to the control.
|
|
38
|
+
*
|
|
39
|
+
* - `none` (default) - a static, non-selectable list item (`role="listitem"`).
|
|
40
|
+
* - `radio` - hosts a `pie-radio` (used inside a `pie-radio-group`); the item is `presentation`.
|
|
41
|
+
* - `checkbox` - hosts a `pie-checkbox` (used inside a `pie-checkbox-group`); the item is `presentation`.
|
|
42
|
+
* - `switch` - hosts a `pie-switch`; there is no group, so the item stays `role="listitem"`.
|
|
43
|
+
*
|
|
44
|
+
* Set this on each selectable row. When the rows sit inside a `pie-radio-group`, the group lays
|
|
45
|
+
* them out as a divided list automatically; this prop governs the row's role and behaviour.
|
|
46
|
+
*/
|
|
47
|
+
selectionType?: typeof selectionTypes[number];
|
|
48
|
+
/**
|
|
49
|
+
* Marks the row as disabled: it takes on the disabled styling and stops forwarding row clicks to
|
|
50
|
+
* its control. Set it alongside the slotted control's own `disabled` (the control still governs
|
|
51
|
+
* its own interactivity and keyboard behaviour). Has no visible effect on a non-selectable
|
|
52
|
+
* (static) item.
|
|
53
|
+
*/
|
|
54
|
+
disabled?: boolean;
|
|
31
55
|
}
|
|
32
56
|
export type DefaultProps = ComponentDefaultProps<ListItemProps, keyof Omit<ListItemProps, 'primaryText' | 'secondaryText' | 'metaText'>>;
|
|
33
57
|
export declare const defaultProps: DefaultProps;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"defs.d.ts","sourceRoot":"","sources":["../../src/pie-list-item/defs.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,qBAAqB,EAAE,MAAM,gCAAgC,CAAC;AAE5E,MAAM,WAAW,aAAa;IAC1B;;OAEG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB;;OAEG;IACH,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB;;OAEG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAA;IAEjB;;;;OAIG;IACH,SAAS,CAAC,EAAE,OAAO,CAAA;IAEnB;;OAEG;IACH,MAAM,CAAC,EAAE,OAAO,CAAA;IAEhB;;;;OAIG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAA;CACrB;AAED,MAAM,MAAM,YAAY,GAAG,qBAAqB,CAAC,aAAa,EAAE,MAAM,IAAI,CAAC,aAAa,EAAE,aAAa,GAAG,eAAe,GAAG,UAAU,CAAC,CAAC,CAAC;AAEzI,eAAO,MAAM,YAAY,EAAE,
|
|
1
|
+
{"version":3,"file":"defs.d.ts","sourceRoot":"","sources":["../../src/pie-list-item/defs.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,qBAAqB,EAAE,MAAM,gCAAgC,CAAC;AAE5E,eAAO,MAAM,cAAc,kDAAmD,CAAC;AAE/E,MAAM,MAAM,aAAa,GAAG,OAAO,cAAc,CAAC,MAAM,CAAC,CAAC;AAE1D,MAAM,WAAW,aAAa;IAC1B;;OAEG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB;;OAEG;IACH,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB;;OAEG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAA;IAEjB;;;;OAIG;IACH,SAAS,CAAC,EAAE,OAAO,CAAA;IAEnB;;OAEG;IACH,MAAM,CAAC,EAAE,OAAO,CAAA;IAEhB;;;;OAIG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAA;IAElB;;;;;;;;;;;;;OAaG;IACH,aAAa,CAAC,EAAE,OAAO,cAAc,CAAC,MAAM,CAAC,CAAA;IAE7C;;;;;OAKG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAA;CACrB;AAED,MAAM,MAAM,YAAY,GAAG,qBAAqB,CAAC,aAAa,EAAE,MAAM,IAAI,CAAC,aAAa,EAAE,aAAa,GAAG,eAAe,GAAG,UAAU,CAAC,CAAC,CAAC;AAEzI,eAAO,MAAM,YAAY,EAAE,YAM1B,CAAC"}
|
|
@@ -4,6 +4,8 @@ import { ListItemProps } from './defs';
|
|
|
4
4
|
declare const componentSelector = "pie-list-item";
|
|
5
5
|
/**
|
|
6
6
|
* @tagname pie-list-item
|
|
7
|
+
* @slot leading - Content shown at the start of the item (for example an icon, avatar, or a slotted radio/checkbox).
|
|
8
|
+
* @slot trailing - Content shown at the end of the item. Mutually exclusive with `metaText`.
|
|
7
9
|
*/
|
|
8
10
|
export declare class PieListItem extends PieElement implements ListItemProps {
|
|
9
11
|
primaryText: ListItemProps['primaryText'];
|
|
@@ -12,7 +14,39 @@ export declare class PieListItem extends PieElement implements ListItemProps {
|
|
|
12
14
|
isCompact: boolean;
|
|
13
15
|
isBold: boolean;
|
|
14
16
|
hasMedia: boolean;
|
|
17
|
+
selectionType: "checkbox" | "none" | "radio" | "switch";
|
|
18
|
+
disabled: boolean;
|
|
19
|
+
private _parentDisabled;
|
|
20
|
+
private _ariaProvider;
|
|
21
|
+
private _abortController;
|
|
22
|
+
private _hasExplicitRole;
|
|
23
|
+
private get _isSelectable();
|
|
24
|
+
private get _ownedByGroup();
|
|
25
|
+
private get _isDisabled();
|
|
26
|
+
private get _control();
|
|
15
27
|
connectedCallback(): void;
|
|
28
|
+
disconnectedCallback(): void;
|
|
29
|
+
protected updated(): void;
|
|
30
|
+
/**
|
|
31
|
+
* Sets the item's role from `selectionType`: `presentation` for radio/checkbox (so the group
|
|
32
|
+
* owns those controls directly), otherwise `listitem` (static items and switches). A role set
|
|
33
|
+
* explicitly by the consumer is left untouched.
|
|
34
|
+
*/
|
|
35
|
+
private _applyRole;
|
|
36
|
+
/**
|
|
37
|
+
* The accessible name and description this item provides to its slotted control, stitched from
|
|
38
|
+
* its text. Only provided in a selectable list. Each control consumes this via `ariaContext`
|
|
39
|
+
* and decides how to apply it: `pie-radio` names its host (which carries `role="radio"`),
|
|
40
|
+
* while `pie-checkbox` / `pie-switch` name their internal input (their host is role-less, so
|
|
41
|
+
* `aria-label` there would be invalid). Context reaches across the shadow boundary that
|
|
42
|
+
* `aria-labelledby` cannot.
|
|
43
|
+
*/
|
|
44
|
+
private get _providedAria();
|
|
45
|
+
/**
|
|
46
|
+
* Forwards a click anywhere on the row to the slotted control, so the whole item is a hit
|
|
47
|
+
* target. Skips clicks that already landed on the control, to avoid a double toggle.
|
|
48
|
+
*/
|
|
49
|
+
private _handleHostClick;
|
|
16
50
|
_renderSecondaryText(): import('lit-html').TemplateResult<1> | typeof nothing;
|
|
17
51
|
_renderTrailingContent(): import('lit-html').TemplateResult<1>;
|
|
18
52
|
render(): import('lit-html').TemplateResult<1>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/pie-list-item/index.ts"],"names":[],"mappings":"AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/pie-list-item/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACa,OAAO,EAC1B,MAAM,KAAK,CAAC;AAWb,OAAO,EAAE,UAAU,EAAE,MAAM,yDAAyD,CAAC;AACrF,OAAO,EAAE,KAAK,aAAa,EAAgC,MAAM,QAAQ,CAAC;AAG1E,QAAA,MAAM,iBAAiB,kBAAkB,CAAC;AAE1C;;;;GAIG;AACH,qBACa,WAAY,SAAQ,UAAW,YAAW,aAAa;IAE5D,WAAW,EAAG,aAAa,CAAC,aAAa,CAAC,CAAC;IAG3C,aAAa,EAAE,aAAa,CAAC,eAAe,CAAC,CAAC;IAG9C,QAAQ,EAAE,aAAa,CAAC,UAAU,CAAC,CAAC;IAGpC,SAAS,UAA0B;IAGnC,MAAM,UAAuB;IAG7B,QAAQ,UAAyB;IAIjC,aAAa,2CAA8B;IAG3C,QAAQ,UAAyB;IAMrC,OAAO,CAAC,eAAe,CAAS;IAYhC,OAAO,CAAC,aAAa,CAA8E;IAEnG,OAAO,CAAC,gBAAgB,CAAmB;IAE3C,OAAO,CAAC,gBAAgB,CAAS;IAEjC,OAAO,KAAK,aAAa,GAExB;IAKD,OAAO,KAAK,aAAa,GAExB;IAKD,OAAO,KAAK,WAAW,GAEtB;IAID,OAAO,KAAK,QAAQ,GAEnB;IAED,iBAAiB;IAUjB,oBAAoB;IAKpB,SAAS,CAAC,OAAO;IAKjB;;;;OAIG;IACH,OAAO,CAAC,UAAU;IAKlB;;;;;;;OAOG;IACH,OAAO,KAAK,aAAa,GAMxB;IAED;;;OAGG;IACH,OAAO,CAAC,gBAAgB,CAQtB;IAEF,oBAAoB;IAUpB,sBAAsB;IAStB,MAAM;IA4BN,MAAM,CAAC,MAAM,0BAAqB;CACrC;AAED,OAAO,CAAC,MAAM,CAAC;IACX,UAAU,qBAAqB;QAC3B,CAAC,iBAAiB,CAAC,EAAE,WAAW,CAAC;KACpC;CACJ"}
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import "lit";
|
|
2
2
|
import "lit/decorators.js";
|
|
3
|
-
import "@justeattakeaway/pie-webc-core";
|
|
4
|
-
import "../PieElement-BsEd8lGj.js";
|
|
5
3
|
import "lit/directives/class-map.js";
|
|
6
|
-
import { P as s } from "../index-
|
|
4
|
+
import { P as s } from "../index-KnN5fPmj.js";
|
|
5
|
+
import "@justeattakeaway/pie-webc-core";
|
|
6
|
+
import "../PieElement-B3g_8vKy.js";
|
|
7
7
|
export {
|
|
8
8
|
s as PieListItem
|
|
9
9
|
};
|
|
@@ -1,15 +1,16 @@
|
|
|
1
1
|
import * as e from "react";
|
|
2
2
|
import { createComponent as t } from "@lit/react";
|
|
3
|
-
import { P as
|
|
4
|
-
import { d as c } from "../index-
|
|
3
|
+
import { P as s } from "../index-KnN5fPmj.js";
|
|
4
|
+
import { d as c, s as n } from "../index-KnN5fPmj.js";
|
|
5
5
|
const i = t({
|
|
6
6
|
displayName: "PieListItem",
|
|
7
|
-
elementClass:
|
|
7
|
+
elementClass: s,
|
|
8
8
|
react: e,
|
|
9
9
|
tagName: "pie-list-item",
|
|
10
10
|
events: {}
|
|
11
11
|
}), a = i;
|
|
12
12
|
export {
|
|
13
13
|
a as PieListItem,
|
|
14
|
-
c as defaultProps
|
|
14
|
+
c as defaultProps,
|
|
15
|
+
n as selectionTypes
|
|
15
16
|
};
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@justeattakeaway/pie-list",
|
|
3
3
|
"description": "PIE Design System List built using Web Components",
|
|
4
|
-
"version": "0.
|
|
4
|
+
"version": "0.2.0",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
7
7
|
"module": "dist/index.js",
|
|
@@ -38,11 +38,12 @@
|
|
|
38
38
|
"license": "Apache-2.0",
|
|
39
39
|
"devDependencies": {
|
|
40
40
|
"@justeattakeaway/pie-components-config": "0.21.3",
|
|
41
|
-
"@justeattakeaway/pie-css": "1.
|
|
42
|
-
"@justeattakeaway/pie-monorepo-utils": "0.9.
|
|
41
|
+
"@justeattakeaway/pie-css": "1.3.1",
|
|
42
|
+
"@justeattakeaway/pie-monorepo-utils": "0.9.7"
|
|
43
43
|
},
|
|
44
44
|
"dependencies": {
|
|
45
|
-
"@justeattakeaway/pie-webc-core": "
|
|
45
|
+
"@justeattakeaway/pie-webc-core": "16.1.0",
|
|
46
|
+
"@lit/context": "1.1.6"
|
|
46
47
|
},
|
|
47
48
|
"customElements": "custom-elements.json",
|
|
48
49
|
"sideEffects": [
|
package/src/list.scss
CHANGED
|
@@ -3,9 +3,5 @@
|
|
|
3
3
|
:host {
|
|
4
4
|
display: block;
|
|
5
5
|
|
|
6
|
-
|
|
7
|
-
// This allows list-items following other list-items to have 1px stripped off of their padding to account for the added border.
|
|
8
|
-
--list-item-size-modifier: 1px;
|
|
9
|
-
--list-item-border-override: var(--list-item-size-modifier) solid var(--dt-color-divider-default);
|
|
10
|
-
}
|
|
6
|
+
@include p.list-item-divider;
|
|
11
7
|
}
|
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
import { type ComponentDefaultProps } from '@justeattakeaway/pie-webc-core';
|
|
2
2
|
|
|
3
|
+
export const selectionTypes = ['none', 'radio', 'checkbox', 'switch'] as const;
|
|
4
|
+
|
|
5
|
+
export type SelectionType = typeof selectionTypes[number];
|
|
6
|
+
|
|
3
7
|
export interface ListItemProps {
|
|
4
8
|
/**
|
|
5
9
|
* **Required:** Provides an overview of the content.
|
|
@@ -32,6 +36,30 @@ export interface ListItemProps {
|
|
|
32
36
|
* **Note**: This has no effect when `secondaryText` is set, and should not be combined with `isCompact`.
|
|
33
37
|
*/
|
|
34
38
|
hasMedia?: boolean
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* The kind of interactive control this item hosts in its `leading` or `trailing` slot. This
|
|
42
|
+
* makes the whole row a selectable target: the item takes the appropriate role, provides its
|
|
43
|
+
* text as the control's accessible name/description, hides the duplicated visible text, and
|
|
44
|
+
* forwards row clicks to the control.
|
|
45
|
+
*
|
|
46
|
+
* - `none` (default) - a static, non-selectable list item (`role="listitem"`).
|
|
47
|
+
* - `radio` - hosts a `pie-radio` (used inside a `pie-radio-group`); the item is `presentation`.
|
|
48
|
+
* - `checkbox` - hosts a `pie-checkbox` (used inside a `pie-checkbox-group`); the item is `presentation`.
|
|
49
|
+
* - `switch` - hosts a `pie-switch`; there is no group, so the item stays `role="listitem"`.
|
|
50
|
+
*
|
|
51
|
+
* Set this on each selectable row. When the rows sit inside a `pie-radio-group`, the group lays
|
|
52
|
+
* them out as a divided list automatically; this prop governs the row's role and behaviour.
|
|
53
|
+
*/
|
|
54
|
+
selectionType?: typeof selectionTypes[number]
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Marks the row as disabled: it takes on the disabled styling and stops forwarding row clicks to
|
|
58
|
+
* its control. Set it alongside the slotted control's own `disabled` (the control still governs
|
|
59
|
+
* its own interactivity and keyboard behaviour). Has no visible effect on a non-selectable
|
|
60
|
+
* (static) item.
|
|
61
|
+
*/
|
|
62
|
+
disabled?: boolean
|
|
35
63
|
}
|
|
36
64
|
|
|
37
65
|
export type DefaultProps = ComponentDefaultProps<ListItemProps, keyof Omit<ListItemProps, 'primaryText' | 'secondaryText' | 'metaText'>>;
|
|
@@ -40,4 +68,6 @@ export const defaultProps: DefaultProps = {
|
|
|
40
68
|
isCompact: false,
|
|
41
69
|
isBold: false,
|
|
42
70
|
hasMedia: false,
|
|
71
|
+
selectionType: 'none',
|
|
72
|
+
disabled: false,
|
|
43
73
|
};
|
|
@@ -1,15 +1,26 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
html, isServer, nothing, unsafeCSS,
|
|
3
|
+
} from 'lit';
|
|
4
|
+
import { property, state } from 'lit/decorators.js';
|
|
5
5
|
import { classMap } from 'lit/directives/class-map.js';
|
|
6
|
-
import {
|
|
6
|
+
import { consume, ContextProvider } from '@lit/context';
|
|
7
|
+
import {
|
|
8
|
+
safeCustomElement,
|
|
9
|
+
validPropertyValues,
|
|
10
|
+
parentDisabledContext,
|
|
11
|
+
ariaContext,
|
|
12
|
+
type ContextualAria,
|
|
13
|
+
} from '@justeattakeaway/pie-webc-core';
|
|
14
|
+
import { PieElement } from '@justeattakeaway/pie-webc-core/src/internals/PieElement';
|
|
15
|
+
import { type ListItemProps, defaultProps, selectionTypes } from './defs';
|
|
7
16
|
import styles from './list-item.scss?inline';
|
|
8
17
|
|
|
9
18
|
const componentSelector = 'pie-list-item';
|
|
10
19
|
|
|
11
20
|
/**
|
|
12
21
|
* @tagname pie-list-item
|
|
22
|
+
* @slot leading - Content shown at the start of the item (for example an icon, avatar, or a slotted radio/checkbox).
|
|
23
|
+
* @slot trailing - Content shown at the end of the item. Mutually exclusive with `metaText`.
|
|
13
24
|
*/
|
|
14
25
|
@safeCustomElement('pie-list-item')
|
|
15
26
|
export class PieListItem extends PieElement implements ListItemProps {
|
|
@@ -31,14 +42,119 @@ export class PieListItem extends PieElement implements ListItemProps {
|
|
|
31
42
|
@property({ type: Boolean })
|
|
32
43
|
hasMedia = defaultProps.hasMedia;
|
|
33
44
|
|
|
45
|
+
@property({ type: String, attribute: 'selection-type' })
|
|
46
|
+
@validPropertyValues(componentSelector, selectionTypes, defaultProps.selectionType)
|
|
47
|
+
selectionType = defaultProps.selectionType;
|
|
48
|
+
|
|
49
|
+
@property({ type: Boolean })
|
|
50
|
+
disabled = defaultProps.disabled;
|
|
51
|
+
|
|
52
|
+
// Whether a disabling ancestor (e.g. `pie-radio-group`) has provided its disabled state.
|
|
53
|
+
// Defaults to false when there is no provider (a standalone item or a static list).
|
|
54
|
+
@consume({ context: parentDisabledContext, subscribe: true })
|
|
55
|
+
@state()
|
|
56
|
+
private _parentDisabled = false;
|
|
57
|
+
|
|
58
|
+
// Provides this item's accessible name/description down to its slotted control via the shared
|
|
59
|
+
// aria context, which the control consumes and applies to the element carrying its semantics
|
|
60
|
+
// (the internal input for pie-checkbox / pie-switch). See `ariaContext` in pie-webc-core.
|
|
61
|
+
//
|
|
62
|
+
// Guarded with `isServer`: `@lit/context`'s ContextProvider attaches `context-request`
|
|
63
|
+
// listeners to the host in its constructor (via `host.addEventListener`). During SSR/prerender
|
|
64
|
+
// the element is constructed without a DOM host, so that call throws
|
|
65
|
+
// ("host.addEventListener is not a function") and breaks the build. The provider is client-only
|
|
66
|
+
// anyway (context is delivered after `connectedCallback`, which SSR never runs), so it is safe
|
|
67
|
+
// to skip on the server.
|
|
68
|
+
private _ariaProvider = isServer ? undefined : new ContextProvider(this, { context: ariaContext });
|
|
69
|
+
|
|
70
|
+
private _abortController!: AbortController;
|
|
71
|
+
|
|
72
|
+
private _hasExplicitRole = false;
|
|
73
|
+
|
|
74
|
+
private get _isSelectable (): boolean {
|
|
75
|
+
return this.selectionType !== 'none';
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
// radio/checkbox are owned by a selection group, which is why the item becomes `presentation`
|
|
79
|
+
// (so the group owns the controls directly) and the radio is named on its host. A switch has
|
|
80
|
+
// no group, so the item stays a `listitem`.
|
|
81
|
+
private get _ownedByGroup (): boolean {
|
|
82
|
+
return this.selectionType === 'radio' || this.selectionType === 'checkbox';
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
// True when the row should be treated as disabled: either its own `disabled` prop is set, or the
|
|
86
|
+
// containing group is disabled (provided via context). Declarative and reactive, so the styling
|
|
87
|
+
// and row-click guard react without observing the slotted control.
|
|
88
|
+
private get _isDisabled (): boolean {
|
|
89
|
+
return this.disabled || this._parentDisabled;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
// The interactive control (radio/checkbox/switch) slotted into this item, if any. Used only by
|
|
93
|
+
// the client-side row-click handler.
|
|
94
|
+
private get _control (): HTMLElement | null {
|
|
95
|
+
return this.querySelector('pie-radio, pie-checkbox, pie-switch');
|
|
96
|
+
}
|
|
97
|
+
|
|
34
98
|
connectedCallback () {
|
|
35
99
|
super.connectedCallback();
|
|
36
100
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
101
|
+
// Respect a role the consumer set explicitly; otherwise we manage it from `selectionType`.
|
|
102
|
+
this._hasExplicitRole = this.hasAttribute('role');
|
|
103
|
+
|
|
104
|
+
this._abortController = new AbortController();
|
|
105
|
+
this.addEventListener('click', this._handleHostClick, { signal: this._abortController.signal });
|
|
40
106
|
}
|
|
41
107
|
|
|
108
|
+
disconnectedCallback () {
|
|
109
|
+
super.disconnectedCallback();
|
|
110
|
+
this._abortController.abort();
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
protected updated () {
|
|
114
|
+
this._applyRole();
|
|
115
|
+
this._ariaProvider?.setValue(this._providedAria);
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
/**
|
|
119
|
+
* Sets the item's role from `selectionType`: `presentation` for radio/checkbox (so the group
|
|
120
|
+
* owns those controls directly), otherwise `listitem` (static items and switches). A role set
|
|
121
|
+
* explicitly by the consumer is left untouched.
|
|
122
|
+
*/
|
|
123
|
+
private _applyRole (): void {
|
|
124
|
+
if (this._hasExplicitRole) return;
|
|
125
|
+
this.setAttribute('role', this._ownedByGroup ? 'presentation' : 'listitem');
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
/**
|
|
129
|
+
* The accessible name and description this item provides to its slotted control, stitched from
|
|
130
|
+
* its text. Only provided in a selectable list. Each control consumes this via `ariaContext`
|
|
131
|
+
* and decides how to apply it: `pie-radio` names its host (which carries `role="radio"`),
|
|
132
|
+
* while `pie-checkbox` / `pie-switch` name their internal input (their host is role-less, so
|
|
133
|
+
* `aria-label` there would be invalid). Context reaches across the shadow boundary that
|
|
134
|
+
* `aria-labelledby` cannot.
|
|
135
|
+
*/
|
|
136
|
+
private get _providedAria (): ContextualAria | undefined {
|
|
137
|
+
if (!this._isSelectable) return undefined;
|
|
138
|
+
|
|
139
|
+
const description = [this.secondaryText, this.metaText].filter(Boolean).join('. ');
|
|
140
|
+
|
|
141
|
+
return { label: this.primaryText, description: description || undefined };
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
/**
|
|
145
|
+
* Forwards a click anywhere on the row to the slotted control, so the whole item is a hit
|
|
146
|
+
* target. Skips clicks that already landed on the control, to avoid a double toggle.
|
|
147
|
+
*/
|
|
148
|
+
private _handleHostClick = (event: MouseEvent): void => {
|
|
149
|
+
if (!this._isSelectable || this._isDisabled) return;
|
|
150
|
+
|
|
151
|
+
const control = this._control;
|
|
152
|
+
if (!control || event.composedPath().includes(control)) return;
|
|
153
|
+
|
|
154
|
+
control.click();
|
|
155
|
+
control.focus();
|
|
156
|
+
};
|
|
157
|
+
|
|
42
158
|
_renderSecondaryText () {
|
|
43
159
|
const { secondaryText } = this;
|
|
44
160
|
if (secondaryText) {
|
|
@@ -52,7 +168,7 @@ export class PieListItem extends PieElement implements ListItemProps {
|
|
|
52
168
|
_renderTrailingContent () {
|
|
53
169
|
const { metaText } = this;
|
|
54
170
|
if (metaText) {
|
|
55
|
-
return html`<span class="c-listItem-metaText c-listItem-trailing">${metaText}</span>`;
|
|
171
|
+
return html`<span class="c-listItem-metaText c-listItem-trailing" aria-hidden=${this._isSelectable ? 'true' : nothing}>${metaText}</span>`;
|
|
56
172
|
}
|
|
57
173
|
|
|
58
174
|
return html`<div class="c-listItem-trailing"><slot name="trailing"></slot></div>`;
|
|
@@ -66,6 +182,8 @@ export class PieListItem extends PieElement implements ListItemProps {
|
|
|
66
182
|
'is-compact': this.isCompact,
|
|
67
183
|
'is-bold': this.isBold,
|
|
68
184
|
'has-media': this.hasMedia,
|
|
185
|
+
'is-selectable': this._isSelectable,
|
|
186
|
+
'is-disabled': this._isDisabled,
|
|
69
187
|
};
|
|
70
188
|
|
|
71
189
|
return html`
|
|
@@ -74,7 +192,7 @@ export class PieListItem extends PieElement implements ListItemProps {
|
|
|
74
192
|
<slot name="leading"></slot>
|
|
75
193
|
</div>
|
|
76
194
|
|
|
77
|
-
<div class="c-listItem-text">
|
|
195
|
+
<div class="c-listItem-text" aria-hidden=${this._isSelectable ? 'true' : nothing}>
|
|
78
196
|
<span class="c-listItem-primaryText">${primaryText}</span>
|
|
79
197
|
${this._renderSecondaryText()}
|
|
80
198
|
</div>
|
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
// host declaration wins over a value inherited from an ancestor.
|
|
7
7
|
--list-item-inline-padding: var(--dt-spacing-d);
|
|
8
8
|
--list-item-alignment: flex-start;
|
|
9
|
+
--list-item-border: none;
|
|
9
10
|
|
|
10
11
|
// Using contents to remove the host from the box model so that the internal container element fully acts as the component shell
|
|
11
12
|
display: block;
|
|
@@ -29,7 +30,7 @@
|
|
|
29
30
|
align-items: var(--list-item-alignment);
|
|
30
31
|
gap: var(--dt-spacing-c);
|
|
31
32
|
min-height: 56px;
|
|
32
|
-
border-bottom: var(--list-item-border
|
|
33
|
+
border-bottom: var(--list-item-border);
|
|
33
34
|
}
|
|
34
35
|
|
|
35
36
|
// Two lines of text (primary + secondary) need top-alignment so leading/trailing
|
|
@@ -48,6 +49,32 @@
|
|
|
48
49
|
min-height: 48px;
|
|
49
50
|
}
|
|
50
51
|
|
|
52
|
+
// Interactive row states. When the item is inside a radio/checkbox group the whole row
|
|
53
|
+
// is a click target (it forwards the click to the slotted control), so it shows hover and
|
|
54
|
+
// active surface tints, matching the control's own interactive states. These are suppressed
|
|
55
|
+
// when the slotted control is disabled (the item reflects this as `is-disabled`). The
|
|
56
|
+
// defaults use the standard PIE interactive overlay tokens; override `--list-item-hover-bg` /
|
|
57
|
+
// `--list-item-active-bg` if design specifies dedicated list tokens.
|
|
58
|
+
.c-listItem-container.is-selectable:not(.is-disabled) {
|
|
59
|
+
--list-item-hover-bg: hsl(var(--dt-color-black-h), var(--dt-color-black-s), var(--dt-color-black-l), var(--dt-color-hover-01));
|
|
60
|
+
--list-item-active-bg: hsl(var(--dt-color-black-h), var(--dt-color-black-s), var(--dt-color-black-l), var(--dt-color-active-01));
|
|
61
|
+
|
|
62
|
+
@supports (background-color: color-mix(in srgb, black, white)) {
|
|
63
|
+
--list-item-hover-bg: color-mix(in srgb, var(--dt-color-hover-01-bg) var(--dt-color-hover-01), transparent);
|
|
64
|
+
--list-item-active-bg: color-mix(in srgb, var(--dt-color-active-01-bg) var(--dt-color-active-01), transparent);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
cursor: pointer;
|
|
68
|
+
|
|
69
|
+
&:hover {
|
|
70
|
+
background-color: var(--list-item-hover-bg);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
&:active {
|
|
74
|
+
background-color: var(--list-item-active-bg);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
51
78
|
// Larger slotted media (e.g. pie-thumbnail) reduces the block padding, but only
|
|
52
79
|
// when the primary text stands alone (`:only-child` == no secondary text). With
|
|
53
80
|
// secondary text the default padding is kept so two lines of text sit correctly.
|
package/dist/index-C0_lfUTv.js
DELETED
|
@@ -1,79 +0,0 @@
|
|
|
1
|
-
import { unsafeCSS as p, html as o, nothing as g } from "lit";
|
|
2
|
-
import { property as n } from "lit/decorators.js";
|
|
3
|
-
import { safeCustomElement as h } from "@justeattakeaway/pie-webc-core";
|
|
4
|
-
import { P as f } from "./PieElement-BsEd8lGj.js";
|
|
5
|
-
import { classMap as y } from "lit/directives/class-map.js";
|
|
6
|
-
const m = {
|
|
7
|
-
isCompact: !1,
|
|
8
|
-
isBold: !1,
|
|
9
|
-
hasMedia: !1
|
|
10
|
-
}, v = "*,*:after,*:before{box-sizing:inherit}:host{--list-item-inline-padding: var(--dt-spacing-d);--list-item-alignment: flex-start;display:block}.c-listItem-container{--list-item-block-padding: var(--dt-spacing-d);--list-item-block-end-padding: calc(var(--list-item-block-padding) - var(--list-item-size-modifier));padding-inline-start:var(--list-item-inline-padding);padding-inline-end:var(--list-item-inline-padding);padding-block-start:var(--list-item-block-padding);padding-block-end:var(--list-item-block-end-padding, var(--list-item-block-padding));display:flex;align-items:var(--list-item-alignment);gap:var(--dt-spacing-c);min-height:56px;border-bottom:var(--list-item-border-override, none)}.c-listItem-container:has(.c-listItem-secondaryText){align-items:var(--list-item-alignment);min-height:76px}.c-listItem-container.is-compact{--list-item-block-padding: var(--dt-spacing-c);--list-item-alignment: center;align-items:var(--list-item-alignment);min-height:48px}.c-listItem-container.has-media:has(.c-listItem-primaryText:only-child){--list-item-block-padding: var(--dt-spacing-b)}.c-listItem-text{flex:1}slot[name=trailing]::slotted(*),.c-listItem-metaText{padding-inline-start:var(--dt-spacing-a)}.c-listItem-leading,slot[name=leading],.c-listItem-trailing,slot[name=trailing]{display:contents}.c-listItem-text>*{display:block}.c-listItem-trailing{margin-inline-start:auto}.c-listItem-metaText{display:block;max-width:33.3333333333%}::slotted(.c-pieIcon){--icon-size-override: 24px }.c-listItem-primaryText{font-family:var(--dt-font-body-l-family);font-weight:var(--dt-font-body-l-weight);font-size:calc(var(--dt-font-body-l-size) * 1px);line-height:calc(var(--dt-font-body-l-line-height) * 1px);color:var(--dt-color-content-default)}.c-listItem-container.is-bold .c-listItem-primaryText{font-family:var(--dt-font-body-strong-l-family);font-weight:var(--dt-font-body-strong-l-weight);font-size:calc(var(--dt-font-body-strong-l-size) * 1px);line-height:calc(var(--dt-font-body-strong-l-line-height) * 1px)}.c-listItem-secondaryText,.c-listItem-metaText{font-family:var(--dt-font-body-s-family);font-weight:var(--dt-font-body-s-weight);font-size:calc(var(--dt-font-body-s-size) * 1px);line-height:calc(var(--dt-font-body-s-line-height) * 1px);color:var(--dt-color-content-subdued)}";
|
|
11
|
-
var b = Object.defineProperty, x = Object.getOwnPropertyDescriptor, a = (t, s, r, l) => {
|
|
12
|
-
for (var e = l > 1 ? void 0 : l ? x(s, r) : s, d = t.length - 1, c; d >= 0; d--)
|
|
13
|
-
(c = t[d]) && (e = (l ? c(s, r, e) : c(e)) || e);
|
|
14
|
-
return l && e && b(s, r, e), e;
|
|
15
|
-
};
|
|
16
|
-
let i = class extends f {
|
|
17
|
-
constructor() {
|
|
18
|
-
super(...arguments), this.isCompact = m.isCompact, this.isBold = m.isBold, this.hasMedia = m.hasMedia;
|
|
19
|
-
}
|
|
20
|
-
connectedCallback() {
|
|
21
|
-
super.connectedCallback(), this.hasAttribute("role") || this.setAttribute("role", "listitem");
|
|
22
|
-
}
|
|
23
|
-
_renderSecondaryText() {
|
|
24
|
-
const { secondaryText: t } = this;
|
|
25
|
-
return t ? o`<span class="c-listItem-secondaryText">${t}</span>` : g;
|
|
26
|
-
}
|
|
27
|
-
// metaText is another form of trailing content. The component can only ever display either slotted trailing content or the metaText string
|
|
28
|
-
_renderTrailingContent() {
|
|
29
|
-
const { metaText: t } = this;
|
|
30
|
-
return t ? o`<span class="c-listItem-metaText c-listItem-trailing">${t}</span>` : o`<div class="c-listItem-trailing"><slot name="trailing"></slot></div>`;
|
|
31
|
-
}
|
|
32
|
-
render() {
|
|
33
|
-
const { primaryText: t } = this, s = {
|
|
34
|
-
"c-listItem-container": !0,
|
|
35
|
-
"is-compact": this.isCompact,
|
|
36
|
-
"is-bold": this.isBold,
|
|
37
|
-
"has-media": this.hasMedia
|
|
38
|
-
};
|
|
39
|
-
return o`
|
|
40
|
-
<div class=${y(s)}>
|
|
41
|
-
<div class="c-listItem-leading">
|
|
42
|
-
<slot name="leading"></slot>
|
|
43
|
-
</div>
|
|
44
|
-
|
|
45
|
-
<div class="c-listItem-text">
|
|
46
|
-
<span class="c-listItem-primaryText">${t}</span>
|
|
47
|
-
${this._renderSecondaryText()}
|
|
48
|
-
</div>
|
|
49
|
-
|
|
50
|
-
${this._renderTrailingContent()}
|
|
51
|
-
</div>`;
|
|
52
|
-
}
|
|
53
|
-
};
|
|
54
|
-
i.styles = p(v);
|
|
55
|
-
a([
|
|
56
|
-
n({ type: String })
|
|
57
|
-
], i.prototype, "primaryText", 2);
|
|
58
|
-
a([
|
|
59
|
-
n({ type: String })
|
|
60
|
-
], i.prototype, "secondaryText", 2);
|
|
61
|
-
a([
|
|
62
|
-
n({ type: String })
|
|
63
|
-
], i.prototype, "metaText", 2);
|
|
64
|
-
a([
|
|
65
|
-
n({ type: Boolean })
|
|
66
|
-
], i.prototype, "isCompact", 2);
|
|
67
|
-
a([
|
|
68
|
-
n({ type: Boolean })
|
|
69
|
-
], i.prototype, "isBold", 2);
|
|
70
|
-
a([
|
|
71
|
-
n({ type: Boolean })
|
|
72
|
-
], i.prototype, "hasMedia", 2);
|
|
73
|
-
i = a([
|
|
74
|
-
h("pie-list-item")
|
|
75
|
-
], i);
|
|
76
|
-
export {
|
|
77
|
-
i as P,
|
|
78
|
-
m as d
|
|
79
|
-
};
|