tailwind-styled-v4 5.1.28 → 5.1.29

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -11,6 +11,40 @@ dan project ini mengikuti [Semantic Versioning](https://semver.org/spec/v2.0.0.h
11
11
 
12
12
  All Wave 1-3 features are published to npm and integrated in production (next-js-app example).
13
13
 
14
+ #### Wave 5.4: Boolean/Number/String Variant Type Safety (v5.0.18+ ✅ JULY 4, 2026)
15
+
16
+ - **Fixed: Variant Type Enforcement in `defaultVariants` and Props** ✅
17
+ - **Problem:** TypeScript now correctly enforces type matching between variant keys and `defaultVariants` values
18
+ - **Impact:** 20 `styles.ts` files + 3+ `page.tsx` files in example app had string `"false"` in boolean variant defaults, or passed string `"true"`/`"false"` to boolean props
19
+ - **What changed:** Example code updated to match correct types:
20
+ ```typescript
21
+ // Before (now errors)
22
+ defaultVariants: { active: "false" } // ❌ String
23
+ <Chip active={isOpen ? "true" : "false"} /> // ❌ Strings
24
+
25
+ // After (correct)
26
+ defaultVariants: { active: false } // ✅ Boolean
27
+ <Chip active={isOpen} /> // ✅ Boolean
28
+ ```
29
+ - **Type Safety Matrix:**
30
+ ```
31
+ Variant Keys | Type | defaultVariants | Usage
32
+ { true: "...", false: "" }| bool | active: false | <C active={bool} />
33
+ { 0: "...", 1: "..." } | num | level: 1 | <C level={num} />
34
+ { "x": "...", "y": "" } | str | mode: "x" | <C mode="string" />
35
+ ```
36
+ - **Steering Guide:** New `.kiro/steering/boolean-variants.md` documents:
37
+ - Type matching rules (boolean, number, string)
38
+ - Common mistakes and fixes
39
+ - Migration patterns
40
+ - Pre-shipping checklist
41
+ - **Affected files fixed:**
42
+ - 20 styles.ts: Changed `"false"` → `false` in defaultVariants
43
+ - 3+ page.tsx: Changed string ternaries to boolean expressions
44
+ - Specific files: All `learn/*/styles.ts` + css-functions-future, container-style-queries, popover-api
45
+ - **Validation:** `examples/next-js-app tsc --noEmit` → 0 errors ✅
46
+ - **Reference:** `known-issues.md` (2026-07-04 boolean variants entry), `.kiro/steering/boolean-variants.md` ⭐ (NEW)
47
+
14
48
  #### Wave 5.3: TypeScript Props Type Inference Fix (v5.0.18+ ✅ JULY 4, 2026)
15
49
 
16
50
  - **Fixed: `RuntimeProps` Type Now Supports All HTML Attributes (ARIA, data-*, event handlers, etc.)** ✅
package/dist/index.d.mts CHANGED
@@ -13,7 +13,7 @@ type VariantLiterals = string | number | boolean;
13
13
  /** Sizes sugar syntax — shorthand untuk variants.size */
14
14
  type SizesConfig = Record<string, string>;
15
15
  type InferVariantProps<T extends ComponentConfig> = {
16
- [K in keyof T["variants"]]?: T["variants"][K] extends Record<infer Key, any> ? Key extends "true" | "false" ? boolean : Key : never;
16
+ [K in keyof T["variants"]]?: T["variants"][K] extends Record<infer Key, any> ? Key extends "true" | "false" ? boolean : Key extends `${infer N extends number}` ? N | number : Key : never;
17
17
  };
18
18
  type InferSizeProps<T extends ComponentConfig> = T["sizes"] extends Record<string, string> ? {
19
19
  size?: keyof T["sizes"];
@@ -74,7 +74,8 @@ interface ComponentConfig {
74
74
  /** Variants — nested: { intent: { primary: "..." }, size: { sm: "..." } }
75
75
  * Supports string and boolean keys: { disabled: { true: "...", false: "..." } }
76
76
  */
77
- variants?: Record<string, Record<string | "true" | "false", string>>;
77
+ variants?: Record<string, Record<string | "true" | "false" | number, string>>;
78
+ /** defaultVariants accepts string | number | boolean to match all possible variant key types */
78
79
  defaultVariants?: Record<string, string | number | boolean>;
79
80
  compoundVariants?: Array<{
80
81
  class: string;
@@ -257,7 +258,7 @@ interface TwSubComponent<P = unknown> {
257
258
  interface TwTemplateFactory<Config extends ComponentConfig = ComponentConfig, Tag extends HtmlTagName = HtmlTagName> {
258
259
  <const T extends string>(strings: readonly [T], ...exprs: []): TwStyledComponent<Config, ExtractSubNames<T>, Record<string, never>, Tag>;
259
260
  (strings: TemplateStringsArray, ...exprs: unknown[]): TwStyledComponent<Config, string, Record<string, never>, Tag>;
260
- <C extends ComponentConfig>(config: C): TwStyledComponent<C, InferSubFromConfig<C>, InferSubTagsFromConfig<C> extends Record<string, string> ? InferSubTagsFromConfig<C> : Record<string, never>, Tag>;
261
+ <const C extends ComponentConfig>(config: C): TwStyledComponent<C, InferSubFromConfig<C>, InferSubTagsFromConfig<C> extends Record<string, string> ? InferSubTagsFromConfig<C> : Record<string, never>, Tag>;
261
262
  }
262
263
  type TwTagFactory = {
263
264
  [K in HtmlTagName]: TwTemplateFactory<ComponentConfig, K>;
package/dist/index.d.ts CHANGED
@@ -13,7 +13,7 @@ type VariantLiterals = string | number | boolean;
13
13
  /** Sizes sugar syntax — shorthand untuk variants.size */
14
14
  type SizesConfig = Record<string, string>;
15
15
  type InferVariantProps<T extends ComponentConfig> = {
16
- [K in keyof T["variants"]]?: T["variants"][K] extends Record<infer Key, any> ? Key extends "true" | "false" ? boolean : Key : never;
16
+ [K in keyof T["variants"]]?: T["variants"][K] extends Record<infer Key, any> ? Key extends "true" | "false" ? boolean : Key extends `${infer N extends number}` ? N | number : Key : never;
17
17
  };
18
18
  type InferSizeProps<T extends ComponentConfig> = T["sizes"] extends Record<string, string> ? {
19
19
  size?: keyof T["sizes"];
@@ -74,7 +74,8 @@ interface ComponentConfig {
74
74
  /** Variants — nested: { intent: { primary: "..." }, size: { sm: "..." } }
75
75
  * Supports string and boolean keys: { disabled: { true: "...", false: "..." } }
76
76
  */
77
- variants?: Record<string, Record<string | "true" | "false", string>>;
77
+ variants?: Record<string, Record<string | "true" | "false" | number, string>>;
78
+ /** defaultVariants accepts string | number | boolean to match all possible variant key types */
78
79
  defaultVariants?: Record<string, string | number | boolean>;
79
80
  compoundVariants?: Array<{
80
81
  class: string;
@@ -257,7 +258,7 @@ interface TwSubComponent<P = unknown> {
257
258
  interface TwTemplateFactory<Config extends ComponentConfig = ComponentConfig, Tag extends HtmlTagName = HtmlTagName> {
258
259
  <const T extends string>(strings: readonly [T], ...exprs: []): TwStyledComponent<Config, ExtractSubNames<T>, Record<string, never>, Tag>;
259
260
  (strings: TemplateStringsArray, ...exprs: unknown[]): TwStyledComponent<Config, string, Record<string, never>, Tag>;
260
- <C extends ComponentConfig>(config: C): TwStyledComponent<C, InferSubFromConfig<C>, InferSubTagsFromConfig<C> extends Record<string, string> ? InferSubTagsFromConfig<C> : Record<string, never>, Tag>;
261
+ <const C extends ComponentConfig>(config: C): TwStyledComponent<C, InferSubFromConfig<C>, InferSubTagsFromConfig<C> extends Record<string, string> ? InferSubTagsFromConfig<C> : Record<string, never>, Tag>;
261
262
  }
262
263
  type TwTagFactory = {
263
264
  [K in HtmlTagName]: TwTemplateFactory<ComponentConfig, K>;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tailwind-styled-v4",
3
- "version": "5.1.28",
3
+ "version": "5.1.29",
4
4
  "packageManager": "npm@11.11.1",
5
5
  "engines": {
6
6
  "node": ">=20"