diff --git a/assets/web/css/cpd-common-base.css b/assets/web/css/cpd-common-base.css index 1223ecc7..0c62283d 100644 --- a/assets/web/css/cpd-common-base.css +++ b/assets/web/css/cpd-common-base.css @@ -43,9 +43,9 @@ --cpd-font-heading-lg-regular: var(--cpd-font-weight-regular) var(--cpd-font-size-heading-lg)/var(--cpd-font-line-height-tight) var(--cpd-font-family-sans); --cpd-font-heading-md-semibold: var(--cpd-font-weight-semibold) var(--cpd-font-size-heading-md)/var(--cpd-font-line-height-tight) var(--cpd-font-family-sans); --cpd-font-heading-md-regular: var(--cpd-font-weight-regular) var(--cpd-font-size-heading-md)/var(--cpd-font-line-height-tight) var(--cpd-font-family-sans); - --cpd-font-heading-sm-semibold: var(--cpd-font-weight-semibold) var(--cpd-font-line-height-tight)rem/1.25 var(--cpd-font-family-sans); - --cpd-font-heading-sm-medium: var(--cpd-font-weight-medium) var(--cpd-font-line-height-tight)rem/1.25 var(--cpd-font-family-sans); - --cpd-font-heading-sm-regular: var(--cpd-font-weight-regular) var(--cpd-font-line-height-tight)rem/1.25 var(--cpd-font-family-sans); + --cpd-font-heading-sm-semibold: var(--cpd-font-weight-semibold) var(--cpd-font-size-heading-sm)/var(--cpd-font-line-height-tight) var(--cpd-font-family-sans); + --cpd-font-heading-sm-medium: var(--cpd-font-weight-medium) var(--cpd-font-size-heading-sm)/var(--cpd-font-line-height-tight) var(--cpd-font-family-sans); + --cpd-font-heading-sm-regular: var(--cpd-font-weight-regular) var(--cpd-font-size-heading-sm)/var(--cpd-font-line-height-tight) var(--cpd-font-family-sans); --cpd-font-body-lg-semibold: var(--cpd-font-weight-semibold) var(--cpd-font-size-body-lg)/var(--cpd-font-line-height-regular) var(--cpd-font-family-sans); --cpd-font-body-lg-medium: var(--cpd-font-weight-medium) var(--cpd-font-size-body-lg)/var(--cpd-font-line-height-regular) var(--cpd-font-family-sans); --cpd-font-body-lg-regular: var(--cpd-font-weight-regular) var(--cpd-font-size-body-lg)/var(--cpd-font-line-height-regular) var(--cpd-font-family-sans); diff --git a/build.ts b/build.ts index 07ed9696..f862cd69 100644 --- a/build.ts +++ b/build.ts @@ -18,19 +18,20 @@ import type { Platform, Theme } from "./src/@types/index"; import * as setupStyleDictionary from "./src/setupStyleDictionary"; import { generateCssIndex } from "./src/utils/generateCssIndex"; import generateIconTokens from "./src/utils/generateIconTokens"; +import { normalizeTokens } from "./src/utils/normalizeTokens"; const themes: Theme[] = ["light", "light-hc", "dark", "dark-hc"]; const platforms: Platform[] = ["web", "android", "ios"]; -(async () => { - generateIconTokens(); - generateCssIndex(); - for (const platform of platforms) { - for (const theme of themes) { - const sb = await setupStyleDictionary.themed(theme, platform); - sb.buildAllPlatforms(); - } - const sb = await setupStyleDictionary.common(platform); +await normalizeTokens(); +generateIconTokens(); +generateCssIndex(); + +for (const platform of platforms) { + for (const theme of themes) { + const sb = await setupStyleDictionary.themed(theme, platform); sb.buildAllPlatforms(); } -})(); + const sb = await setupStyleDictionary.common(platform); + sb.buildAllPlatforms(); +} diff --git a/src/utils/normalizeTokens.ts b/src/utils/normalizeTokens.ts new file mode 100644 index 00000000..3b3882ff --- /dev/null +++ b/src/utils/normalizeTokens.ts @@ -0,0 +1,67 @@ +/* +Copyright 2024 New Vector Ltd. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +import { readFile, writeFile } from "node:fs/promises"; + +interface Typography { + fontWeight: unknown; + fontSize: unknown; + lineHeight: unknown; + fontFamily: unknown; + letterSpacing: unknown; +} + +function normalizeTypography({ + fontWeight, + fontSize, + lineHeight, + fontFamily, + letterSpacing, +}: Typography): Typography { + // Put the properties in the same order as they appear in CSS font shorthands + return { fontWeight, fontSize, lineHeight, fontFamily, letterSpacing }; +} + +function normalize(data: unknown): unknown { + if (typeof data === "object" && data !== null) { + if ("type" in data && "value" in data) + return data.type === "typography" + ? { ...data, value: normalizeTypography(data.value as Typography) } + : data; + + return Object.fromEntries( + Object.entries(data).map(([k, v]) => [k, normalize(v)]), + ); + } + + return data; +} + +// Due to a deficiency of Style Dictionary when recovering variable references +// from properties that were flattened from an object into a string, we must +// normalize some tokens to ensure that their properties appear in the same +// order in the input as they do in the output. +// https://github.com/amzn/style-dictionary/blob/4575dd5a9cc226ebb378f23ce5f1f2d22e2e108a/lib/common/formatHelpers/createPropertyFormatter.js#L201 +export async function normalizeTokens(): Promise { + const webTokens: object = JSON.parse( + await readFile("tokens/platform-web.json", { encoding: "utf8" }), + ); + const normalized = normalize(webTokens); + await writeFile( + "tokens/platform-web.json", + JSON.stringify(normalized, undefined, 2), + ); +} diff --git a/tokens/platform-web.json b/tokens/platform-web.json index 36ccc977..21d8226e 100644 --- a/tokens/platform-web.json +++ b/tokens/platform-web.json @@ -123,30 +123,30 @@ "xs": { "regular": { "value": { - "fontFamily": "{font.family.sans}", "fontWeight": "{font.weight.regular}", - "lineHeight": "{font.line-height.regular}", "fontSize": "{font.size.body.xs}", + "lineHeight": "{font.line-height.regular}", + "fontFamily": "{font.family.sans}", "letterSpacing": "{font.letter-spacing.body.xs}" }, "type": "typography" }, "medium": { "value": { - "fontFamily": "{font.family.sans}", "fontWeight": "{font.weight.medium}", - "lineHeight": "{font.line-height.regular}", "fontSize": "{font.size.body.xs}", + "lineHeight": "{font.line-height.regular}", + "fontFamily": "{font.family.sans}", "letterSpacing": "{font.letter-spacing.body.xs}" }, "type": "typography" }, "semibold": { "value": { - "fontFamily": "{font.family.sans}", "fontWeight": "{font.weight.semibold}", - "lineHeight": "{font.line-height.regular}", "fontSize": "{font.size.body.xs}", + "lineHeight": "{font.line-height.regular}", + "fontFamily": "{font.family.sans}", "letterSpacing": "{font.letter-spacing.body.xs}" }, "type": "typography" @@ -155,30 +155,30 @@ "sm": { "regular": { "value": { - "fontFamily": "{font.family.sans}", "fontWeight": "{font.weight.regular}", - "lineHeight": "{font.line-height.regular}", "fontSize": "{font.size.body.sm}", + "lineHeight": "{font.line-height.regular}", + "fontFamily": "{font.family.sans}", "letterSpacing": "{font.letter-spacing.body.sm}" }, "type": "typography" }, "medium": { "value": { - "fontFamily": "{font.family.sans}", "fontWeight": "{font.weight.medium}", - "lineHeight": "{font.line-height.regular}", "fontSize": "{font.size.body.sm}", + "lineHeight": "{font.line-height.regular}", + "fontFamily": "{font.family.sans}", "letterSpacing": "{font.letter-spacing.body.sm}" }, "type": "typography" }, "semibold": { "value": { - "fontFamily": "{font.family.sans}", "fontWeight": "{font.weight.semibold}", - "lineHeight": "{font.line-height.regular}", "fontSize": "{font.size.body.sm}", + "lineHeight": "{font.line-height.regular}", + "fontFamily": "{font.family.sans}", "letterSpacing": "{font.letter-spacing.body.sm}" }, "type": "typography" @@ -187,30 +187,30 @@ "md": { "regular": { "value": { - "fontFamily": "{font.family.sans}", "fontWeight": "{font.weight.regular}", - "lineHeight": "{font.line-height.regular}", "fontSize": "{font.size.body.md}", + "lineHeight": "{font.line-height.regular}", + "fontFamily": "{font.family.sans}", "letterSpacing": "{font.letter-spacing.body.md}" }, "type": "typography" }, "medium": { "value": { - "fontFamily": "{font.family.sans}", "fontWeight": "{font.weight.medium}", - "lineHeight": "{font.line-height.regular}", "fontSize": "{font.size.body.md}", + "lineHeight": "{font.line-height.regular}", + "fontFamily": "{font.family.sans}", "letterSpacing": "{font.letter-spacing.body.md}" }, "type": "typography" }, "semibold": { "value": { - "fontFamily": "{font.family.sans}", "fontWeight": "{font.weight.semibold}", - "lineHeight": "{font.line-height.regular}", "fontSize": "{font.size.body.md}", + "lineHeight": "{font.line-height.regular}", + "fontFamily": "{font.family.sans}", "letterSpacing": "{font.letter-spacing.body.md}" }, "type": "typography" @@ -219,30 +219,30 @@ "lg": { "regular": { "value": { - "fontFamily": "{font.family.sans}", "fontWeight": "{font.weight.regular}", - "lineHeight": "{font.line-height.regular}", "fontSize": "{font.size.body.lg}", + "lineHeight": "{font.line-height.regular}", + "fontFamily": "{font.family.sans}", "letterSpacing": "{font.letter-spacing.body.lg}" }, "type": "typography" }, "medium": { "value": { - "fontFamily": "{font.family.sans}", "fontWeight": "{font.weight.medium}", - "lineHeight": "{font.line-height.regular}", "fontSize": "{font.size.body.lg}", + "lineHeight": "{font.line-height.regular}", + "fontFamily": "{font.family.sans}", "letterSpacing": "{font.letter-spacing.body.lg}" }, "type": "typography" }, "semibold": { "value": { - "fontFamily": "{font.family.sans}", "fontWeight": "{font.weight.semibold}", - "lineHeight": "{font.line-height.regular}", "fontSize": "{font.size.body.lg}", + "lineHeight": "{font.line-height.regular}", + "fontFamily": "{font.family.sans}", "letterSpacing": "{font.letter-spacing.body.lg}" }, "type": "typography" @@ -253,30 +253,30 @@ "sm": { "regular": { "value": { - "fontFamily": "{font.family.sans}", "fontWeight": "{font.weight.regular}", - "lineHeight": "{font.line-height.tight}", "fontSize": "{font.size.heading.sm}", + "lineHeight": "{font.line-height.tight}", + "fontFamily": "{font.family.sans}", "letterSpacing": "{font.letter-spacing.heading.sm}" }, "type": "typography" }, "medium": { "value": { - "fontFamily": "{font.family.sans}", "fontWeight": "{font.weight.medium}", - "lineHeight": "{font.line-height.tight}", "fontSize": "{font.size.heading.sm}", + "lineHeight": "{font.line-height.tight}", + "fontFamily": "{font.family.sans}", "letterSpacing": "{font.letter-spacing.heading.sm}" }, "type": "typography" }, "semibold": { "value": { - "fontFamily": "{font.family.sans}", "fontWeight": "{font.weight.semibold}", - "lineHeight": "{font.line-height.tight}", "fontSize": "{font.size.heading.sm}", + "lineHeight": "{font.line-height.tight}", + "fontFamily": "{font.family.sans}", "letterSpacing": "{font.letter-spacing.heading.sm}" }, "type": "typography" @@ -285,20 +285,20 @@ "md": { "regular": { "value": { - "fontFamily": "{font.family.sans}", "fontWeight": "{font.weight.regular}", - "lineHeight": "{font.line-height.tight}", "fontSize": "{font.size.heading.md}", + "lineHeight": "{font.line-height.tight}", + "fontFamily": "{font.family.sans}", "letterSpacing": "{font.letter-spacing.heading.md}" }, "type": "typography" }, "semibold": { "value": { - "fontFamily": "{font.family.sans}", "fontWeight": "{font.weight.semibold}", - "lineHeight": "{font.line-height.tight}", "fontSize": "{font.size.heading.md}", + "lineHeight": "{font.line-height.tight}", + "fontFamily": "{font.family.sans}", "letterSpacing": "{font.letter-spacing.heading.md}" }, "type": "typography" @@ -307,20 +307,20 @@ "lg": { "regular": { "value": { - "fontFamily": "{font.family.sans}", "fontWeight": "{font.weight.regular}", - "lineHeight": "{font.line-height.tight}", "fontSize": "{font.size.heading.lg}", + "lineHeight": "{font.line-height.tight}", + "fontFamily": "{font.family.sans}", "letterSpacing": "{font.letter-spacing.heading.lg}" }, "type": "typography" }, "semibold": { "value": { - "fontFamily": "{font.family.sans}", "fontWeight": "{font.weight.semibold}", - "lineHeight": "{font.line-height.tight}", "fontSize": "{font.size.heading.lg}", + "lineHeight": "{font.line-height.tight}", + "fontFamily": "{font.family.sans}", "letterSpacing": "{font.letter-spacing.heading.lg}" }, "type": "typography" @@ -329,20 +329,20 @@ "xl": { "regular": { "value": { - "fontFamily": "{font.family.sans}", "fontWeight": "{font.weight.regular}", - "lineHeight": "{font.line-height.tight}", "fontSize": "{font.size.heading.xl}", + "lineHeight": "{font.line-height.tight}", + "fontFamily": "{font.family.sans}", "letterSpacing": "{font.letter-spacing.heading.xl}" }, "type": "typography" }, "semibold": { "value": { - "fontFamily": "{font.family.sans}", "fontWeight": "{font.weight.semibold}", - "lineHeight": "{font.line-height.tight}", "fontSize": "{font.size.heading.xl}", + "lineHeight": "{font.line-height.tight}", + "fontFamily": "{font.family.sans}", "letterSpacing": "{font.letter-spacing.heading.xl}" }, "type": "typography"