Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
1 change: 1 addition & 0 deletions .config/cem.yaml
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
sourceControlRootUrl: https://github.com/patternfly/patternfly-elements/tree/main/
generate:
output: ./elements/custom-elements.json
files:
- ./elements/*/*.ts
- ./core/*/*.ts
Expand Down
1 change: 1 addition & 0 deletions elements/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@
"./pf-v5-progress/pf-v5-progress.js": "./pf-v5-progress/pf-v5-progress.js",
"./pf-v5-search-input/pf-v5-search-input.js": "./pf-v5-search-input/pf-v5-search-input.js",
"./pf-v5-spinner/pf-v5-spinner.js": "./pf-v5-spinner/pf-v5-spinner.js",
"./pf-v6-spinner/pf-v6-spinner.js": "./pf-v6-spinner/pf-v6-spinner.js",
"./pf-v5-switch/pf-v5-switch.js": "./pf-v5-switch/pf-v5-switch.js",
"./pf-v5-table/context.js": "./pf-v5-table/context.js",
"./pf-v5-table/pf-v5-caption.js": "./pf-v5-table/pf-v5-caption.js",
Expand Down
17 changes: 17 additions & 0 deletions elements/pf-v6-spinner/demo/basic.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
---
name: Basic
description: A basic spinner indicates that an action is in progress.
---
<section>
<pf-v6-spinner accessible-label="Loading contents">Loading...</pf-v6-spinner>
</section>

<script type="module">
import '@patternfly/elements/pf-v6-spinner/pf-v6-spinner.js';
</script>

<style>
section {
padding: 1em;
}
</style>
17 changes: 17 additions & 0 deletions elements/pf-v6-spinner/demo/custom-size.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
---
name: Custom size
description: A spinner can have a custom diameter using the `diameter` attribute.
---
<section>
<pf-v6-spinner diameter="80px" accessible-label="Custom size spinner">Loading...</pf-v6-spinner>
</section>

<script type="module">
import '@patternfly/elements/pf-v6-spinner/pf-v6-spinner.js';
</script>

<style>
section {
padding: 1em;
}
</style>
35 changes: 35 additions & 0 deletions elements/pf-v6-spinner/demo/inline-size.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
---
name: Inline size
description: An inline spinner inherits its font size, so its size will match the content around it.
---
<section>
<h1>
Heading
<pf-v6-spinner inline accessible-label="Spinner in a heading">Loading...</pf-v6-spinner>
</h1>
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed hendrerit nisi in cursus maximus.</p>
<h2>
Second level
<pf-v6-spinner inline accessible-label="Spinner in a subheading">Loading...</pf-v6-spinner>
</h2>
<p>
Curabitur accumsan turpis pharetra blandit. Quisque condimentum maximus mi,
<pf-v6-spinner inline accessible-label="Spinner in a paragraph">Loading...</pf-v6-spinner>
sit amet commodo arcu rutrum id. Proin pretium urna vel cursus venenatis.
Suspendisse potenti.
</p>
<small>
Sometimes you need small text
<pf-v6-spinner inline accessible-label="Spinner in small text">Loading...</pf-v6-spinner>
</small>
</section>

<script type="module">
import '@patternfly/elements/pf-v6-spinner/pf-v6-spinner.js';
</script>

<style>
section {
padding: 1em;
}
</style>
24 changes: 24 additions & 0 deletions elements/pf-v6-spinner/demo/size-variations.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
---
name: Size variations
description: Spinners can be sized using the `size` attribute with values `xs`, `sm`, `md`, `lg`, and `xl`.
---
<section>
<pf-v6-spinner size="xs" accessible-label="Extra small spinner">Loading...</pf-v6-spinner>
<pf-v6-spinner size="sm" accessible-label="Small spinner">Loading...</pf-v6-spinner>
<pf-v6-spinner size="md" accessible-label="Medium spinner">Loading...</pf-v6-spinner>
<pf-v6-spinner size="lg" accessible-label="Large spinner">Loading...</pf-v6-spinner>
<pf-v6-spinner size="xl" accessible-label="Extra large spinner">Loading...</pf-v6-spinner>
</section>

<script type="module">
import '@patternfly/elements/pf-v6-spinner/pf-v6-spinner.js';
</script>

<style>
section {
display: flex;
align-items: center;
gap: 1em;
padding: 1em;
}
</style>
112 changes: 112 additions & 0 deletions elements/pf-v6-spinner/pf-v6-spinner.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
:host {
display: inline-block;
width: min-content;
min-height: 0;
aspect-ratio: 1 / 1;
}

[hidden] {
display: none !important;
}

svg {
overflow: hidden;
width: var(--pf-v6-c-spinner--Width,
var(--pf-v6-c-spinner--diameter,
var(--pf-t--global--icon--size--2xl, 3.5rem)));
height: var(--pf-v6-c-spinner--Height,
var(--pf-v6-c-spinner--diameter,
var(--pf-t--global--icon--size--2xl, 3.5rem)));
animation:
rotate
calc(var(--pf-v6-c-spinner--AnimationDuration, 1.4s) * 2)
var(--pf-v6-c-spinner--AnimationTimingFunction, linear) infinite;
}

