From e994ecc32178df3963dd98217d75a34c864655ce Mon Sep 17 00:00:00 2001 From: jorenbroekema Date: Tue, 23 Jan 2024 15:40:51 +0100 Subject: [PATCH] feat: allow $ props for w3c spec compliance --- .changeset/thin-bottles-act.md | 5 +++ src/types/tokens/DeepKeyTokenMap.ts | 8 ++-- src/types/tokens/SingleGenericToken.ts | 57 ++++++++++++++++++++++---- 3 files changed, 59 insertions(+), 11 deletions(-) create mode 100644 .changeset/thin-bottles-act.md diff --git a/.changeset/thin-bottles-act.md b/.changeset/thin-bottles-act.md new file mode 100644 index 0000000..1fcfe53 --- /dev/null +++ b/.changeset/thin-bottles-act.md @@ -0,0 +1,5 @@ +--- +'@tokens-studio/types': minor +--- + +Add compatibility with W3C DTCG specification for design tokens. diff --git a/src/types/tokens/DeepKeyTokenMap.ts b/src/types/tokens/DeepKeyTokenMap.ts index 1a103c4..9bdd950 100644 --- a/src/types/tokens/DeepKeyTokenMap.ts +++ b/src/types/tokens/DeepKeyTokenMap.ts @@ -1,5 +1,7 @@ import { SingleToken } from './SingleToken.js'; -export interface DeepKeyTokenMap { - [key: string]: DeepKeyTokenMap | SingleToken; -} +export interface _DeepKeyTokenMap { + [key: string]: _DeepKeyTokenMap | SingleToken; +} + +export type DeepKeyTokenMap = _DeepKeyTokenMap & { $type?: string }; \ No newline at end of file diff --git a/src/types/tokens/SingleGenericToken.ts b/src/types/tokens/SingleGenericToken.ts index 74b1071..1e3732a 100644 --- a/src/types/tokens/SingleGenericToken.ts +++ b/src/types/tokens/SingleGenericToken.ts @@ -1,16 +1,14 @@ import { TokenTypes } from '../../constants/TokenTypes.js'; import { ColorModifier } from '../Modifier.js'; -export type SingleGenericToken< - T extends TokenTypes, - V = string | number, - Named extends boolean = true, - P = unknown, -> = { - type: T; - value: V; +type _SingleGenericToken = { + type?: T; + $type?: T; + value?: V; + $value?: V; rawValue?: V; description?: string; + $description?: string; oldDescription?: string; oldValue?: V; internal__Parent?: string; @@ -24,3 +22,46 @@ export type SingleGenericToken< name?: string; }) & P; + +/** + * Utility to require one of two optional properties, + * e.g. $value OR value must exist, but not both. + * + * Explanation, we pass in '$value' | 'value': + * 1. R extends keyof T = keyof T -> means that what is passed in (R) must be/extend keys of first arg (T) + * + * 2. Omit means what we pass in (R) is omitted from T + * + * 3. 2nd part of the union simplifies to -> { [K in keyof Required]... }['$value'|'value'] + * + * 4. which then simplifies to -> { $value: ...; value: ...; }['$value'|'value'] + * + * 5. which then simplifies to -> { + * $value: Required<{ '$value'?: string }> & { 'value'?: undefined }; + * value: Required<{ 'value'?: string }> & { '$value'?: undefined }; + * }['$value'|'value'] + * + * 6. which then simplifies to -> { + * $value: { $value: string }; + * value: { value: string }; + * }['$value'|'value'] + * + * 6. and finally -> { $value: string } | { value: string } + * + */ +type RequireOnlyOne = + Omit & + { + [K in keyof Required]: Required> & Partial, undefined>>; + }[Keys]; + +/** + * `$type` and `type` as well as `$value` and `value`, but for each pair respectively, either + * the $prop or the without $ prop needs to be present. + */ +export type SingleGenericToken< + T extends TokenTypes, + V = string | number, + Named extends boolean = true, + P = unknown +> = RequireOnlyOne<_SingleGenericToken, '$value' | 'value'>; \ No newline at end of file