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(back-to-top): pf-back-to-top element #2589

Merged
merged 52 commits into from
Dec 6, 2023
Merged
Show file tree
Hide file tree
Changes from 47 commits
Commits
Show all changes
52 commits
Select commit Hold shift + click to select a range
c4b6fb8
feat(back-to-top): add back-to-top
zeroedin Sep 5, 2023
3f1d82f
fix(back-to-top): improve accessibility
zeroedin Sep 5, 2023
f802302
fix(back-to-top): add href implementation, update demos
zeroedin Sep 5, 2023
c9962cf
docs(back-to-top): improve demos
zeroedin Sep 5, 2023
c54a82e
fix(back-to-top): inline-flex
zeroedin Sep 5, 2023
1452fa3
docs(back-to-top): fix fragment anchors
zeroedin Sep 5, 2023
7220a62
fix(back-to-top): add button part to link
zeroedin Sep 5, 2023
1e02ebb
docs(back-to-top): use main target for all examples
zeroedin Sep 5, 2023
0a3be33
docs(back-to-top): use main target for overview
zeroedin Sep 5, 2023
69972c9
test(back-to-top): add basic tests
zeroedin Sep 11, 2023
6ee1127
fix(back-to-top): rename part to trigger to avoid confusion with button
zeroedin Sep 13, 2023
b1b24e6
docs(back-to-top): update cssprop documentation
zeroedin Sep 13, 2023
c32907d
docs(back-to-top): correct slot descriptions
zeroedin Sep 13, 2023
d0972d4
chore(back-to-top): add changeset
zeroedin Sep 13, 2023
131bb8d
Merge branch 'main' into feat/pf-back-to-top
zeroedin Sep 25, 2023
2a39c34
chore: update typescript version
bennypowers Sep 27, 2023
7b4e311
chore: pat typescript on the head
bennypowers Sep 27, 2023
db72b83
style(back-to-top): small refactors
bennypowers Sep 27, 2023
578c018
perf(back-to-top): prevent memory leak
bennypowers Sep 27, 2023
95588ad
docs(back-to-top): add readme
zeroedin Oct 5, 2023
fb3ce20
docs(back-to-top): update readme
zeroedin Oct 5, 2023
4e31854
docs(back-to-top): move css link to top of demos
zeroedin Oct 12, 2023
5259f3f
fix(back-to-top): remove type assertion
zeroedin Oct 12, 2023
0e886ff
fix(back-to-top): memeber ordering
zeroedin Oct 12, 2023
a9950df
fix(back-to-top): rename classes variable
zeroedin Oct 12, 2023
b1bbfeb
fix(back-to-top): update var
zeroedin Oct 12, 2023
1d3287b
test(back-to-top): improve test ordering
zeroedin Oct 12, 2023
a89749e
fix(back-to-top): move eventlistener bindings to reactive callback
zeroedin Oct 13, 2023
9e62508
fix(back-to-top): wait for updatecomplete to reattach listener
zeroedin Oct 13, 2023
6cd74bc
fix(back-to-top): reorganizing code with suggestions from review
zeroedin Oct 17, 2023
5def05e
refactor(back-to-top): refactor element and tests
zeroedin Oct 23, 2023
985be1b
fix(back-to-top): add label ifDefined back accidental removal
zeroedin Oct 23, 2023
1f74a9f
docs(back-to-top): fix inline doc demos
zeroedin Oct 23, 2023
e356176
fix(back-to-top): re-add vertical alignment for pf-icon
zeroedin Oct 23, 2023
56db723
docs(back-to-top): update scrollable selector inline demos
zeroedin Oct 23, 2023
7a54e20
docs(back-to-top): fix inline scroll selector demos
zeroedin Oct 23, 2023
4a4db0f
docs(back-to-top): update jsdoc
zeroedin Oct 23, 2023
533c955
chore: remove errant changeset
zeroedin Oct 25, 2023
74cb9b2
chore: readd changeset misread review comment
zeroedin Oct 25, 2023
b7105a0
docs: fix elements/readme, was incorrectly edited
zeroedin Oct 25, 2023
1778545
Merge branch 'main' into feat/pf-back-to-top
zeroedin Oct 25, 2023
1c1dfb1
test(back-to-top): fix describe async nesting
zeroedin Oct 30, 2023
965fbe0
docs(back-to-top): remove content guidelines copy
zeroedin Oct 30, 2023
876585f
refactor(back-to-top): label attribute
zeroedin Oct 30, 2023
074b4fa
docs(back-to-top): clarify scrollable selector and distance usage
zeroedin Oct 30, 2023
040057f
test(back-to-top): add tests for label attribute
zeroedin Oct 30, 2023
11892b1
test(back-to-top): test for keyboard accessibility
zeroedin Oct 30, 2023
34d971e
test(back-to-top): use snapshot to check that it doesnt exist in a11y…
zeroedin Oct 31, 2023
357f6c7
test(back-to-top): add async to a11y axe tests
zeroedin Oct 31, 2023
8d0f259
Merge branch 'main' into feat/pf-back-to-top
zeroedin Dec 4, 2023
f357435
Merge branch 'main' into feat/pf-back-to-top
zeroedin Dec 4, 2023
16a5dba
Merge branch 'main' into feat/pf-back-to-top
bennypowers Dec 6, 2023
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
9 changes: 9 additions & 0 deletions .changeset/khaki-bananas-perform.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
---
"@patternfly/elements": minor
---

