Skip to content

Commit

Permalink
feat: support typography
Browse files Browse the repository at this point in the history
  • Loading branch information
mym0404 committed Mar 19, 2024
1 parent 053b9b6 commit 27a9475
Show file tree
Hide file tree
Showing 40 changed files with 5,437 additions and 222 deletions.
21 changes: 2 additions & 19 deletions bin/ret.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,26 +3,9 @@
import type { ColorsValue, RadiiValue, SizesValue, SpaceValue } from './Token';

export interface ThemedTypings {





colors: ColorsValue | "white" | "black" | "transparent" | "gray50" | "gray100" | "gray200" | "gray300" | "gray400" | "gray500" | "gray600" | "gray700" | "gray800" | "gray900" | "violet50" | "violet100" | "violet200" | "violet300" | "violet400" | "violet500" | "violet600" | "violet700" | "violet800" | "violet900" | "green50" | "green100" | "green200" | "green300" | "green400" | "green500" | "green600" | "yellow50" | "yellow100" | "yellow200" | "yellow300" | "yellow400" | "yellow500" | "yellow600" | "red50" | "red100" | "red200" | "red300" | "red400" | "red500" | "red600" | "blue50" | "blue100" | "blue200" | "blue300" | "blue400" | "blue500" | "blue600" | "blue700" | "blue800" | "blue900"







colors: ColorsValue | "white" | "black" | "transparent" | "gray50" | "gray100" | "gray200" | "gray300" | "gray400" | "gray500" | "gray600" | "gray700" | "gray800" | "gray900" | "violet50" | "violet100" | "violet200" | "violet300" | "violet400" | "violet500" | "violet600" | "violet700" | "violet800" | "violet900" | "green50" | "green100" | "green200" | "green300" | "green400" | "green500" | "green600" | "yellow50" | "yellow100" | "yellow200" | "yellow300" | "yellow400" | "yellow500" | "yellow600" | "red50" | "red100" | "red200" | "red300" | "red400" | "red500" | "red600" | "blue50" | "blue100" | "blue200" | "blue300" | "blue400" | "blue500" | "blue600" | "blue700" | "blue800" | "blue900"
radii: RadiiValue | `${number}` | `${number}px` | `${any}px` | "1" | "2" | "sm" | "md"

sizes: SizesValue | `${number}` | `${number}px` | `${any}px` | "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9" | "10" | "12" | "14" | "16" | "18" | "20" | "24" | "28" | "30" | "32" | "40" | "48" | "px" | "0.5"
space: SpaceValue | `${number}` | `${number}px` | `${any}px` | "0" | "-0" | "1" | "-1" | "2" | "-2" | "3" | "-3" | "4" | "-4" | "5" | "-5" | "6" | "-6" | "7" | "-7" | "8" | "-8" | "9" | "-9" | "10" | "-10" | "12" | "-12" | "14" | "-14" | "16" | "-16" | "18" | "-18" | "20" | "-20" | "24" | "-24" | "28" | "-28" | "30" | "-30" | "32" | "-32" | "40" | "-40" | "48" | "-48" | "px" | "-px" | "0.5" | "-0.5"





typography: "h1"
}
28 changes: 4 additions & 24 deletions bin/theme-gen.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import fs from 'fs-extra';
const join = path.join;
const filename = path.basename(__filename);
const _printTag = 'Theme Gen' || filename;
$.verbose = false;
// $.verbose = false;

function exist(path) {
return fs.existsSync(path);
Expand Down Expand Up @@ -137,7 +137,7 @@ const outputFile =
'./node_modules/react-native-themed-styled-system/lib/typescript/@types/ThemedTypings.d.ts';

try {
await $`npx @chakra-ui/cli tokens --no-format --out ${tmpFile} ${source}`;
await $`yarn cli generate --out ${tmpFile} ${source}`;

/**
* export interface ThemedTypings {
Expand All @@ -151,23 +151,6 @@ try {
);
result = result.replace(/export.*/, 'export interface ThemedTypings {');
result = result.replace(/\/\/.*/g, '');
result = result.replace(/blur.*/, '');
result = result.replace(/borders.*/, '');
result = result.replace(/borderStyles.*/, '');
result = result.replace(/borderWidths.*/, '');
result = result.replace(/breakpoints.*/, '');
result = result.replace(/colorSchemes.*/, '');
result = result.replace(/fonts.*/, '');
result = result.replace(/fontSizes.*/, '');
result = result.replace(/fontWeights.*/, '');
result = result.replace(/layerStyles.*/, '');
result = result.replace(/letterSpacings.*/, '');
result = result.replace(/lineHeights.*/, '');
result = result.replace(/shadows.*/, '');
result = result.replace(/textStyles.*/, '');
result = result.replace(/transition.*/, '');
result = result.replace(/zIndices.*/, '');
result = result.replace(/components.*\n.*\n.*/, '');
result = result.replace(/\|? ?\(?string & {}\)?;/g, '');
result = result.replaceAll('string & {}', '');

Expand All @@ -185,11 +168,8 @@ try {
'radii:',
'radii: RadiiValue | `${number}` | `${number}px` | `${any}px` | ',
);

result = result.replace(
'colors:',
'colors: ColorsValue | ',
);

result = result.replace('colors:', 'colors: ColorsValue | ');

result = result.replace(/\|[\s ]*\n/g, ';');

Expand Down
6 changes: 6 additions & 0 deletions bin/theme.ts
Original file line number Diff line number Diff line change
Expand Up @@ -94,4 +94,10 @@ export default {
sm: 48,
md: 12,
},
typography: {
h1: {
fontFamily: 'Noto Sans',
fontSize: 20,
},
},
} satisfies ThemedDict;
1 change: 1 addition & 0 deletions cli/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
dist/
Binary file added cli/.yarn/install-state.gz
Binary file not shown.
893 changes: 893 additions & 0 deletions cli/.yarn/releases/yarn-4.1.1.cjs

