@iyulab/desktop-patterns 0.8.0 → 0.10.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md
CHANGED
|
@@ -115,7 +115,10 @@ nav.items = [
|
|
|
115
115
|
},
|
|
116
116
|
]
|
|
117
117
|
nav.pinnedItems = [{ id: 'settings', icon: '⚙', label: 'Settings' }] // places kept at the foot of the rail
|
|
118
|
-
nav.bottomItems = [
|
|
118
|
+
nav.bottomItems = [
|
|
119
|
+
{ id: 'dense', icon: '▤', label: 'Dense mode', pressed: false }, // a toggle: aria-pressed, owned by you
|
|
120
|
+
{ id: 'sign-out', icon: '⎋', label: 'Sign out' }, // actions, not places
|
|
121
|
+
]
|
|
119
122
|
nav.setAttribute('nav-label', 'Main') // names the navigation landmark
|
|
120
123
|
```
|
|
121
124
|
|
|
@@ -136,6 +139,11 @@ nav.setAttribute('nav-label', 'Main') // names t
|
|
|
136
139
|
settings or help page shown there is marked as the current page.
|
|
137
140
|
- **Bottom items are actions**: each click fires `dp-sidebar-action` (`itemId`) — every time, so a failed action can
|
|
138
141
|
be retried — and never moves `aria-current`. (In 0.2.x they fired `dp-sidebar-select` and took the active mark.)
|
|
142
|
+
- **Toggle actions**: a bottom action with `pressed` (`{ id, icon, label, pressed: true | false }`) is a setting it
|
|
143
|
+
turns on and off. The button carries `aria-pressed`, and an on toggle gets a quiet ground and an accent icon
|
|
144
|
+
(`--dp-sidebar-pressed-bg`, `--dp-sidebar-pressed-icon-color`) that still shows in the collapsed rail. Name it after
|
|
145
|
+
the setting ("Dense mode"), not the click ("Turn dense mode on"). The sidebar does not flip it — change the value
|
|
146
|
+
on `dp-sidebar-action` and set `bottomItems` again.
|
|
139
147
|
|
|
140
148
|
Every component takes its user-facing text as a plain attribute/property or slot — there is no
|
|
141
149
|
built-in i18n layer. See each component's Storybook story (`npm run storybook`) for its full API.
|
|
@@ -16,6 +16,12 @@ export declare class DpListDetail extends LitElement {
|
|
|
16
16
|
static styles: import('lit').CSSResult;
|
|
17
17
|
/** Below desktop width, show the picked item instead of the list. Above it both are always shown. */
|
|
18
18
|
detailOpen: boolean;
|
|
19
|
+
/**
|
|
20
|
+
* At desktop width, fold the list away and give the item the whole width — for reading a wide item. The
|
|
21
|
+
* consumer owns it, with a control that brings the list back. Below desktop width it changes nothing:
|
|
22
|
+
* `detail-open` already picks the one pane shown.
|
|
23
|
+
*/
|
|
24
|
+
listCollapsed: boolean;
|
|
19
25
|
render(): import('lit-html').TemplateResult<1>;
|
|
20
26
|
}
|
|
21
27
|
declare global {
|
|
@@ -12,6 +12,19 @@ export interface SidebarItem {
|
|
|
12
12
|
label: string;
|
|
13
13
|
href?: string;
|
|
14
14
|
}
|
|
15
|
+
/**
|
|
16
|
+
* One bottom action. With `pressed` it is a toggle — a setting the action turns on and off (a dense
|
|
17
|
+
* or touch mode, a theme): the button carries `aria-pressed` and, when on, a quiet ground and an accent
|
|
18
|
+
* icon. Its `label` then names the setting, not what a click would do. The sidebar does not flip it;
|
|
19
|
+
* the consumer owns the state, changes it on `dp-sidebar-action`, and passes the new value back.
|
|
20
|
+
*/
|
|
21
|
+
export interface SidebarAction {
|
|
22
|
+
id: string;
|
|
23
|
+
/** Text fallback for the `icon-<id>` slot. */
|
|
24
|
+
icon: string;
|
|
25
|
+
label: string;
|
|
26
|
+
pressed?: boolean;
|
|
27
|
+
}
|
|
15
28
|
/** A named set of items under one disclosure. */
|
|
16
29
|
export interface SidebarGroup {
|
|
17
30
|
id: string;
|
|
@@ -68,7 +81,7 @@ export declare class DpSidebar extends LitElement {
|
|
|
68
81
|
*/
|
|
69
82
|
pinnedItems: SidebarItem[];
|
|
70
83
|
/** Actions, not places — see `DpSidebarActionEvent`. A place belongs in `pinnedItems`. */
|
|
71
|
-
bottomItems:
|
|
84
|
+
bottomItems: SidebarAction[];
|
|
72
85
|
activeId: string;
|
|
73
86
|
header: string;
|
|
74
87
|
/** Accessible name of the navigation landmark. Unset leaves it unnamed. */
|
package/dist/list-detail.js
CHANGED
|
@@ -5,7 +5,7 @@ import { customElement as a, property as o } from "lit/decorators.js";
|
|
|
5
5
|
//#region src/components/list-detail/dp-list-detail.ts
|
|
6
6
|
var s = class extends n {
|
|
7
7
|
constructor(...e) {
|
|
8
|
-
super(...e), this.detailOpen = !1;
|
|
8
|
+
super(...e), this.detailOpen = !1, this.listCollapsed = !1;
|
|
9
9
|
}
|
|
10
10
|
static {
|
|
11
11
|
this.styles = r`
|
|
@@ -46,6 +46,11 @@ var s = class extends n {
|
|
|
46
46
|
.detail {
|
|
47
47
|
display: block;
|
|
48
48
|
}
|
|
49
|
+
/* Folded away: the item takes the whole width until the list is wanted again. */
|
|
50
|
+
:host([list-collapsed]) .list,
|
|
51
|
+
:host([list-collapsed][detail-open]) .list {
|
|
52
|
+
display: none;
|
|
53
|
+
}
|
|
49
54
|
}
|
|
50
55
|
/* On paper only the item picked is printed, at its full length. */
|
|
51
56
|
@media print {
|
|
@@ -75,6 +80,10 @@ t([o({
|
|
|
75
80
|
type: Boolean,
|
|
76
81
|
reflect: !0,
|
|
77
82
|
attribute: "detail-open"
|
|
78
|
-
})], s.prototype, "detailOpen", void 0),
|
|
83
|
+
})], s.prototype, "detailOpen", void 0), t([o({
|
|
84
|
+
type: Boolean,
|
|
85
|
+
reflect: !0,
|
|
86
|
+
attribute: "list-collapsed"
|
|
87
|
+
})], s.prototype, "listCollapsed", void 0), s = t([a("dp-list-detail")], s);
|
|
79
88
|
//#endregion
|
|
80
89
|
export { s as DpListDetail };
|
package/dist/sidebar.js
CHANGED
|
@@ -105,10 +105,19 @@ var c = (e) => Array.isArray(e.items), l = class extends Event {
|
|
|
105
105
|
justify-content: center;
|
|
106
106
|
padding: var(--dc-space-3, 12px) 0;
|
|
107
107
|
}
|
|
108
|
-
/*
|
|
109
|
-
:host(:not([collapsed])) .group-items .item {
|
|
108
|
+
/* A group with an icon is a parent item: its items sit one step in, so it reads as a set. */
|
|
109
|
+
:host(:not([collapsed])) .group:not(.heading) .group-items .item {
|
|
110
110
|
padding-left: calc(var(--dc-space-3, 12px) * 2);
|
|
111
111
|
}
|
|
112
|
+
/* A group without one is a heading over its items: smaller and quieter than they are, its label flush
|
|
113
|
+
with their icons, and the items at the rail's own indent - the heading, not an indent, makes the set. */
|
|
114
|
+
.group.heading > .group-toggle {
|
|
115
|
+
padding-top: var(--dc-space-3, 12px);
|
|
116
|
+
padding-bottom: var(--dc-space-1, 4px);
|
|
117
|
+
font-size: var(--dp-sidebar-group-size, var(--dc-font-size-xs, 11px));
|
|
118
|
+
font-weight: var(--dc-font-weight-semibold, 600);
|
|
119
|
+
color: var(--dc-color-text-muted, #6b6b73);
|
|
120
|
+
}
|
|
112
121
|
/* In the collapsed rail a group has no label to show; a rule marks where it starts. */
|
|
113
122
|
:host([collapsed]) .group + .group,
|
|
114
123
|
:host([collapsed]) .item + .group,
|
|
@@ -137,6 +146,17 @@ var c = (e) => Array.isArray(e.items), l = class extends Event {
|
|
|
137
146
|
.item[aria-current='page']:hover {
|
|
138
147
|
background: var(--dc-selection-bg, var(--dc-color-surface-hover, #ececed));
|
|
139
148
|
}
|
|
149
|
+
/* A toggle that is on. Not a place, so not the rail marker or the current-page colour of the label:
|
|
150
|
+
a quiet ground (--dp-sidebar-pressed-bg) and the accent on the icon, so it still reads in the
|
|
151
|
+
collapsed rail, where only the icon shows. Declared after :hover so hovering keeps the ground. */
|
|
152
|
+
.item[aria-pressed='true'],
|
|
153
|
+
.item[aria-pressed='true']:hover {
|
|
154
|
+
background: var(--dp-sidebar-pressed-bg, var(--dc-selection-bg, var(--dc-color-surface-hover, #ececed)));
|
|
155
|
+
color: var(--dc-color-text, #1d1d1f);
|
|
156
|
+
}
|
|
157
|
+
.item[aria-pressed='true'] .icon {
|
|
158
|
+
color: var(--dp-sidebar-pressed-icon-color, var(--dc-color-accent-text, var(--dc-color-accent, #2563eb)));
|
|
159
|
+
}
|
|
140
160
|
.item:focus-visible {
|
|
141
161
|
outline: 2px solid var(--dc-color-accent, #2563eb);
|
|
142
162
|
outline-offset: -2px;
|
|
@@ -175,16 +195,16 @@ var c = (e) => Array.isArray(e.items), l = class extends Event {
|
|
|
175
195
|
`;
|
|
176
196
|
}
|
|
177
197
|
#e(e) {
|
|
178
|
-
let t = e.items.some((e) => e.id === this.activeId), n = e.collapsed === !0, a = this.collapsed || t || n === this.toggledGroups.has(e.id), o = `group-${e.id}
|
|
198
|
+
let t = e.items.some((e) => e.id === this.activeId), n = e.collapsed === !0, a = this.collapsed || t || n === this.toggledGroups.has(e.id), o = `group-${e.id}`, s = !e.icon;
|
|
179
199
|
return r`
|
|
180
|
-
<div class
|
|
200
|
+
<div class=${s ? "group heading" : "group"}>
|
|
181
201
|
${this.collapsed ? i : r`<button
|
|
182
202
|
class="item group-toggle"
|
|
183
203
|
aria-expanded=${a ? "true" : "false"}
|
|
184
204
|
aria-controls=${o}
|
|
185
205
|
@click=${() => this.#a(e.id)}
|
|
186
206
|
>
|
|
187
|
-
${this.#r(e.id, e.icon ?? "")}
|
|
207
|
+
${s ? i : this.#r(e.id, e.icon ?? "")}
|
|
188
208
|
<span class="label">${e.label}</span>
|
|
189
209
|
<span class="caret" aria-hidden="true">▾</span>
|
|
190
210
|
</button>`}
|
|
@@ -219,6 +239,7 @@ var c = (e) => Array.isArray(e.items), l = class extends Event {
|
|
|
219
239
|
<button
|
|
220
240
|
class="item"
|
|
221
241
|
title=${this.collapsed ? e.label : i}
|
|
242
|
+
aria-pressed=${e.pressed === void 0 ? i : e.pressed ? "true" : "false"}
|
|
222
243
|
@click=${() => this.dispatchEvent(new d(e.id))}
|
|
223
244
|
>
|
|
224
245
|
${this.#r(e.id, e.icon)} ${this.collapsed ? i : r`<span class="label">${e.label}</span>`}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@iyulab/desktop-patterns",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.10.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -82,10 +82,10 @@
|
|
|
82
82
|
"lit": "^3.3.3"
|
|
83
83
|
},
|
|
84
84
|
"peerDependencies": {
|
|
85
|
-
"@iyulab/desktop-compact": "^0.2.0 || ^0.3.0 || ^0.4.0 || ^0.5.0 || ^0.6.0 || ^0.7.0 || ^0.8.0 || ^0.9.0 || ^0.10.0 || ^0.11.0"
|
|
85
|
+
"@iyulab/desktop-compact": "^0.2.0 || ^0.3.0 || ^0.4.0 || ^0.5.0 || ^0.6.0 || ^0.7.0 || ^0.8.0 || ^0.9.0 || ^0.10.0 || ^0.11.0 || ^0.12.0"
|
|
86
86
|
},
|
|
87
87
|
"devDependencies": {
|
|
88
|
-
"@iyulab/desktop-compact": "^0.
|
|
88
|
+
"@iyulab/desktop-compact": "^0.12.0",
|
|
89
89
|
"@open-wc/testing": "^5.0.0",
|
|
90
90
|
"@storybook/web-components": "^10.6.0",
|
|
91
91
|
"@storybook/web-components-vite": "^10.6.0",
|
package/tokens.css
CHANGED
|
@@ -22,6 +22,11 @@
|
|
|
22
22
|
syntax: '*';
|
|
23
23
|
inherits: true;
|
|
24
24
|
}
|
|
25
|
+
/* dp-sidebar's heading size for a group without an icon. Unset, the sidebar uses var(--dc-font-size-xs, 11px). */
|
|
26
|
+
@property --dp-sidebar-group-size {
|
|
27
|
+
syntax: '*';
|
|
28
|
+
inherits: true;
|
|
29
|
+
}
|
|
25
30
|
:root {
|
|
26
31
|
--dp-sidebar-width: 220px;
|
|
27
32
|
--dp-sidebar-width-collapsed: 52px;
|