Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(disclosure): add <rh-disclosure> #2043

Open
wants to merge 27 commits into
base: staging/cubone
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 6 commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
51a82d4
feat(disclosure): add `<rh-disclosure>`
adamjohnson Nov 7, 2024
6f9598c
fix(disclosure): make borders show up when used without a context pro…
adamjohnson Nov 8, 2024
0271e0f
fix(disclosure): avoid 1px outer + inner border overlap inconsistencies
adamjohnson Nov 8, 2024
501ebcc
fix(disclosure): export RhDisclosure class, fix tests
adamjohnson Nov 8, 2024
6e021d2
feat(disclosure): enable ESC to close
adamjohnson Nov 8, 2024
a6cfa99
test(disclosure): ignore fallback value error
adamjohnson Nov 11, 2024
bfea41e
test(disclosure): fix `removeEventListener` error
adamjohnson Nov 11, 2024
9d6b727
fix(disclosure): escape closes currently focused disclosure
adamjohnson Nov 13, 2024
de409de
feat(disclosure): add `!isServer` check for SSR
adamjohnson Nov 13, 2024
5c8d706
fix(disclosure): proper nested rh-icon caret rotation on open/close
adamjohnson Nov 13, 2024
f791d69
fix(disclosure): correct gap spacing on `<summary>`
adamjohnson Nov 18, 2024
4b53e2e
refactor(disclosure): move `details`/`summary` to shadowdom
adamjohnson Nov 18, 2024
e5c35c8
feat(disclosure): add lightdom shim + example demo
adamjohnson Nov 18, 2024
f87b480
fix(disclosure): improve FOUC / CLS
adamjohnson Nov 19, 2024
35e7146
refactor(disclosure): `summary-label` slot becomes `summary`
adamjohnson Nov 19, 2024
0f58da8
fix(disclosure): remove default content for `summary` slot
adamjohnson Nov 19, 2024
b850ac5
fix(disclosure): expand `summary` focus outline
adamjohnson Nov 19, 2024
f196568
fix(disclosure): let `render` handle elements/state
adamjohnson Nov 19, 2024
4530f6a
Merge branch 'staging/cubone' into feat/rh-disclosure
bennypowers Nov 20, 2024
452925e
feat(disclosure): add `summary` prop, convert demos to use it
adamjohnson Nov 20, 2024
5dee62a
fix(disclosure): remove `display: flex;` from `<summay>`
adamjohnson Nov 20, 2024
dbe6e6d
fix(disclosure): prevent ESC from closing disclosure on certain inter…
adamjohnson Nov 20, 2024
b5cce6f
fix(disclosure): improve outline on focus
adamjohnson Nov 20, 2024
fe71de0
fix(disclosure): move FOUC styles to lightdom-shim, remove FOUC demo
adamjohnson Nov 20, 2024
dbe8f1f
feat(disclosure): add `toggle` event and events demo
adamjohnson Nov 20, 2024
190120e
fix(disclosure): prevent wrapping in slotted summary demo via demo st…
adamjohnson Nov 20, 2024
b1e0b00
fix(disclosure): use `composedPath()` for ESC functionality
adamjohnson Nov 21, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 2 additions & 5 deletions elements/rh-disclosure/demo/color-context.html
Original file line number Diff line number Diff line change
@@ -1,13 +1,10 @@
<rh-context-demo>
<rh-disclosure>
<span slot="summary">
Collapsed panel title
</span>
<rh-disclosure summary="Collapsed panel title">
<p>Lorem ipsum dolor sit amet consectetur adipisicing, elit. Velit distinctio, nesciunt nobis sit.</p>
</rh-disclosure>
</rh-context-demo>

<link rel="stylesheet" href="../rh-disclosure-lightdom.css">
<link rel="stylesheet" href="../rh-disclosure-lightdom-shim.css">

<script type="module">
import '@rhds/elements/lib/elements/rh-context-demo/rh-context-demo.js';
Expand Down
26 changes: 26 additions & 0 deletions elements/rh-disclosure/demo/events.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
<form id="disclosure-events">
<rh-disclosure summary="Collapsed panel title">
<p>Lorem ipsum dolor <a href="#">sit amet consectetur</a> adipisicing, elit. Velit distinctio, nesciunt nobis sit, a dolor, non numquam rerum recusandae, deserunt enim assumenda quidem. Id impedit necessitatibus obcaecati ratione reprehenderit laborum?</p>
</rh-disclosure>

<fieldset>
<legend>Events Fired</legend>
<output name="events">No events yet</output>
</fieldset>
</form>

<link rel="stylesheet" href="../rh-disclosure-lightdom-shim.css">

<script type="module">
import '@rhds/elements/rh-disclosure/rh-disclosure.js';

