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:
@@ -22,7 +22,7 @@
|
|||||||
|
|
||||||
onMount(() => $contextStore?.register(id));
|
onMount(() => $contextStore?.register(id));
|
||||||
|
|
||||||
$: slotProps = $contextStore!.slotProps;
|
$: slotProps = $contextStore!.slotProps || {};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<Render
|
<Render
|
||||||
|
|||||||
@@ -71,6 +71,7 @@
|
|||||||
{...$$restProps}
|
{...$$restProps}
|
||||||
{as}
|
{as}
|
||||||
use={[...use, forwardEvents]}
|
use={[...use, forwardEvents]}
|
||||||
|
slotProps={{}}
|
||||||
name={"PopoverGroup"}
|
name={"PopoverGroup"}
|
||||||
bind:el={groupRef}
|
bind:el={groupRef}
|
||||||
>
|
>
|
||||||
|
|||||||
@@ -208,6 +208,7 @@
|
|||||||
{...{ ...$$restProps, ...propsWeControl }}
|
{...{ ...$$restProps, ...propsWeControl }}
|
||||||
{as}
|
{as}
|
||||||
use={[...use, forwardEvents]}
|
use={[...use, forwardEvents]}
|
||||||
|
slotProps={{}}
|
||||||
name={"RadioGroup"}
|
name={"RadioGroup"}
|
||||||
bind:el={radioGroupRef}
|
bind:el={radioGroupRef}
|
||||||
aria-labelledby={labelledby}
|
aria-labelledby={labelledby}
|
||||||
|
|||||||
@@ -42,6 +42,7 @@
|
|||||||
{...$$restProps}
|
{...$$restProps}
|
||||||
{as}
|
{as}
|
||||||
use={[...use, forwardEvents]}
|
use={[...use, forwardEvents]}
|
||||||
|
slotProps={{}}
|
||||||
name={"SwitchGroup"}
|
name={"SwitchGroup"}
|
||||||
>
|
>
|
||||||
<DescriptionProvider name="SwitchDescription">
|
<DescriptionProvider name="SwitchDescription">
|
||||||
|
|||||||
@@ -195,6 +195,7 @@
|
|||||||
{...$$restProps}
|
{...$$restProps}
|
||||||
{as}
|
{as}
|
||||||
use={[...use, forwardEvents]}
|
use={[...use, forwardEvents]}
|
||||||
|
slotProps={{}}
|
||||||
name={"TransitionChild"}
|
name={"TransitionChild"}
|
||||||
bind:el={container}
|
bind:el={container}
|
||||||
class={classes}
|
class={classes}
|
||||||
|
|||||||
@@ -34,16 +34,27 @@
|
|||||||
import { forwardEventsBuilder } from "$lib/internal/forwardEventsBuilder";
|
import { forwardEventsBuilder } from "$lib/internal/forwardEventsBuilder";
|
||||||
const forwardEvents = forwardEventsBuilder(get_current_component());
|
const forwardEvents = forwardEventsBuilder(get_current_component());
|
||||||
|
|
||||||
|
type TSlotProps = $$Generic<{}>;
|
||||||
|
|
||||||
export let name: string;
|
export let name: string;
|
||||||
export let as: SvelteComponent | SupportedElement;
|
export let as: SvelteComponent | SupportedElement;
|
||||||
|
export let slotProps: TSlotProps;
|
||||||
|
|
||||||
export let el: HTMLElement | null = null;
|
export let el: HTMLElement | null = null;
|
||||||
export let use: ActionArray = [];
|
export let use: ActionArray = [];
|
||||||
export let slotProps: unknown = {};
|
|
||||||
export let visible = true;
|
export let visible = true;
|
||||||
export let features: Features = Features.None;
|
export let features: Features = Features.None;
|
||||||
// The static and unmount props are only used in conjunction with the render strategies
|
// The static and unmount props are only used in conjunction with the render strategies
|
||||||
export let unmount = true;
|
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) {
|
if (!as) {
|
||||||
throw new Error(`<${name}> did not provide an \`as\` value to <Render>`);
|
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 =
|
$: show =
|
||||||
visible ||
|
visible ||
|
||||||
@@ -74,10 +87,9 @@
|
|||||||
bind:el
|
bind:el
|
||||||
use={[...use, forwardEvents]}
|
use={[...use, forwardEvents]}
|
||||||
{...$$restProps}
|
{...$$restProps}
|
||||||
class={typeof classStyle === "function"
|
class={computedClass}
|
||||||
? classStyle(slotProps)
|
style={`${computedStyle ?? ""}${hidden ? " display: none" : ""}` ||
|
||||||
: classStyle}
|
undefined}
|
||||||
style={hidden ? "display: none" : $$props.style}
|
|
||||||
hidden={hidden || undefined}
|
hidden={hidden || undefined}
|
||||||
>
|
>
|
||||||
<slot />
|
<slot />
|
||||||
|
|||||||
52
src/lib/utils/render.test.ts
vendored
Normal file
52
src/lib/utils/render.test.ts
vendored
Normal 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");
|
||||||
|
});
|
||||||
Reference in New Issue
Block a user