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
6 changes: 6 additions & 0 deletions .changeset/kind-colors-share.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
"@fluentui-react-native/design": patch
"@fluentui-react-native/theme-tokens": patch
---

Share high-contrast alias token processing across Windows platforms from the design package and expose it through the theme-tokens compatibility shim.
5 changes: 5 additions & 0 deletions .changeset/warm-themes-reuse.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@fluentui-react-native/win32-theme": patch
---

Reuse high-contrast alias tokens from `@fluentui-react-native/design/tokens/legacy`.
1 change: 1 addition & 0 deletions apps/bundle-size/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
"@rnx-kit/metro-config": "catalog:",
"@rnx-kit/metro-resolver-symlinks": "catalog:",
"@rnx-kit/metro-serializer-esbuild": "catalog:",
"@rnx-kit/tools-filesystem": "^0.2.0",
"metro": "^0.83.1",
"oxc-resolver": "catalog:"
},
Expand Down
19 changes: 9 additions & 10 deletions apps/bundle-size/scripts/measure.mjs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { readJSONFileSync, writeJSONFileSync } from '@rnx-kit/tools-filesystem';
import { spawnSync } from 'node:child_process';
import { existsSync, mkdirSync, readFileSync, statSync, writeFileSync } from 'node:fs';
import { mkdir } from 'node:fs/promises';
Expand All @@ -7,7 +8,7 @@ import { gzipSync } from 'node:zlib';