const disclosure = document.querySelector('rh-disclosure');
const form = document.getElementById('disclosure-events');
const events = [];
form.addEventListener('submit', e => e.preventDefault());
const onDisclosureEvent = event => {
events.push(event.type);
form.elements.events.value = events.join(', ');
};
disclosure.addEventListener('toggle', onDisclosureEvent);
</script>
52 changes: 39 additions & 13 deletions elements/rh-disclosure/demo/nested-disclosures.html
Original file line number Diff line number Diff line change
@@ -1,23 +1,49 @@
<rh-disclosure>
<span slot="summary">
This is the top level disclosure
</span>
<rh-disclosure summary="This is the top level disclosure">
<p>Be sure to test the ESC key + focus when nesting disclosures together. Lorem ipsum dolor <a href="#">fake link</a> adipisicing.</p>
<rh-disclosure>
<span slot="summary">
This is the second level disclosure
</span>
<rh-disclosure summary="This is the second level disclosure">
<p>You can hit escape to test focus and see which details element closes!</p>
<rh-disclosure>
<span slot="summary">
Third nested disclosure
</span>
<rh-disclosure summary="Third nested disclosure">
<p>This is nesting! <a href="#">fake link 2</a> and more text.</p>
<form action="#" method="get" class="form-example">
<div class="form-example">
<label for="name">Enter your name: </label>
<input type="text" name="name" id="name" required />
</div>
<div class="form-example">
<label for="favcity">Which is your favorite city?</label>
<select id="favcity" name="select">
<option value="1">Amsterdam</option>
<option value="2">Buenos Aires</option>
</select>
</div>
<div class="form-example">
<fieldset>
<legend>Choose a shipping method:</legend>
<input id="overnight" type="radio" name="shipping" value="overnight">
<label for="overnight">Overnight</label><br>
<input id="twoday" type="radio" name="shipping" value="twoday">
<label for="twoday">Two day</label><br>
</fieldset>
</div>
<div class="form-example">
<fieldset>
<legend>Select your pizza toppings:</legend>
<input id="ham" type="checkbox" name="toppings" value="ham">
<label for="ham">Ham</label><br>
<input id="pepperoni" type="checkbox" name="toppings" value="pepperoni">
<label for="pepperoni">Pepperoni</label><br>
</fieldset>
</div>
<div class="form-example">
<input type="submit" value="Subscribe!" />
</div>
</form>
<p>This is a sentence with <a href="#">a link</a>.</p>
</rh-disclosure>
</rh-disclosure>
</rh-disclosure>

<link rel="stylesheet" href="../rh-disclosure-lightdom.css">
<link rel="stylesheet" href="../rh-disclosure-lightdom-shim.css">

<script type="module">
import '@rhds/elements/rh-disclosure/rh-disclosure.js';
Expand Down
26 changes: 0 additions & 26 deletions elements/rh-disclosure/demo/no-fouc.html

This file was deleted.

7 changes: 2 additions & 5 deletions elements/rh-disclosure/demo/rh-disclosure.html
Original file line number Diff line number Diff line change
@@ -1,11 +1,8 @@
<rh-disclosure>
<span slot="summary">
Collapsed panel title
</span>
<rh-disclosure summary="Collapsed panel title">
<p>Lorem ipsum dolor <a href="#">sit amet consectetur</a> adipisicing, elit. Velit distinctio, nesciunt nobis sit, a dolor, non numquam rerum recusandae, deserunt enim assumenda quidem. Id impedit necessitatibus obcaecati ratione reprehenderit laborum?</p>
</rh-disclosure>

<link rel="stylesheet" href="../rh-disclosure-lightdom.css">
<link rel="stylesheet" href="../rh-disclosure-lightdom-shim.css">

<script type="module">
import '@rhds/elements/rh-disclosure/rh-disclosure.js';
Expand Down
26 changes: 26 additions & 0 deletions elements/rh-disclosure/demo/slotted-summary.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
<rh-disclosure>
<span slot="summary">
This is a slotted summary with extra markup <rh-icon set="ui" icon="like"></rh-icon>
</span>
<p>Instead of using <code>&lt;rh-disclosure summary="Hello world"&gt;</code>, users can slot content into a <code>summary</code> slot and include additional HTML if needed.</p>
<p>Also note that slotted <code>summary</code> content will render on the page if/when JavaScript fails to load.</p>
</rh-disclosure>

<link rel="stylesheet" href="../rh-disclosure-lightdom-shim.css">

<script type="module">
import '@rhds/elements/rh-disclosure/rh-disclosure.js';
import '@rhds/elements/rh-icon/rh-icon.js';
</script>

<style>
span[slot='summary'] {
display: flex;
align-items: center;
gap: var(--rh-space-sm, 6px);
}

