From 1fe85c1203d5806a72ac58874d92db039ef57739 Mon Sep 17 00:00:00 2001 From: nikita Date: Wed, 25 Jun 2025 16:07:43 +0300 Subject: [PATCH 1/2] refactor: apply newer patterns to components --- src/components/avatar/Avatar.tsx | 71 +++++++++++++------- src/components/codemockup/CodeMockup.tsx | 32 +++++---- src/components/diff/Diff.tsx | 33 +++++---- src/components/flex/Flex.tsx | 43 +++++++----- src/components/join/Join.tsx | 17 +++-- src/components/skeleton/Skeleton.tsx | 13 ++-- src/components/table/TableRow.tsx | 6 +- src/components/windowmockup/WindowMockup.tsx | 23 ++++--- 8 files changed, 150 insertions(+), 88 deletions(-) diff --git a/src/components/avatar/Avatar.tsx b/src/components/avatar/Avatar.tsx index 4412dd05..f7681128 100644 --- a/src/components/avatar/Avatar.tsx +++ b/src/components/avatar/Avatar.tsx @@ -2,7 +2,8 @@ import { type JSX, splitProps, Show, - children as getSolidChildren, + children as resolveChildren, + createMemo, } from "solid-js"; import { Dynamic } from "solid-js/web"; import { twMerge } from "tailwind-merge"; @@ -46,8 +47,21 @@ export type AvatarProps = Omit< // Void elements rarely used here, but we'll allow generic `as` const VoidElementList: ElementType[] = [ - "area", "base", "br", "col", "embed", "hr", "img", "input", "link", "keygen", - "meta", "param", "source", "track", "wbr", + "area", + "base", + "br", + "col", + "embed", + "hr", + "img", + "input", + "link", + "keygen", + "meta", + "param", + "source", + "track", + "wbr", ]; const Avatar = ( @@ -74,10 +88,11 @@ const Avatar = ( ] ); - const Tag = local.as || "div"; + const resolvedChildren = resolveChildren(() => local.children); + const Tag = createMemo(() => local.as || "div"); // Container classes - const containerClass = () => + const containerClass = createMemo(() => twMerge( "avatar", local.class, @@ -87,19 +102,21 @@ const Avatar = ( "avatar-offline": local.offline, "avatar-placeholder": !local.src, }) - ); + ) + ); // Inner element dimensions - const customSizeStyle = + const customSizeStyle = createMemo(() => typeof local.size === "number" ? { width: `${local.size}px`, height: `${local.size}px` } - : undefined; + : undefined + ); // Shared inner classes - const baseInner = () => twMerge(local.innerClass); + const baseInner = createMemo(() => twMerge(local.innerClass)); // Image wrapper classes - const imgClasses = () => + const imgClasses = createMemo(() => clsx(baseInner(), { ring: local.border, "ring-offset-base-100 ring-offset-2": local.border, @@ -110,10 +127,11 @@ const Avatar = ( "w-24 h-24": local.size === "md", "w-14 h-14": local.size === "sm", "w-10 h-10": local.size === "xs", - }); + }) + ); // Placeholder wrapper classes - const placeholderClasses = () => + const placeholderClasses = createMemo(() => clsx(baseInner(), { "bg-neutral-focus": !local.color, "text-neutral-content": !local.color || local.color === "neutral", @@ -128,34 +146,37 @@ const Avatar = ( "w-24 h-24 text-xl": local.size === "md", "w-14 h-14": local.size === "sm", "w-10 h-10": local.size === "xs", - }); + }) + ); - // Resolve children to detect single-string - const resolved = getSolidChildren(() => local.children)(); - const isStringChild = typeof resolved === "string"; + // Check if child is a single string + const isStringChild = createMemo(() => { + const child = resolvedChildren(); + return typeof child === "string"; + }); const renderContents = () => { // If src => image avatar return local.src ? ( -
+
- ) : local.letters || isStringChild ? ( -
- {local.letters ?? resolved} + ) : local.letters || isStringChild() ? ( +
+ {local.letters ?? resolvedChildren()}
) : ( -
- {local.children} +
+ {resolvedChildren()}
); }; // Render void tags (unlikely) or normal - if (VoidElementList.includes(Tag)) { + if (VoidElementList.includes(Tag())) { return ( ( return ( & { - dataTheme?: AppTheme; -}; +type CodeMockupProps = JSX.HTMLAttributes & IComponentBaseProps; const CodeMockup = (props: ParentProps): JSX.Element => { - const merged = mergeProps({ class: "", "aria-label": "Code mockup" }, props); - const [local, rest] = splitProps(merged, ["class", "children", "dataTheme"]); + const [local, rest] = splitProps(props, [ + "class", + "className", + "children", + "dataTheme", + "aria-label", + ]); - const resolvedChildren = getChildren(() => local.children); + const resolvedChildren = resolveChildren(() => local.children); + + const classes = createMemo(() => + twMerge("mockup-code w-full", local.class, local.className) + ); return (
{resolvedChildren()} @@ -29,4 +37,4 @@ const CodeMockup = (props: ParentProps): JSX.Element => { ); }; -export default CodeMockup; \ No newline at end of file +export default CodeMockup; diff --git a/src/components/diff/Diff.tsx b/src/components/diff/Diff.tsx index 81dd0261..17b41af6 100644 --- a/src/components/diff/Diff.tsx +++ b/src/components/diff/Diff.tsx @@ -1,28 +1,35 @@ -import { createMemo, splitProps, type JSX } from "solid-js"; +import { + createMemo, + splitProps, + type JSX, + children as resolveChildren, +} from "solid-js"; import { twMerge } from "tailwind-merge"; import { IComponentBaseProps } from "../types"; -export type DiffProps = JSX.HTMLAttributes & IComponentBaseProps & { - secondItem: JSX.Element; -}; +export type DiffProps = JSX.HTMLAttributes & + IComponentBaseProps & { + secondItem: JSX.Element; + }; -const Diff = (props: DiffProps) => { +const Diff = (props: DiffProps): JSX.Element => { const [local, rest] = splitProps(props, [ "class", "children", "secondItem", - "className" + "className", ]); -const classes = createMemo(() => twMerge("diff aspect-[16/9]", local.class, local.className)) + const resolvedChildren = resolveChildren(() => local.children); + const resolvedSecondItem = resolveChildren(() => local.secondItem); + const classes = createMemo(() => + twMerge("diff aspect-[16/9]", local.class, local.className) + ); return ( -
-
{local.children}
-
{local.secondItem}
+
+
{resolvedChildren()}
+
{resolvedSecondItem()}
); diff --git a/src/components/flex/Flex.tsx b/src/components/flex/Flex.tsx index 7b5700bf..f2cf74b2 100644 --- a/src/components/flex/Flex.tsx +++ b/src/components/flex/Flex.tsx @@ -1,4 +1,9 @@ -import { type JSX, splitProps, children as resolveChildren } from "solid-js"; +import { + type JSX, + splitProps, + children as resolveChildren, + createMemo, +} from "solid-js"; import { Dynamic } from "solid-js/web"; import clsx from "clsx"; import { twMerge } from "tailwind-merge"; @@ -149,7 +154,7 @@ const basisMap = { xl: "basis-32", }; -const Flex = (props: FlexProps) => { +const Flex = (props: FlexProps): JSX.Element => { const [local, rest] = splitProps(props, [ "as", "class", @@ -166,26 +171,30 @@ const Flex = (props: FlexProps) => { "basis", ]); - const tag = local.as || "div"; + const tag = createMemo(() => local.as || "div"); const resolvedChildren = resolveChildren(() => local.children); - const classes = clsx( - "flex", - mapResponsiveProp(local.direction, directionMap), - mapResponsiveProp(local.justify, justifyMap), - mapResponsiveProp(local.align, alignMap), - mapResponsiveProp(local.wrap, wrapMap), - mapResponsiveProp(local.gap, gapMap), - mapResponsiveProp(local.gapX, gapXMap), - mapResponsiveProp(local.gapY, gapYMap), - mapResponsiveProp(local.grow, growMap), - mapResponsiveProp(local.shrink, shrinkMap), - mapResponsiveProp(local.basis, basisMap), - local.class + const classes = createMemo(() => + twMerge( + clsx( + "flex", + mapResponsiveProp(local.direction, directionMap), + mapResponsiveProp(local.justify, justifyMap), + mapResponsiveProp(local.align, alignMap), + mapResponsiveProp(local.wrap, wrapMap), + mapResponsiveProp(local.gap, gapMap), + mapResponsiveProp(local.gapX, gapXMap), + mapResponsiveProp(local.gapY, gapYMap), + mapResponsiveProp(local.grow, growMap), + mapResponsiveProp(local.shrink, shrinkMap), + mapResponsiveProp(local.basis, basisMap), + local.class + ) + ) ); return ( - + {resolvedChildren()} ); diff --git a/src/components/join/Join.tsx b/src/components/join/Join.tsx index 2ee29e57..045657ca 100644 --- a/src/components/join/Join.tsx +++ b/src/components/join/Join.tsx @@ -1,4 +1,9 @@ -import { splitProps, type JSX } from "solid-js"; +import { + splitProps, + type JSX, + createMemo, + children as resolveChildren, +} from "solid-js"; import { clsx } from "clsx"; import { twMerge } from "tailwind-merge"; import type { IComponentBaseProps } from "../types"; @@ -19,9 +24,12 @@ const Join = (props: JoinProps): JSX.Element => { "className", "dataTheme", "style", + "children", ]); - const classes = () => + const resolvedChildren = resolveChildren(() => local.children); + + const classes = createMemo(() => twMerge( "join", clsx({ @@ -31,7 +39,8 @@ const Join = (props: JoinProps): JSX.Element => { }), local.class, local.className - ); + ) + ); return (
{ data-theme={local.dataTheme} style={local.style} > - {props.children} + {resolvedChildren()}
); }; diff --git a/src/components/skeleton/Skeleton.tsx b/src/components/skeleton/Skeleton.tsx index 14a35140..bada09a2 100644 --- a/src/components/skeleton/Skeleton.tsx +++ b/src/components/skeleton/Skeleton.tsx @@ -1,12 +1,12 @@ import type { JSX } from "solid-js"; -import { splitProps } from "solid-js"; +import { splitProps, createMemo, children as resolveChildren } from "solid-js"; import { twMerge } from "tailwind-merge"; import type { IComponentBaseProps } from "../types"; export type SkeletonProps = JSX.HTMLAttributes & IComponentBaseProps; -const Skeleton = (props: SkeletonProps) => { +const Skeleton = (props: SkeletonProps): JSX.Element => { const [local, others] = splitProps(props, [ "dataTheme", "class", @@ -14,11 +14,14 @@ const Skeleton = (props: SkeletonProps) => { "children", ]); - const classes = twMerge("skeleton", local.class, local.className); + const resolvedChildren = resolveChildren(() => local.children); + const classes = createMemo(() => + twMerge("skeleton", local.class, local.className) + ); return ( -
- {local.children} +
+ {resolvedChildren()}
); }; diff --git a/src/components/table/TableRow.tsx b/src/components/table/TableRow.tsx index e3421110..08ecbe9e 100644 --- a/src/components/table/TableRow.tsx +++ b/src/components/table/TableRow.tsx @@ -15,14 +15,14 @@ export type TableRowProps = JSX.HTMLAttributes & noCell?: boolean; }; -const TableRow: Component = (props) => { +const TableRow: Component = (props): JSX.Element => { const [local, rest] = splitProps(props, [ "children", "class", "active", "noCell", "className", - "class", + "dataTheme", ]); const classes = createMemo(() => twMerge( @@ -37,7 +37,7 @@ const TableRow: Component = (props) => { const resolved = resolveChildren(() => local.children); return ( - + {resolved()} ); diff --git a/src/components/windowmockup/WindowMockup.tsx b/src/components/windowmockup/WindowMockup.tsx index a9f251e2..ed845f27 100644 --- a/src/components/windowmockup/WindowMockup.tsx +++ b/src/components/windowmockup/WindowMockup.tsx @@ -19,7 +19,9 @@ export type WindowMockupProps = JSX.HTMLAttributes & borderColor?: WindowMockupColors; }; -const WindowMockup: ParentComponent = (props) => { +const WindowMockup: ParentComponent = ( + props +): JSX.Element => { const [local, others] = splitProps(props, [ "children", "class", @@ -31,10 +33,13 @@ const WindowMockup: ParentComponent = (props) => { "frameColor", ]); - const borderColorValue = () => - local.borderColor || local.frameColor || "neutral"; + const resolvedChildren = resolveChildren(() => local.children); + + const borderColorValue = createMemo( + () => local.borderColor || local.frameColor || "neutral" + ); - const classes = () => + const classes = createMemo(() => twMerge( "mockup-window", local.class, @@ -58,9 +63,10 @@ const WindowMockup: ParentComponent = (props) => { "bg-warning": local.frameColor === "warning", "bg-error": local.frameColor === "error", }) - ); + ) + ); - const innerClasses = () => + const innerClasses = createMemo(() => twMerge( "p-4", local.backgroundColor && `bg-${local.backgroundColor}`, @@ -75,9 +81,8 @@ const WindowMockup: ParentComponent = (props) => { "bg-warning": local.backgroundColor === "warning", "bg-error": local.backgroundColor === "error", }) - ); - - const resolvedChildren = resolveChildren(() => local.children); + ) + ); const innerElement = createMemo(() => { const childrenArray = Array.isArray(resolvedChildren()) From 0c31985a8985bb94f9765e18a4773ba9c4bd3da1 Mon Sep 17 00:00:00 2001 From: nikita Date: Wed, 25 Jun 2025 16:14:50 +0300 Subject: [PATCH 2/2] refactor: proper dataTheme usage in all components --- src/components/avatar/Avatar.tsx | 5 +- src/components/dropdown/DropdownMenu.tsx | 12 ++-- src/components/menu/MenuDropdown.tsx | 19 +++--- src/components/radio/Radio.tsx | 73 +++++++++++++----------- src/components/range/Range.tsx | 61 +++++++++++--------- src/components/stats/Stat.tsx | 22 +++---- src/components/steps/Step.tsx | 43 +++++++++----- src/components/steps/Steps.tsx | 43 +++++++++----- 8 files changed, 160 insertions(+), 118 deletions(-) diff --git a/src/components/avatar/Avatar.tsx b/src/components/avatar/Avatar.tsx index f7681128..62fd724b 100644 --- a/src/components/avatar/Avatar.tsx +++ b/src/components/avatar/Avatar.tsx @@ -85,6 +85,7 @@ const Avatar = ( "className", "style", "children", + "dataTheme", ] ); @@ -178,7 +179,7 @@ const Avatar = ( @@ -189,7 +190,7 @@ const Avatar = ( diff --git a/src/components/dropdown/DropdownMenu.tsx b/src/components/dropdown/DropdownMenu.tsx index 926130bf..b9a3658c 100644 --- a/src/components/dropdown/DropdownMenu.tsx +++ b/src/components/dropdown/DropdownMenu.tsx @@ -1,4 +1,4 @@ -import { type JSX, splitProps } from "solid-js"; +import { type JSX, splitProps, createMemo } from "solid-js"; import { twMerge } from "tailwind-merge"; import type { IComponentBaseProps } from "../types"; @@ -8,7 +8,6 @@ export type DropdownMenuProps = JSX.HTMLAttributes & class?: string; className?: string; style?: JSX.CSSProperties; - "data-theme"?: string; "aria-labelledby"?: string; }; @@ -16,18 +15,19 @@ const DropdownMenu = (props: DropdownMenuProps): JSX.Element => { const [local, others] = splitProps(props, [ "class", "className", - "data-theme", + "dataTheme", "style", "id", "aria-labelledby", ]); - const classes = () => + const classes = createMemo(() => twMerge( "dropdown-content menu p-2 shadow bg-base-100 rounded-box", local.class, local.className - ); + ) + ); return (
    { id={local.id} aria-labelledby={local["aria-labelledby"]} tabindex={0} - data-theme={local["data-theme"]} + data-theme={local.dataTheme} class={classes()} style={local.style} role="menu" diff --git a/src/components/menu/MenuDropdown.tsx b/src/components/menu/MenuDropdown.tsx index de4bb9af..cfc5df72 100644 --- a/src/components/menu/MenuDropdown.tsx +++ b/src/components/menu/MenuDropdown.tsx @@ -1,4 +1,4 @@ -import { type JSX, splitProps, type Component } from "solid-js"; +import { type JSX, splitProps, type Component, createMemo } from "solid-js"; import { twMerge } from "tailwind-merge"; import { clsx } from "clsx"; @@ -12,10 +12,9 @@ export type MenuDropdownProps = JSX.HTMLAttributes & className?: string; style?: JSX.CSSProperties; children?: JSX.Element; - "data-theme"?: string; }; -const MenuDropdown: Component = (props) => { +const MenuDropdown: Component = (props): JSX.Element => { const [local, others] = splitProps(props, [ "label", "open", @@ -23,19 +22,21 @@ const MenuDropdown: Component = (props) => { "className", "style", "children", - "data-theme", + "dataTheme", ]); - const spanClasses = () => + const spanClasses = createMemo(() => twMerge( "menu-dropdown-toggle", local.class, local.className, clsx({ "menu-dropdown-show": local.open }) - ); + ) + ); - const ulClasses = () => - clsx("menu-dropdown", { "menu-dropdown-show": local.open }); + const ulClasses = createMemo(() => + clsx("menu-dropdown", { "menu-dropdown-show": local.open }) + ); return ( <> @@ -43,7 +44,7 @@ const MenuDropdown: Component = (props) => { {...others} class={spanClasses()} style={local.style} - data-theme={local["data-theme"]} + data-theme={local.dataTheme} > {local.label} diff --git a/src/components/radio/Radio.tsx b/src/components/radio/Radio.tsx index e42b6b55..c23de6ac 100644 --- a/src/components/radio/Radio.tsx +++ b/src/components/radio/Radio.tsx @@ -1,6 +1,7 @@ import clsx from "clsx"; -import { splitProps, type JSX } from "solid-js"; +import { splitProps, type JSX, createMemo } from "solid-js"; import { twMerge } from "tailwind-merge"; +import { IComponentBaseProps } from "../types"; export type ComponentColor = | "primary" @@ -16,27 +17,28 @@ export type ComponentSize = "xs" | "sm" | "md" | "lg" | "xl"; export type RadioProps = Omit< JSX.InputHTMLAttributes, "size" -> & { - color?: ComponentColor; - size?: ComponentSize; - "data-theme"?: string; - // ARIA attributes - "aria-label"?: string; - "aria-describedby"?: string; - "aria-invalid"?: boolean; - "aria-required"?: boolean; - "aria-labelledby"?: string; - "aria-checked"?: boolean; -}; +> & + IComponentBaseProps & { + color?: ComponentColor; + size?: ComponentSize; + // ARIA attributes + "aria-label"?: string; + "aria-describedby"?: string; + "aria-invalid"?: boolean; + "aria-required"?: boolean; + "aria-labelledby"?: string; + "aria-checked"?: boolean; + }; -const Radio = (props: RadioProps) => { +const Radio = (props: RadioProps): JSX.Element => { const [local, rest] = splitProps(props, [ "class", + "className", "color", "size", "name", "type", - "data-theme", + "dataTheme", "aria-label", "aria-describedby", "aria-invalid", @@ -45,23 +47,26 @@ const Radio = (props: RadioProps) => { "aria-checked", ]); - const classes = twMerge( - "radio", - local.class, - clsx({ - "radio-xs": local.size === "xs", - "radio-sm": local.size === "sm", - "radio-md": local.size === "md", - "radio-lg": local.size === "lg", - "radio-xl": local.size === "xl", - "radio-primary": local.color === "primary", - "radio-secondary": local.color === "secondary", - "radio-accent": local.color === "accent", - "radio-info": local.color === "info", - "radio-success": local.color === "success", - "radio-warning": local.color === "warning", - "radio-error": local.color === "error", - }) + const classes = createMemo(() => + twMerge( + "radio", + local.class, + local.className, + clsx({ + "radio-xs": local.size === "xs", + "radio-sm": local.size === "sm", + "radio-md": local.size === "md", + "radio-lg": local.size === "lg", + "radio-xl": local.size === "xl", + "radio-primary": local.color === "primary", + "radio-secondary": local.color === "secondary", + "radio-accent": local.color === "accent", + "radio-info": local.color === "info", + "radio-success": local.color === "success", + "radio-warning": local.color === "warning", + "radio-error": local.color === "error", + }) + ) ); return ( @@ -69,8 +74,8 @@ const Radio = (props: RadioProps) => { {...rest} name={local.name} type="radio" - class={classes} - data-theme={local["data-theme"]} + class={classes()} + data-theme={local.dataTheme} aria-label={local["aria-label"]} aria-describedby={local["aria-describedby"]} aria-invalid={local["aria-invalid"]} diff --git a/src/components/range/Range.tsx b/src/components/range/Range.tsx index 8b0a78fd..0be1451e 100644 --- a/src/components/range/Range.tsx +++ b/src/components/range/Range.tsx @@ -1,6 +1,7 @@ import { splitProps, createMemo, JSX, Show, For } from "solid-js"; import clsx from "clsx"; import { twMerge } from "tailwind-merge"; +import { IComponentBaseProps } from "../types"; export type ComponentColor = | "primary" @@ -16,17 +17,18 @@ export type ComponentSize = "xs" | "sm" | "md" | "lg" | "xl"; export type RangeProps = Omit< JSX.InputHTMLAttributes, "size" -> & { - color?: ComponentColor; - size?: ComponentSize; - displayTicks?: boolean; - ticksStep?: number; - "data-theme"?: string; -}; +> & + IComponentBaseProps & { + color?: ComponentColor; + size?: ComponentSize; + displayTicks?: boolean; + ticksStep?: number; + }; -const Range = (props: RangeProps) => { +const Range = (props: RangeProps): JSX.Element => { const [local, rest] = splitProps(props, [ "class", + "className", "color", "size", "step", @@ -34,26 +36,29 @@ const Range = (props: RangeProps) => { "ticksStep", "min", "max", - "data-theme", + "dataTheme", ]); - const classes = twMerge( - "range", - local.class, - clsx({ - "range-xs": local.size === "xs", - "range-sm": local.size === "sm", - "range-md": local.size === "md", - "range-lg": local.size === "lg", - "range-xl": local.size === "xl", - "range-primary": local.color === "primary", - "range-secondary": local.color === "secondary", - "range-accent": local.color === "accent", - "range-info": local.color === "info", - "range-success": local.color === "success", - "range-warning": local.color === "warning", - "range-error": local.color === "error", - }) + const classes = createMemo(() => + twMerge( + "range", + local.class, + local.className, + clsx({ + "range-xs": local.size === "xs", + "range-sm": local.size === "sm", + "range-md": local.size === "md", + "range-lg": local.size === "lg", + "range-xl": local.size === "xl", + "range-primary": local.color === "primary", + "range-secondary": local.color === "secondary", + "range-accent": local.color === "accent", + "range-info": local.color === "info", + "range-success": local.color === "success", + "range-warning": local.color === "warning", + "range-error": local.color === "error", + }) + ) ); const ticks = createMemo(() => { @@ -75,8 +80,8 @@ const Range = (props: RangeProps) => { {...rest} type="range" step={local.step} - class={classes} - data-theme={local["data-theme"]} + class={classes()} + data-theme={local.dataTheme} /> 0}>
    diff --git a/src/components/stats/Stat.tsx b/src/components/stats/Stat.tsx index f3333da6..0bc3f0f4 100644 --- a/src/components/stats/Stat.tsx +++ b/src/components/stats/Stat.tsx @@ -1,21 +1,21 @@ -import { splitProps, type JSX } from "solid-js"; +import { splitProps, type JSX, createMemo } from "solid-js"; import { twMerge } from "tailwind-merge"; import { clsx } from "clsx"; import StatSection, { type StatSectionProps } from "./StatSection"; +import { IComponentBaseProps } from "../types"; -export type StatProps = JSX.HTMLAttributes & { - "data-theme"?: string; -}; +export type StatProps = JSX.HTMLAttributes & + IComponentBaseProps; + +const Stat = (props: StatProps): JSX.Element => { + const [local, rest] = splitProps(props, ["class", "className", "dataTheme"]); -const Stat = (props: StatProps) => { - const [local, rest] = splitProps(props, ["class", "data-theme"]); + const classes = createMemo(() => + twMerge("stat", clsx(local.class, local.className)) + ); return ( -
    +
    {props.children}
    ); diff --git a/src/components/steps/Step.tsx b/src/components/steps/Step.tsx index 6006c15f..4af91b20 100644 --- a/src/components/steps/Step.tsx +++ b/src/components/steps/Step.tsx @@ -1,4 +1,4 @@ -import { type JSX, splitProps } from "solid-js"; +import { type JSX, splitProps, createMemo } from "solid-js"; import { Dynamic } from "solid-js/web"; import { twMerge } from "tailwind-merge"; import { clsx } from "clsx"; @@ -18,7 +18,6 @@ type StepBaseProps = { className?: string; style?: JSX.CSSProperties; children?: JSX.Element; - "data-theme"?: string; }; type PropsOf = JSX.IntrinsicElements[E]; @@ -32,11 +31,26 @@ export type StepProps = Omit< // Common void elements, unlikely for
  • const VoidElementList: ElementType[] = [ - "area","base","br","col","embed","hr","img","input","link","keygen", - "meta","param","source","track","wbr", + "area", + "base", + "br", + "col", + "embed", + "hr", + "img", + "input", + "link", + "keygen", + "meta", + "param", + "source", + "track", + "wbr", ]; -const Step = (props: StepProps): JSX.Element => { +const Step = ( + props: StepProps +): JSX.Element => { const [local, others] = splitProps( props as StepBaseProps & Record, [ @@ -47,13 +61,13 @@ const Step = (props: StepProps): JSX.Element => "className", "style", "children", - "data-theme", + "dataTheme", ] ); - const Tag = local.as || ("li" as ElementType); + const Tag = createMemo(() => local.as || ("li" as ElementType)); - const classes = () => + const classes = createMemo(() => twMerge( "step", local.class, @@ -68,16 +82,17 @@ const Step = (props: StepProps): JSX.Element => "step-warning": local.color === "warning", "step-error": local.color === "error", }) - ); + ) + ); // Even if Tag is a void element, render without children - if (VoidElementList.includes(Tag)) { + if (VoidElementList.includes(Tag())) { return ( (props: StepProps): JSX.Element => return ( = JSX.IntrinsicElements[E]; @@ -30,11 +29,26 @@ export type StepsProps = Omit< // Void elements rarely used here, but included for completeness const VoidElementList: ElementType[] = [ - "area","base","br","col","embed","hr","img","input","link","keygen", - "meta","param","source","track","wbr", + "area", + "base", + "br", + "col", + "embed", + "hr", + "img", + "input", + "link", + "keygen", + "meta", + "param", + "source", + "track", + "wbr", ]; -const Steps = (props: StepsProps): JSX.Element => { +const Steps = ( + props: StepsProps +): JSX.Element => { const [local, others] = splitProps( props as StepsBaseProps & Record, [ @@ -45,13 +59,13 @@ const Steps = (props: StepsProps): JSX.Element "class", "className", "style", - "data-theme", + "dataTheme", ] ); - const Tag = local.as || ("ul" as ElementType); + const Tag = createMemo(() => local.as || ("ul" as ElementType)); - const classes = () => + const classes = createMemo(() => twMerge( "steps", local.class, @@ -60,16 +74,17 @@ const Steps = (props: StepsProps): JSX.Element "steps-vertical": local.vertical, "steps-horizontal": local.horizontal, }) - ); + ) + ); - if (VoidElementList.includes(Tag)) { + if (VoidElementList.includes(Tag())) { return ( @@ -78,11 +93,11 @@ const Steps = (props: StepsProps): JSX.Element return (