circle {
width: 100%;
height: 100%;
transform-origin: 50% 50%;
stroke-linecap: round;
stroke-dasharray: 283;
stroke-dashoffset: 280;
stroke: var(--pf-v6-c-spinner--Color,
var(--pf-t--global--icon--color--brand--default, #0066cc));
stroke-width: var(--pf-v6-c-spinner--StrokeWidth, 10);
animation:
dash
var(--pf-v6-c-spinner--AnimationDuration, 1.4s)
var(--pf-v6-c-spinner__path--AnimationTimingFunction, ease-in-out) infinite;
}

:host([size="xs"]) svg {
--pf-v6-c-spinner--diameter: var(--pf-v6-c-spinner--m-xs--diameter,
var(--pf-t--global--icon--size--sm, 0.75rem));

& circle {
stroke-width: var(--pf-v6-c-spinner--StrokeWidth, 15);
}
}

:host([size="sm"]) svg {
--pf-v6-c-spinner--diameter: var(--pf-v6-c-spinner--m-sm--diameter,
var(--pf-t--global--icon--size--md, 0.875rem));
}

:host([size="md"]) svg {
--pf-v6-c-spinner--diameter: var(--pf-v6-c-spinner--m-md--diameter,
var(--pf-t--global--icon--size--lg, 1rem));
}

:host([size="lg"]) svg {
--pf-v6-c-spinner--diameter: var(--pf-v6-c-spinner--m-lg--diameter,
var(--pf-t--global--icon--size--xl, 1.5rem));
}

:host([size="xl"]) svg {
--pf-v6-c-spinner--diameter: var(--pf-v6-c-spinner--m-xl--diameter,
var(--pf-t--global--icon--size--2xl, 3.5rem));
}

:host([inline]) svg {
--pf-v6-c-spinner--diameter: var(--pf-v6-c-spinner--m-inline--diameter, 1em);
}

@keyframes rotate {
0% {
rotate: 0deg;
}

100% {
rotate: 360deg;
}
}

@keyframes dash {
0% {
stroke-dashoffset: 280;
rotate: 0deg;
}

15% {
stroke-width: calc(var(--pf-v6-c-spinner__path--StrokeWidth,
var(--pf-v6-c-spinner--StrokeWidth, 10)) - 4);
}

40% {
stroke-dasharray: 220;
stroke-dashoffset: 150;
}

100% {
stroke-dashoffset: 280;
rotate: 720deg;
}
}

@media (prefers-reduced-motion: reduce) {
svg,
circle {
animation-duration: 0s;
}
}
73 changes: 73 additions & 0 deletions elements/pf-v6-spinner/pf-v6-spinner.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
import { LitElement, html, type TemplateResult } from 'lit';
import { customElement } from 'lit/decorators/custom-element.js';
import { property } from 'lit/decorators/property.js';

import { InternalsController } from '@patternfly/pfe-core/controllers/internals-controller.js';

import styles from './pf-v6-spinner.css';

export type SpinnerSize = 'xs' | 'sm' | 'md' | 'lg' | 'xl';

/**
* A **spinner** is an animated visual that indicates when a quick action is
* in progress. For actions that may take a long time, use a progress bar instead.
* @summary Indicates that an action is in progress.
* @cssprop {<length>} [--pf-v6-c-spinner--diameter] - Custom diameter of the spinner
* @cssprop {<color>} [--pf-v6-c-spinner--Color] - Color of the spinner stroke
* @cssprop {<time>} [--pf-v6-c-spinner--AnimationDuration=1.4s] - Duration of one animation cycle
* @cssprop {<number>} [--pf-v6-c-spinner--StrokeWidth=10] - Width of the spinner stroke
*/
@customElement('pf-v6-spinner')
export class PfV6Spinner extends LitElement {
static readonly styles: CSSStyleSheet[] = [styles];

/** Preset sizes for the spinner */
@property({ reflect: true }) size?: SpinnerSize;

/**
* When true, the spinner inherits its font size from the surrounding text,
* allowing it to display inline with content.
*/
@property({ type: Boolean, reflect: true }) inline = false;

/** Custom diameter of spinner set as CSS variable */
@property({ reflect: true }) diameter?: string;

/** Accessible label describing what is loading */
@property({ attribute: 'accessible-label' }) accessibleLabel?: string;

#internals = InternalsController.of(this, {
role: 'progressbar',
ariaValueText: 'Loading...',
ariaLabel: 'Loading...',
});

override willUpdate(changed: Map<PropertyKey, unknown>): void {
if (changed.has('accessibleLabel')) {
const label = this.accessibleLabel ?? 'Loading...';
this.#internals.ariaLabel = label;
this.#internals.ariaValueText = label;
}
if (changed.has('diameter')) {
if (this.diameter) {
this.style.setProperty('--pf-v6-c-spinner--diameter', this.diameter);
} else {
this.style.removeProperty('--pf-v6-c-spinner--diameter');
}
}
}

override render(): TemplateResult {
return html`
<svg viewBox="0 0 100 100" aria-hidden="true">
<circle cx="50" cy="50" r="45" fill="none" />
</svg>
`;
}
}

declare global {
interface HTMLElementTagNameMap {
'pf-v6-spinner': PfV6Spinner;
}
}
Loading
Loading