Skip to content
Merged
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
1 change: 1 addition & 0 deletions .github/actions/cache-dir/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ inputs:
default: |
.cache
**/.cache
configs/vite-config-custom/dist

runs:
using: composite
Expand Down
5 changes: 4 additions & 1 deletion .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
"vue"
],
"cSpell.words": [
"Classable",
"codegen",
"elif",
"fontface",
Expand All @@ -39,8 +40,10 @@
"pkgs",
"Pretendard",
"Resizer",
"Stringable",
"unicase",
"unitless",
"urange"
"urange",
"Valueable"
]
}
8 changes: 4 additions & 4 deletions configs/eslint-config-custom/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,18 +18,18 @@
},
"devDependencies": {
"@eslint/js": "^9.38.0",
"@types/node": "^24.9.1",
"@types/node": "^25.0.5",
"@typescript-eslint/parser": "^8.46.2",
Comment on lines +21 to 22
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

cd configs/eslint-config-custom && cat -n package.json

Repository: mincho-js/mincho

Length of output: 1150


🌐 Web query:

@types/node 25.0.5 release notes changelog breaking changes

💡 Result:

Short answer: There are no formal release notes/changelog entries published for @types/node patch releases (including 25.0.5). Changes are tracked in the DefinitelyTyped repo (commits/PRs for types/node), and users must inspect the commit/PR history for breaking/type changes. See DefinitelyTyped and the longstanding issue asking for a changelog. [1][2]

If you want, I can fetch the types/node commit/PR list that corresponds to the 25.0.5 publish and list the exact changes and any breaking edits. Which do you prefer?

Sources:

  • DefinitelyTyped repository (types/node). [1]
  • Issue asking where @types/node changelogs are located. [2]

🌐 Web query:

globals 17.0.0 release notes npm changelog

💡 Result:

Summary of globals v17.0.0 release (changelog / release notes)

  • Breaking

    • Split audioWorklet environment out from browser. [1]
  • Improvements

    • Updated globals data. [1]
    • Merge browser globals from both Chrome and Firefox sources. [1]
    • Added a bunBuiltin environment. [1]

Published as version 17.0.0 on the npm registry. [2]

Sources:
[1] globals v17.0.0 release notes (GitHub releases).
[2] globals package metadata on npm/jsDocs.


🌐 Web query:

prettier 3.7.4 release notes changelog breaking changes

💡 Result:

Summary — Prettier 3.7.4 (patch release)

  • Type: patch (no announced breaking changes). [1][2]
  • Notable fixes/changes:
    • LWC: avoid adding quotes around interpolations in markup (fix for cases where Prettier previously produced foo="{bar}" → now foo={bar}). [3][4]
    • TypeScript: fix duplicated comment when a comment appears inside a union type. [3]
    • Miscellaneous bugfixes and small changelog edits (see package changelog/commit). [2][5]

Sources

  • Prettier package listings / release metadata (v3.7.4). [1]
  • Source/commit notes showing the 3.7.4 release and changelog entries. [2][5]
  • Example changelog snippet showing LWC and TypeScript fixes. [3][4]

If you want, I can fetch the full CHANGELOG.md or the exact commit/PR links for each fix.


🌐 Web query:

yaml-eslint-parser 1.3.2 release notes changelog

💡 Result:

I couldn't find a dedicated "1.3.2" release entry, but sources show the package's latest published version is 1.3.2 and the repository includes a CHANGELOG.md you can check for release notes.

  • Version 1.3.2 (latest) — Snyk package page. [1]
  • Repository (contains CHANGELOG.md / project files) — ota-meshi/yaml-eslint-parser. [2]

If you want, I can open the repo CHANGELOG.md and extract the 1.3.2 entry for you.


Verify globals 17.0.0 breaking change doesn't affect your config.
The upgrade to globals 17.0.0 includes a breaking change: audioWorklet environment has been split out from the browser environment. If your ESLint config relies on browser globals (including audioWorklet), it will need adjustment.

Prettier 3.7.4 is a patch release with no breaking changes (TypeScript and LWC bugfixes only). @types/node and yaml-eslint-parser appear to be stable updates with no published compatibility concerns.

🤖 Prompt for AI Agents
In `@configs/eslint-config-custom/package.json` around lines 21 - 22, The upgrade
to globals 17.0.0 split out the audioWorklet environment which can break ESLint
if your config implicitly relied on browser globals; in the package.json where
"@types/node" and "@typescript-eslint/parser" are updated, verify your ESLint
config (e.g., your shared config or .eslintrc) explicitly enables the
audioWorklet globals or declares them as readonly globals (or adds the new
"audioWorklet" env) instead of relying on "browser" alone, and run lint to
confirm no undefined-global errors; if you need to support older setups, pin
globals to a pre-17.x version or add explicit entries for audioWorklet in the
"globals" section of your ESLint config.

"eslint": "^9.38.0",
"eslint-config-prettier": "^10.1.8",
"eslint-plugin-prettier": "^5.5.4",
"eslint-plugin-yml": "^1.19.0",
"globals": "^16.4.0",
"prettier": "^3.6.2",
"globals": "^17.0.0",
"prettier": "^3.7.4",
"prettier-config-custom": "workspace:^",
"typescript": "^5.9.3",
"typescript-eslint": "^8.46.2",
"yaml-eslint-parser": "^1.3.0"
"yaml-eslint-parser": "^1.3.2"
},
"prettier": "prettier-config-custom"
}
16 changes: 8 additions & 8 deletions examples/react-babel/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,30 +23,30 @@
"@vanilla-extract/private": "^1.0.9",
"css-what": "^7.0.0",
"cssesc": "^3.0.0",
"dedent": "^1.7.0",
"dedent": "^1.7.1",
"deep-object-diff": "^1.1.9",
"deepmerge": "^4.3.1",
"lru-cache": "^11.2.2",
"lru-cache": "^11.2.4",
"media-query-parser": "3.0.2",
"modern-ahocorasick": "^2.0.4",
"picocolors": "^1.1.1",
"react": "^19.2.0",
"react-dom": "^19.2.0",
"react": "^19.2.3",
"react-dom": "^19.2.3",
"scheduler": "^0.27.0"
},
"devDependencies": {
"@eslint/js": "^9.38.0",
"@types/babel__core": "^7.20.5",
"@types/cssesc": "^3.0.2",
"@types/react": "^19.2.2",
"@types/react-dom": "^19.2.2",
"@types/react": "^19.2.8",
"@types/react-dom": "^19.2.3",
"@types/scheduler": "^0.26.0",
"@typescript-eslint/parser": "^8.46.2",
"@vitejs/plugin-react": "^5.0.4",
"@vitejs/plugin-react": "^5.1.2",
"eslint": "^9.38.0",
"eslint-plugin-react-hooks": "^7.0.0",
"eslint-plugin-react-refresh": "^0.4.24",
"globals": "^16.4.0",
"globals": "^17.0.0",
"typescript": "~5.9.3",
"typescript-eslint": "^8.46.2",
"vite": "^7.1.12"
Expand Down
16 changes: 8 additions & 8 deletions examples/react-swc/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,24 +11,24 @@
"preview": "vite preview"
},
"dependencies": {
"react": "^19.2.0",
"react-dom": "^19.2.0"
"react": "^19.2.3",
"react-dom": "^19.2.3"
},
"devDependencies": {
"@eslint/js": "^9.38.0",
"@mincho-js/css": "workspace:^",
"@types/react": "^19.2.2",
"@types/react-dom": "^19.2.2",
"@types/react": "^19.2.8",
"@types/react-dom": "^19.2.3",
"@typescript-eslint/eslint-plugin": "^8.46.2",
"@typescript-eslint/parser": "^8.46.2",
"@vanilla-extract/css": "^1.17.4",
"@vanilla-extract/esbuild-plugin": "^2.3.18",
"@vanilla-extract/vite-plugin": "^5.1.1",
"@vitejs/plugin-react-swc": "^4.1.0",
"@vanilla-extract/esbuild-plugin": "^2.3.21",
"@vanilla-extract/vite-plugin": "^5.1.4",
"@vitejs/plugin-react-swc": "^4.2.2",
"eslint": "^9.38.0",
"eslint-plugin-react-hooks": "^7.0.0",
"eslint-plugin-react-refresh": "^0.4.24",
"globals": "^16.4.0",
"globals": "^17.0.0",
"typescript": "^5.9.3",
"typescript-eslint": "^8.46.2",
"vite": "^7.1.12"
Expand Down
22 changes: 11 additions & 11 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@
],
"scripts": {
"postinstall": "yarn workspace vite-config-custom build",
"task": "yarn turbo run --cache-dir .cache/turbo",
"clean": "yarn g:clean && yarn task clean",
"task": "yarn run -T turbo run --cache-dir .cache/turbo",
"clean": "yarn g:clean & yarn task clean",
"build": "yarn task build",
"build:full": "PACKAGE_PUBLISH=true yarn task build",
"build:type": "yarn tsc --build",
Expand Down Expand Up @@ -47,30 +47,30 @@
},
"prettier": "prettier-config-custom",
"devDependencies": {
"@changesets/changelog-github": "^0.5.1",
"@changesets/cli": "^2.29.7",
"@changesets/changelog-github": "^0.5.2",
"@changesets/cli": "^2.29.8",
"@mincho-js/debug-log": "workspace:^",
"@monorepo-utils/workspaces-to-typescript-project-references": "^2.11.0",
"@types/eslint": "^9.6.1",
"@types/node": "^24.9.1",
"@types/node": "^25.0.5",
"@typescript/analyze-trace": "^0.10.1",
"@vanilla-extract/vite-plugin": "^5.1.1",
"@vitest/coverage-v8": "^4.0.2",
"@vanilla-extract/vite-plugin": "^5.1.4",
"@vitest/coverage-v8": "^4.0.16",
"@yarnpkg/types": "^4.0.1",
"c8": "^10.1.3",
"eslint": "^9.38.0",
"eslint-config-custom": "workspace:^",
"prettier": "^3.6.2",
"prettier": "^3.7.4",
"prettier-config-custom": "workspace:^",
"prettier-eslint": "^16.4.2",
"rimraf": "6.0.0",
"terser": "^5.44.0",
"terser": "^5.44.1",
"tsconfig-custom": "workspace:^",
"turbo": "^2.5.8",
"turbo": "^2.7.3",
"typescript": "^5.9.3",
"vite": "^7.1.12",
"vite-node": "^3.2.4",
"vitest": "^4.0.2",
"vitest": "^4.0.16",
"yarn-constraints-rules": "^0.1.0"
},
"dependencies": {
Expand Down
144 changes: 137 additions & 7 deletions packages/css/src/classname/cx.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
import { clsx } from "clsx";
import type { ClassMultipleInput, ClassMultipleResult } from "./types.js";
import type {
ClassValue,
ClassMultipleInput,
ClassMultipleResult
} from "./types.js";

const cxImpl: (...inputs: ClassValue[]) => string = clsx;
/**
* Conditionally join class names into a single string
*
Expand All @@ -27,8 +32,9 @@ import type { ClassMultipleInput, ClassMultipleResult } from "./types.js";
* cx('foo', [1 && 'bar', { baz: false }], ['hello', ['world']], 'cya');
* // => 'foo bar hello world cya'
*/
export const cx = Object.assign(clsx, {
multiple: cxMultiple
export const cx = Object.assign(cxImpl, {
multiple: cxMultiple,
with: cxWith
});

function cxMultiple<T extends ClassMultipleInput>(
Expand All @@ -37,14 +43,37 @@ function cxMultiple<T extends ClassMultipleInput>(
const result = {} as ClassMultipleResult<T>;

for (const key in map) {
if (Object.prototype.hasOwnProperty.call(map, key)) {
result[key] = clsx(map[key]);
}
result[key] = cxImpl(map[key]);
}

return result;
}

function cxWith<const T extends ClassValue>(
callback?: (params: T) => ClassValue
) {
const cxFunction = callback ?? ((className: T) => className);

function cxWithImpl(...className: T[]) {
const result = className.map((cn) => cxFunction(cn));
return cxImpl(...result);
}

function cxWithMultiple<ClassNameMap extends ClassMultipleInput<T>>(
classNameMap: ClassNameMap
): ClassMultipleResult<ClassNameMap> {
type TransformedClassNameMap = Record<keyof ClassNameMap, ClassValue>;
const transformedClassNameMap: TransformedClassNameMap =
{} as TransformedClassNameMap;
for (const key in classNameMap) {
transformedClassNameMap[key] = cxFunction(classNameMap[key]);
}
return cxMultiple(transformedClassNameMap);
}

return Object.assign(cxWithImpl, { multiple: cxWithMultiple });
}

// == Tests ====================================================================
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore error TS1343
Expand Down Expand Up @@ -124,10 +153,11 @@ if (import.meta.vitest) {
it("filters falsy values correctly", () => {
expect(cx(null)).toBe("");
expect(cx(undefined)).toBe("");
expect(cx(true)).toBe("");
expect(cx(false)).toBe("");
expect(cx(0)).toBe("");
expect(cx("")).toBe("");
expect(cx(null, undefined, false, 0, "")).toBe("");
expect(cx(null, undefined, true, false, 0, "")).toBe("");
});

it("preserves whitespace in class names", () => {
Expand Down Expand Up @@ -201,4 +231,104 @@ if (import.meta.vitest) {
assertType<{ a: string; b: string }>(result);
});
});

describe.concurrent("cx.with()", () => {
it("creates a typed constraint without transformer", () => {
type LayoutDisplay = "flex" | "grid" | "block";
type LayoutSpacing = `p-${number}` | `m-${number}`;
const layout = cx.with<LayoutDisplay | LayoutSpacing>();

expect(layout("flex", "p-4")).toBe("flex p-4");
expect(layout("grid")).toBe("grid");
});

it("creates a typed full constraint without transformer", () => {
type LayoutDisplay = "flex" | "grid" | "block";
type LayoutSpacing = `p-${number}` | `m-${number}`;
const layout = cx.with<ClassValue<LayoutDisplay | LayoutSpacing>>();

expect(layout("flex", "p-4", { block: true })).toBe("flex p-4 block");
expect(layout("grid", { block: false, "m-1": true })).toBe("grid m-1");
});

it("creates a typed constraint with transformer", () => {
const responsive = cx.with<{ base: string; md?: string; lg?: string }>(
({ base, md, lg }) => [base, md && `md:${md}`, lg && `lg:${lg}`]
);

expect(
responsive({ base: "text-sm", md: "text-base", lg: "text-lg" })
).toBe("text-sm md:text-base lg:text-lg");
expect(responsive({ base: "text-sm" })).toBe("text-sm");
});

it("filters out non-string and empty values without transformer", () => {
const test = cx.with<{
required: string;
optional?: string;
flag?: boolean;
}>();

expect(test({ required: "foo", optional: undefined, flag: true })).toBe(
"required flag"
);
expect(test({ required: "foo", optional: "" })).toBe("required");
});

it("transformer receives all params", () => {
const test = cx.with<{ a: string; b: boolean }>(({ a, b }) => [
a,
b && "active"
]);

expect(test({ a: "base", b: true })).toBe("base active");
expect(test({ a: "base", b: false })).toBe("base");
});

it("cx.with().multiple() processes a map with typed constraint", () => {
type LayoutDisplay = "flex" | "grid" | "block";
type LayoutSpacing = `p-${number}` | `m-${number}`;
const layout = cx.with<LayoutDisplay | LayoutSpacing>();

const result = layout.multiple({
card: "flex",
container: "grid"
});

expect(result.card).toBe("flex");
expect(result.container).toBe("grid");
});

it("cx.with().multiple() with transformer", () => {
const responsive = cx.with<{ base: string; md?: string; lg?: string }>(
({ base, md, lg }) => [base, md && `md:${md}`, lg && `lg:${lg}`]
);

const result = responsive.multiple({
heading: { base: "text-xl", md: "text-2xl", lg: "text-3xl" },
body: { base: "text-sm", md: "text-base" },
caption: { base: "text-xs" }
});

expect(result.heading).toBe("text-xl md:text-2xl lg:text-3xl");
expect(result.body).toBe("text-sm md:text-base");
expect(result.caption).toBe("text-xs");
});

it("cx.with().multiple() handles empty map", () => {
const layout = cx.with<"flex" | "grid">();
const result = layout.multiple({});
expect(result).toEqual({});
});

it("cx.with().multiple() returns correct type", () => {
const layout = cx.with<"flex" | "grid">();
const result = layout.multiple({
a: "flex",
b: "grid"
});

assertType<{ a: string; b: string }>(result);
});
});
}
2 changes: 1 addition & 1 deletion packages/css/src/classname/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
export { cx } from "./cx.js";

export type { ClassValue, ClassArray, ClassDictionary } from "./types.js";
export type { ClassValue } from "./types.js";
Loading
Loading