const workspaceRoot = dirname(dirname(fileURLToPath(import.meta.url)));
const repositoryRoot = dirname(dirname(workspaceRoot));
const yarnVersion = JSON.parse(readFileSync(join(repositoryRoot, 'package.json'), 'utf8')).packageManager.split('@')[1];
const yarnVersion = readJSONFileSync(join(repositoryRoot, 'package.json')).packageManager.split('@')[1];
const yarnPath = join(repositoryRoot, '.yarn', 'releases', `yarn-${yarnVersion}.cjs`);
const configPath = join(workspaceRoot, 'scenarios.json');
const defaultBaselinePath = join(workspaceRoot, 'baseline.json');
Expand Down Expand Up @@ -68,7 +69,7 @@ function getWorkspacePackage(source) {
while (directory.startsWith(packagesRoot)) {
const manifestPath = join(directory, 'package.json');
if (existsSync(manifestPath)) {
return JSON.parse(readFileSync(manifestPath, 'utf8')).name;
return readJSONFileSync(manifestPath).name;
}
directory = dirname(directory);
}
Expand Down Expand Up @@ -153,8 +154,8 @@ function runBundle(platform, scenario, resetCache) {
}

const bundle = readFileSync(bundlePath);
const sourceMap = JSON.parse(readFileSync(sourceMapPath, 'utf8'));
const metafile = JSON.parse(readFileSync(metafilePath, 'utf8'));
const sourceMap = readJSONFileSync(sourceMapPath);
const metafile = readJSONFileSync(metafilePath);
const contributions = getWorkspaceContributions(metafile);

return {
Expand Down Expand Up @@ -263,7 +264,7 @@ const {
if (updateBaseline && selectedPlatforms) {
throw new Error('Baseline updates must include every configured platform; omit --platform');
}
const selectedConfig = JSON.parse(readFileSync(selectedConfigPath, 'utf8'));
const selectedConfig = readJSONFileSync(selectedConfigPath);
const platforms = selectedPlatforms ?? selectedConfig.platforms;

await mkdir(entryRoot, { recursive: true });
Expand All @@ -284,12 +285,10 @@ const currentBaseline = {
results: measurements.map(baselineResult),
};
if (updateBaseline) {
writeFileSync(selectedBaselinePath, `${JSON.stringify(currentBaseline, null, 2)}\n`);
writeJSONFileSync(selectedBaselinePath, currentBaseline);
}

const baseline = existsSync(selectedBaselinePath)
? JSON.parse(readFileSync(selectedBaselinePath, 'utf8'))
: { schemaVersion: 1, results: [] };
const baseline = existsSync(selectedBaselinePath) ? readJSONFileSync(selectedBaselinePath) : { schemaVersion: 1, results: [] };
if (baseline.schemaVersion !== 1) {
throw new Error(`Unsupported baseline schema version: ${baseline.schemaVersion}`);
}
Expand All @@ -315,7 +314,7 @@ const report = {
};
const reportPath = join(outputRoot, 'results.json');
const markdownReportPath = join(outputRoot, 'report.md');
writeFileSync(reportPath, `${JSON.stringify(report, null, 2)}\n`);
writeJSONFileSync(reportPath, report);
writeFileSync(markdownReportPath, createMarkdownReport(results));

console.table(results);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import { processAliasTokens, transformWin32PlatformColorName, transformWindowsPlatformColorName } from '../processAliasTokens';

jest.mock('react-native', () => ({
PlatformColor: (color: string) => `PlatformColor('${color}')`,
}));

const createAliasTokens = () => ({
colors: {
buttonFace: 'PlatformColor(ButtonFace)',
},
});

it('maps Windows platform colors to SystemColor names', () => {
expect(processAliasTokens(createAliasTokens(), transformWindowsPlatformColorName)).toEqual({
colors: {
buttonFace: "PlatformColor('SystemColorButtonFaceColor')",
},
});
});

it('preserves raw Win32 platform color names', () => {
expect(processAliasTokens(createAliasTokens(), transformWin32PlatformColorName)).toEqual({
colors: {
buttonFace: "PlatformColor('ButtonFace')",
},
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import { PlatformColor } from 'react-native';

type AliasTokens = Record<string, Record<string, unknown>>;
type PlatformColorNameTransform = (color: string) => string;

export const transformWindowsPlatformColorName: PlatformColorNameTransform = (color) => `SystemColor${color}Color`;
export const transformWin32PlatformColorName: PlatformColorNameTransform = (color) => color;

export function processAliasTokens<T extends AliasTokens>(aliasTokens: T, transformColorName: PlatformColorNameTransform): T {
// The imported token JSON is intentionally mutated once when its module loads.
for (const key in aliasTokens) {
const tokenGroup: Record<string, unknown> = aliasTokens[key];
for (const innerKey in tokenGroup) {
const entry = tokenGroup[innerKey];
if (typeof entry === 'string' && entry.includes('PlatformColor')) {
const color = transformColorName(entry.substring(14, entry.length - 1));
// eslint-disable-next-line @react-native/platform-colors
tokenGroup[innerKey] = PlatformColor(color);
}
}
}

return aliasTokens;
}
Original file line number Diff line number Diff line change
@@ -1,20 +1,5 @@
import { PlatformColor } from 'react-native';

import aliasTokens from '@fluentui-react-native/design-tokens-win32/hc/tokens-aliases.json';

export const hcAliasTokens = processAliasTokens(aliasTokens);

function processAliasTokens(aliasTokens: any) {
for (const key in aliasTokens) {
for (const innerKey in aliasTokens[key]) {
const entry = aliasTokens[key][innerKey];
if (typeof entry === 'string' && entry.includes('PlatformColor')) {
const color = 'SystemColor' + entry.substring(14, entry.length - 1) + 'Color';
// eslint-disable-next-line @react-native/platform-colors
aliasTokens[key][innerKey] = PlatformColor(color);
}
}
}
import { processAliasTokens, transformWindowsPlatformColorName } from './processAliasTokens';

return aliasTokens;
}
export const hcAliasTokens = processAliasTokens(aliasTokens, transformWindowsPlatformColorName);
Original file line number Diff line number Diff line change
@@ -1,20 +1,5 @@
import { PlatformColor } from 'react-native';

import aliasTokens from '@fluentui-react-native/design-tokens-win32/hc/tokens-aliases.json';

export const hcAliasTokens = processAliasTokens(aliasTokens);

function processAliasTokens(aliasTokens: any) {
for (const key in aliasTokens) {
for (const innerKey in aliasTokens[key]) {
const entry = aliasTokens[key][innerKey];
if (typeof entry === 'string' && entry.includes('PlatformColor')) {
const color = entry.substring(14, entry.length - 1);
// eslint-disable-next-line @react-native/platform-colors
aliasTokens[key][innerKey] = PlatformColor(color);
}
}
}
import { processAliasTokens, transformWin32PlatformColorName } from './processAliasTokens';

return aliasTokens;
}
export const hcAliasTokens = processAliasTokens(aliasTokens, transformWin32PlatformColorName);
1 change: 1 addition & 0 deletions packages/agentic/design/src/tokens/legacy/index.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
export { default as globalTokens } from './tokens-global';
export { getAliasTokens, getShadowTokens } from './getTokens';
export { hcAliasTokens } from './highContrast/tokens-alias';
5 changes: 3 additions & 2 deletions packages/shim/theme-tokens/README.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
# Theme-tokens

> **Deprecated:** Import `globalTokens`, `getAliasTokens`, and `getShadowTokens`
> from `@fluentui-react-native/design/tokens/legacy` instead.
> **Deprecated:** Import `globalTokens`, `getAliasTokens`, `getShadowTokens`,
> and `hcAliasTokens` from `@fluentui-react-native/design/tokens/legacy`
> instead.

This package is a compatibility shim and will not receive new APIs. It preserves
the existing entry point while consumers migrate to the design package.
2 changes: 1 addition & 1 deletion packages/shim/theme-tokens/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// This package is a compatibility shim. Legacy Fluent token values now live in
// the `@fluentui-react-native/design/tokens/legacy` submodule. These explicit
// re-exports preserve the existing `@fluentui-react-native/theme-tokens` entry point.
export { getAliasTokens, getShadowTokens, globalTokens } from '@fluentui-react-native/design/tokens/legacy';
export { getAliasTokens, getShadowTokens, globalTokens, hcAliasTokens } from '@fluentui-react-native/design/tokens/legacy';
3 changes: 1 addition & 2 deletions packages/theming/win32-theme/src/getOfficeTokens.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,7 @@ import colorfulShadowTokens from '@fluentui-react-native/design-tokens-win32/col
import darkGrayAliasTokens from '@fluentui-react-native/design-tokens-win32/darkgray/tokens-aliases.json';
import darkGrayShadowTokens from '@fluentui-react-native/design-tokens-win32/darkgray/tokens-shadow.json';
import hcShadowTokens from '@fluentui-react-native/design-tokens-win32/hc/tokens-shadow.json';

import { hcAliasTokens } from './highContrast/tokens-alias';
import { hcAliasTokens } from '@fluentui-react-native/design/tokens/legacy';

export function getOfficeAliasTokens(officeTheme: string) {
if (officeTheme === 'White' || officeTheme === 'Colorful') {
Expand Down
20 changes: 0 additions & 20 deletions packages/theming/win32-theme/src/highContrast/tokens-alias.ts

This file was deleted.

1 change: 1 addition & 0 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -2652,6 +2652,7 @@ __metadata:
"@rnx-kit/metro-config": "catalog:"
"@rnx-kit/metro-resolver-symlinks": "catalog:"
"@rnx-kit/metro-serializer-esbuild": "catalog:"
"@rnx-kit/tools-filesystem": "npm:^0.2.0"
"@types/react": "npm:~19.1.4"
metro: "npm:^0.83.1"
oxc-resolver: "catalog:"
Expand Down
Loading