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 34 commits into
base: staging/cubone
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 10 commits
Commits
Show all changes
34 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
7122d7a
fix(disclosure): focus / active ring color
adamjohnson Dec 17, 2024
0d84003
fix(disclosure): make focus/active ring appear above left red border
adamjohnson Dec 17, 2024
be7e536
fix(disclosure): details content spacing
adamjohnson Dec 17, 2024
7e5761d
docs(disclosure): remove link from demo
adamjohnson Dec 19, 2024
2b3f87d
fix(disclosure): spacing and interactive states
adamjohnson Dec 19, 2024
9f15499
feat(disclosure): improve no js styles, add color fallbacks
adamjohnson Dec 19, 2024
1a7f3f0
Merge branch 'staging/cubone' into feat/rh-disclosure
adamjohnson Jan 7, 2025
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
21 changes: 21 additions & 0 deletions .changeset/nasty-ravens-joke.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
---
"@rhds/elements": minor
---

✨ Added `<rh-disclosure>`

A disclosure is a widget that enables content to be either collapsed (hidden) or expanded (visible).

```html
<rh-disclosure>
<details>
<summary>
<rh-icon set="ui" icon="caret-down"></rh-icon>
Collapsed panel title
</summary>
<div class="details-content"> <!-- `.details-content` class required -->
Lorem ipsum dolor sit amet consectetur adipisicing, elit.
</div>
</details>
</rh-disclosure>
```
12 changes: 12 additions & 0 deletions docs/_data/repoStatus.ts
Original file line number Diff line number Diff line change
Expand Up @@ -199,6 +199,18 @@ export default [
docs: 'ready',
},
},
{
tagName: 'rh-disclosure',
name: 'Disclosure',
type: 'element',
overallStatus: 'ready',
libraries: {
figma: 'ready',
rhds: 'ready',
shared: 'ready',
docs: 'ready',
},
},
{
tagName: 'rh-footer',
name: 'Footer',
Expand Down
22 changes: 22 additions & 0 deletions elements/rh-disclosure/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
# Disclosure

A disclosure is a widget that enables content to be either
collapsed (hidden) or expanded (visible).

## Usage

Place the following markup on your page:

```html
<rh-disclosure>
<details>
<summary>
<rh-icon set="ui" icon="caret-down"></rh-icon>
Collapsed panel title
</summary>
<div class="details-content"> <!-- `.details-content` class required -->
Lorem ipsum dolor sit amet consectetur adipisicing, elit. Velit distinctio, nesciunt nobis sit, a dolor, non numquam rerum recusandae, deserunt enim assumenda quidem. Id impedit necessitatibus obcaecati ratione reprehenderit laborum?
</div>
</details>
</rh-disclosure>
```
21 changes: 21 additions & 0 deletions elements/rh-disclosure/demo/color-context.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
<rh-context-demo>
<rh-disclosure>
<details>
<summary>
<rh-icon set="ui" icon="caret-down"></rh-icon>
Collapsed panel title
</summary>
<div class="details-content"> <!-- `.details-content` class required -->
Lorem ipsum dolor sit amet consectetur adipisicing, elit. Velit distinctio, nesciunt nobis sit, a dolor, non numquam rerum recusandae, deserunt enim assumenda quidem. Id impedit necessitatibus obcaecati ratione reprehenderit laborum?
</div>
</details>
</rh-disclosure>
</rh-context-demo>

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

<script type="module">
import '@rhds/elements/lib/elements/rh-context-demo/rh-context-demo.js';
import '@rhds/elements/rh-disclosure/rh-disclosure.js';
import '@rhds/elements/rh-icon/rh-icon.js';
</script>
44 changes: 44 additions & 0 deletions elements/rh-disclosure/demo/nested-disclosures.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
<rh-disclosure>
<details>
<summary>
<rh-icon set="ui" icon="caret-down"></rh-icon>
This is the top level disclosure
</summary>
<div class="details-content"> <!-- `.details-content` class required -->
<p>Be sure to test the ESC key + focus when nesting disclosures together. Lorem ipsum dolor <a href="#">fake link</a> adipisicing, elit.</p>

<rh-disclosure>
<details>
<summary>
<rh-icon set="ui" icon="caret-down"></rh-icon>
Be sure to open this disclosure
</summary>
<div class="details-content"> <!-- `.details-content` class required -->
<p>You can hit escape to test focus and see which details element closes!</p>

<rh-disclosure>
<details>
<summary>
<rh-icon set="ui" icon="caret-down"></rh-icon>
Third nested disclosure
</summary>
<div class="details-content"> <!-- `.details-content` class required -->
<p>This is nesting! <a href="#">fake link 2</a> and more text.</p>
</div>
</details>
</rh-disclosure>

</div>
</details>
</rh-disclosure>

</div>
</details>
</rh-disclosure>

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

<script type="module">
import '@rhds/elements/rh-disclosure/rh-disclosure.js';
import '@rhds/elements/rh-icon/rh-icon.js';
</script>
18 changes: 18 additions & 0 deletions elements/rh-disclosure/demo/rh-disclosure.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
<rh-disclosure>
<details>
<summary>
<rh-icon set="ui" icon="caret-down"></rh-icon>
Collapsed panel title
</summary>
<div class="details-content"> <!-- `.details-content` class required -->
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?
</div>
</details>
</rh-disclosure>

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

<script type="module">
import '@rhds/elements/rh-disclosure/rh-disclosure.js';
import '@rhds/elements/rh-icon/rh-icon.js';
</script>
9 changes: 9 additions & 0 deletions elements/rh-disclosure/docs/00-overview.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
## When to use

- When you want to have some content you want to expand and collapse
- When putting all of the content on the page might not be relevant to all users
or distract them from the main content on the page

<div id="overview-image-description" class="visually-hidden">
An expanded disclosure element with a panel trigger and lorem ipsum for details content
</div>
1 change: 1 addition & 0 deletions elements/rh-disclosure/docs/10-style.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
## Style
1 change: 1 addition & 0 deletions elements/rh-disclosure/docs/20-guidelines.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
## Guidelines
1 change: 1 addition & 0 deletions elements/rh-disclosure/docs/40-accessibility.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
## Accessibility
Binary file added elements/rh-disclosure/docs/screenshot.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
59 changes: 59 additions & 0 deletions elements/rh-disclosure/rh-disclosure-lightdom.css
adamjohnson marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
rh-disclosure {
& details {
/* stylelint-disable-next-line rhds/token-values */
border: var(--rh-border-width-sm, 1px) solid var(--rh-color-border-subtle, #c7c7c7);
font-family: var(--rh-font-family-body-text);

& .details-content {
font-size: var(--rh-font-size-body-text-md, 1rem);
line-height: var(--rh-line-height-body-text, 1.5);
padding: var(--rh-space-xl, 24px);
padding-block-start: var(--rh-space-lg, 16px);

& :is(p, h2, h3, h4, h5, h6):first-of-type {
margin-block-start: 0;
}
}
}

& 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-length-sm, 6px);
adamjohnson marked this conversation as resolved.
Show resolved Hide resolved
list-style: none;
padding: var(--rh-space-lg, 16px) var(--rh-space-xl, 24px);

& rh-icon[icon='caret-down'] {
inline-size: var(--rh-space-lg, 16px);
block-size: var(--rh-space-lg, 16px);
transition: 0.2s;
will-change: rotate;
}

&::-webkit-details-marker,
&::marker {
display: none;
}
}

details[open] {
box-shadow: var(--rh-box-shadow-sm, 0 2px 4px 0 rgba(21, 21, 21, 0.2));
position: relative;

&:before {
content: '';
border-inline-start: 3px solid var(--rh-color-brand-red-on-light, #ee0000);
position: absolute;
z-index: 1;
inset-inline-start: -1px;
inset-block: -1px;
}

& > summary rh-icon[icon='caret-down'] {
transform: rotate(-180deg);
}
}
}
3 changes: 3 additions & 0 deletions elements/rh-disclosure/rh-disclosure.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
:host {
display: block;
}
58 changes: 58 additions & 0 deletions elements/rh-disclosure/rh-disclosure.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import { LitElement, html, isServer } from 'lit';
import { customElement } from 'lit/decorators/custom-element.js';

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

/**
* @summary A disclosure is a widget that enables content to be either collapsed (hidden) or expanded (visible).
* @slot - Place the `details`, `summary`, and `.details-content` elements in the default slot.
*/

@customElement('rh-disclosure')
export class RhDisclosure extends LitElement {
static readonly styles = [styles];

#details?: HTMLDetailsElement;
#summary?: HTMLElement;

firstUpdated() {
this.#details = this.querySelector<HTMLDetailsElement>('details')!;
this.#summary = this.querySelector<HTMLElement>('details summary')!;
if (!isServer) {
this.#details?.addEventListener('keydown', this.#handleKeyDown.bind(this));
}
}

disconnectedCallback() {
if (!isServer && this.#details) {
this.#details.removeEventListener('keydown', this.#handleKeyDown.bind(this));
}
super.disconnectedCallback();
}

render() {
return html`
<slot></slot>
`;
}

#handleKeyDown(event: KeyboardEvent): void {
if (event.code === 'Escape') {
adamjohnson marked this conversation as resolved.
Show resolved Hide resolved
event.stopPropagation();
this.#closeDetails();
}
}

#closeDetails(): void {
if (this.#details?.open) {
this.#details.open = false;
this.#summary?.focus();
}
}
}

