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
5 changes: 5 additions & 0 deletions .changeset/plenty-regions-shake.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@stackoverflow/stacks-svelte": patch
---

Allow class prop to be array or object
1 change: 1 addition & 0 deletions packages/stacks-svelte/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
"svelte": "^5.0.0"
},
"dependencies": {
"clsx": "^2.1.1",
"@floating-ui/core": "^1.7.3",
"@stackoverflow/stacks-icons": "^7.0.0-beta.18",
"@stackoverflow/stacks-icons-legacy": "npm:@stackoverflow/stacks-icons@^6.9.0",
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
<script lang="ts" module>
import { defineMeta } from "@storybook/addon-svelte-csf";
import { parseClassValue } from "../../storybook-utils";
import Icon from "../Icon/Icon.svelte";
import Button from "../Button/Button.svelte";
import { IconNotification } from "@stackoverflow/stacks-icons/icons";
Expand Down Expand Up @@ -28,11 +29,27 @@
control: "select",
options: ActivityIndicatorSizes,
},
class: {
control: "text",
},
},
args: {
label: "New activities",
content: 99,
},
});
</script>

<Story name="Base" args={{ label: "New activities", content: 99 }} />
<Story name="Base">
{#snippet template({ class: classArg, ...args })}
<ActivityIndicator
{...args}
class={parseClassValue(
typeof classArg === "string" ? classArg : undefined
)}
/>
{/snippet}
</Story>

<Story name="Variants" asChild>
<div class="d-flex fd-column g64">
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
<script module lang="ts">
import clsx from "clsx";
import type { ClassValue } from "svelte/elements";
export type Variant = "" | "success" | "warning" | "danger";
export type Size = "" | "sm";
</script>
Expand Down Expand Up @@ -29,7 +32,7 @@
/**
* Additional CSS classes added to the element
*/
class?: string;
class?: ClassValue;
}
const {
Expand All @@ -41,26 +44,15 @@
}: Props = $props();
const getClasses = (
className: string,
className: ClassValue,
variant: Variant,
size: Size
): string => {
) => {
const base = "s-activity-indicator";
let classes = base;
if (variant) {
classes += ` ${base}__${variant}`;
}
if (size) {
classes += ` ${base}__${size}`;
}
if (className) {
classes += ` ${className}`;
}
return classes;
const classes = [variant, size]
.filter(Boolean)
.map((modifier) => `${base}__${modifier}`);
return clsx(base, className, classes);
};
const classes = $derived(getClasses(className, variant, size));
Expand Down
23 changes: 19 additions & 4 deletions packages/stacks-svelte/src/components/Avatar/Avatar.stories.svelte
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
<script lang="ts" module>
import { defineMeta } from "@storybook/addon-svelte-csf";
import { parseClassValue } from "../../storybook-utils";
import Avatar, { type Size } from "./Avatar.svelte";

const AvatarSizes: Size[] = [16, 24, 32, 48, 64, 96, 128];

const { Story } = defineMeta({
Expand All @@ -15,14 +17,27 @@
control: "select",
options: AvatarSizes,
},
class: {
control: "text",
},
},
args: {
name: "example",
src: "https://picsum.photos/128",
},
});
</script>

<Story
name="Base"
args={{ name: "example", src: "https://picsum.photos/128" }}
/>
<Story name="Base">
{#snippet template({ class: classArg, ...args })}
<Avatar
{...args}
class={parseClassValue(
typeof classArg === "string" ? classArg : undefined
)}
/>
{/snippet}
</Story>

<Story name="Sizes" asChild>
<div class="d-flex fd-column g64">
Expand Down
20 changes: 6 additions & 14 deletions packages/stacks-svelte/src/components/Avatar/Avatar.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,11 @@
</script>

<script lang="ts">
import clsx from "clsx";
import Icon from "../Icon/Icon.svelte";
import ActivityIndicator from "../ActivityIndicator/ActivityIndicator.svelte";
import { IconShieldXSm } from "@stackoverflow/stacks-icons-legacy/icons";
import type { HTMLAnchorAttributes } from "svelte/elements";
import type { ClassValue, HTMLAnchorAttributes } from "svelte/elements";
interface Props {
/**
Expand Down Expand Up @@ -47,7 +48,7 @@
/**
* Additional CSS classes added to the element
*/
class?: string;
class?: ClassValue;
}
const {
Expand All @@ -63,19 +64,10 @@
...restProps
}: Props & HTMLAnchorAttributes = $props();
const getClasses = (className: string, size: Size): string => {
const getClasses = (className: ClassValue, size: Size) => {
const base = "s-avatar";
let classes = base;
if (className) {
classes += ` ${className}`;
}
if (size !== 16) {
classes += ` ${base}__${size}`;
}
return classes;
const classes = size === 16 ? [] : [`${base}__${size}`];
return clsx(base, className, classes);
};
const classes = $derived(getClasses(className, size));
Expand Down
14 changes: 12 additions & 2 deletions packages/stacks-svelte/src/components/Badge/Badge.stories.svelte
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
<script lang="ts" module>
import { defineMeta } from "@storybook/addon-svelte-csf";
import { parseClassValue } from "../../storybook-utils";
import {
IconDocument,
IconCompose,
Expand Down Expand Up @@ -73,13 +74,22 @@
important: {
control: "boolean",
},
class: {
control: "text",
},
},
});
</script>

