diff --git a/.changeset/flat-snails-admire.md b/.changeset/flat-snails-admire.md
new file mode 100644
index 0000000000..fa25475ac2
--- /dev/null
+++ b/.changeset/flat-snails-admire.md
@@ -0,0 +1,7 @@
+---
+"@spectrum-css/infieldprogresscircle": major
+---
+
+## Infield Progresscircle S2 Migration
+
+In-field progress circle is a new component created to replace progress circle (size S) in t-shirt size components. The button, textfield, combo box, and picker `template.js` files have all been updated to call for infield progress circles. This component comes in four sizes: (S, M, L, XL), has updated color variants (default, white, black), and has a unified track thickness.
diff --git a/components/button/stories/template.js b/components/button/stories/template.js
index cecada6f7a..1fa7369774 100644
--- a/components/button/stories/template.js
+++ b/components/button/stories/template.js
@@ -1,6 +1,6 @@
import { Template as Icon } from "@spectrum-css/icon/stories/template.js";
+import { Template as InfieldProgressCircle } from "@spectrum-css/infieldprogresscircle/stories/template.js";
import { Container, getRandomId } from "@spectrum-css/preview/decorators";
-import { Template as ProgressCircle } from "@spectrum-css/progresscircle/stories/template.js";
import { html } from "lit";
import { classMap } from "lit/directives/class-map.js";
import { ifDefined } from "lit/directives/if-defined.js";
@@ -89,15 +89,12 @@ export const Template = ({
Icon({ iconName, setName: iconSet, size }, context)
)}
${when(isPending, () =>
- ProgressCircle(
- {
- size: "s",
- testId: "progress-circle",
- staticColor,
- isIndeterminate: true,
- },
- context
- )
+ InfieldProgressCircle({
+ size: size,
+ staticColor,
+ isIndeterminate: true,
+ testId: "infield-progress-circle"
+ }, context)
)}
`;
diff --git a/components/combobox/stories/template.js b/components/combobox/stories/template.js
index 96dfdcf25e..f8cc0dbc1b 100644
--- a/components/combobox/stories/template.js
+++ b/components/combobox/stories/template.js
@@ -63,7 +63,7 @@ const Combobox = ({
],
customInputClasses: [`${rootClass}-input`],
isLoading,
- customProgressCircleClasses: ["spectrum-Combobox-progress-circle"],
+ customInfieldProgressCircleClasses: ["spectrum-Combobox-progress-circle"],
name: "field",
isReadOnly,
value,
diff --git a/components/infieldprogresscircle/README.md b/components/infieldprogresscircle/README.md
new file mode 100644
index 0000000000..4d411cc950
--- /dev/null
+++ b/components/infieldprogresscircle/README.md
@@ -0,0 +1,7 @@
+# @spectrum-css/infieldprogresscircle
+
+> The Spectrum CSS infield progress circle component
+
+This package is part of the [Spectrum CSS project](https://github.com/adobe/spectrum-css).
+
+See the [Spectrum CSS documentation](https://opensource.adobe.com/spectrum-css/) and [Spectrum CSS on GitHub](https://github.com/adobe/spectrum-css) for details.
diff --git a/components/infieldprogresscircle/dist/metadata.json b/components/infieldprogresscircle/dist/metadata.json
new file mode 100644
index 0000000000..ffc95f1139
--- /dev/null
+++ b/components/infieldprogresscircle/dist/metadata.json
@@ -0,0 +1,25 @@
+{
+ "sourceFile": "index.css",
+ "selectors": [
+ ".spectrum-InfieldProgressCircle",
+ ".spectrum-InfieldProgressCircle .spectrum-ProgressCircle-fill",
+ ".spectrum-InfieldProgressCircle--sizeL",
+ ".spectrum-InfieldProgressCircle--sizeS",
+ ".spectrum-InfieldProgressCircle--sizeXL"
+ ],
+ "modifiers": [],
+ "component": [
+ "--spectrum-in-field-progress-circle-edge-to-fill",
+ "--spectrum-in-field-progress-circle-size-100",
+ "--spectrum-in-field-progress-circle-size-200",
+ "--spectrum-in-field-progress-circle-size-300",
+ "--spectrum-in-field-progress-circle-size-75",
+ "--spectrum-infieldprogresscircle-padding-block"
+ ],
+ "global": ["--spectrum-progress-circle-thickness-small"],
+ "passthroughs": [
+ "--mod-progress-circle-size",
+ "--mod-progress-circle-thickness"
+ ],
+ "high-contrast": []
+}
diff --git a/components/infieldprogresscircle/index.css b/components/infieldprogresscircle/index.css
new file mode 100644
index 0000000000..e3525eccc4
--- /dev/null
+++ b/components/infieldprogresscircle/index.css
@@ -0,0 +1,37 @@
+/*!
+Copyright 2025 Adobe. All rights reserved.
+This file is licensed to you under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License. You may obtain a copy
+of the License at http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software distributed under
+the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
+OF ANY KIND, either express or implied. See the License for the specific language
+governing permissions and limitations under the License.
+*/
+
+.spectrum-InfieldProgressCircle {
+ --mod-progress-circle-thickness: var(--spectrum-progress-circle-thickness-small);
+ --mod-progress-circle-size: var(--spectrum-in-field-progress-circle-size-100);
+ --spectrum-infieldprogresscircle-padding-block: var(--spectrum-in-field-progress-circle-edge-to-fill);
+}
+
+.spectrum-InfieldProgressCircle--sizeS {
+ --mod-progress-circle-size: var(--spectrum-in-field-progress-circle-size-75);
+}
+
+.spectrum-InfieldProgressCircle--sizeL {
+ --mod-progress-circle-size: var(--spectrum-in-field-progress-circle-size-200);
+}
+
+.spectrum-InfieldProgressCircle--sizeXL {
+ --mod-progress-circle-size: var(--spectrum-in-field-progress-circle-size-300);
+}
+
+.spectrum-InfieldProgressCircle {
+ padding-block: var(--spectrum-infieldprogresscircle-padding-block);
+
+ .spectrum-ProgressCircle-fill {
+ stroke-linecap: square;
+ }
+}
diff --git a/components/infieldprogresscircle/package.json b/components/infieldprogresscircle/package.json
new file mode 100644
index 0000000000..a8248fc83c
--- /dev/null
+++ b/components/infieldprogresscircle/package.json
@@ -0,0 +1,52 @@
+{
+ "name": "@spectrum-css/infieldprogresscircle",
+ "version": "0.0.0",
+ "description": "The Spectrum CSS infieldprogresscircle component",
+ "license": "Apache-2.0",
+ "author": "Adobe",
+ "homepage": "https://opensource.adobe.com/spectrum-css/?path=/docs/components-in-field-progress-circle--docs",
+ "repository": {
+ "type": "git",
+ "url": "https://github.com/adobe/spectrum-css.git",
+ "directory": "components/infieldprogresscircle"
+ },
+ "bugs": {
+ "url": "https://github.com/adobe/spectrum-css/issues"
+ },
+ "exports": {
+ ".": "./dist/index.css",
+ "./*.md": "./*.md",
+ "./dist/*": "./dist/*",
+ "./index-*.css": "./dist/index-*.css",
+ "./index.css": "./dist/index.css",
+ "./metadata.json": "./dist/metadata.json",
+ "./package.json": "./package.json",
+ "./stories/*": "./stories/*"
+ },
+ "main": "dist/index.css",
+ "peerDependencies": {
+ "@spectrum-css/tokens": ">=16"
+ },
+ "devDependencies": {
+ "@spectrum-css/tokens": "16.0.0"
+ },
+ "keywords": [
+ "design-system",
+ "spectrum",
+ "spectrum-css",
+ "adobe",
+ "adobe-spectrum",
+ "component",
+ "css"
+ ],
+ "publishConfig": {
+ "access": "public"
+ },
+ "spectrum": [
+ {
+ "guidelines": "https://spectrum.adobe.com/page/progress-circle",
+ "rootClass": "spectrum-InfieldProgressCircle",
+ "swc": "https://opensource.adobe.com/spectrum-web-components/components/progress-circle/"
+ }
+ ]
+}
diff --git a/components/infieldprogresscircle/project.json b/components/infieldprogresscircle/project.json
new file mode 100644
index 0000000000..ff11b0651f
--- /dev/null
+++ b/components/infieldprogresscircle/project.json
@@ -0,0 +1,17 @@
+{
+ "$schema": "../../node_modules/nx/schemas/project-schema.json",
+ "name": "infieldprogresscircle",
+ "tags": ["component"],
+ "targets": {
+ "build": {},
+ "clean": {},
+ "compare": {},
+ "format": {},
+ "lint": {},
+ "report": {},
+ "test": {
+ "defaultConfiguration": "scope"
+ },
+ "validate": {}
+ }
+}
diff --git a/components/infieldprogresscircle/stories/infieldprogresscircle.stories.js b/components/infieldprogresscircle/stories/infieldprogresscircle.stories.js
new file mode 100644
index 0000000000..e8c60ee9d6
--- /dev/null
+++ b/components/infieldprogresscircle/stories/infieldprogresscircle.stories.js
@@ -0,0 +1,121 @@
+import { Sizes } from "@spectrum-css/preview/decorators";
+import { disableDefaultModes } from "@spectrum-css/preview/modes";
+import { size } from "@spectrum-css/preview/types";
+import { default as ProgressCircle } from "@spectrum-css/progresscircle/stories/progresscircle.stories.js";
+import metadata from "../dist/metadata.json";
+import packageJson from "../package.json";
+import { InfieldProgressCircleGroup } from "./infieldprogresscircle.test.js";
+import { Template } from "./template.js";
+
+/**
+ * In-field progress circles are used in t-shirt size components such as [buttons](/docs/components-button--docs), [combo boxes](/docs/components-combobox--docs), and [pickers](/docs/components-picker--docs). The in-field progress circle can be used in place of an icon or in tight spaces when space is limited both vertically and horizontally.
+*/
+
+export default {
+ title: "In-field progress circle",
+ component: "InfieldProgressCircle",
+ argTypes: {
+ ...ProgressCircle.argTypes,
+ size: size(["s", "m", "l", "xl"]),
+ },
+ args: {
+ ...ProgressCircle.args,
+ rootClass: "spectrum-InfieldProgressCircle",
+ },
+ parameters: {
+ ...ProgressCircle.parameters,
+ design: {
+ type: "figma",
+ url: "https://www.figma.com/design/eoZHKJH9a3LJkHYCGt60Vb/S2-token-specs?node-id=14970-6050",
+ },
+ packageJson,
+ metadata,
+ }
+};
+
+export const Default = InfieldProgressCircleGroup.bind({});
+Default.args = {};
+
+// ********* VRT ONLY ********* //
+export const WithForcedColors = InfieldProgressCircleGroup.bind({});
+WithForcedColors.args = Default.args;
+WithForcedColors.tags = ["!autodocs", "!dev"];
+WithForcedColors.parameters = {
+ chromatic: {
+ forcedColors: "active",
+ modes: disableDefaultModes,
+ },
+};
+
+// ********* DOCS ONLY ********* //
+
+export const Sizing = (args, context) => Sizes({
+ Template,
+ withHeading: false,
+ withBorder: false,
+ ...args,
+}, context);
+Sizing.args = {};
+Sizing.tags = ["!dev"];
+Sizing.parameters = {
+ chromatic: { disableSnapshot: true },
+};
+
+/**
+ * The indeterminate progress circle displays a repeating animation for the inner fill.
+ */
+export const Indeterminate = (args, context) => Sizes({
+ Template,
+ withHeading: false,
+ withBorder: false,
+ ...args,
+}, context);
+Indeterminate.args = {
+ isIndeterminate: true,
+};
+Indeterminate.tags = ["!dev"];
+Indeterminate.parameters = {
+ chromatic: { disableSnapshot: true },
+};
+
+export const StaticWhiteDeterminate = Sizing.bind({});
+StaticWhiteDeterminate.tags = ["!dev"];
+StaticWhiteDeterminate.storyName = "Static white, default";
+StaticWhiteDeterminate.args = {
+ staticColor: "white",
+};
+StaticWhiteDeterminate.parameters = {
+ chromatic: { disableSnapshot: true },
+};
+
+export const StaticWhiteIndeterminate = Sizing.bind({});
+StaticWhiteIndeterminate.tags = ["!dev"];
+StaticWhiteIndeterminate.storyName = "Static white, indeterminate";
+StaticWhiteIndeterminate.args = {
+ staticColor: "white",
+ isIndeterminate: true,
+};
+StaticWhiteIndeterminate.parameters = {
+ chromatic: { disableSnapshot: true },
+};
+
+export const StaticBlackDeterminate = Sizing.bind({});
+StaticBlackDeterminate.tags = ["!dev"];
+StaticBlackDeterminate.storyName = "Static black, default";
+StaticBlackDeterminate.args = {
+ staticColor: "black",
+};
+StaticBlackDeterminate.parameters = {
+ chromatic: { disableSnapshot: true },
+};
+
+export const StaticBlackIndeterminate = Sizing.bind({});
+StaticBlackIndeterminate.tags = ["!dev"];
+StaticBlackIndeterminate.storyName = "Static black, indeterminate";
+StaticBlackIndeterminate.args = {
+ staticColor: "black",
+ isIndeterminate: true,
+};
+StaticBlackIndeterminate.parameters = {
+ chromatic: { disableSnapshot: true },
+};
diff --git a/components/infieldprogresscircle/stories/infieldprogresscircle.test.js b/components/infieldprogresscircle/stories/infieldprogresscircle.test.js
new file mode 100644
index 0000000000..2ef07f947a
--- /dev/null
+++ b/components/infieldprogresscircle/stories/infieldprogresscircle.test.js
@@ -0,0 +1,25 @@
+import { Variants } from "@spectrum-css/preview/decorators";
+import { Template } from "./template.js";
+
+export const InfieldProgressCircleGroup = Variants({
+ Template,
+ testData: [
+ {
+ testHeading: "Default",
+ },
+ {
+ testHeading: "Static white",
+ staticColor: "white",
+ },
+ {
+ testHeading: "Static black",
+ staticColor: "black",
+ },
+ ],
+ stateData: [
+ {
+ testHeading: "Indeterminate",
+ isIndeterminate: true,
+ }
+ ]
+});
diff --git a/components/infieldprogresscircle/stories/template.js b/components/infieldprogresscircle/stories/template.js
new file mode 100644
index 0000000000..7f8fc1f8de
--- /dev/null
+++ b/components/infieldprogresscircle/stories/template.js
@@ -0,0 +1,21 @@
+import { Template as ProgressCircle } from "@spectrum-css/progresscircle/stories/template.js";
+import { capitalize } from "lodash-es";
+import "../index.css";
+
+export const Template = ({
+ customClasses = [],
+ rootClass = "spectrum-InfieldProgressCircle",
+ size = "m",
+ staticColor,
+ ...item
+} = {}, context = {}) => ProgressCircle({
+ customClasses: [
+ rootClass,
+ typeof size !== "undefined" ? `${rootClass}--size${size.toUpperCase()}` : null,
+ typeof staticColor !== "undefined" ? `${rootClass}--static${capitalize(staticColor)}` : null,
+ ...customClasses
+ ].filter(Boolean),
+ size,
+ staticColor,
+ ...item
+}, context );
diff --git a/components/picker/stories/template.js b/components/picker/stories/template.js
index f1219f9808..0d8bec6d42 100644
--- a/components/picker/stories/template.js
+++ b/components/picker/stories/template.js
@@ -1,9 +1,9 @@
import { Template as FieldLabel } from "@spectrum-css/fieldlabel/stories/template.js";
import { Template as HelpText } from "@spectrum-css/helptext/stories/template.js";
import { Template as Icon } from "@spectrum-css/icon/stories/template.js";
+import { Template as InfieldProgressCircle } from "@spectrum-css/infieldprogresscircle/stories/template.js";
import { Template as Popover } from "@spectrum-css/popover/stories/template.js";
import { Container, getRandomId } from "@spectrum-css/preview/decorators";
-import { Template as ProgressCircle } from "@spectrum-css/progresscircle/stories/template.js";
import { Template as Switch } from "@spectrum-css/switch/stories/template.js";
import { html } from "lit";
import { classMap } from "lit/directives/class-map.js";
@@ -78,8 +78,8 @@ export const Picker = ({
}
${placeholder}
${when(isLoading, () =>
- ProgressCircle({
- size: "s",
+ InfieldProgressCircle({
+ size: size,
isIndeterminate: true,
}, context)
)}
diff --git a/components/progresscircle/stories/progresscircle.stories.js b/components/progresscircle/stories/progresscircle.stories.js
index ac3f311133..9146a54f0f 100644
--- a/components/progresscircle/stories/progresscircle.stories.js
+++ b/components/progresscircle/stories/progresscircle.stories.js
@@ -17,11 +17,18 @@ export default {
isIndeterminate,
staticColor,
value: {
+ name: "Percent filled",
+ type: { name: "number" },
+ table: {
+ type: { summary: "number" },
+ category: "Content",
+ },
control: {
type: "range",
min: 0,
max: 100
- }
+ },
+ if: { arg: "isIndeterminate", truthy: false },
}
},
args: {
diff --git a/components/textfield/stories/template.js b/components/textfield/stories/template.js
index 55c2d55d12..9413a7504e 100644
--- a/components/textfield/stories/template.js
+++ b/components/textfield/stories/template.js
@@ -1,8 +1,8 @@
import { Template as FieldLabel } from "@spectrum-css/fieldlabel/stories/template.js";
import { Template as HelpText } from "@spectrum-css/helptext/stories/template.js";
import { Template as Icon } from "@spectrum-css/icon/stories/template.js";
+import { Template as InfieldProgressCircle } from "@spectrum-css/infieldprogresscircle/stories/template.js";
import { Container, getRandomId } from "@spectrum-css/preview/decorators";
-import { Template as ProgressCircle } from "@spectrum-css/progresscircle/stories/template.js";
import { html } from "lit";
import { classMap } from "lit/directives/class-map.js";
import { ifDefined } from "lit/directives/if-defined.js";
@@ -18,7 +18,7 @@ import "../index.css";
* @property {string[]} [customClasses=[]]
* @property {string[]} [customInputClasses=[]]
* @property {string[]} [customIconClasses=[]]
- * @property {string[]} [customProgressCircleClasses=[]]
+ * @property {string[]} [customInfieldProgressCircleClasses=[]]
* @property {Record} [customStyles={}]
* @property {boolean} [isInvalid=false]
* @property {boolean} [isValid=false]
@@ -58,7 +58,7 @@ export const Template = ({
customClasses = [],
customInputClasses = [],
customIconClasses = [],
- customProgressCircleClasses = [],
+ customInfieldProgressCircleClasses = [],
isInvalid = false,
isValid = false,
multiline = false,
@@ -196,10 +196,10 @@ export const Template = ({
})}
/>`
)}
- ${when(isLoading, () => ProgressCircle({
+ ${when(isLoading, () => InfieldProgressCircle({
isIndeterminate: true,
- size: "s",
- customClasses: customProgressCircleClasses,
+ size: size,
+ customClasses: customInfieldProgressCircleClasses,
}, context))}
${when(helpText, () =>
HelpText({
diff --git a/tools/bundle/package.json b/tools/bundle/package.json
index 118d537cbb..705df26f32 100644
--- a/tools/bundle/package.json
+++ b/tools/bundle/package.json
@@ -74,6 +74,7 @@
"@spectrum-css/icon": "workspace:^",
"@spectrum-css/illustratedmessage": "workspace:^",
"@spectrum-css/infieldbutton": "workspace:^",
+ "@spectrum-css/infieldprogresscircle": "workspace:^",
"@spectrum-css/inlinealert": "workspace:^",
"@spectrum-css/link": "workspace:^",
"@spectrum-css/logicbutton": "workspace:^",
diff --git a/tools/bundle/src/index.css b/tools/bundle/src/index.css
index 31d68ccee0..3f1db509c7 100644
--- a/tools/bundle/src/index.css
+++ b/tools/bundle/src/index.css
@@ -66,6 +66,7 @@
@import "@spectrum-css/icon";
@import "@spectrum-css/illustratedmessage";
@import "@spectrum-css/infieldbutton";
+@import "@spectrum-css/infieldprogresscircle";
@import "@spectrum-css/inlinealert";
@import "@spectrum-css/link";
@import "@spectrum-css/logicbutton";
diff --git a/yarn.lock b/yarn.lock
index 6a9bc09938..86493c1f22 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -3902,6 +3902,7 @@ __metadata:
"@spectrum-css/icon": "workspace:^"
"@spectrum-css/illustratedmessage": "workspace:^"
"@spectrum-css/infieldbutton": "workspace:^"
+ "@spectrum-css/infieldprogresscircle": "workspace:^"
"@spectrum-css/inlinealert": "workspace:^"
"@spectrum-css/link": "workspace:^"
"@spectrum-css/logicbutton": "workspace:^"
@@ -4440,6 +4441,16 @@ __metadata:
languageName: unknown
linkType: soft
+"@spectrum-css/infieldprogresscircle@workspace:^, @spectrum-css/infieldprogresscircle@workspace:components/infieldprogresscircle":
+ version: 0.0.0-use.local
+ resolution: "@spectrum-css/infieldprogresscircle@workspace:components/infieldprogresscircle"
+ dependencies:
+ "@spectrum-css/tokens": "npm:16.0.0"
+ peerDependencies:
+ "@spectrum-css/tokens": ">=16"
+ languageName: unknown
+ linkType: soft
+
"@spectrum-css/inlinealert@workspace:^, @spectrum-css/inlinealert@workspace:components/inlinealert":
version: 0.0.0-use.local
resolution: "@spectrum-css/inlinealert@workspace:components/inlinealert"