diff --git a/.config/cem.yaml b/.config/cem.yaml index febc90fcec..86f5f070a6 100644 --- a/.config/cem.yaml +++ b/.config/cem.yaml @@ -1,5 +1,6 @@ sourceControlRootUrl: https://github.com/patternfly/patternfly-elements/tree/main/ generate: + output: ./elements/custom-elements.json files: - ./elements/*/*.ts - ./core/*/*.ts diff --git a/elements/package.json b/elements/package.json index fe8dda2080..6e3341d464 100644 --- a/elements/package.json +++ b/elements/package.json @@ -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", diff --git a/elements/pf-v6-spinner/demo/basic.html b/elements/pf-v6-spinner/demo/basic.html new file mode 100644 index 0000000000..38bfd69761 --- /dev/null +++ b/elements/pf-v6-spinner/demo/basic.html @@ -0,0 +1,17 @@ +--- +name: Basic +description: A basic spinner indicates that an action is in progress. +--- +
+ Loading... +
+ + + + diff --git a/elements/pf-v6-spinner/demo/custom-size.html b/elements/pf-v6-spinner/demo/custom-size.html new file mode 100644 index 0000000000..5c0b3f6d31 --- /dev/null +++ b/elements/pf-v6-spinner/demo/custom-size.html @@ -0,0 +1,17 @@ +--- +name: Custom size +description: A spinner can have a custom diameter using the `diameter` attribute. +--- +
+ Loading... +
+ + + + diff --git a/elements/pf-v6-spinner/demo/inline-size.html b/elements/pf-v6-spinner/demo/inline-size.html new file mode 100644 index 0000000000..ac12dc37a2 --- /dev/null +++ b/elements/pf-v6-spinner/demo/inline-size.html @@ -0,0 +1,35 @@ +--- +name: Inline size +description: An inline spinner inherits its font size, so its size will match the content around it. +--- +
+

+ Heading + Loading... +

+

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed hendrerit nisi in cursus maximus.

+

+ Second level + Loading... +

+

+ Curabitur accumsan turpis pharetra blandit. Quisque condimentum maximus mi, + Loading... + sit amet commodo arcu rutrum id. Proin pretium urna vel cursus venenatis. + Suspendisse potenti. +

+ + Sometimes you need small text + Loading... + +
+ + + + diff --git a/elements/pf-v6-spinner/demo/size-variations.html b/elements/pf-v6-spinner/demo/size-variations.html new file mode 100644 index 0000000000..16c5cd04af --- /dev/null +++ b/elements/pf-v6-spinner/demo/size-variations.html @@ -0,0 +1,24 @@ +--- +name: Size variations +description: Spinners can be sized using the `size` attribute with values `xs`, `sm`, `md`, `lg`, and `xl`. +--- +
+ Loading... + Loading... + Loading... + Loading... + Loading... +
+ + + + diff --git a/elements/pf-v6-spinner/pf-v6-spinner.css b/elements/pf-v6-spinner/pf-v6-spinner.css new file mode 100644 index 0000000000..cbe75ade0d --- /dev/null +++ b/elements/pf-v6-spinner/pf-v6-spinner.css @@ -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; + } +} diff --git a/elements/pf-v6-spinner/pf-v6-spinner.ts b/elements/pf-v6-spinner/pf-v6-spinner.ts new file mode 100644 index 0000000000..3d77fc1a5c --- /dev/null +++ b/elements/pf-v6-spinner/pf-v6-spinner.ts @@ -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 {} [--pf-v6-c-spinner--diameter] - Custom diameter of the spinner + * @cssprop {} [--pf-v6-c-spinner--Color] - Color of the spinner stroke + * @cssprop {