declare global {
interface HTMLElementTagNameMap {
'rh-disclosure': RhDisclosure;
}
}
25 changes: 25 additions & 0 deletions elements/rh-disclosure/test/rh-disclosure.e2e.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import { test } from '@playwright/test';
import { PfeDemoPage } from '@patternfly/pfe-tools/test/playwright/PfeDemoPage.js';
import { SSRPage } from '@patternfly/pfe-tools/test/playwright/SSRPage.js';

const tagName = 'rh-disclosure';

test.describe(tagName, () => {
test('snapshot', async ({ page }) => {
const componentPage = new PfeDemoPage(page, tagName);
await componentPage.navigate();
await componentPage.snapshot();
});

test('ssr', async ({ browser }) => {
const fixture = new SSRPage({
tagName,
browser,
demoDir: new URL('../demo/', import.meta.url),
importSpecifiers: [
`@patternfly/elements/${tagName}/${tagName}.js`,
],
});
await fixture.snapshots();
});
});
44 changes: 44 additions & 0 deletions elements/rh-disclosure/test/rh-disclosure.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import { expect, html } from '@open-wc/testing';
import { createFixture } from '@patternfly/pfe-tools/test/create-fixture.js';
import { RhDisclosure } from '@rhds/elements/rh-disclosure/rh-disclosure.js';

describe('<rh-disclosure>', function() {
describe('simply instantiating', function() {
let element: RhDisclosure;
it('imperatively instantiates', function() {
expect(document.createElement('rh-disclosure')).to.be.an.instanceof(RhDisclosure);
});

it('should upgrade', async function() {
element = await createFixture<RhDisclosure>(html`<rh-disclosure></rh-disclosure>`);
const klass = customElements.get('rh-disclosure');
expect(element)
.to.be.an.instanceOf(klass)
.and
.to.be.an.instanceOf(RhDisclosure);
});
});

describe('when the element loads', function() {
let element: RhDisclosure;
beforeEach(async function() {
element = await createFixture<RhDisclosure>(html`
<rh-disclosure>
<details>
<summary>
Summary title
</summary>
<div class="details-content">
Details content goes here.
</div>
</details>
</rh-disclosure>
`);
await element.updateComplete;
});

it('should be accessible', async function() {
await expect(element).to.be.accessible();
});
});
});
Loading