Skip to content

Commit de1b0b3

Browse files
authored
Color semantic tokens. Solutions banner. (#37)
1 parent f9f7b6f commit de1b0b3

35 files changed

+295
-257
lines changed

app/screens/GameDetailsScreen.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import { useSafeAreaInsets } from 'react-native-safe-area-context'
55
import { colors, sizes } from '../../shared/theme'
66
import { Text } from '../components/Text'
77

8-
export const GamesListScreen = () => {
8+
export const GameDetailsScreen = () => {
99
const { bottom: paddingBottom, top: paddingTop } = useSafeAreaInsets()
1010

1111
return (
@@ -21,7 +21,7 @@ export const GamesListScreen = () => {
2121

2222
const $screen: ViewStyle = {
2323
flex: 1,
24-
backgroundColor: colors.tokens.backgroundSurface100,
24+
backgroundColor: colors.background.primary,
2525
paddingHorizontal: sizes.spacing.md,
2626
justifyContent: 'space-between',
2727
}

app/screens/GamesListScreen.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ export const GamesListScreen = () => {
2121

2222
const $screen: ViewStyle = {
2323
flex: 1,
24-
backgroundColor: colors.tokens.backgroundSurface100,
24+
backgroundColor: colors.background.primary,
2525
paddingHorizontal: sizes.spacing.md,
2626
justifyContent: 'space-between',
2727
}

app/screens/ReviewScreen.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import { useSafeAreaInsets } from 'react-native-safe-area-context'
55
import { colors, sizes } from '../../shared/theme'
66
import { Text } from '../components/Text'
77

8-
export const GamesListScreen = () => {
8+
export const ReviewScreen = () => {
99
const { bottom: paddingBottom, top: paddingTop } = useSafeAreaInsets()
1010

1111
return (
@@ -21,7 +21,7 @@ export const GamesListScreen = () => {
2121

2222
const $screen: ViewStyle = {
2323
flex: 1,
24-
backgroundColor: colors.tokens.backgroundSurface100,
24+
backgroundColor: colors.background.primary,
2525
paddingHorizontal: sizes.spacing.md,
2626
justifyContent: 'space-between',
2727
}

index.js

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,13 @@ import { name as appName } from './app.json'
1111
import AppAssignment from './app/App'
1212
import { setupMockServer } from './msw'
1313
import { customFontsToLoad } from './shared/theme'
14-
import { setupAppModeSelector } from './shared/utils/trainingHelper'
14+
import {
15+
setupTrainingAppModeSelector,
16+
TrainingBanners,
17+
} from './shared/utils/trainingHelper'
1518
import AppChapter7 from './solutions/chapter7/App'
1619

17-
const activeAppMode = setupAppModeSelector()
20+
const activeAppMode = setupTrainingAppModeSelector()
1821

1922
setupMockServer()
2023

@@ -48,7 +51,11 @@ function App() {
4851

4952
if (!areFontsLoaded) return null
5053

51-
return <AppMode />
54+
return (
55+
<TrainingBanners appMode={activeAppMode}>
56+
<AppMode />
57+
</TrainingBanners>
58+
)
5259
}
5360

5461
AppRegistry.registerComponent(appName, () => App)

package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,10 @@
55
"scripts": {
66
"android": "react-native run-android",
77
"clean": "./scripts/clean",
8-
"generate:theme": "style-dictionary build --config ./sd.config.js",
8+
"generate:tokens": "style-dictionary build --config ./sd.config.js",
99
"postinstall": "./scripts/postinstall",
1010
"ios": "react-native run-ios",
11-
"lint": "./scripts/lint-format",
11+
"lint": "./scripts/tsc-lint-format",
1212
"setup": "./scripts/setup/index",
1313
"start": "react-native start",
1414
"test": "jest"
Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
11
#!/usr/bin/env bash
22
set -e
33

4+
# Runs tsc.
5+
tsc ./index.js --skipLibCheck --noEmit --jsx react-native --esModuleInterop --allowJs --resolveJsonModule
6+
47
# Runs eslint (and eslint prettier plugin) for the specified extensions.
58
eslint . --fix --ext .js,.ts,.tsx,.cjs,.mjs --cache
69

710
# Additionally format files outside of eslint's scope.
8-
prettier --write "**/*.{json,md,yml,yaml}" .eslintrc.js --cache
9-
11+
prettier --write "**/*.{json,md,yml,yaml}" .eslintrc.js --cache

sd.config.js

Lines changed: 65 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -53,94 +53,93 @@ const figmaVariablesCollections = Object.entries(figmaVariables).map(
5353

5454
const designTokens = deepmerge.all(Object.values(figmaVariablesCollections))
5555

56-
function isPrimitiveToken(token) {
57-
return (
58-
token.original.extensions.ReactNativeEssentials.collectionName ===
59-
'primitives'
60-
)
61-
}
62-
6356
function isSemanticToken(token) {
6457
return (
6558
token.original.extensions.ReactNativeEssentials.collectionName ===
6659
'semantics'
6760
)
6861
}
6962

70-
function isFunctionalToken(token) {
71-
return (
72-
token.original.extensions.ReactNativeEssentials.collectionName === 'tokens'
73-
)
63+
/**
64+
* Generates a file configuration object for design tokens.
65+
*
66+
* @param {Object} params - The parameters for file configuration.
67+
* @param {'color' | 'size'} params.category - The category of the token.
68+
* @param {'background' | 'border' | 'text' | 'tint' | 'spacing' | 'radius'} params.type - The type of the token.
69+
* @param {function} params.tokenPredicateFn - A function that takes a token and returns a boolean indicating whether the token should be included.
70+
* @param {string} params.fileName - The name of the file to which the tokens will be written.
71+
* @returns {Object} An object containing the format, destination, and filter function for the design tokens.
72+
*/
73+
function createFileConfig({ category, type, tokenPredicateFn, fileName }) {
74+
return {
75+
format: 'javascript/es6',
76+
destination: fileName,
77+
filter: token =>
78+
(category ? token.attributes.category === category : true) &&
79+
(type ? token.attributes.type === type : true) &&
80+
(tokenPredicateFn ? tokenPredicateFn(token) : true),
81+
}
7482
}
7583

7684
module.exports = {
7785
tokens: designTokens,
7886
platforms: {
79-
'color: primitives & tokens': {
87+
'color: semantics': {
8088
transforms: ['attribute/cti', 'name/ti/camel/strip', 'color/hex8'],
8189
buildPath: './shared/theme/tokens/',
82-
options: { stripFromPath: ['color'] },
83-
files: [
84-
{
85-
format: 'javascript/es6',
86-
destination: 'colorPrimitives.ts',
87-
filter: token => token.type === 'color' && isPrimitiveToken(token),
88-
},
89-
{
90-
format: 'javascript/es6',
91-
destination: 'colorTokens.ts',
92-
filter: token => token.type === 'color' && isFunctionalToken(token),
93-
},
94-
],
95-
},
96-
'size: primitives & tokens': {
97-
transforms: ['attribute/cti', 'name/ti/camel/strip'],
98-
buildPath: './shared/theme/tokens/',
99-
options: { stripFromPath: ['size'] },
90+
options: {
91+
stripFromPath: ['color', 'background', 'tint', 'text', 'border'],
92+
},
10093
files: [
101-
{
102-
format: 'javascript/es6',
103-
destination: 'sizePrimitives.ts',
104-
filter: token =>
105-
token.type === 'dimension' && isPrimitiveToken(token),
106-
},
107-
{
108-
format: 'javascript/es6',
109-
destination: 'sizeTokens.ts',
110-
filter: token =>
111-
token.type === 'dimension' && isFunctionalToken(token),
112-
},
94+
createFileConfig({
95+
category: 'color',
96+
type: 'background',
97+
tokenPredicateFn: isSemanticToken,
98+
fileName: 'colorBackgroundSemantics.ts',
99+
}),
100+
createFileConfig({
101+
category: 'color',
102+
type: 'tint',
103+
tokenPredicateFn: isSemanticToken,
104+
fileName: 'colorTintSemantics.ts',
105+
}),
106+
createFileConfig({
107+
category: 'color',
108+
type: 'text',
109+
tokenPredicateFn: isSemanticToken,
110+
fileName: 'colorTextSemantics.ts',
111+
}),
112+
createFileConfig({
113+
category: 'color',
114+
type: 'border',
115+
tokenPredicateFn: isSemanticToken,
116+
fileName: 'colorBorderSemantics.ts',
117+
}),
113118
],
114119
},
115120
'size: semantics': {
116121
transforms: ['attribute/cti', 'name/ti/camel/strip'],
117122
buildPath: './shared/theme/tokens/',
118123
options: { stripFromPath: ['size', 'spacing', 'radius', 'border'] },
119124
files: [
120-
{
121-
format: 'javascript/es6',
122-
destination: 'sizeSpacingSemantics.ts',
123-
filter: token =>
124-
token.type === 'dimension' &&
125-
token.path.includes('spacing') &&
126-
isSemanticToken(token),
127-
},
128-
{
129-
format: 'javascript/es6',
130-
destination: 'sizeRadiusSemantics.ts',
131-
filter: token =>
132-
token.type === 'dimension' &&
133-
token.path.includes('radius') &&
134-
isSemanticToken(token),
135-
},
136-
{
137-
format: 'javascript/es6',
138-
destination: 'sizeBorderSemantics.ts',
139-
filter: token =>
140-
token.type === 'dimension' &&
141-
token.path.includes('border') &&
142-
isSemanticToken(token),
143-
},
125+
createFileConfig({
126+
category: 'size',
127+
type: 'spacing',
128+
tokenPredicateFn: isSemanticToken,
129+
fileName: 'sizeSpacingSemantics.ts',
130+
}),
131+
createFileConfig({
132+
category: 'size',
133+
type: 'radius',
134+
tokenPredicateFn: isSemanticToken,
135+
fileName: 'sizeRadiusSemantics.ts',
136+
}),
137+
createFileConfig({
138+
category: 'size',
139+
type: 'border',
140+
tokenPredicateFn: isSemanticToken,
141+
fileName: 'sizeBorderSemantics.ts',
142+
}),
144143
],
145144
},
146145
},

shared/theme/index.ts

Lines changed: 23 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,37 @@
1-
import * as colorPrimitives from './tokens/colorPrimitives'
2-
import * as colorTokens from './tokens/colorTokens'
1+
import * as colorBackgroundSemantics from './tokens/colorBackgroundSemantics'
2+
import * as colorBorderSemantics from './tokens/colorBorderSemantics'
3+
import * as colorTextSemantics from './tokens/colorTextSemantics'
4+
import * as colorTintSemantics from './tokens/colorTintSemantics'
35
import * as sizeBorderSemantics from './tokens/sizeBorderSemantics'
4-
import * as sizePrimitives from './tokens/sizePrimitives'
56
import * as sizeRadiusSemantics from './tokens/sizeRadiusSemantics'
67
import * as sizeSpacingSemantics from './tokens/sizeSpacingSemantics'
7-
import * as sizeTokens from './tokens/sizeTokens'
8+
9+
// prettier-ignore
10+
const hexAlphaSuffixes = ['00', '03', '05', '08', '0A', '0D', '0F', '12', '14', '17', '1A', '1C', '1F', '21', '24', '26', '29', '2B', '2E', '30', '33', '36', '38', '3B', '3D', '40', '42', '45', '47', '4A', '4D', '4F', '52', '54', '57', '59', '5C', '5E', '61', '63', '66', '69', '6B', '6E', '70', '73', '75', '78', '7A', '7D', '80', '82', '85', '87', '8A', '8C', '8F', '91', '94', '96', '99', '9C', '9E', 'A1', 'A3', 'A6', 'A8', 'AB', 'AD', 'B0', 'B3', 'B5', 'B8', 'BA', 'BD', 'BF', 'C2', 'C4', 'C7', 'C9', 'CC', 'CF', 'D1', 'D4', 'D6', 'D9', 'DB', 'DE', 'E0', 'E3', 'E6', 'E8', 'EB', 'ED', 'F0', 'F2', 'F5', 'F7', 'FA', 'FC', 'FF'] as const
11+
12+
export function changeHexAlpha(hexColor: string, opacityPercentage: number) {
13+
if (!/^#(?:[a-f\d]{6}(?:[a-f\d]{2})?)$/i.test(hexColor)) return hexColor
14+
15+
const suffix =
16+
hexAlphaSuffixes[Math.min(Math.max(Math.round(opacityPercentage), 0), 100)]
17+
18+
if (hexColor.length === 7) return `${hexColor}${suffix}`
19+
20+
return `${hexColor.slice(0, 7)}${suffix}`
21+
}
822

923
const colors = {
10-
primitives: colorPrimitives,
11-
tokens: colorTokens,
24+
background: colorBackgroundSemantics,
25+
text: colorTextSemantics,
26+
tint: colorTintSemantics,
27+
border: colorBorderSemantics,
28+
manipulators: { changeHexAlpha },
1229
}
1330

1431
const sizes = {
15-
primitives: sizePrimitives,
1632
radius: sizeRadiusSemantics,
1733
border: sizeBorderSemantics,
1834
spacing: sizeSpacingSemantics,
19-
tokens: sizeTokens,
2035
}
2136

2237
export { colors, sizes }
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
/**
2+
* Do not edit directly
3+
* Generated on Fri, 12 Jan 2024 04:20:14 GMT
4+
*/
5+
6+
export const primary = '#ffffffff'
7+
export const secondary = '#e6e6e6ff'
8+
export const accent = '#490448ff'
9+
export const accentMuted = '#ae84aeff'
10+
export const brand = '#dbff00ff'
11+
export const reflection = '#000000ff'
12+
export const transparent = '#ffffff00'
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
/**
2+
* Do not edit directly
3+
* Generated on Fri, 12 Jan 2024 04:20:14 GMT
4+
*/
5+
6+
export const base = '#000000ff'
7+
export const accent = '#490448ff'
8+
export const transparent = '#ffffff00'

0 commit comments

Comments
 (0)