Support style as a function

Seems useful to add.

Also improve the prop typing of <Render>, marginally, though as these types do not carry over to end users yet, it's just cosmetic for now.
This commit is contained in:
Ryan Gossiaux
2022-02-01 12:38:35 -08:00
parent bfc68577cc
commit 495fa64bf9
7 changed files with 75 additions and 7 deletions

View File

@@ -22,7 +22,7 @@
onMount(() => $contextStore?.register(id));
$: slotProps = $contextStore!.slotProps;
$: slotProps = $contextStore!.slotProps || {};
</script>
<Render

View File

@@ -71,6 +71,7 @@
{...$$restProps}
{as}
use={[...use, forwardEvents]}
slotProps={{}}
name={"PopoverGroup"}
bind:el={groupRef}
>

View File

@@ -208,6 +208,7 @@
{...{ ...$$restProps, ...propsWeControl }}
{as}
use={[...use, forwardEvents]}
slotProps={{}}
name={"RadioGroup"}
bind:el={radioGroupRef}
aria-labelledby={labelledby}

View File

@@ -42,6 +42,7 @@
{...$$restProps}
{as}
use={[...use, forwardEvents]}
slotProps={{}}
name={"SwitchGroup"}
>
<DescriptionProvider name="SwitchDescription">

View File

@@ -195,6 +195,7 @@
{...$$restProps}
{as}
use={[...use, forwardEvents]}
slotProps={{}}
name={"TransitionChild"}
bind:el={container}
class={classes}

View File

@@ -34,16 +34,27 @@
import { forwardEventsBuilder } from "$lib/internal/forwardEventsBuilder";
const forwardEvents = forwardEventsBuilder(get_current_component());
type TSlotProps = $$Generic<{}>;
export let name: string;
export let as: SvelteComponent | SupportedElement;
export let slotProps: TSlotProps;
export let el: HTMLElement | null = null;
export let use: ActionArray = [];
export let slotProps: unknown = {};
export let visible = true;
export let features: Features = Features.None;
// The static and unmount props are only used in conjunction with the render strategies
export let unmount = true;
let classProp: ((props: TSlotProps) => string) | string | undefined =
undefined;
export { classProp as class };
// This is not in upstream Headless UI, but we might as well add it here
export let style: ((props: TSlotProps) => string) | string | undefined =
undefined;
if (!as) {
throw new Error(`<${name}> did not provide an \`as\` value to <Render>`);
}
@@ -55,7 +66,9 @@
);
}
$: classStyle = $$props.class;
$: computedClass =
typeof classProp === "function" ? classProp(slotProps) : classProp;
$: computedStyle = typeof style === "function" ? style(slotProps) : style;
$: show =
visible ||
@@ -74,10 +87,9 @@
bind:el
use={[...use, forwardEvents]}
{...$$restProps}
class={typeof classStyle === "function"
? classStyle(slotProps)
: classStyle}
style={hidden ? "display: none" : $$props.style}
class={computedClass}
style={`${computedStyle ?? ""}${hidden ? " display: none" : ""}` ||
undefined}
hidden={hidden || undefined}
>
<slot />

52
src/lib/utils/render.test.ts vendored Normal file
View File

@@ -0,0 +1,52 @@
import Render from "$lib/utils/Render.svelte";
// import svelte from "svelte-inline-compile";
import { getByTestId, render } from "@testing-library/svelte";
it("should be possible to use class as a string", () => {
let { container } = render(Render, {
as: "div",
name: "test",
slotProps: {},
class: "test-class",
"data-testid": "test-id",
});
let element = getByTestId(container, "test-id");
expect(element).toHaveClass("test-class");
});
it("should be possible to use class as a function", () => {
render(Render, {
as: "div",
name: "test",
slotProps: { foo: "bar" },
class: JSON.stringify,
id: "test-id",
});
expect("" + document.querySelector("#test-id")?.classList).toEqual(
JSON.stringify({ foo: "bar" })
);
});
it("should be possible to use style as a string", () => {
let { container } = render(Render, {
as: "div",
name: "test",
slotProps: {},
style: "background-color: green",
"data-testid": "test-id",
});
let element = getByTestId(container, "test-id");
expect(element).toHaveStyle("background-color: green");
});
it("should be possible to use style as a function", () => {
let { container } = render(Render, {
as: "div",
name: "test",
slotProps: { enabled: true },
style: ({ enabled }: { enabled: boolean }) => enabled ? "background-color: red" : "background-color: green",
"data-testid": "test-id",
});
let element = getByTestId(container, "test-id");
expect(element).toHaveStyle("background-color: red");
});