Large diffs are not rendered by default.

2 changes: 2 additions & 0 deletions cli/.yarnrc.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
yarnPath: .yarn/releases/yarn-4.1.1.cjs
nodeLinker: node-modules
8 changes: 8 additions & 0 deletions cli/bin/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
#!/usr/bin/env node

import { run } from '../dist/index.js';

run().catch((e) => {
console.error(e);
process.exit(1);
});
31 changes: 31 additions & 0 deletions cli/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
{
"name": "cli",
"version": "0.0.0",
"private": true,
"description": "Generate theme typings for autocomplete",
"type": "module",
"main": "dist/cjs/index.cjs",
"module": "dist/esm/index.mjs",
"types": "dist/types/index.d.ts",
"scripts": {
"build": "rm -rf dist && tsup src --format esm --shims",
"check:type": "tsc --noEmit"
},
"dependencies": {
"bundle-n-require": "^1.0.1",
"chokidar": "^3.5.3",
"cli-welcome": "^2.2.2",
"commander": "^11.0.0",
"ora": "^7.0.1",
"prettier": "^3.0.2",
"update-notifier": "^6.0.2"
},
"bin": "bin/index.js",
"devDependencies": {
"@types/ora": "^3.2.0",
"@types/update-notifier": "6.0.4",
"tsup": "^8.0.2",
"typescript": "5.2.2"
},
"packageManager": "yarn@4.1.1"
}
8 changes: 8 additions & 0 deletions cli/src/config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import type { ThemeKeyOptions } from './create-theme-typings-interface.js';

export const themeKeyConfiguration: ThemeKeyOptions[] = [
{ key: 'colors', maxScanDepth: 3 },
{ key: 'radii' },
{ key: 'sizes', maxScanDepth: 2 },
{ key: 'space', flatMap: (value) => [value, `-${value}`] },
];
104 changes: 104 additions & 0 deletions cli/src/create-theme-typings-interface.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
import { isObject } from './utils/is-object.js';
import { extractPropertyKeys } from './extract-property-keys.js';
import { extractPropertyPaths, printUnionMap } from './extract-property-paths.js';
import { extractSemanticTokenKeys } from './extract-semantic-token-keys.js';

export interface ThemeKeyOptions {
/**
* Property key in the theme object
* @example colors
*/
key: string;
/**
* Maximum extraction level
* @example
* union: gray.500
* level: 1---|2--|
* @default 3
*/
maxScanDepth?: number;
/**
* Pass a function to filter extracted values
* @example
* Exclude numeric index values from `breakpoints`
* @default () => true
*/
filter?: (value: string) => boolean;

/**
* Pass a function to flatMap extracted values
* @default value => value
*/
flatMap?: (value: string) => string | string[];
}

export type TypingsTemplate = 'default' | 'augmentation';

export interface CreateThemeTypingsInterfaceOptions {
config: ThemeKeyOptions[];
strictComponentTypes?: boolean;
format?: boolean;
strictTokenTypes?: boolean;
template?: TypingsTemplate;
}

function applyThemeTypingTemplate(typingContent: string, template: TypingsTemplate) {
switch (template) {
case 'augmentation':
return `// regenerate by running
// npx @chakra-ui/cli tokens path/to/your/theme.(js|ts) --template augmentation --out path/to/this/file
import { BaseThemeTypings } from "@chakra-ui/styled-system";
declare module "@chakra-ui/styled-system" {
export interface CustomThemeTypings extends BaseThemeTypings {
${typingContent}
}
}
`;
case 'default':
default:
return `// regenerate by running
// npx @chakra-ui/cli tokens path/to/your/theme.(js|ts)
import { BaseThemeTypings } from "./shared.types.js"
export interface ThemeTypings extends BaseThemeTypings {
${typingContent}
}
`;
}
}

