{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "ridiculous-type-kit",
  "title": "Ridiculous Type Kit",
  "description": "Shared template-literal type machinery powering every ridiculous component. Provides char/number primitives, CSS dimension validators (IsLength/IsAngle/IsTime/…), DimensionOf, and paren-aware parser combinators.",
  "dependencies": [],
  "registryDependencies": [],
  "files": [
    {
      "path": "src/lib/ridiculous-type-kit/index.ts",
      "content": "// =====================================================================\n// ridiculous-type-kit — shared template-literal type machinery.\n//\n// Pure types only (no runtime). Boolean predicates return `true`/`false`;\n// compose with And/Or/Not then collapse with KeepIf<B, S> to build an\n// `S | never` validator.\n//\n// CALL-SITE HELPER IDIOM (copy into each component's *.types.ts — cannot\n// be factored into a runtime helper because TS has no higher-kinded types):\n//\n//   export const cssThing = <S extends string>(v: S & CssThingLiteral<S>): S => v\n// =====================================================================\n\nexport type * from \"./combinators\"\nexport type * from \"./dimensions\"\nexport type * from \"./primitives\"\n",
      "type": "registry:lib",
      "target": "lib/ridiculous-type-kit/index.ts"
    },
    {
      "path": "src/lib/ridiculous-type-kit/primitives.ts",
      "content": "// =====================================================================\n// primitives.ts — char classes, trim, boolean logic, char-count.\n// Extracted from the inlined copies in color-picker / easing-picker /\n// unit-input types. Boolean predicates return true | false.\n// =====================================================================\n\nexport type Digit = \"0\" | \"1\" | \"2\" | \"3\" | \"4\" | \"5\" | \"6\" | \"7\" | \"8\" | \"9\"\n\nexport type HexDigit =\n  | Digit\n  | \"a\"\n  | \"b\"\n  | \"c\"\n  | \"d\"\n  | \"e\"\n  | \"f\"\n  | \"A\"\n  | \"B\"\n  | \"C\"\n  | \"D\"\n  | \"E\"\n  | \"F\"\n\n// ASCII letters, both cases. Hoisted from the per-component CSS-ident\n// validators (grid-builder / transition-editor / font-editor), which all\n// re-declared this identical A–Z + a–z union.\nexport type Letter =\n  | \"a\"\n  | \"b\"\n  | \"c\"\n  | \"d\"\n  | \"e\"\n  | \"f\"\n  | \"g\"\n  | \"h\"\n  | \"i\"\n  | \"j\"\n  | \"k\"\n  | \"l\"\n  | \"m\"\n  | \"n\"\n  | \"o\"\n  | \"p\"\n  | \"q\"\n  | \"r\"\n  | \"s\"\n  | \"t\"\n  | \"u\"\n  | \"v\"\n  | \"w\"\n  | \"x\"\n  | \"y\"\n  | \"z\"\n  | \"A\"\n  | \"B\"\n  | \"C\"\n  | \"D\"\n  | \"E\"\n  | \"F\"\n  | \"G\"\n  | \"H\"\n  | \"I\"\n  | \"J\"\n  | \"K\"\n  | \"L\"\n  | \"M\"\n  | \"N\"\n  | \"O\"\n  | \"P\"\n  | \"Q\"\n  | \"R\"\n  | \"S\"\n  | \"T\"\n  | \"U\"\n  | \"V\"\n  | \"W\"\n  | \"X\"\n  | \"Y\"\n  | \"Z\"\n\n// ASCII letter or digit — the alphanumeric char class.\nexport type Alpha = Letter | Digit\n\nexport type WS = \" \" | \"\\n\" | \"\\t\"\n\nexport type TrimLeft<S extends string> = S extends `${WS}${infer R}`\n  ? TrimLeft<R>\n  : S\nexport type TrimRight<S extends string> = S extends `${infer R}${WS}`\n  ? TrimRight<R>\n  : S\nexport type Trim<S extends string> = TrimLeft<TrimRight<S>>\n\n// Every char of `S` must be a member of the `Allowed` union (e.g. `Digit`).\n// Faithful extraction from the shipped components — callers pass a char union.\nexport type AllChars<S extends string, Allowed extends string> = S extends \"\"\n  ? true\n  : S extends `${infer C}${infer R}`\n    ? C extends Allowed\n      ? AllChars<R, Allowed>\n      : false\n    : false\n\nexport type NonEmptyAllChars<\n  S extends string,\n  Allowed extends string,\n> = S extends \"\" ? false : AllChars<S, Allowed>\n\nexport type And<A extends boolean, B extends boolean> = A extends true\n  ? B extends true\n    ? true\n    : false\n  : false\n\nexport type Or<A extends boolean, B extends boolean> = A extends true\n  ? true\n  : B extends true\n    ? true\n    : false\n\nexport type Not<A extends boolean> = A extends true ? false : true\n\nexport type KeepIf<B extends boolean, S extends string> = B extends true\n  ? S\n  : never\n\nexport type Length<\n  S extends string,\n  A extends unknown[] = [],\n> = S extends `${string}${infer R}` ? Length<R, [...A, unknown]> : A[\"length\"]\n\n// --- integer range machinery -----------------------------------------\n\ntype Enumerate<\n  N extends number,\n  A extends number[] = [],\n> = A[\"length\"] extends N ? A[number] : Enumerate<N, [...A, A[\"length\"]]>\n\nexport type IntRange<From extends number, To extends number> = Exclude<\n  Enumerate<To>,\n  Enumerate<From>\n>\n\ntype StripLeadingZeros<S extends string> = S extends `0${infer R}`\n  ? R extends \"\"\n    ? \"0\"\n    : StripLeadingZeros<R>\n  : S\n\ntype NormalizeInt<S extends string> = S extends \"\" ? \"0\" : StripLeadingZeros<S>\n\ntype IsIntPart<S extends string> = S extends \"\"\n  ? true\n  : NonEmptyAllChars<S, Digit>\n\n// --- number shape predicates -----------------------------------------\n\nexport type IsNonNegativeNumber<S extends string> =\n  S extends `${infer I}.${infer F}`\n    ? And<IsIntPart<I>, NonEmptyAllChars<F, Digit>>\n    : NonEmptyAllChars<S, Digit>\n\nexport type IsSignedDecimal<S extends string> = S extends `-${infer R}`\n  ? IsNonNegativeNumber<R>\n  : IsNonNegativeNumber<S>\n\nexport type IsNumber<S extends string> = S extends `+${infer R}`\n  ? IsNonNegativeNumber<R>\n  : IsSignedDecimal<S>\n\nexport type IsPositiveInt<S extends string> = S extends \"0\"\n  ? false\n  : S extends \"\" | \"-\"\n    ? false\n    : NonEmptyAllChars<S, Digit>\n\n// --- bounded-number predicates ---------------------------------------\n//\n// One generic engine for \"is `S` a number in a closed integer-capped range\".\n// Three char-set parameters pin the exact accepted values so every existing\n// alias keeps byte-identical behavior:\n//   • `IntSet`     — bare-integer forms accepted (the integer branch).\n//   • `DecIntSet`  — integer-parts STRICTLY BELOW the cap (a non-zero\n//                    fraction is allowed for these).\n//   • `MaxLit`     — the cap's integer literal; valid only with an all-zero\n//                    fraction (e.g. `\"100\"` → `100.0` ok, `100.5` not).\n// Each set may be a bare-literal union (`\"0\" | \"1\"`) or an `IntRange<…>`\n// template — `IsNumber0To1` uses the former, the rest use the latter.\n// `IsByte` is the integer-only degenerate: passing `never` for both decimal\n// sets makes the fraction branch always reject, leaving the integer check.\nexport type IsNumberInClosedRange<\n  S extends string,\n  IntSet extends string,\n  DecIntSet extends string,\n  MaxLit extends string,\n> = S extends `${infer I}.${infer F}`\n  ? And<IsIntPart<I>, NonEmptyAllChars<F, Digit>> extends true\n    ? NormalizeInt<I> extends DecIntSet\n      ? true\n      : NormalizeInt<I> extends MaxLit\n        ? AllChars<F, \"0\">\n        : false\n    : false\n  : NonEmptyAllChars<S, Digit> extends true\n    ? NormalizeInt<S> extends IntSet\n      ? true\n      : false\n    : false\n\nexport type IsByte<S extends string> = IsNumberInClosedRange<\n  S,\n  `${IntRange<0, 256>}`,\n  never,\n  never\n>\n\nexport type IsNumber0To1<S extends string> = IsNumberInClosedRange<\n  S,\n  \"0\" | \"1\",\n  \"0\",\n  \"1\"\n>\n\nexport type IsNumber0To100<S extends string> = IsNumberInClosedRange<\n  S,\n  `${IntRange<0, 101>}`,\n  `${IntRange<0, 100>}`,\n  \"100\"\n>\n\nexport type IsNumber0To360<S extends string> = IsNumberInClosedRange<\n  S,\n  `${IntRange<0, 361>}`,\n  `${IntRange<0, 360>}`,\n  \"360\"\n>\n\nexport type IsNumber0To400<S extends string> = IsNumberInClosedRange<\n  S,\n  `${IntRange<0, 401>}`,\n  `${IntRange<0, 400>}`,\n  \"400\"\n>\n\n// Trims the numeric part before range-checking, mirroring `IsPercentage`\n// (dimensions.ts), which does `IsNumber<Trim<N>>`. Both now treat `\" 50%\"`\n// identically (previously this returned false here while IsPercentage\n// returned true — an inconsistency across the public API). The `%` must\n// still be the literal final char (no trailing-whitespace acceptance), so\n// only the inner number is trimmed — exactly as IsPercentage does.\nexport type IsPercent0To100<S extends string> = S extends `${infer N}%`\n  ? IsNumber0To100<Trim<N>>\n  : false\n",
      "type": "registry:lib",
      "target": "lib/ridiculous-type-kit/primitives.ts"
    },
    {
      "path": "src/lib/ridiculous-type-kit/dimensions.ts",
      "content": "import type { IsNonNegativeNumber, IsNumber, Trim } from \"./primitives\"\n\n// Try each unit suffix in turn; on a matched-but-non-numeric prefix keep\n// trying (handles ambiguous suffixes like rem/em, dvh/vh). OR over the set.\ntype HasUnit<\n  S extends string,\n  Units extends readonly string[],\n> = Units extends readonly [\n  infer U extends string,\n  ...infer Rest extends readonly string[],\n]\n  ? S extends `${infer N}${U}`\n    ? IsNumber<Trim<N>> extends true\n      ? true\n      : HasUnit<S, Rest>\n    : HasUnit<S, Rest>\n  : false\n\n// Longest-first ordering is defensive only — HasUnit ORs over the whole set.\ntype LengthUnits = [\n  \"cqmin\",\n  \"cqmax\",\n  \"vmin\",\n  \"vmax\",\n  \"svw\",\n  \"svh\",\n  \"svi\",\n  \"svb\",\n  \"lvw\",\n  \"lvh\",\n  \"lvi\",\n  \"lvb\",\n  \"dvw\",\n  \"dvh\",\n  \"dvi\",\n  \"dvb\",\n  \"cqw\",\n  \"cqh\",\n  \"cqi\",\n  \"cqb\",\n  \"rlh\",\n  \"rem\",\n  \"cap\",\n  \"rex\",\n  \"px\",\n  \"em\",\n  \"ex\",\n  \"ch\",\n  \"ic\",\n  \"lh\",\n  \"vw\",\n  \"vh\",\n  \"vi\",\n  \"vb\",\n  \"cm\",\n  \"mm\",\n  \"in\",\n  \"pt\",\n  \"pc\",\n  \"Q\",\n]\ntype AngleUnits = [\"turn\", \"grad\", \"deg\", \"rad\"]\ntype TimeUnits = [\"ms\", \"s\"]\ntype ResolutionUnits = [\"dpcm\", \"dppx\", \"dpi\", \"x\"]\n\nexport type IsLength<S extends string> = HasUnit<S, LengthUnits>\nexport type IsAngle<S extends string> = HasUnit<S, AngleUnits>\nexport type IsTime<S extends string> = HasUnit<S, TimeUnits>\nexport type IsResolution<S extends string> = HasUnit<S, ResolutionUnits>\n\nexport type IsPercentage<S extends string> = S extends `${infer N}%`\n  ? IsNumber<Trim<N>>\n  : false\n\nexport type IsFlex<S extends string> = S extends `${infer N}fr`\n  ? IsNonNegativeNumber<Trim<N>>\n  : false\n\nexport type Dimension =\n  | \"length\"\n  | \"angle\"\n  | \"time\"\n  | \"percent\"\n  | \"number\"\n  | \"flex\"\n  | \"resolution\"\n\n// Order matters: unit-bearing dimensions are checked before bare number.\nexport type DimensionOf<S extends string> =\n  Trim<S> extends infer T extends string\n    ? IsPercentage<T> extends true\n      ? \"percent\"\n      : IsAngle<T> extends true\n        ? \"angle\"\n        : IsTime<T> extends true\n          ? \"time\"\n          : IsResolution<T> extends true\n            ? \"resolution\"\n            : IsFlex<T> extends true\n              ? \"flex\"\n              : IsLength<T> extends true\n                ? \"length\"\n                : IsNumber<T> extends true\n                  ? \"number\"\n                  : never\n    : never\n",
      "type": "registry:lib",
      "target": "lib/ridiculous-type-kit/dimensions.ts"
    },
    {
      "path": "src/lib/ridiculous-type-kit/combinators.ts",
      "content": "import type { Trim } from \"./primitives\"\n\nexport type StartsWith<\n  S extends string,\n  P extends string,\n> = S extends `${P}${string}` ? true : false\n\nexport type EndsWith<\n  S extends string,\n  P extends string,\n> = S extends `${string}${P}` ? true : false\n\n// --- paren/bracket-aware top-level splitter --------------------------\n// Walks char-by-char tracking () and [] depth. Splits only on Sep when\n// depth is 0. Tail-recursive (TS eliminates the tail recursion).\n\ntype Push<Acc extends string[], Cur extends string> = [...Acc, Cur]\n\ntype SplitTopLevel<\n  S extends string,\n  Sep extends string,\n  Depth extends unknown[] = [],\n  Cur extends string = \"\",\n  Acc extends string[] = [],\n> = S extends `${infer C}${infer Rest}`\n  ? C extends \"(\" | \"[\"\n    ? SplitTopLevel<Rest, Sep, [...Depth, unknown], `${Cur}${C}`, Acc>\n    : C extends \")\" | \"]\"\n      ? SplitTopLevel<\n          Rest,\n          Sep,\n          Depth extends [unknown, ...infer D] ? D : [],\n          `${Cur}${C}`,\n          Acc\n        >\n      : C extends Sep\n        ? Depth[\"length\"] extends 0\n          ? SplitTopLevel<Rest, Sep, Depth, \"\", Push<Acc, Cur>>\n          : SplitTopLevel<Rest, Sep, Depth, `${Cur}${C}`, Acc>\n        : SplitTopLevel<Rest, Sep, Depth, `${Cur}${C}`, Acc>\n  : Push<Acc, Cur>\n\n// Trim every token; for space-splitting also drop empties (collapses runs).\ntype TrimAll<T extends string[], DropEmpty extends boolean> = T extends [\n  infer H extends string,\n  ...infer R extends string[],\n]\n  ? Trim<H> extends \"\"\n    ? DropEmpty extends true\n      ? TrimAll<R, DropEmpty>\n      : [\"\", ...TrimAll<R, DropEmpty>]\n    : [Trim<H>, ...TrimAll<R, DropEmpty>]\n  : []\n\nexport type SplitByComma<S extends string> = TrimAll<\n  SplitTopLevel<S, \",\">,\n  false\n>\n\nexport type SplitBySpace<S extends string> = TrimAll<\n  SplitTopLevel<S, \" \">,\n  true\n>\n\n// --- function parser --------------------------------------------------\n// Splits on the FIRST \"(\" (name) and the LAST \")\" (args), so the outer\n// call wins for nested functions. Name is trimmed; args kept verbatim.\n\nexport type ParseFunction<S extends string> =\n  Trim<S> extends `${infer Name}(${infer Args})`\n    ? { name: Trim<Name>; args: Args }\n    : never\n",
      "type": "registry:lib",
      "target": "lib/ridiculous-type-kit/combinators.ts"
    }
  ],
  "type": "registry:lib"
}