✨ Added `<pf-back-to-top>`

```html
<pf-back-to-top href="#top" scrollable-selector="main">Back to Top</pf-back-to-top>
```
4 changes: 4 additions & 0 deletions .changeset/pfe-tools-ts52.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
---
"@patternfly/pfe-tools": patch
---
Update typescript version
2 changes: 1 addition & 1 deletion elements/README.md
zeroedin marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# PatternFly Elements

See [PatternFly Elements Docs](https://patternflyelements.org) for more
See [PatternFly Elements Docs](https://patternflyelements.org) for more
information.
1 change: 1 addition & 0 deletions elements/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
"./pf-accordion/pf-accordion.js": "./pf-accordion/pf-accordion.js",
"./pf-avatar/BaseAvatar.js": "./pf-avatar/BaseAvatar.js",
"./pf-avatar/pf-avatar.js": "./pf-avatar/pf-avatar.js",
"./pf-back-to-top/pf-back-to-top.js": "./pf-back-to-top/pf-back-to-top.js",
"./pf-background-image/pf-background-image.js": "./pf-background-image/pf-background-image.js",
"./pf-badge/BaseBadge.js": "./pf-badge/BaseBadge.js",
"./pf-badge/pf-badge.js": "./pf-badge/pf-badge.js",
Expand Down
32 changes: 32 additions & 0 deletions elements/pf-back-to-top/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
# Back to top

The **back to top** component is a shortcut that allows users to quickly navigate to the top of a lengthy content page.


## Installation
Load `<pf-back-to-top>` via CDN:

```html
<script src="https://jspm.dev/@patternfly/elements/pf-back-to-top/pf-back-to-top.js"></script>


Or, if you are using [NPM](https://npm.im), install it

```bash
npm install @patternfly/elements
```

Then once installed, import it to your application:

```js
import '@patternfly/elements/pf-back-to-top/pf-back-to-top.js';
```

## Usage

```html
<pf-back-to-top href="#top">Back to Top</pf-back-to-top>

```

[docs]: https://patternflyelements.org/components/back-to-top
12 changes: 12 additions & 0 deletions elements/pf-back-to-top/demo/always-visible.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<link rel="stylesheet" href="demo.css">

<div class="outer-container padded" id="top">
<h2>Always visible</h2>
<a href="#focusable-element-top" id="top">Focusable element (top)</a>
</div>

<pf-back-to-top always-visible href="#top">Back to top</pf-back-to-top>

<script type="module">
import '@patternfly/elements/pf-back-to-top/pf-back-to-top.js';
</script>
22 changes: 22 additions & 0 deletions elements/pf-back-to-top/demo/button-no-text.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
<link rel="stylesheet" href="demo.css">

<div class="outer-container" id="top">
<div class="scroll-indicator padded">
<h2>Button No Text</h2>
<p><a href="#focusable-element-top">Focusable element (top)</a></p>
<pf-icon icon="arrow-down"></pf-icon> Scroll down to end of cyan box, 400px (default).
</div>
</div>
<a href="#focusable-element-bottom">Focusable element (bottom)</a>

<pf-back-to-top scrollable-selector="main"></pf-back-to-top>

<script type="module">
import '@patternfly/elements/pf-back-to-top/pf-back-to-top.js';
document.querySelector('pf-back-to-top').addEventListener('click', function() {
// scroll to some element
const target = document.querySelector('#top');
target.scrollIntoView();
target.focus();
});
</script>
27 changes: 27 additions & 0 deletions elements/pf-back-to-top/demo/button.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
<link rel="stylesheet" href="demo.css">

<pf-banner variant="info" id="top">
<pf-icon icon="info-circle" slot="icon"></pf-icon>
<strong>Accessibility Warning</strong> Using the Button/JS variant, implementation must apply click event and focus to the element that is scrolled to.
</pf-banner>
<div class="outer-container">
<div class="scroll-indicator padded">
<h2>Button</h2>
<p><a href="#focusable-element-top">Focusable element (top)</a></p>
<pf-icon icon="arrow-down"></pf-icon> Scroll down to end of cyan box, 400px (default).
</div>
</div>
<a href="#focusable-element-bottom">Focusable element (bottom)</a>

<pf-back-to-top scrollable-selector="main">Back to top</pf-back-to-top>

<script type="module">
import '@patternfly/elements/pf-back-to-top/pf-back-to-top.js';
import '@patternfly/elements/pf-banner/pf-banner.js';
document.querySelector('pf-back-to-top').addEventListener('click', function() {
// scroll to some element
const target = document.querySelector('#top');
target.scrollIntoView();
target.focus();
});
</script>
25 changes: 25 additions & 0 deletions elements/pf-back-to-top/demo/demo.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
:root {
--_scroll-distance: 400px;
}

main {
scroll-behavior: smooth;
}

.scroll-distance {
--_scroll-distance: 200px;
}

.outer-container {
height: calc(100vh - var(--pf-demo-header-height) + var(--_scroll-distance));
}

.padded {
padding: var(--pf-global--spacer--md, 1rem);
}

.scroll-indicator {
height: var(--_scroll-distance);
background-color: var(--pf-global--palette--cyan-50, #f2f9f9) !important;
}

16 changes: 16 additions & 0 deletions elements/pf-back-to-top/demo/label.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<link rel="stylesheet" href="demo.css">

<div class="outer-container" id="top">
<div class="scroll-indicator padded">
<h2>Default</h2>
<p><a href="#focusable-element-top">Focusable element (top)</a></p>
<pf-icon icon="arrow-down"></pf-icon> Scroll down to end of cyan box, 400px (default).
</div>
</div>
<a href="#focusable-element-bottom">Focusable element (bottom)</a>

<pf-back-to-top scrollable-selector="main" href="#top" label="Top"></pf-back-to-top>

<script type="module">
import '@patternfly/elements/pf-back-to-top/pf-back-to-top.js';
</script>
16 changes: 16 additions & 0 deletions elements/pf-back-to-top/demo/no-text.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<link rel="stylesheet" href="demo.css">

<div class="outer-container" id="top">
<div class="scroll-indicator padded">
<h2>No Text</h2>
<p><a href="#focusable-element-top">Focusable element (top)</a></p>
<pf-icon icon="arrow-down"></pf-icon> Scroll down to end of cyan box, 400px (default).
</div>
</div>
<a href="#focusable-element-bottom">Focusable element (bottom)</a>

<pf-back-to-top scrollable-selector="main" href="top"></pf-back-to-top>

<script type="module">
import '@patternfly/elements/pf-back-to-top/pf-back-to-top.js';
</script>
16 changes: 16 additions & 0 deletions elements/pf-back-to-top/demo/pf-back-to-top.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<link rel="stylesheet" href="demo.css">

<div class="outer-container" id="top">
<div class="scroll-indicator padded">
<h2>Default</h2>
<p><a href="#focusable-element-top">Focusable element (top)</a></p>
<pf-icon icon="arrow-down"></pf-icon> Scroll down to end of cyan box, 400px (default).
</div>
</div>
<a href="#focusable-element-bottom">Focusable element (bottom)</a>

<pf-back-to-top scrollable-selector="main" href="#top">Back to top</pf-back-to-top>

<script type="module">
import '@patternfly/elements/pf-back-to-top/pf-back-to-top.js';
</script>
16 changes: 16 additions & 0 deletions elements/pf-back-to-top/demo/scroll-distance.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<link rel="stylesheet" href="demo.css">

<div class="outer-container scroll-distance" id="top">
<div class="scroll-indicator padded">
<h2>Default</h2>
<p><a href="#focusable-element-top" id="top">Focusable element (top)</a></p>
<pf-icon icon="arrow-down"></pf-icon> Scroll down to end of cyan box, 200px (default).
</div>
</div>
<a href="#focusable-element-bottom">Focusable element (bottom)</a>

<pf-back-to-top href="#top" scrollable-selector="main" scroll-distance="200">Back to top</pf-back-to-top>

<script type="module">
import '@patternfly/elements/pf-back-to-top/pf-back-to-top.js';
</script>
110 changes: 110 additions & 0 deletions elements/pf-back-to-top/docs/pf-back-to-top.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
<style>
:not(.override) > .example-preview pf-back-to-top {
position: sticky !important;
left: 100%;
bottom: 0;
}

:not(.override) > .example-preview pf-back-to-top::part(trigger) {
display: inline-block !important;
}

.override > .example-preview :is(#scrollable-selector-example, #scroll-distance-example) {
position: relative;
height: 200px;
overflow-y: scroll;
}

.override > .example-preview :is(#scrollable-selector-example, #scroll-distance-example) pf-back-to-top {
position: sticky !important;
left: 100%;
bottom: 0;
}

.overflow {
height: 573px;
position: relative;
}

.scroll-indicator {
padding: var(--pf-global--spacer--md, 1rem);
background-color: var(--pf-global--palette--cyan-50, #f2f9f9) !important;
}

#scrollable-selector-example .scroll-indicator {
height: 400px;
}

#scroll-distance-example .scroll-indicator {
height: 100px;
}

</style>

{% renderOverview %}
Back to top button is designed to only be used once per page.
<pf-back-to-top href="#main">Back to top</pf-back-to-top>
{% endrenderOverview %}

{% band header="Usage" %}

### Default
{% htmlexample %}<pf-back-to-top href="#main">Back to top</pf-back-to-top>{% endhtmlexample %}

### Label attribute
{% htmlexample %}<pf-back-to-top href="#main" label="Return to top"></pf-back-to-top>{% endhtmlexample %}

### No text or label attribute
`[aria-label]` attribute defaults to text 'Back to top'
{% htmlexample %}

<pf-back-to-top href="#main"></pf-back-to-top>
{% endhtmlexample %}

<div class="override">

### Scrollable Selector

See [scrollable-selector](#attributes) in Attributes section below for more information.

{% htmlexample %}
<div id="scrollable-selector-example">
<div class="overflow" tabindex="0">
<div class="scroll-indicator">
<pf-icon icon="arrow-down"></pf-icon> Scroll down to end of cyan box, 400px (default).
</div>
</div>
<pf-back-to-top href="#main" scrollable-selector="#scrollable-selector-example">Back to top</pf-back-to-top>
</div>
{% endhtmlexample %}

### Scroll Distance

See [scroll-distance](#attributes) in Attributes section below for more information.

{% htmlexample %}
zeroedin marked this conversation as resolved.
Show resolved Hide resolved
<div id="scroll-distance-example">
<div class="overflow" tabindex="0">
<div class="scroll-indicator">
<pf-icon icon="arrow-down"></pf-icon> Scroll down to end of cyan box, 100px.
</div>
</div>
<pf-back-to-top href="#main" scroll-distance="100" scrollable-selector="#scroll-distance-example">Back to top</pf-back-to-top>
</div>
{% endhtmlexample %}

</div>

{% endband %}

{% renderSlots %}{% endrenderSlots %}

{% renderAttributes %}{% endrenderAttributes %}

{% renderMethods %}{% endrenderMethods %}

{% renderEvents %}{% endrenderEvents %}

{% renderCssCustomProperties %}{% endrenderCssCustomProperties %}

{% renderCssParts %}{% endrenderCssParts %}
53 changes: 53 additions & 0 deletions elements/pf-back-to-top/pf-back-to-top.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
:host {
display: inline-block;
position: absolute;
right: var(--pf-c-back-to-top--Right, var(--pf-global--spacer--2xl, 3rem));
bottom: var(--pf-c-back-to-top--Bottom, var(--pf-global--spacer--lg, 1.5rem));
}

[part="trigger"] {
box-shadow: var(--pf-c-back-to-top--c-button--BoxShadow, var(--pf-global--BoxShadow--lg-bottom, 0 0.75rem 0.75rem -0.5rem rgba(3, 3, 3, 0.18)));

--pf-c-button--FontSize: var(--pf-c-back-to-top--c-button--FontSize, var(--pf-global--FontSize--xs, 0.75rem));
--pf-c-button--BorderRadius: var(--pf-c-back-to-top--c-button--BorderRadius, var(--pf-global--BorderRadius--lg, 30em));
--pf-c-button--PaddingTop: var(--pf-c-back-to-top--c-button--PaddingTop, var(--pf-global--spacer--xs, 0.25rem));
--pf-c-button--PaddingRight: var(--pf-c-back-to-top--c-button--PaddingRight, var(--pf-global--spacer--sm, 0.5rem));
--pf-c-button--PaddingBottom: var(--pf-c-back-to-top--c-button--PaddingBottom, var(--pf-global--spacer--xs, 0.25rem));
--pf-c-button--PaddingLeft: var(--pf-c-back-to-top--c-button--PaddingLeft, var(--pf-global--spacer--sm, 0.5rem));
}

a {
display: inline-flex;
align-items: center;
justify-content: center;
color: var(--pf-c-button--m-primary--Color, var(--pf-global--Color--light-100, #fff));
background-color: var(--pf-c-button--m-primary--BackgroundColor, var(--pf-global--primary-color--100, #06c));
text-decoration: none;
font-size: var(--pf-c-button--FontSize);
padding: var(--pf-c-button--PaddingTop) var(--pf-c-button--PaddingRight) var(--pf-c-button--PaddingBottom) var(--pf-c-button--PaddingLeft);
border-radius: var(--pf-c-button--BorderRadius);
gap: var(--pf-c-button__icon--m-end--MarginLeft, var(--pf-global--spacer--xs, 0.25rem));
}

[part="trigger"][hidden] {
display: none;
}

pf-icon {
/* override icon size as default sm variant is incorrect */
--pf-icon--size: var(--pf-c-button--FontSize);
vertical-align: -0.125rem;
}

span {
display: inline-flex;
align-items: center;
justify-content: center;
gap: var(--pf-c-button__icon--m-end--MarginLeft, var(--pf-global--spacer--xs, 0.25rem));
}

@media (min-width: 768px) {
:host {
--pf-c-back-to-top--Bottom: var(--pf-c-back-to-top--md--Bottom, var(--pf-global--spacer--2xl, 3rem));
}
}
Loading
Loading