export async function createThemeTypingsInterface(
theme: Record<string, unknown>,
{ config }: CreateThemeTypingsInterfaceOptions,
) {
const unions = config.reduce(
(allUnions, { key, maxScanDepth, filter = () => true, flatMap = (value) => value }) => {
const target = theme[key];

allUnions[key] = [];

if (isObject(target) || Array.isArray(target)) {
allUnions[key] = extractPropertyPaths(target, maxScanDepth).filter(filter).flatMap(flatMap);
}

if (isObject(theme.semanticTokens)) {
const semanticTokenKeys = extractSemanticTokenKeys(theme, key)
.filter(filter)
.flatMap(flatMap);

allUnions[key].push(...semanticTokenKeys);
}

return allUnions;
},
{} as Record<string, string[]>,
);

const typography = extractPropertyKeys(theme, 'typography');

const typingContent = `${printUnionMap(
{ ...unions, typography },
(targetKey) => targetKey === 'conditions',
)}`;

return applyThemeTypingTemplate(typingContent, 'default');
}
24 changes: 24 additions & 0 deletions cli/src/extract-color-schemes.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import { isColorHue } from "./utils/is-color-hue.js"
import { isObject } from "./utils/is-object.js"

/**
* Extract color scheme names
* by validating that every property of type ColorHue is in the object
*/
export function extractColorSchemeTypes(theme: Record<string, unknown>) {
const { colors } = theme
if (!isObject(colors)) {
return []
}

return Object.entries(colors).reduce(
(acc: string[], [colorName, colorValues]) => {
if (isColorHue(colorValues)) {
acc.push(colorName)
}

return acc
},
[],
)
}
51 changes: 51 additions & 0 deletions cli/src/extract-component-types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import { isObject } from "./utils/is-object.js"
import { printUnionMap } from "./extract-property-paths.js"

interface ComponentType extends Record<string, string[]> {
sizes: string[]
variants: string[]
}

export function extractComponentTypes(theme: Record<string, unknown>) {
const components = theme.components
if (!isObject(components)) {
return {}
}

return Object.entries(components).reduce(
(allDefs, [componentName, definition]) => {
if (definition) {
allDefs[componentName] = {
sizes: Object.keys(definition.sizes ?? {}),
variants: Object.keys(definition.variants ?? {}),
}
}

return allDefs
},
{} as Record<string, ComponentType>,
)
}

function esc(name: string) {
return name.match(/^[a-zA-Z0-9\-_]+$/) ? name : `"${name}"`
}

export function printComponentTypes(
componentTypes: Record<string, ComponentType>,
strict = false,
) {
const types = Object.entries(componentTypes)
.map(
([componentName, unions]) =>
`${esc(componentName)}: {
${printUnionMap(unions, strict)}
}`,
)
.join(`\n`)

return `components: {
${types}
}
`
}
16 changes: 16 additions & 0 deletions cli/src/extract-property-keys.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { isObject } from "./utils/is-object.js"

/**
* Extract textStyles keys
*/
export function extractPropertyKeys(
theme: Record<string, unknown>,
themePropertyName: string,
) {
const themeProperty = theme[themePropertyName]
if (!isObject(themeProperty)) {
return []
}

return Object.keys(themeProperty)
}
42 changes: 42 additions & 0 deletions cli/src/extract-property-paths.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import { isObject } from "./utils/is-object.js"
import { printUnionType } from "./utils/print-union-type.js"

/**
* @example
* { colors: ['red.500', 'green.500'] } => `colors: "red.500" | "green.500"`
*/
export function printUnionMap(
unions: Record<string, string[]>,
strict: boolean | ((targetKey: string) => boolean) = false,
) {
return Object.entries(unions)
.sort(([a], [b]) => a.localeCompare(b))
.map(([targetKey, union]) => {
const isStrict = typeof strict === "function" ? strict(targetKey) : strict
return `${targetKey}: ${printUnionType(union, isStrict)};`
})
.join("\n")
}

/**
* Extract recursively all property paths with a max depth
*/
export function extractPropertyPaths(target: unknown, maxDepth = 3) {
if ((!isObject(target) && !Array.isArray(target)) || !maxDepth) {
return []
}

return Object.entries(target).reduce((allPropertyPaths, [key, value]) => {
if (isObject(value)) {
extractPropertyPaths(value, maxDepth - 1).forEach((childKey) =>
// e.g. gray.500
allPropertyPaths.push(`${key}.${childKey}`),
)
} else {
// e.g. transparent
allPropertyPaths.push(key)
}

return allPropertyPaths
}, [] as string[])
}
Loading

0 comments on commit 27a9475

Please sign in to comment.