<Story name="Base">
{#snippet template({ text, ...args })}
<Badge text={text ?? "1.23k"} {...args} />
{#snippet template({ text, class: classArg, ...args })}
<Badge
text={text ?? "1.23k"}
{...args}
class={parseClassValue(
typeof classArg === "string" ? classArg : undefined
)}
/>
{/snippet}
</Story>

Expand Down
61 changes: 38 additions & 23 deletions packages/stacks-svelte/src/components/Badge/Badge.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,11 @@
</script>

<script lang="ts">
import clsx from "clsx";
import Bling from "../Bling/Bling.svelte";
import Icon from "../Icon/Icon.svelte";
import type { ClassValue } from "svelte/elements";

interface Props {
/**
* The text content of the badge
Expand Down Expand Up @@ -87,7 +90,7 @@
/**
* Additional CSS classes added to the badge element
*/
class?: string;
class?: ClassValue;
}

const {
Expand All @@ -104,36 +107,48 @@
class: className = "",
}: Props = $props();

const classes = $derived(() => {
const getClasses = (
className: ClassValue,
size: BadgeSize,
squared: boolean,
important: boolean,
type: BadgeType | undefined,
state: BadgeState | undefined,
userType: UserType | undefined,
award: Award | undefined
) => {
const base = "s-badge";
let classes = base;

if (className) {
classes += ` ${className}`;
}

if (size) {
classes += ` ${base}__${size}`;
}

const classes: string[] = [size]
.filter(Boolean)
.map((modifier) => `${base}__${modifier}`);
if (squared) {
classes += ` ${base}__squared`;
classes.push(`${base}__squared`);
}

if (important) {
classes += ` ${base}__important`;
classes.push(`${base}__important`);
}

if (type === "state" && state) {
classes += ` ${base}__${state}`;
classes.push(`${base}__${state}`);
} else if (type === "user" && userType) {
classes += ` ${base}__${userType}`;
classes.push(`${base}__${userType}`);
} else if (type === "tag" && award) {
classes += ` ${base}__${award}`;
classes.push(`${base}__${award}`);
}

return classes;
});
return clsx(base, className, classes);
};

const classes = $derived(
getClasses(
className,
size,
squared,
important,
type,
state,
userType,
award
)
);

const needsBling = $derived(() => {
return (
Expand Down Expand Up @@ -166,7 +181,7 @@
});
</script>

<span class={classes()}>
<span class={classes}>
{#if needsBling()}
<Bling
type={blingType()}
Expand Down
38 changes: 27 additions & 11 deletions packages/stacks-svelte/src/components/Bling/Bling.stories.svelte
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
<script lang="ts" module>
import { defineMeta } from "@storybook/addon-svelte-csf";
import { parseClassValue } from "../../storybook-utils";
import Bling, { type Type, type Size } from "./Bling.svelte";

const BlingSizes: Size[] = ["sm", "", "lg"];
const BlingTypes: Type[] = [
"",
Expand All @@ -14,21 +16,35 @@
const { Story } = defineMeta({
title: "Components/Bling",
component: Bling,
argTypes: {
type: {
control: "select",
options: BlingTypes,
},
size: {
control: "select",
options: BlingSizes,
},
filled: {
control: "boolean",
},
class: {
control: "text",
},
},
args: {
name: "Bling",
},
});
</script>

<Story
name="Base"
args={{
name: "Bling",
}}
>
{#snippet template(args)}
<Story name="Base">
{#snippet template({ class: classArg, ...args })}
<Bling
type={args.type}
name={args.name}
size={args.size}
filled={args.filled}
{...args}
class={parseClassValue(
typeof classArg === "string" ? classArg : undefined
)}
/>
{/snippet}
</Story>
Expand Down
Loading
Loading