Skip to content

Commit cbca93e

Browse files
committed
[site] Replace theme menu with synced toggle
1 parent 697feba commit cbca93e

21 files changed

Lines changed: 574 additions & 404 deletions

packages/lit-dev-content/rollup.config.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ export default [
3535
// lit-hydrate-support MUST be loaded first to make sure lit hydration
3636
// helpers are bundled before LitElement attempts to use hydration support
3737
'lib/global/lit-hydrate-support.js',
38+
'lib/global/theme-worker.js',
3839
'lib/components/copy-button.js',
3940
'lib/components/litdev-banner.js',
4041
'lib/components/litdev-drawer.js',
@@ -151,7 +152,7 @@ export default [
151152
// the asynchronously-loaded module bundles above.
152153
{
153154
input: [
154-
'lib/global/apply-saved-theme.js',
155+
'lib/global/initialize-theme.js',
155156
'lib/global/apply-mods.js',
156157
'lib/global/initialize-typescript-mode.js',
157158
'lib/global/mobile-drawer.js',

packages/lit-dev-content/site/_includes/default.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
<link rel="modulepreload" href="{{ site.baseurl }}/js/global/hydrate-common-components.js">
1616

1717
<meta name="theme-color" content="#fff">
18-
{% inlinejs "global/apply-saved-theme.js" %}
18+
{% inlinejs "global/initialize-theme.js" %}
1919
{% inlinecss "colors.css" %}
2020
{% inlinecss "global.css" %}
2121

packages/lit-dev-content/site/_includes/header.html

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,12 @@
1717

1818
<litdev-ripple-icon-button
1919
id="mobileMenuButton"
20-
label="Open menu"
20+
label="Navigation menu"
21+
button-title="Open navigation menu"
22+
expanded="false"
23+
controls="mobileDrawer"
2124
>
22-
<svg height="24" width="24" fill="currentcolor">
25+
<svg height="24" width="24" fill="currentcolor" aria-hidden="true">
2326
<path d="M3 18h18v-2H3v2zm0-5h18v-2H3v2zm0-7v2h18V6H3z" />
2427
</svg>
2528
</litdev-ripple-icon-button>

packages/lit-dev-content/site/playground/index.html

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -55,21 +55,22 @@ <h2 class="exampleSectionHeading">{{ section.name }}</h2>
5555
</litdev-playground-share-button>
5656

5757
<litdev-ripple-icon-button
58-
button-title="Toggle view mode"
58+
label="Show preview only"
59+
button-title="Show preview only"
5960
id="view-mode-button">
6061
<lazy-svg
6162
class="preview"
62-
label="Show Only Preview"
63+
svg-aria-hidden
6364
href="{{ site.baseurl }}/images/icons/preview.svg#icon"
6465
loading="eager"></lazy-svg>
6566
<lazy-svg
6667
class="code"
67-
label="Show Only Code"
68+
svg-aria-hidden
6869
href="{{ site.baseurl }}/images/icons/code.svg#icon"
6970
loading="eager"></lazy-svg>
7071
<lazy-svg
7172
class="splitscreen"
72-
label="Show Split View"
73+
svg-aria-hidden
7374
href="{{ site.baseurl }}/images/icons/splitscreen.svg#icon"
7475
loading="eager"></lazy-svg>
7576
</litdev-ripple-icon-button>

packages/lit-dev-content/src/components/litdev-drawer.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ const closeIcon = html` <svg
2222
height="24"
2323
viewBox="0 0 24 24"
2424
fill="currentcolor"
25+
aria-hidden="true"
2526
>
2627
<path
2728
d="M19 6.41L17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z"
@@ -34,6 +35,7 @@ const bookIcon = html` <svg
3435
height="24"
3536
viewBox="0 0 24 24"
3637
fill="currentcolor"
38+
aria-hidden="true"
3739
>
3840
<path
3941
d="M21,5c-1.11-0.35-2.33-0.5-3.5-0.5c-1.95,0-4.05,0.4-5.5,1.5c-1.45-1.1-3.55-1.5-5.5-1.5S2.45,4.9,1,6v14.65 c0,0.25,0.25,0.5,0.5,0.5c0.1,0,0.15-0.05,0.25-0.05C3.1,20.45,5.05,20,6.5,20c1.95,0,4.05,0.4,5.5,1.5c1.35-0.85,3.8-1.5,5.5-1.5 c1.65,0,3.35,0.3,4.75,1.05c0.1,0.05,0.15,0.05,0.25,0.05c0.25,0,0.5-0.25,0.5-0.5V6C22.4,5.55,21.75,5.25,21,5z M21,18.5 c-1.1-0.35-2.3-0.5-3.5-0.5c-1.7,0-4.15,0.65-5.5,1.5V8c1.35-0.85,3.8-1.5,5.5-1.5c1.2,0,2.4,0.15,3.5,0.5V18.5z"
@@ -152,7 +154,9 @@ export class LitDevDrawer extends LitElement {
152154
153155
<litdev-ripple-icon-button
154156
id="openCloseButton"
155-
aria-label="Open or close examples drawer"
157+
label="Examples drawer"
158+
.expanded=${this.open ? 'true' : 'false'}
159+
controls="content"
156160
@click=${this._onClickToggleButton}
157161
>
158162
${this.open ? closeIcon : bookIcon}

packages/lit-dev-content/src/components/litdev-playground-page.ts

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ import type {LitDevPlaygroundShareButton} from './litdev-playground-share-button
3232
import type {LitDevPlaygroundDownloadButton} from './litdev-playground-download-button.js';
3333
import type {LitDevDrawer} from './litdev-drawer.js';
3434
import type {LitDevExampleControls} from './litdev-example-controls.js';
35+
import type {LitDevRippleIconButton} from './litdev-ripple-icon-button.js';
3536
import type {PlaygroundProject} from 'playground-elements/playground-project.js';
3637
import type {PlaygroundPreview} from 'playground-elements/playground-preview.js';
3738
import type {PlaygroundFileEditor} from 'playground-elements/playground-file-editor.js';
@@ -115,7 +116,9 @@ export class LitDevPlaygroundPage extends LitElement {
115116
firstUpdated(changed: PropertyValues<this>) {
116117
super.firstUpdated(changed);
117118
// toggle previewFullscreen when the fullscreen button is clicked
118-
const iconButton = this.querySelector('#view-mode-button');
119+
const iconButton = this.querySelector(
120+
'#view-mode-button'
121+
) as LitDevRippleIconButton | null;
119122
iconButton?.addEventListener('click', () => {
120123
const lastMode = this.viewMode;
121124
if (lastMode === 'split') {
@@ -126,6 +129,7 @@ export class LitDevPlaygroundPage extends LitElement {
126129
this.viewMode = 'split';
127130
}
128131
});
132+
this._syncViewModeButton();
129133
}
130134

131135
update(changed: PropertyValues<this>) {
@@ -161,6 +165,31 @@ export class LitDevPlaygroundPage extends LitElement {
161165
super.update(changed);
162166
}
163167

168+
updated(changed: PropertyValues<this>) {
169+
if (changed.has('viewMode')) {
170+
this._syncViewModeButton();
171+
}
172+
super.updated(changed);
173+
}
174+
175+
private _syncViewModeButton() {
176+
const button = this.querySelector(
177+
'#view-mode-button'
178+
) as LitDevRippleIconButton | null;
179+
if (!button) {
180+
return;
181+
}
182+
183+
const label =
184+
this.viewMode === 'split'
185+
? 'Show preview only'
186+
: this.viewMode === 'preview'
187+
? 'Show code only'
188+
: 'Show split view';
189+
button.label = label;
190+
button.buttonTitle = label;
191+
}
192+
164193
/**
165194
* When the code editor is changed, store that there are unsaved changes.
166195
*/

packages/lit-dev-content/src/components/litdev-ripple-icon-button.ts

Lines changed: 49 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -11,47 +11,35 @@ import {customElement, property} from 'lit/decorators.js';
1111
@customElement('litdev-ripple-icon-button')
1212
export class LitDevRippleIconButton extends LitElement {
1313
/**
14-
* Aria label for the button.
14+
* Accessible label for the button.
1515
*/
1616
@property()
1717
label = '';
1818

1919
/**
20-
* Sets aria-live for the button.
21-
*/
22-
@property({type: String})
23-
live = '';
24-
25-
/**
26-
* Aria label for the button.
20+
* Tooltip text for the button.
2721
*/
2822
@property({attribute: 'button-title'})
2923
buttonTitle = '';
3024

3125
/**
32-
* Aria haspopup for the button.
26+
* ARIA pressed state for toggle buttons.
3327
*/
34-
@property()
35-
haspopup = '';
28+
@property({attribute: false})
29+
pressed?: boolean;
3630

3731
/**
38-
* Aria expanded for the button.
32+
* ARIA expanded state for disclosure buttons.
3933
*/
4034
@property()
41-
expanded = '';
35+
expanded: '' | 'true' | 'false' = '';
4236

4337
/**
44-
* Aria controls for the button.
38+
* ID of the element controlled by a disclosure button.
4539
*/
4640
@property()
4741
controls = '';
4842

49-
/**
50-
* Sets the role for the inner button.
51-
*/
52-
@property({attribute: 'button-role'})
53-
buttonRole = '';
54-
5543
/**
5644
* Href for the link button. If defined, this component switches to using an
5745
* anchor element instead of a button.
@@ -105,7 +93,13 @@ export class LitDevRippleIconButton extends LitElement {
10593
-webkit-tap-highlight-color: transparent;
10694
}
10795
108-
.root:disabled {
96+
.root:focus-visible {
97+
outline: 2px solid currentColor;
98+
outline-offset: 2px;
99+
}
100+
101+
.root:disabled,
102+
.root[aria-disabled='true'] {
109103
cursor: default;
110104
pointer-events: none;
111105
opacity: 0.38;
@@ -160,17 +154,33 @@ export class LitDevRippleIconButton extends LitElement {
160154
return this.href ? this.renderAnchorRoot() : this.renderButtonRoot();
161155
}
162156

157+
protected override firstUpdated() {
158+
// Lit hydration adopts server attributes without patching client-only
159+
// state, so reconcile ARIA state once after the initial hydration pass.
160+
const button = this.renderRoot.querySelector('button');
161+
if (this.pressed !== undefined) {
162+
button?.setAttribute('aria-pressed', String(this.pressed));
163+
}
164+
if (this.expanded) {
165+
button?.setAttribute('aria-expanded', this.expanded);
166+
}
167+
if (this.controls) {
168+
button?.setAttribute('aria-controls', this.controls);
169+
}
170+
}
171+
163172
protected renderButtonRoot() {
164173
return html`
165174
<button
175+
type="button"
166176
class="root"
167177
part="root button"
168-
role=${this.buttonRole ? this.buttonRole : nothing}
169-
aria-live=${this.live ? this.live : nothing}
170178
aria-label=${this.label ? this.label : nothing}
171-
aria-haspopup=${this.haspopup ? this.haspopup : nothing}
172-
aria-expanded=${this.expanded ? this.expanded : nothing}
173-
aria-controls=${this.controls ? this.controls : nothing}
179+
aria-pressed=${this.pressed === undefined
180+
? nothing
181+
: String(this.pressed)}
182+
aria-expanded=${this.expanded || nothing}
183+
aria-controls=${this.controls || nothing}
174184
?disabled=${this.disabled}
175185
title=${this.buttonTitle ?? (nothing as unknown as string)}
176186
>
@@ -184,9 +194,13 @@ export class LitDevRippleIconButton extends LitElement {
184194
<a
185195
class="root"
186196
part="root anchor"
187-
href=${this.href}
197+
href=${this.disabled ? nothing : this.href}
198+
role=${this.disabled ? 'link' : nothing}
188199
aria-label=${this.label ? this.label : nothing}
189-
?disabled=${this.disabled}
200+
aria-disabled=${this.disabled ? 'true' : nothing}
201+
tabindex=${this.disabled ? '-1' : nothing}
202+
title=${this.buttonTitle || nothing}
203+
@click=${this._handleAnchorClick}
190204
>
191205
${this.renderContent()}
192206
</a>
@@ -197,4 +211,11 @@ export class LitDevRippleIconButton extends LitElement {
197211
return html`<div id="ripple"></div>
198212
<slot></slot>`;
199213
}
214+
215+
private _handleAnchorClick(event: MouseEvent) {
216+
if (this.disabled) {
217+
event.preventDefault();
218+
event.stopImmediatePropagation();
219+
}
220+
}
200221
}

packages/lit-dev-content/src/components/litdev-tutorial.ts

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -363,11 +363,9 @@ export class LitDevTutorial extends LitElement {
363363
protected renderHeader() {
364364
return html`<div id="tutorialHeader">
365365
<div class="lhs">
366-
<a href="/tutorials/" tabindex="-1">
367-
<litdev-ripple-icon-button label="Tutorial Catalog">
368-
${catalogIcon}
369-
</litdev-ripple-icon-button>
370-
</a>
366+
<litdev-ripple-icon-button label="Tutorial Catalog" href="/tutorials/">
367+
${catalogIcon}
368+
</litdev-ripple-icon-button>
371369
<span class="tutorial-metadata">
372370
${this._manifestTask.render({
373371
complete: (manifest) => html` <span class="tutorial-title"

0 commit comments

Comments
 (0)