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
2 changes: 1 addition & 1 deletion src/browser/tsconfig.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"compilerOptions": {
"lib": ["es5", "es2015.collection", "dom"],
"lib": ["es2017", "dom"],
"types": [],
"module": "esnext",
"moduleResolution": "node",
Expand Down
5 changes: 5 additions & 0 deletions src/build/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,4 +13,9 @@ export {
Value,
resolveTheme,
resolveThemeWithPaths,
ReferenceTokens,
ColorReferenceTokens,
ColorPaletteInput,
ColorPaletteDefinition,
PaletteStep,
} from '../shared/theme';
23 changes: 23 additions & 0 deletions src/shared/theme/__tests__/builder.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,3 +55,26 @@ test('theme adds context', () => {
},
});
});

test('theme adds reference tokens', () => {
builder.addReferenceTokens({
color: {
neutral: { 900: '#242E3C' },
warning: { 400: '#ff9900' },
},
});

const theme = builder.build();

expect(theme.referenceTokens).toMatchObject({
color: {
neutral: { 900: '#242E3C' },
warning: { 400: '#ff9900' },
},
});

expect(theme.tokens).toMatchObject({
colorNeutral900: '#242E3C',
colorWarning400: '#ff9900',
});
});
64 changes: 63 additions & 1 deletion src/shared/theme/builder.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,15 @@
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
import { Theme, Context, Mode } from './interfaces';
import {
Theme,
Context,
Mode,
ReferenceTokens,
ColorReferenceTokens,
ColorPaletteInput,
PaletteStep,
ColorPaletteDefinition,
} from './interfaces';

export type TokenCategory<T extends string, V> = Record<T, V>;

Expand Down Expand Up @@ -46,7 +55,60 @@ export class ThemeBuilder {
return this;
}

addReferenceTokens(referenceTokens: ReferenceTokens): ThemeBuilder {
this.theme.referenceTokens = referenceTokens;

// Process reference tokens and add generated tokens to theme
if (referenceTokens.color) {
const generatedTokens = this.processReferenceTokens(referenceTokens.color);
this.theme.tokens = { ...this.theme.tokens, ...generatedTokens };
}

return this;
}

build(): Theme {
return this.theme;
}

private processReferenceTokens(colorTokens: ColorReferenceTokens): TokenCategory<string, string> {
const generatedTokens: TokenCategory<string, string> = {};

Object.entries(colorTokens).forEach(([colorName, paletteInput]) => {
const palette = this.processColorPaletteInput(paletteInput);

// Add generated palette tokens with naming convention: colorPrimary50, colorPrimary600, etc.
Object.entries(palette).forEach(([step, value]) => {
const tokenName = `color${this.capitalize(colorName)}${step}`;
generatedTokens[tokenName] = value;
});
});

return generatedTokens;
}

// Right now just validates steps, but will also handle seed token color generation in a future PR
private processColorPaletteInput(input: ColorPaletteInput): ColorPaletteDefinition {
const validSteps: number[] = [];
// Add steps 50-1000 in increments of 50
for (let i = 50; i <= 1000; i += 50) {
validSteps.push(i);
}

const result: ColorPaletteDefinition = {};

// Add explicit step values
Object.entries(input).forEach(([step, value]) => {
const numStep = Number(step);
if (value && validSteps.includes(numStep)) {
result[numStep as PaletteStep] = value;
}
});

return result;
}

private capitalize(str: string): string {
return str.charAt(0).toUpperCase() + str.slice(1);
}
}
5 changes: 5 additions & 0 deletions src/shared/theme/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,11 @@ export {
GlobalValue,
ModeValue,
TypedModeValueOverride,
ReferenceTokens,
ColorReferenceTokens,
ColorPaletteInput,
ColorPaletteDefinition,
PaletteStep,
} from './interfaces';
export { ThemeBuilder, TokenCategory } from './builder';
export {
Expand Down
54 changes: 54 additions & 0 deletions src/shared/theme/interfaces.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,62 @@ export interface Theme {
modes: Record<string, Mode>;
tokenModeMap: Record<string, string>;
contexts: Record<string, Context>;
referenceTokens?: ReferenceTokens;
}

/**
* Reference tokens enable seed-based palette generation and semantic token organization.
*/
export interface ReferenceTokens {
color?: ColorReferenceTokens;
}

export interface ColorReferenceTokens {
primary?: ColorPaletteInput;
neutral?: ColorPaletteInput;
error?: ColorPaletteInput;
success?: ColorPaletteInput;
warning?: ColorPaletteInput;
info?: ColorPaletteInput;
}

/**
* Color reference tokens organized by semantic color categories.
* Each category is defined as a palette definition with explicit color values.
*/
export type ColorPaletteInput = ColorPaletteDefinition;

/**
* Palette steps available across all color types. Different color categories
* may use different subsets of these steps.
*/
export type PaletteStep =
| 50
| 100
| 150
| 200
| 250
| 300
| 350
| 400
| 450
| 500
| 550
| 600
| 650
| 700
| 750
| 800
| 850
| 900
| 950
| 1000;

/**
* Color palette definition with explicit color values for palette steps.
*/
export type ColorPaletteDefinition = Partial<Record<PaletteStep, string>>;

type Tokens = Partial<Record<string, GlobalValue | TypedModeValueOverride>>;

export interface Override {
Expand Down
Loading