diff --git a/.changeset/solid-mugs-jog.md b/.changeset/solid-mugs-jog.md new file mode 100644 index 0000000000..12a642a7c5 --- /dev/null +++ b/.changeset/solid-mugs-jog.md @@ -0,0 +1,10 @@ +--- +"@stackoverflow/stacks": patch +"@stackoverflow/stacks-svelte": minor +--- + +**Activity Indicator Updates:** + +- **Stacks Classic**: Updated activity indicator component to the new visual language (default 16x16). Introduced `.s-activity-indicator__sm` variant (10x10). + +- **Stacks Svelte**: Added new `ActivityIndicator` component. diff --git a/packages/stacks-classic/lib/components/activity-indicator/activity-indicator.a11y.test.ts b/packages/stacks-classic/lib/components/activity-indicator/activity-indicator.a11y.test.ts index 21379b90ac..239b25d079 100644 --- a/packages/stacks-classic/lib/components/activity-indicator/activity-indicator.a11y.test.ts +++ b/packages/stacks-classic/lib/components/activity-indicator/activity-indicator.a11y.test.ts @@ -5,9 +5,15 @@ describe("activity-indicator", () => { runA11yTests({ baseClass: "s-activity-indicator", variants: ["danger", "success", "warning"], + modifiers: { + primary: ["sm"], + }, children: { default: `
New activity
`, new: `new
New activity
`, }, + excludedTestids: [ + /^s-activity-indicator-(?=.*sm).*new$/, // s-activity-indicator with content in sm size not supported + ], }); }); diff --git a/packages/stacks-classic/lib/components/activity-indicator/activity-indicator.less b/packages/stacks-classic/lib/components/activity-indicator/activity-indicator.less index 555806d93d..42967b4779 100644 --- a/packages/stacks-classic/lib/components/activity-indicator/activity-indicator.less +++ b/packages/stacks-classic/lib/components/activity-indicator/activity-indicator.less @@ -1,7 +1,8 @@ .s-activity-indicator { - --_ai-translucent: var(--translucent-secondary); --_ai-bg: var(--theme-secondary-400); --_ai-fc: var(--white); + --_ai-min-size: var(--su-static16); + --_ai-p: 0 calc(var(--su-static4) - var(--su-static1)); .highcontrast-mode({ --_ai-bg: var(--theme-secondary-500); @@ -10,7 +11,6 @@ // VARIANTS &&__danger { --_ai-bg: var(--red-400); - --_ai-translucent: var(--translucent-error); .highcontrast-mode({ --_ai-bg: var(--red-500); @@ -19,7 +19,6 @@ &&__success { --_ai-bg: var(--green-400); - --_ai-translucent: var(--translucent-success); .highcontrast-mode({ --_ai-bg: var(--green-500); @@ -29,7 +28,6 @@ &&__warning { --_ai-bg: var(--yellow-400); --_ai-fc: var(--_black-static); - --_ai-translucent: var(--translucent-warning); .highcontrast-mode({ --_ai-bg: var(--yellow-500); // needs to be here to override default high contrast @@ -37,17 +35,24 @@ }); } + &&__sm { + --_ai-min-size: calc(var(--su-static8) + var(--su-static2)); + --_ai-p: 0; + } + background-color: var(--_ai-bg); - box-shadow: 0 0 0 var(--su-static4) var(--_ai-translucent); color: var(--_ai-fc); + min-width: var(--_ai-min-size); + min-height: var(--_ai-min-size); + padding: var(--_ai-p); border-radius: 1000px; - display: inline-block; + display: inline-flex; font-size: var(--fs-fine); - font-weight: 700; - line-height: 1.1; // Custom line-height to satisfy 1x screens - min-width: var(--su-static12); - min-height: var(--su-static12); - padding: var(--su2) var(--su4); + font-weight: 600; + line-height: 1.1; + text-align: center; + align-items: center; + justify-content: center; text-transform: uppercase; } diff --git a/packages/stacks-classic/lib/components/activity-indicator/activity-indicator.visual.test.ts b/packages/stacks-classic/lib/components/activity-indicator/activity-indicator.visual.test.ts index ac7a25c32d..f0cfbb3028 100644 --- a/packages/stacks-classic/lib/components/activity-indicator/activity-indicator.visual.test.ts +++ b/packages/stacks-classic/lib/components/activity-indicator/activity-indicator.visual.test.ts @@ -6,10 +6,16 @@ describe("activity-indicator", () => { runVisualTests({ baseClass: "s-activity-indicator", variants: ["danger", "success", "warning"], + modifiers: { + primary: ["sm"], + }, children: { default: `
New activity
`, new: `new
New activity
`, }, + excludedTestids: [ + /^s-activity-indicator-(?=.*sm).*new$/, // s-activity-indicator with content in sm size not supported + ], template: ({ component, testid }) => html`
-
+
@@ -71,12 +73,20 @@
- @Svg.Bell + @Svg.Notification -
+
+ +
+ @Svg.Notification + +
+ 3
+
+
{% endhighlight %}
@@ -89,7 +99,7 @@
-
+
New activity
G
@@ -99,12 +109,20 @@
- {% icon "Bell" %} + {% icon "Notification" %} -
+
New activity
+ +
+ {% icon "Notification" %} + +
+ 3
New activities
+
+
@@ -137,7 +155,7 @@
-
+
New activity
G
@@ -147,12 +165,20 @@
- {% icon "Bell" %} + {% icon "Notification" %} -
+
New activity
+ +
+ {% icon "Notification" %} + +
+ 3
New activities
+
+
{% endfor %}
diff --git a/packages/stacks-svelte/src/components/ActivityIndicator/ActivityIndicator.stories.svelte b/packages/stacks-svelte/src/components/ActivityIndicator/ActivityIndicator.stories.svelte new file mode 100644 index 0000000000..038ed1e1c6 --- /dev/null +++ b/packages/stacks-svelte/src/components/ActivityIndicator/ActivityIndicator.stories.svelte @@ -0,0 +1,209 @@ + + + + + +
+ + + + + + + + + + {#each ActivityIndicatorVariants as variant (variant)} + + + + + {/each} + +
VariantExample
+ {variant || "default"} + + +
+
+
+ + +
+ + + + + + + + + + {#each ActivityIndicatorSizes as size (size)} + + + + + {/each} + +
SizeExample
+ {size || "default"} + + +
+
+
+ + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
ContentExample
Number (3) + +
Number (12) + +
Number (370) + +
Text ("new") + +
+
+
+ + +
+ + + + + + + + + + + + + + +
ContentExample
Notifications + + + +
+
+
diff --git a/packages/stacks-svelte/src/components/ActivityIndicator/ActivityIndicator.svelte b/packages/stacks-svelte/src/components/ActivityIndicator/ActivityIndicator.svelte new file mode 100644 index 0000000000..e458c3e2b7 --- /dev/null +++ b/packages/stacks-svelte/src/components/ActivityIndicator/ActivityIndicator.svelte @@ -0,0 +1,72 @@ + + + + +
+ {#if content && size !== "sm"}{content}{/if} +
{label}
+
diff --git a/packages/stacks-svelte/src/components/ActivityIndicator/ActivityIndicator.test.ts b/packages/stacks-svelte/src/components/ActivityIndicator/ActivityIndicator.test.ts new file mode 100644 index 0000000000..eb031ae0d9 --- /dev/null +++ b/packages/stacks-svelte/src/components/ActivityIndicator/ActivityIndicator.test.ts @@ -0,0 +1,81 @@ +import { expect } from "@open-wc/testing"; +import { render, screen } from "@testing-library/svelte"; + +import ActivityIndicator from "./ActivityIndicator.svelte"; + +describe("ActivityIndicator", () => { + it("should render the indicator with the required label as screen reader text", () => { + render(ActivityIndicator, { label: "test activity" }); + expect(screen.getByText("test activity")).to.exist; + }); + + it("should render the content when provided", () => { + render(ActivityIndicator, { label: "test activity", content: 3 }); + expect(screen.getByText("3")).to.exist; + }); + + it("should render text content when provided", () => { + render(ActivityIndicator, { + label: "test activity", + content: "new", + }); + expect(screen.getByText("new")).to.exist; + }); + + it("should apply the success variant class", () => { + render(ActivityIndicator, { + label: "test activity", + variant: "success", + }); + expect(screen.getByText("test activity").parentElement).to.have.class( + "s-activity-indicator__success" + ); + }); + + it("should apply the warning variant class", () => { + render(ActivityIndicator, { + label: "test activity", + variant: "warning", + }); + expect(screen.getByText("test activity").parentElement).to.have.class( + "s-activity-indicator__warning" + ); + }); + + it("should apply the danger variant class", () => { + render(ActivityIndicator, { + label: "test activity", + variant: "danger", + }); + expect(screen.getByText("test activity").parentElement).to.have.class( + "s-activity-indicator__danger" + ); + }); + + it("should apply the small size class", () => { + render(ActivityIndicator, { label: "test activity", size: "sm" }); + expect(screen.getByText("test activity").parentElement).to.have.class( + "s-activity-indicator__sm" + ); + }); + + it("should not render content when size is sm", () => { + render(ActivityIndicator, { + label: "test activity", + size: "sm", + content: 3, + }); + expect(screen.queryByText("3")).to.not.exist; + expect(screen.getByText("test activity")).to.exist; + }); + + it("should render the indicator with arbitrary classes", () => { + render(ActivityIndicator, { + label: "test activity", + class: "custom-class", + }); + expect(screen.getByText("test activity").parentElement).to.have.class( + "custom-class" + ); + }); +}); diff --git a/packages/stacks-svelte/src/components/index.ts b/packages/stacks-svelte/src/components/index.ts index 7e1b5ebf2d..04a6a216a4 100644 --- a/packages/stacks-svelte/src/components/index.ts +++ b/packages/stacks-svelte/src/components/index.ts @@ -1,3 +1,4 @@ +export { default as ActivityIndicator } from "./ActivityIndicator/ActivityIndicator.svelte"; export { default as AwardBling } from "./AwardBling/AwardBling.svelte"; export { default as Avatar } from "./Avatar/Avatar.svelte"; export { default as Button } from "./Button/Button.svelte";