From 4e5283121e2ca1cd714660d29056716d84024407 Mon Sep 17 00:00:00 2001 From: jp calvo Date: Sun, 29 Dec 2024 11:14:08 +0800 Subject: [PATCH 1/3] chore(core): handle svelte class value in mergeProps --- packages/core/src/merge-props.ts | 58 +++++++++++++++++-- .../svelte/tests/merge-props.test.ts | 14 +++-- 2 files changed, 62 insertions(+), 10 deletions(-) diff --git a/packages/core/src/merge-props.ts b/packages/core/src/merge-props.ts index d1e0e8ab63..993c14b8a6 100644 --- a/packages/core/src/merge-props.ts +++ b/packages/core/src/merge-props.ts @@ -4,11 +4,59 @@ interface Props { [key: string]: any } -const clsx = (...args: (string | undefined)[]) => - args - .map((str) => str?.trim?.()) - .filter(Boolean) - .join(" ") +type ClassValue = ClassValue[] | Record | string | number | bigint | null | boolean | undefined + +const classValueToString = (mix: ClassValue) => { + let i: any + let j: any + + let str = "" + + if (typeof mix === "string" || typeof mix === "number") { + str += mix + } else if (typeof mix === "object") { + if (Array.isArray(mix)) { + const len = mix.length + + for (i = 0; i < len; i++) { + if (mix[i]) { + if ((j = classValueToString(mix[i]))) { + str && (str += " ") + str += j + } + } + } + } else { + for (j in mix) { + if (mix![j]) { + str && (str += " ") + str += j + } + } + } + } + + return str +} + +const clsx = (...args: ClassValue[]) => { + let idx = 0 + let tmp: ClassValue + let cls: string + let str = "" + let len = args.length + + for (; idx < len; idx++) { + if ((tmp = args[idx])) { + if ((cls = classValueToString(tmp))) { + str && (str += " ") + str += cls + } + } + } + + return str +} const CSS_REGEX = /((?:--)?(?:\w+-?)+)\s*:\s*([^;]*)/g diff --git a/packages/frameworks/svelte/tests/merge-props.test.ts b/packages/frameworks/svelte/tests/merge-props.test.ts index b65e20904b..eabe95e03a 100644 --- a/packages/frameworks/svelte/tests/merge-props.test.ts +++ b/packages/frameworks/svelte/tests/merge-props.test.ts @@ -1,4 +1,4 @@ -import { describe, it, expect, vi } from "vitest" +import { describe, expect, it, vi } from "vitest" import { mergeProps } from "../src" describe("mergeProps for Svelte", () => { @@ -29,14 +29,18 @@ describe("mergeProps for Svelte", () => { it("combines css classes", () => { const className1 = "primary" - const className2 = "hover" - const className3 = "focus" + const className2 = ["hover", "focus", null, undefined] + const className3 = { + md: false, + lg: true, + xl: false, + } const props = mergeProps({ class: className1 }, { class: className2 }, { class: className3 }) - expect(props.class).toBe("primary hover focus") + expect(props.class).toBe("primary hover focus lg") const props2 = mergeProps({ className: className1 }, { className: className2 }, { className: className3 }) - expect(props2.className).toBe("primary hover focus") + expect(props2.className).toBe("primary hover focus lg") }) it("combines styles", () => { From e943da36e31fa377945dea0d56368c87ca709088 Mon Sep 17 00:00:00 2001 From: jp calvo Date: Sun, 29 Dec 2024 11:45:40 +0800 Subject: [PATCH 2/3] test(svelte): add test for object inside array class value --- packages/frameworks/svelte/tests/merge-props.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/frameworks/svelte/tests/merge-props.test.ts b/packages/frameworks/svelte/tests/merge-props.test.ts index eabe95e03a..ee1ac51a00 100644 --- a/packages/frameworks/svelte/tests/merge-props.test.ts +++ b/packages/frameworks/svelte/tests/merge-props.test.ts @@ -29,7 +29,7 @@ describe("mergeProps for Svelte", () => { it("combines css classes", () => { const className1 = "primary" - const className2 = ["hover", "focus", null, undefined] + const className2 = ["hover", { focus: true }, null, undefined] const className3 = { md: false, lg: true, From ee61e650e9e38d914ec4314c34cb311117c63e9b Mon Sep 17 00:00:00 2001 From: jp calvo Date: Sun, 29 Dec 2024 17:53:31 +0800 Subject: [PATCH 3/3] chore: handle svelte class merging in svelte package mergeProps instead of core --- packages/core/src/merge-props.ts | 58 ++------------- packages/frameworks/svelte/src/merge-props.ts | 72 ++++++++++++++++++- .../svelte/tests/merge-props.test.ts | 4 +- 3 files changed, 78 insertions(+), 56 deletions(-) diff --git a/packages/core/src/merge-props.ts b/packages/core/src/merge-props.ts index 993c14b8a6..d1e0e8ab63 100644 --- a/packages/core/src/merge-props.ts +++ b/packages/core/src/merge-props.ts @@ -4,59 +4,11 @@ interface Props { [key: string]: any } -type ClassValue = ClassValue[] | Record | string | number | bigint | null | boolean | undefined - -const classValueToString = (mix: ClassValue) => { - let i: any - let j: any - - let str = "" - - if (typeof mix === "string" || typeof mix === "number") { - str += mix - } else if (typeof mix === "object") { - if (Array.isArray(mix)) { - const len = mix.length - - for (i = 0; i < len; i++) { - if (mix[i]) { - if ((j = classValueToString(mix[i]))) { - str && (str += " ") - str += j - } - } - } - } else { - for (j in mix) { - if (mix![j]) { - str && (str += " ") - str += j - } - } - } - } - - return str -} - -const clsx = (...args: ClassValue[]) => { - let idx = 0 - let tmp: ClassValue - let cls: string - let str = "" - let len = args.length - - for (; idx < len; idx++) { - if ((tmp = args[idx])) { - if ((cls = classValueToString(tmp))) { - str && (str += " ") - str += cls - } - } - } - - return str -} +const clsx = (...args: (string | undefined)[]) => + args + .map((str) => str?.trim?.()) + .filter(Boolean) + .join(" ") const CSS_REGEX = /((?:--)?(?:\w+-?)+)\s*:\s*([^;]*)/g diff --git a/packages/frameworks/svelte/src/merge-props.ts b/packages/frameworks/svelte/src/merge-props.ts index d9f4da9b22..a783c20691 100644 --- a/packages/frameworks/svelte/src/merge-props.ts +++ b/packages/frameworks/svelte/src/merge-props.ts @@ -14,8 +14,77 @@ const serialize = (style: string): CSSObject => { return res } +type ClassValue = ClassValue[] | Record | string | number | bigint | null | boolean | undefined + +const classValueToString = (mix: ClassValue) => { + let i: any + let j: any + + let str = "" + + if (typeof mix === "string" || typeof mix === "number") { + str += mix + } else if (typeof mix === "object") { + if (Array.isArray(mix)) { + const len = mix.length + + for (i = 0; i < len; i++) { + if (mix[i]) { + if ((j = classValueToString(mix[i]))) { + str && (str += " ") + str += j + } + } + } + } else { + for (j in mix) { + if (mix![j]) { + str && (str += " ") + str += j + } + } + } + } + + return str +} + +const clsx = (...args: ClassValue[]) => { + let idx = 0 + let tmp: ClassValue + let cls: string + let str = "" + let len = args.length + + for (; idx < len; idx++) { + if ((tmp = args[idx])) { + if ((cls = classValueToString(tmp))) { + str && (str += " ") + str += cls + } + } + } + + return str +} + export function mergeProps(...args: Record[]) { - const merged = zagMergeProps(...args) + const copy = args.map((arg) => Object.assign({}, arg)) + const classes: ClassValue[] = [] + + for (const arg of copy) { + if ("class" in arg) { + classes.push(arg.class) + delete arg.class + } + + if ("className" in arg) { + classes.push(arg.className) + delete arg.className + } + } + + const merged = zagMergeProps(...copy) if ("style" in merged) { if (typeof merged.style === "string") { @@ -24,5 +93,6 @@ export function mergeProps(...args: Record[]) { merged.style = toStyleString(merged.style) } + classes.length && (merged.class = clsx(...classes)) return merged } diff --git a/packages/frameworks/svelte/tests/merge-props.test.ts b/packages/frameworks/svelte/tests/merge-props.test.ts index ee1ac51a00..c5b775bd0c 100644 --- a/packages/frameworks/svelte/tests/merge-props.test.ts +++ b/packages/frameworks/svelte/tests/merge-props.test.ts @@ -10,7 +10,7 @@ describe("mergeProps for Svelte", () => { const props = mergeProps({ onClick, className, id }) expect(props.onClick).toBe(onClick) - expect(props.className).toBe(className) + expect(props.class).toBe(className) expect(props.id).toBe(id) }) @@ -40,7 +40,7 @@ describe("mergeProps for Svelte", () => { expect(props.class).toBe("primary hover focus lg") const props2 = mergeProps({ className: className1 }, { className: className2 }, { className: className3 }) - expect(props2.className).toBe("primary hover focus lg") + expect(props2.class).toBe("primary hover focus lg") }) it("combines styles", () => {