p {
margin-block-end: var(--rh-space-lg, 16px);
}
</style>
20 changes: 13 additions & 7 deletions elements/rh-disclosure/rh-disclosure-lightdom-shim.css
Original file line number Diff line number Diff line change
@@ -1,8 +1,14 @@
/**
* WARNING: Using this stylesheet acknoledges this component requires JavaScript
* If you are OK with a FOUC, you do not need to link this file in your app
* 👇 Hides all content in the default slot
*/
rh-disclosure:not(:defined) *:not([slot]) {
display: none;
rh-disclosure {
/* stylelint-disable-next-line rhds/token-values */
border: var(--rh-border-width-sm, 1px) solid var(--rh-color-border-subtle, #c7c7c7);
display: block;
font-family: var(--rh-font-family-body-text);
padding: var(--rh-space-lg, 16px) var(--rh-space-xl, 24px);
}

rh-disclosure > [slot='summary'] {
display: block;
font-size: var(--rh-font-size-body-text-md, 1rem);
font-weight: var(--rh-font-weight-body-text-medium, 500);
font-family: var(--rh-font-family-body-text);
}
14 changes: 0 additions & 14 deletions elements/rh-disclosure/rh-disclosure-lightdom.css
adamjohnson marked this conversation as resolved.
Outdated
Show resolved Hide resolved

This file was deleted.

15 changes: 11 additions & 4 deletions elements/rh-disclosure/rh-disclosure.css
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,9 @@
}

summary {
align-items: center;
cursor: pointer;
display: flex;
font-size: var(--rh-font-size-body-text-md, 1rem);
font-weight: var(--rh-font-weight-body-text-medium, 500);
gap: var(--rh-space-md, 8px);
list-style: none;
position: relative;

Expand All @@ -25,7 +22,14 @@ summary {
}

&:focus {
outline-offset: var(--rh-space-lg, 16px);
outline: 0;
}

&:focus:before {
outline: var(--rh-border-width-md, 2px) solid;
/* stylelint-disable-next-line rhds/token-values */
outline-color: var(--rh-color-interactive-primary-focus, #003366);
outline-offset: -2px;
}

& ::slotted([slot='summary']) {
Expand All @@ -40,6 +44,9 @@ summary {
block-size: var(--rh-space-lg, 16px);
transition: 0.2s;
will-change: rotate;
position: relative;
inset-block-start: 3px;
margin-inline-end: var(--rh-space-md, 8px);
}

#details-content {
Expand Down
36 changes: 33 additions & 3 deletions elements/rh-disclosure/rh-disclosure.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,17 @@ import '@rhds/elements/rh-icon/rh-icon.js';

import styles from './rh-disclosure.css';

export class DisclosureToggleEvent extends Event {
constructor() {
super('toggle', { bubbles: true, cancelable: true });
}
}

/**
* @summary A disclosure is a widget that enables content to be either collapsed (hidden) or expanded (visible).
* @slot - Place the content you want to disclose in the default slot. This content is hidden by default.
* @slot summary - The title of the disclosure
* @fires {DisclosureToggleEvent} toggle - Fires when a user opens or closes a disclosure.
* @csspart caret - The caret icon in the shadow DOM
*/
@customElement('rh-disclosure')
Expand All @@ -22,6 +29,11 @@ export class RhDisclosure extends LitElement {
*/
@property({ type: Boolean, reflect: true }) open = false;

/**
* Sets the disclosure title via an attribute
*/
@property({ reflect: true }) summary?: string;

@query('details') private detailsEl!: HTMLDetailsElement;
@query('summary') private summaryEl!: HTMLElement;

Expand All @@ -33,7 +45,7 @@ export class RhDisclosure extends LitElement {
@toggle="${this.#onToggle}">
<summary>
<rh-icon part="caret" id="caret" set="ui" icon="caret-down"></rh-icon>
<slot name="summary"></slot>
<slot name="summary">${this.summary}</slot>
</summary>
<div id="details-content">
<slot></slot>
Expand All @@ -44,16 +56,34 @@ export class RhDisclosure extends LitElement {

#onToggle(): void {
this.open = this.detailsEl.open;
const event = new DisclosureToggleEvent();
this.dispatchEvent(event);
}

#onKeydown(event: KeyboardEvent): void {
const preventEscElements = `
adamjohnson marked this conversation as resolved.
Show resolved Hide resolved
input:not([type='hidden']):not([type='radio']):not([inert]):not([inert] *):not([tabindex^='-']):not(:disabled),
input[type='radio']:not([inert]):not([inert] *):not([tabindex^='-']):not(:disabled),
select:not([inert]):not([inert] *):not([tabindex^='-']):not(:disabled),
textarea:not([inert]):not([inert] *):not([tabindex^='-']):not(:disabled),
iframe:not([inert]):not([inert] *):not([tabindex^='-']),
audio[controls]:not([inert]):not([inert] *):not([tabindex^='-']),
video[controls]:not([inert]):not([inert] *):not([tabindex^='-']),
[contenteditable]:not([inert]):not([inert] *):not([tabindex^='-'])
`;
if (event.code === 'Escape') {
adamjohnson marked this conversation as resolved.
Show resolved Hide resolved
event.stopPropagation();
this.#closeDetails();
if (document.activeElement?.matches(preventEscElements)) {
return;
}
this.#closeDisclosure();
}
}

#closeDetails(): void {
#closeDisclosure(): void {
if (!this.open) {
return;
}
this.detailsEl.open = false;
this.open = false;
this.summaryEl.focus();
Expand Down
Loading