@interactivethings/scripts 2.1.4 → 2.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.d.ts +2 -0
- package/dist/cloudflare/cli.d.ts +13 -0
- package/dist/cloudflare/cloudflare.d.ts +69 -0
- package/dist/cloudflare/deployments.d.ts +9 -0
- package/dist/config.d.ts +92 -0
- package/dist/config.js +0 -11
- package/dist/figma/api.d.ts +69 -0
- package/dist/figma/cli.d.ts +30 -0
- package/dist/figma/cli.test.d.ts +1 -0
- package/dist/figma/images.d.ts +1 -0
- package/dist/figma/utils.d.ts +10 -0
- package/dist/index.d.ts +8 -0
- package/dist/init/cli.d.ts +5 -0
- package/dist/shared/cli.d.ts +32 -0
- package/dist/shared/deployment-service.d.ts +7 -0
- package/dist/shared/wait-deployment.d.ts +7 -0
- package/dist/tokens-studio/__tests__/fixtures/invalid-transformer.d.ts +9 -0
- package/dist/tokens-studio/__tests__/fixtures/test-transformer.d.ts +18 -0
- package/dist/tokens-studio/cli.d.ts +14 -0
- package/dist/tokens-studio/cli.test.d.ts +1 -0
- package/dist/tokens-studio/index.d.ts +9 -0
- package/dist/tokens-studio/index.js +6 -1
- package/dist/tokens-studio/require.d.ts +3 -0
- package/dist/tokens-studio/types.d.ts +22 -0
- package/dist/tokens-studio/utils.d.ts +60 -0
- package/dist/tokens-studio/utils.js +37 -1
- package/dist/types.d.ts +2 -0
- package/dist/vercel/cli.d.ts +11 -0
- package/dist/vercel/cli.test.d.ts +1 -0
- package/dist/vercel/deployments.d.ts +8 -0
- package/dist/vercel/vercel.d.ts +15 -0
- package/examples/README.md +62 -0
- package/examples/custom-transform.js +41 -0
- package/examples/ixt.config.example.ts +33 -0
- package/examples/mui-transform.ts +158 -0
- package/examples/tailwind-transform.ts +167 -0
- package/package.json +3 -2
package/dist/cli.d.ts
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
type Args = {
|
|
3
|
+
subcommand: "wait-deployment";
|
|
4
|
+
commit: string;
|
|
5
|
+
interval: number;
|
|
6
|
+
timeout: number;
|
|
7
|
+
project?: string;
|
|
8
|
+
email?: string;
|
|
9
|
+
account_id?: string;
|
|
10
|
+
config?: string;
|
|
11
|
+
};
|
|
12
|
+
declare const _default: import("../shared/cli").CLIModule<Args>;
|
|
13
|
+
export default _default;
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { IDeploymentService, Deployment } from "../shared/deployment-service";
|
|
2
|
+
/** /!\ Inferred with ChatGPT */
|
|
3
|
+
export type CloudflareDeployment = {
|
|
4
|
+
id: string;
|
|
5
|
+
short_id: string;
|
|
6
|
+
project_id: string;
|
|
7
|
+
project_name: string;
|
|
8
|
+
environment: string;
|
|
9
|
+
url: string;
|
|
10
|
+
created_on: string;
|
|
11
|
+
modified_on: string;
|
|
12
|
+
latest_stage: {
|
|
13
|
+
name: string;
|
|
14
|
+
started_on: string;
|
|
15
|
+
ended_on: string;
|
|
16
|
+
status: string;
|
|
17
|
+
};
|
|
18
|
+
deployment_trigger: {
|
|
19
|
+
type: string;
|
|
20
|
+
metadata: {
|
|
21
|
+
branch: string;
|
|
22
|
+
commit_hash: string;
|
|
23
|
+
commit_message: string;
|
|
24
|
+
commit_dirty: boolean;
|
|
25
|
+
};
|
|
26
|
+
};
|
|
27
|
+
stages: {
|
|
28
|
+
name: string;
|
|
29
|
+
started_on: string;
|
|
30
|
+
ended_on: string;
|
|
31
|
+
status: string;
|
|
32
|
+
}[];
|
|
33
|
+
build_config: {
|
|
34
|
+
build_command: string;
|
|
35
|
+
destination_dir: string;
|
|
36
|
+
build_caching: boolean;
|
|
37
|
+
root_dir: string;
|
|
38
|
+
web_analytics_tag: string | null;
|
|
39
|
+
web_analytics_token: string | null;
|
|
40
|
+
};
|
|
41
|
+
source: {
|
|
42
|
+
type: string;
|
|
43
|
+
config: {
|
|
44
|
+
owner: string;
|
|
45
|
+
repo_name: string;
|
|
46
|
+
production_branch: string;
|
|
47
|
+
pr_comments_enabled: boolean;
|
|
48
|
+
};
|
|
49
|
+
};
|
|
50
|
+
env_vars: Record<string, {
|
|
51
|
+
type: "secret_text" | "plain_text";
|
|
52
|
+
value: string;
|
|
53
|
+
}>;
|
|
54
|
+
compatibility_date: string;
|
|
55
|
+
compatibility_flags: string[];
|
|
56
|
+
build_image_major_version: number;
|
|
57
|
+
usage_model: string;
|
|
58
|
+
aliases: string[];
|
|
59
|
+
is_skipped: boolean;
|
|
60
|
+
production_branch: string;
|
|
61
|
+
};
|
|
62
|
+
export declare class CloudflareDeploymentService implements IDeploymentService {
|
|
63
|
+
private accountId;
|
|
64
|
+
private projectName;
|
|
65
|
+
private email;
|
|
66
|
+
private apiKey;
|
|
67
|
+
constructor(accountId: string, projectName: string, email: string, apiKey: string);
|
|
68
|
+
fetchForCommit(commitSha: string): Promise<Deployment[]>;
|
|
69
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export declare function waitForDeploymentReady({ accountId, project, email, apiKey, commitSha, interval, timeout, }: {
|
|
2
|
+
accountId: string;
|
|
3
|
+
project: string;
|
|
4
|
+
email: string;
|
|
5
|
+
apiKey: string;
|
|
6
|
+
commitSha: string;
|
|
7
|
+
interval: number;
|
|
8
|
+
timeout: number;
|
|
9
|
+
}): Promise<import("../shared/deployment-service").Deployment | undefined>;
|
package/dist/config.d.ts
ADDED
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
/**
|
|
3
|
+
* Figma configuration schema
|
|
4
|
+
*/
|
|
5
|
+
export declare const FigmaAssetConfigSchema: z.ZodObject<{
|
|
6
|
+
url: z.ZodString;
|
|
7
|
+
output: z.ZodString;
|
|
8
|
+
name: z.ZodString;
|
|
9
|
+
}, z.core.$strip>;
|
|
10
|
+
export declare const FigmaConfigSchema: z.ZodObject<{
|
|
11
|
+
token: z.ZodOptional<z.ZodString>;
|
|
12
|
+
assets: z.ZodDefault<z.ZodArray<z.ZodObject<{
|
|
13
|
+
url: z.ZodString;
|
|
14
|
+
output: z.ZodString;
|
|
15
|
+
name: z.ZodString;
|
|
16
|
+
}, z.core.$strip>>>;
|
|
17
|
+
}, z.core.$strip>;
|
|
18
|
+
/**
|
|
19
|
+
* Tokens Studio configuration schema
|
|
20
|
+
*/
|
|
21
|
+
export declare const TokensStudioConfigSchema: z.ZodObject<{
|
|
22
|
+
input: z.ZodDefault<z.ZodString>;
|
|
23
|
+
output: z.ZodOptional<z.ZodString>;
|
|
24
|
+
handler: z.ZodString;
|
|
25
|
+
}, z.core.$strip>;
|
|
26
|
+
/**
|
|
27
|
+
* Vercel configuration schema
|
|
28
|
+
*/
|
|
29
|
+
export declare const VercelConfigSchema: z.ZodObject<{
|
|
30
|
+
team: z.ZodOptional<z.ZodString>;
|
|
31
|
+
project: z.ZodOptional<z.ZodString>;
|
|
32
|
+
}, z.core.$strip>;
|
|
33
|
+
/**
|
|
34
|
+
* Cloudflare configuration schema
|
|
35
|
+
*/
|
|
36
|
+
export declare const CloudflareConfigSchema: z.ZodObject<{
|
|
37
|
+
project: z.ZodOptional<z.ZodString>;
|
|
38
|
+
email: z.ZodOptional<z.ZodString>;
|
|
39
|
+
accountId: z.ZodOptional<z.ZodString>;
|
|
40
|
+
}, z.core.$strip>;
|
|
41
|
+
/**
|
|
42
|
+
* Main IXT Scripts configuration schema
|
|
43
|
+
*/
|
|
44
|
+
export declare const IxtConfigSchema: z.ZodObject<{
|
|
45
|
+
figma: z.ZodOptional<z.ZodObject<{
|
|
46
|
+
token: z.ZodOptional<z.ZodString>;
|
|
47
|
+
assets: z.ZodDefault<z.ZodArray<z.ZodObject<{
|
|
48
|
+
url: z.ZodString;
|
|
49
|
+
output: z.ZodString;
|
|
50
|
+
name: z.ZodString;
|
|
51
|
+
}, z.core.$strip>>>;
|
|
52
|
+
}, z.core.$strip>>;
|
|
53
|
+
tokensStudio: z.ZodOptional<z.ZodObject<{
|
|
54
|
+
input: z.ZodDefault<z.ZodString>;
|
|
55
|
+
output: z.ZodOptional<z.ZodString>;
|
|
56
|
+
handler: z.ZodString;
|
|
57
|
+
}, z.core.$strip>>;
|
|
58
|
+
vercel: z.ZodOptional<z.ZodObject<{
|
|
59
|
+
team: z.ZodOptional<z.ZodString>;
|
|
60
|
+
project: z.ZodOptional<z.ZodString>;
|
|
61
|
+
}, z.core.$strip>>;
|
|
62
|
+
cloudflare: z.ZodOptional<z.ZodObject<{
|
|
63
|
+
project: z.ZodOptional<z.ZodString>;
|
|
64
|
+
email: z.ZodOptional<z.ZodString>;
|
|
65
|
+
accountId: z.ZodOptional<z.ZodString>;
|
|
66
|
+
}, z.core.$strip>>;
|
|
67
|
+
}, z.core.$strip>;
|
|
68
|
+
export type IxtConfig = z.infer<typeof IxtConfigSchema>;
|
|
69
|
+
export type FigmaConfig = z.infer<typeof FigmaConfigSchema>;
|
|
70
|
+
export type FigmaAssetConfig = z.infer<typeof FigmaAssetConfigSchema>;
|
|
71
|
+
export type TokensStudioConfig = z.infer<typeof TokensStudioConfigSchema>;
|
|
72
|
+
export type VercelConfig = z.infer<typeof VercelConfigSchema>;
|
|
73
|
+
export type CloudflareConfig = z.infer<typeof CloudflareConfigSchema>;
|
|
74
|
+
/**
|
|
75
|
+
* Helper function for type-safe configuration definition
|
|
76
|
+
* Provides IntelliSense and validation for the configuration object
|
|
77
|
+
*/
|
|
78
|
+
export declare function defineConfig(config: IxtConfig): IxtConfig;
|
|
79
|
+
/**
|
|
80
|
+
* Load configuration from a TypeScript file
|
|
81
|
+
* Only supports .ts configuration files for better type safety
|
|
82
|
+
*/
|
|
83
|
+
export declare function loadConfig(configPath?: string): Promise<IxtConfig>;
|
|
84
|
+
/**
|
|
85
|
+
* Merge CLI arguments with configuration
|
|
86
|
+
* CLI arguments take precedence over config file values
|
|
87
|
+
*/
|
|
88
|
+
export declare function mergeConfigWithArgs<T extends Record<string, any>>(config: IxtConfig, args: T, section: keyof IxtConfig): T & Partial<IxtConfig[keyof IxtConfig]>;
|
|
89
|
+
/**
|
|
90
|
+
* Validate that required values are present after merging config and args
|
|
91
|
+
*/
|
|
92
|
+
export declare function validateRequiredConfig<T extends Record<string, any>>(mergedConfig: T, requiredFields: (keyof T)[]): void;
|
package/dist/config.js
CHANGED
|
@@ -107,17 +107,6 @@ exports.IxtConfigSchema = zod_1.z.object({
|
|
|
107
107
|
function defineConfig(config) {
|
|
108
108
|
return exports.IxtConfigSchema.parse(config);
|
|
109
109
|
}
|
|
110
|
-
/**
|
|
111
|
-
* Default configuration values
|
|
112
|
-
*/
|
|
113
|
-
const DEFAULT_CONFIG = {
|
|
114
|
-
figma: {
|
|
115
|
-
assets: [],
|
|
116
|
-
},
|
|
117
|
-
tokensStudio: {
|
|
118
|
-
input: "./tokens",
|
|
119
|
-
},
|
|
120
|
-
};
|
|
121
110
|
/**
|
|
122
111
|
* Load configuration from a TypeScript file
|
|
123
112
|
* Only supports .ts configuration files for better type safety
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
type Color = {
|
|
2
|
+
r: number;
|
|
3
|
+
g: number;
|
|
4
|
+
b: number;
|
|
5
|
+
a: number;
|
|
6
|
+
};
|
|
7
|
+
type FileId = string;
|
|
8
|
+
type NodeId = string;
|
|
9
|
+
export type FigmaNode = ({
|
|
10
|
+
type: "RECTANGLE";
|
|
11
|
+
fills: {
|
|
12
|
+
type: "SOLID";
|
|
13
|
+
color: Color;
|
|
14
|
+
}[];
|
|
15
|
+
effects: {
|
|
16
|
+
type: "DROP_SHADOW";
|
|
17
|
+
offset: {
|
|
18
|
+
x: number;
|
|
19
|
+
y: number;
|
|
20
|
+
};
|
|
21
|
+
color: Color;
|
|
22
|
+
radius: number;
|
|
23
|
+
}[];
|
|
24
|
+
} | {
|
|
25
|
+
type: "TEXT";
|
|
26
|
+
style: {
|
|
27
|
+
fontFamily: string;
|
|
28
|
+
fontWeight: number;
|
|
29
|
+
fontSize: number;
|
|
30
|
+
letterSpacing: number;
|
|
31
|
+
lineHeightPx: number;
|
|
32
|
+
};
|
|
33
|
+
}) & {
|
|
34
|
+
name: string;
|
|
35
|
+
id: string;
|
|
36
|
+
};
|
|
37
|
+
export declare const createAPI: (figmaToken: string) => {
|
|
38
|
+
file: {
|
|
39
|
+
fetch: (fileId: FileId) => Promise<any>;
|
|
40
|
+
};
|
|
41
|
+
nodes: {
|
|
42
|
+
fetch: (fileId: FileId, ids: NodeId[]) => Promise<any>;
|
|
43
|
+
};
|
|
44
|
+
styles: {
|
|
45
|
+
fetch: (fileId: FileId) => Promise<{
|
|
46
|
+
nodes: {
|
|
47
|
+
document: FigmaNode;
|
|
48
|
+
}[];
|
|
49
|
+
}>;
|
|
50
|
+
};
|
|
51
|
+
/**
|
|
52
|
+
* Given a root node, fetches all exports of the nodes in the tree.
|
|
53
|
+
* This is especially useful to fetch all icons or assets from a design system.
|
|
54
|
+
*/
|
|
55
|
+
images: {
|
|
56
|
+
fetch: (fileId: FileId, nodeIds: string[], { onFetchSources, onFetchImage, }?: {
|
|
57
|
+
onFetchSources?: (sources: {
|
|
58
|
+
name: string;
|
|
59
|
+
format: string;
|
|
60
|
+
}[]) => void;
|
|
61
|
+
onFetchImage?: (url: string) => void;
|
|
62
|
+
}) => Promise<{
|
|
63
|
+
data: string | Buffer<ArrayBufferLike>;
|
|
64
|
+
name: string;
|
|
65
|
+
format: string;
|
|
66
|
+
}[]>;
|
|
67
|
+
};
|
|
68
|
+
};
|
|
69
|
+
export {};
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* This script downloads the assets from Figma and saves them into the repository.
|
|
3
|
+
* It is configured via the unified ixt configuration system.
|
|
4
|
+
*
|
|
5
|
+
* @example ixt.config.js
|
|
6
|
+
* import { defineConfig } from '@interactivethings/scripts';
|
|
7
|
+
*
|
|
8
|
+
* export default defineConfig({
|
|
9
|
+
* figma: {
|
|
10
|
+
* assets: [{
|
|
11
|
+
* name: "illustrations",
|
|
12
|
+
* url: "https://www.figma.com/design/ElWWZIcOGFhiT06rzfIwRO/Design-System?node-id=11861-10071",
|
|
13
|
+
* output: "src/assets/illustrations"
|
|
14
|
+
* }]
|
|
15
|
+
* }
|
|
16
|
+
* });
|
|
17
|
+
*/
|
|
18
|
+
type FigmaArgs = {
|
|
19
|
+
config?: string;
|
|
20
|
+
token?: string;
|
|
21
|
+
name?: string;
|
|
22
|
+
subcommand: "download";
|
|
23
|
+
} | {
|
|
24
|
+
config?: string;
|
|
25
|
+
token?: string;
|
|
26
|
+
subcommand: "get";
|
|
27
|
+
url: string;
|
|
28
|
+
};
|
|
29
|
+
declare const _default: import("../shared/cli").CLIModule<FigmaArgs>;
|
|
30
|
+
export default _default;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const optimizeImage: (filepath: string) => Promise<void>;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Should parse a URL in the form https://www.figma.com/design/ElWWZIcOGFhiT06rzfIwRO/Design-System-%5BTPW-Mobile-App%5D?node-id=10404-19140&p=f&t=K5K37NzOSt1uwjsX-0
|
|
3
|
+
* and extracts the pageId and nodeId
|
|
4
|
+
* The page id is the part just after /design
|
|
5
|
+
*/
|
|
6
|
+
export declare const parseFigmaURL: (urlString: string) => {
|
|
7
|
+
figmaFileId: string;
|
|
8
|
+
figmaPageId: string;
|
|
9
|
+
};
|
|
10
|
+
export declare const formatFigmaURL: (figmaFileId: string, figmaPageId: string) => string;
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @interactivethings/scripts
|
|
3
|
+
*
|
|
4
|
+
* A collection of useful development tools by Interactive Things
|
|
5
|
+
*/
|
|
6
|
+
export * from "./types";
|
|
7
|
+
export { defineConfig, type IxtConfig, type FigmaConfig, type TokensStudioConfig, } from "./config";
|
|
8
|
+
export * as tokensStudio from "./tokens-studio";
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { ArgumentParser } from "argparse";
|
|
2
|
+
/**
|
|
3
|
+
* Base interface that all CLI modules must implement
|
|
4
|
+
*/
|
|
5
|
+
export interface CLIModule<TArgs = any> {
|
|
6
|
+
/**
|
|
7
|
+
* Function to configure the argument parser for this module
|
|
8
|
+
*/
|
|
9
|
+
configParser: (parser: ArgumentParser) => void;
|
|
10
|
+
/**
|
|
11
|
+
* Function to execute the module logic with parsed arguments
|
|
12
|
+
*/
|
|
13
|
+
run: (args: TArgs) => Promise<void>;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Configuration object for defining a CLI module
|
|
17
|
+
*/
|
|
18
|
+
export interface CLIModuleConfig<TArgs = any> {
|
|
19
|
+
/**
|
|
20
|
+
* Function to configure the argument parser
|
|
21
|
+
*/
|
|
22
|
+
configParser: (parser: ArgumentParser) => void;
|
|
23
|
+
/**
|
|
24
|
+
* Function to execute the module logic
|
|
25
|
+
*/
|
|
26
|
+
run: (args: TArgs) => Promise<void>;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Type-safe factory function for creating CLI modules
|
|
30
|
+
* Provides consistent interface and utilities for all CLI modules
|
|
31
|
+
*/
|
|
32
|
+
export declare function defineCLIModule<TArgs = any>(config: CLIModuleConfig<TArgs>): CLIModule<TArgs>;
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { IDeploymentService } from "./deployment-service";
|
|
2
|
+
export declare function waitForDeploymentReady({ commitSha, interval, timeout, deploymentService, }: {
|
|
3
|
+
commitSha: string;
|
|
4
|
+
interval: number;
|
|
5
|
+
timeout: number;
|
|
6
|
+
deploymentService: IDeploymentService;
|
|
7
|
+
}): Promise<import("./deployment-service").Deployment | undefined>;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Invalid transformer for testing error cases
|
|
3
|
+
* This transformer does not export a transform function
|
|
4
|
+
*/
|
|
5
|
+
declare function someOtherFunction(): string;
|
|
6
|
+
declare const _default: {
|
|
7
|
+
someOtherFunction: typeof someOtherFunction;
|
|
8
|
+
};
|
|
9
|
+
export default _default;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Test transformer for tokens-studio CLI tests
|
|
3
|
+
* This transformer simply wraps the input tokens with metadata
|
|
4
|
+
*/
|
|
5
|
+
declare function transform(input: {
|
|
6
|
+
metadata: any;
|
|
7
|
+
tokenData: any;
|
|
8
|
+
}): {
|
|
9
|
+
source: string;
|
|
10
|
+
metadata: any;
|
|
11
|
+
tokens: any;
|
|
12
|
+
processed: boolean;
|
|
13
|
+
transformedAt: string;
|
|
14
|
+
};
|
|
15
|
+
declare const _default: {
|
|
16
|
+
transform: typeof transform;
|
|
17
|
+
};
|
|
18
|
+
export default _default;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* CLI entry point for tokens-studio transformations
|
|
4
|
+
* Supports different transformer handlers via --handler argument
|
|
5
|
+
*/
|
|
6
|
+
type TokenStudioArgs = {
|
|
7
|
+
config?: string;
|
|
8
|
+
subcommand: "transform";
|
|
9
|
+
handler?: string;
|
|
10
|
+
input?: string;
|
|
11
|
+
output?: string;
|
|
12
|
+
};
|
|
13
|
+
declare const _default: import("../shared/cli").CLIModule<TokenStudioArgs>;
|
|
14
|
+
export default _default;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tokens Studio module for @interactivethings/scripts
|
|
3
|
+
*
|
|
4
|
+
* This module provides utilities and transformers for working with
|
|
5
|
+
* tokens exported from Tokens Studio (Figma plugin).
|
|
6
|
+
*/
|
|
7
|
+
export { simplifyValues, kebabCase, mapEntries, maybeParseToNumber, maybeParseToPx, isToken, deepMerge, resolveReferences, formatValues, flattenTokens, makeResolver, mapKeysRecursively, defineTransform, } from "./utils";
|
|
8
|
+
export type { Metadata, TransformInput, TransformerModule, TokenStudioShadowValue, TokenStudioShadowRecord, } from "./types";
|
|
9
|
+
export * as cli from "./cli";
|
|
@@ -39,7 +39,7 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
39
39
|
};
|
|
40
40
|
})();
|
|
41
41
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
42
|
-
exports.cli = exports.flattenTokens = exports.formatValues = exports.resolveReferences = exports.deepMerge = exports.isToken = exports.maybeParseToPx = exports.maybeParseToNumber = exports.mapEntries = exports.kebabCase = exports.simplifyValues = void 0;
|
|
42
|
+
exports.cli = exports.defineTransform = exports.mapKeysRecursively = exports.makeResolver = exports.flattenTokens = exports.formatValues = exports.resolveReferences = exports.deepMerge = exports.isToken = exports.maybeParseToPx = exports.maybeParseToNumber = exports.mapEntries = exports.kebabCase = exports.simplifyValues = void 0;
|
|
43
43
|
// Export all utility functions
|
|
44
44
|
var utils_1 = require("./utils");
|
|
45
45
|
Object.defineProperty(exports, "simplifyValues", { enumerable: true, get: function () { return utils_1.simplifyValues; } });
|
|
@@ -52,5 +52,10 @@ Object.defineProperty(exports, "deepMerge", { enumerable: true, get: function ()
|
|
|
52
52
|
Object.defineProperty(exports, "resolveReferences", { enumerable: true, get: function () { return utils_1.resolveReferences; } });
|
|
53
53
|
Object.defineProperty(exports, "formatValues", { enumerable: true, get: function () { return utils_1.formatValues; } });
|
|
54
54
|
Object.defineProperty(exports, "flattenTokens", { enumerable: true, get: function () { return utils_1.flattenTokens; } });
|
|
55
|
+
Object.defineProperty(exports, "makeResolver", { enumerable: true, get: function () { return utils_1.makeResolver; } });
|
|
56
|
+
Object.defineProperty(exports, "mapKeysRecursively", { enumerable: true, get: function () { return utils_1.mapKeysRecursively; } });
|
|
57
|
+
Object.defineProperty(exports, "defineTransform", { enumerable: true, get: function () { return utils_1.defineTransform; } });
|
|
58
|
+
// Note: Transformers are now provided as examples in the examples/ directory
|
|
59
|
+
// Users should copy and customize these examples for their specific needs
|
|
55
60
|
// Export the CLI module (for internal use)
|
|
56
61
|
exports.cli = __importStar(require("./cli"));
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
export interface Metadata {
|
|
2
|
+
tokenSetOrder: string[];
|
|
3
|
+
}
|
|
4
|
+
export interface TransformInput {
|
|
5
|
+
metadata: Metadata;
|
|
6
|
+
tokenData: any;
|
|
7
|
+
}
|
|
8
|
+
export interface TransformerModule {
|
|
9
|
+
transform: (input: TransformInput) => any;
|
|
10
|
+
}
|
|
11
|
+
export type TokenStudioShadowValue = {
|
|
12
|
+
color: string;
|
|
13
|
+
x: string;
|
|
14
|
+
y: string;
|
|
15
|
+
blur: string;
|
|
16
|
+
spread: string;
|
|
17
|
+
};
|
|
18
|
+
export type TokenStudioShadowRecord = Record<string, {
|
|
19
|
+
value: TokenStudioShadowValue;
|
|
20
|
+
} | {
|
|
21
|
+
value: TokenStudioShadowValue[];
|
|
22
|
+
}>;
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { $IntentionalAny } from "../types";
|
|
2
|
+
import { Metadata } from "./types";
|
|
3
|
+
/**
|
|
4
|
+
* Shared utility functions for tokens-studio transformations
|
|
5
|
+
*/
|
|
6
|
+
/**
|
|
7
|
+
* Simplifies nested token values by extracting the 'value' property
|
|
8
|
+
*/
|
|
9
|
+
export declare const simplifyValues: (x: {
|
|
10
|
+
value: unknown;
|
|
11
|
+
} | string | null) => $IntentionalAny;
|
|
12
|
+
/**
|
|
13
|
+
* Converts space-separated strings to camelCase
|
|
14
|
+
*/
|
|
15
|
+
export declare const kebabCase: (x: string) => string;
|
|
16
|
+
/**
|
|
17
|
+
* Maps over object entries with a custom mapper function
|
|
18
|
+
*/
|
|
19
|
+
export declare const mapEntries: <K extends string | number | symbol, V, K2 extends string | number | symbol, V2>(obj: Record<K, V>, mapper: (key: K, value: V) => [K2, V2]) => Record<K2, V2>;
|
|
20
|
+
/**
|
|
21
|
+
* Attempts to parse a string or number to a number, returns original if not possible
|
|
22
|
+
*/
|
|
23
|
+
export declare const maybeParseToNumber: (x: string | number) => string | number;
|
|
24
|
+
/**
|
|
25
|
+
* Converts a value to pixels (adds 'px' suffix if it's a number)
|
|
26
|
+
*/
|
|
27
|
+
export declare const maybeParseToPx: (x: string | number) => string;
|
|
28
|
+
/**
|
|
29
|
+
* Type guard to check if an object is a token with value and type properties
|
|
30
|
+
*/
|
|
31
|
+
export declare const isToken: (obj: any) => obj is {
|
|
32
|
+
value: string;
|
|
33
|
+
type: string;
|
|
34
|
+
};
|
|
35
|
+
/**
|
|
36
|
+
* Deep merge utility for combining token objects
|
|
37
|
+
*/
|
|
38
|
+
export declare const deepMerge: (mergedTokens: any, tokenData: any) => void;
|
|
39
|
+
/**
|
|
40
|
+
* Resolves token references (strings like "{path.to.token}") using a value map
|
|
41
|
+
*/
|
|
42
|
+
export declare const resolveReferences: (obj: any, map: Map<string, string>) => void;
|
|
43
|
+
/**
|
|
44
|
+
* Formats token values by extracting the value property
|
|
45
|
+
*/
|
|
46
|
+
export declare const formatValues: (v: {
|
|
47
|
+
type: string;
|
|
48
|
+
value: string | number;
|
|
49
|
+
}) => string | number;
|
|
50
|
+
export declare const flattenTokens: (v: any, depth: number | undefined, transformKey: (key: string, depth: number) => string) => unknown;
|
|
51
|
+
/** Creates a resolver function for token references */
|
|
52
|
+
export declare const makeResolver: <T extends object>(data: T, keys: (keyof T)[]) => (str: string) => any;
|
|
53
|
+
export declare const mapKeysRecursively: (obj: $IntentionalAny, keyMapper: (key: string) => string) => Record<string, any>;
|
|
54
|
+
export declare const defineTransform: <TInput, TOutput = unknown>(transformFn: (input: {
|
|
55
|
+
tokenData: TInput;
|
|
56
|
+
metadata: Metadata;
|
|
57
|
+
}) => TOutput) => (input: {
|
|
58
|
+
tokenData: TInput;
|
|
59
|
+
metadata: Metadata;
|
|
60
|
+
}) => TOutput;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.flattenTokens = exports.formatValues = exports.resolveReferences = exports.deepMerge = exports.isToken = exports.maybeParseToPx = exports.maybeParseToNumber = exports.mapEntries = exports.kebabCase = exports.simplifyValues = void 0;
|
|
3
|
+
exports.defineTransform = exports.mapKeysRecursively = exports.makeResolver = exports.flattenTokens = exports.formatValues = exports.resolveReferences = exports.deepMerge = exports.isToken = exports.maybeParseToPx = exports.maybeParseToNumber = exports.mapEntries = exports.kebabCase = exports.simplifyValues = void 0;
|
|
4
4
|
const remeda_1 = require("remeda");
|
|
5
5
|
/**
|
|
6
6
|
* Shared utility functions for tokens-studio transformations
|
|
@@ -154,3 +154,39 @@ const flattenTokens = (v, depth = 0, transformKey) => {
|
|
|
154
154
|
return v;
|
|
155
155
|
};
|
|
156
156
|
exports.flattenTokens = flattenTokens;
|
|
157
|
+
/** Creates a resolver function for token references */
|
|
158
|
+
const makeResolver = (data, keys) => {
|
|
159
|
+
const index = {};
|
|
160
|
+
for (const k of keys) {
|
|
161
|
+
for (const [vName, value] of Object.entries(data[k])) {
|
|
162
|
+
if (typeof k !== "string")
|
|
163
|
+
continue;
|
|
164
|
+
index[`${k}.${vName}`] = value;
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
return (str) => {
|
|
168
|
+
var _a;
|
|
169
|
+
if (str[0] === "{" && str[str.length - 1] === "}") {
|
|
170
|
+
const path = str.substring(1, str.length - 1);
|
|
171
|
+
return (_a = index[path]) === null || _a === void 0 ? void 0 : _a.value;
|
|
172
|
+
}
|
|
173
|
+
else {
|
|
174
|
+
return str;
|
|
175
|
+
}
|
|
176
|
+
};
|
|
177
|
+
};
|
|
178
|
+
exports.makeResolver = makeResolver;
|
|
179
|
+
const mapKeysRecursively = (obj, keyMapper) => {
|
|
180
|
+
const visitor = (k, v) => {
|
|
181
|
+
if (typeof v === "object") {
|
|
182
|
+
return [keyMapper(k), (0, exports.mapEntries)(v, visitor)];
|
|
183
|
+
}
|
|
184
|
+
else {
|
|
185
|
+
return [keyMapper(k), v];
|
|
186
|
+
}
|
|
187
|
+
};
|
|
188
|
+
return (0, exports.mapEntries)(obj, visitor);
|
|
189
|
+
};
|
|
190
|
+
exports.mapKeysRecursively = mapKeysRecursively;
|
|
191
|
+
const defineTransform = (transformFn) => transformFn;
|
|
192
|
+
exports.defineTransform = defineTransform;
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
type Args = {
|
|
3
|
+
subcommand: "wait-deployment";
|
|
4
|
+
commit: string;
|
|
5
|
+
interval: number;
|
|
6
|
+
timeout: number;
|
|
7
|
+
team: string;
|
|
8
|
+
project: string;
|
|
9
|
+
};
|
|
10
|
+
declare const _default: import("../shared/cli").CLIModule<Args>;
|
|
11
|
+
export default _default;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export declare function waitForDeploymentReady({ team, project, commitSha, interval, timeout, accessToken, }: {
|
|
2
|
+
team: string;
|
|
3
|
+
project: string;
|
|
4
|
+
commitSha: string;
|
|
5
|
+
interval: number;
|
|
6
|
+
timeout: number;
|
|
7
|
+
accessToken: string;
|
|
8
|
+
}): Promise<import("../shared/deployment-service").Deployment | undefined>;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { IDeploymentService, Deployment } from "../shared/deployment-service";
|
|
2
|
+
export type VercelDeployment = {
|
|
3
|
+
state: string;
|
|
4
|
+
url: string;
|
|
5
|
+
meta: {
|
|
6
|
+
githubCommitSha: string;
|
|
7
|
+
};
|
|
8
|
+
};
|
|
9
|
+
export declare class VercelDeploymentService implements IDeploymentService {
|
|
10
|
+
private teamId;
|
|
11
|
+
private projectId;
|
|
12
|
+
private accessToken;
|
|
13
|
+
constructor(teamId: string, projectId: string, accessToken: string);
|
|
14
|
+
fetchForCommit(commitSha: string): Promise<Deployment[]>;
|
|
15
|
+
}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
# Tokens Studio Transform Examples
|
|
2
|
+
|
|
3
|
+
This directory contains example transformer handlers that demonstrate how to use the `ixt tokens-studio transform` command with custom transformation logic.
|
|
4
|
+
|
|
5
|
+
## Development Setup
|
|
6
|
+
|
|
7
|
+
When working in this repository during development, the TypeScript path mappings are configured to resolve `@interactivethings/scripts/*` imports to the local source files.
|
|
8
|
+
|
|
9
|
+
To compile and check the examples:
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
npx tsc --noEmit --project tsconfig.examples.json
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
## Usage
|
|
16
|
+
|
|
17
|
+
### MUI Transform Example
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
ixt tokens-studio transform --handler ./examples/mui-transform.ts --input ./tokens --output mui-theme.json
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
### Tailwind Transform Example
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
ixt tokens-studio transform --handler ./examples/tailwind-transform.ts --input ./tokens --output tailwind-theme.json
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
### Custom Transform Example
|
|
30
|
+
|
|
31
|
+
```bash
|
|
32
|
+
ixt tokens-studio transform --handler ./examples/custom-transform.js --input ./tokens --output custom-theme.json
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
## Creating Your Own Transformer
|
|
36
|
+
|
|
37
|
+
1. Copy one of the example files as a starting point
|
|
38
|
+
2. Modify the `transform` function to suit your needs
|
|
39
|
+
3. The `transform` function receives: `{ metadata, tokenData }`
|
|
40
|
+
4. Return the transformed data object
|
|
41
|
+
|
|
42
|
+
### Using in Production
|
|
43
|
+
|
|
44
|
+
When using these examples in your own project after installing `@interactivethings/scripts`:
|
|
45
|
+
|
|
46
|
+
```typescript
|
|
47
|
+
import {
|
|
48
|
+
kebabCase,
|
|
49
|
+
mapEntries /* ... */,
|
|
50
|
+
} from "@interactivethings/scripts/tokens-studio";
|
|
51
|
+
import { $IntentionalAny } from "@interactivethings/scripts/types";
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
Or using the alias:
|
|
55
|
+
|
|
56
|
+
```typescript
|
|
57
|
+
import {
|
|
58
|
+
kebabCase,
|
|
59
|
+
mapEntries /* ... */,
|
|
60
|
+
} from "@interactivethings/scripts/tokens-studio";
|
|
61
|
+
import { $IntentionalAny } from "@interactivethings/scripts/types";
|
|
62
|
+
```
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Example custom transformer handler
|
|
3
|
+
* This file demonstrates how to create a completely custom transformer
|
|
4
|
+
*
|
|
5
|
+
* Usage:
|
|
6
|
+
* ixt tokens-studio transform --handler ./examples/custom-transform.js --input ./tokens --output theme.json
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
module.exports = {
|
|
10
|
+
transform: (input) => {
|
|
11
|
+
const { metadata, tokenData } = input;
|
|
12
|
+
|
|
13
|
+
// Example: Extract only colors and convert to CSS custom properties
|
|
14
|
+
const colors = tokenData.core || {};
|
|
15
|
+
|
|
16
|
+
const cssVariables = {};
|
|
17
|
+
|
|
18
|
+
// Recursively convert tokens to CSS custom property format
|
|
19
|
+
const convertToCssVars = (obj, prefix = "") => {
|
|
20
|
+
for (const [key, value] of Object.entries(obj)) {
|
|
21
|
+
if (value && typeof value === "object" && "value" in value) {
|
|
22
|
+
// This is a token
|
|
23
|
+
cssVariables[`--${prefix}${key}`] = value.value;
|
|
24
|
+
} else if (value && typeof value === "object") {
|
|
25
|
+
// This is a nested object
|
|
26
|
+
convertToCssVars(value, `${prefix}${key}-`);
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
convertToCssVars(colors, "color-");
|
|
32
|
+
|
|
33
|
+
return {
|
|
34
|
+
cssVariables,
|
|
35
|
+
metadata: {
|
|
36
|
+
generatedAt: new Date().toISOString(),
|
|
37
|
+
tokenSetOrder: metadata.tokenSetOrder,
|
|
38
|
+
},
|
|
39
|
+
};
|
|
40
|
+
},
|
|
41
|
+
};
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { defineConfig } from '@interactivethings/scripts';
|
|
2
|
+
|
|
3
|
+
export default defineConfig({
|
|
4
|
+
figma: {
|
|
5
|
+
// Figma API token (can also be set via FIGMA_TOKEN environment variable)
|
|
6
|
+
token: process.env.FIGMA_TOKEN,
|
|
7
|
+
|
|
8
|
+
// Assets to download from Figma
|
|
9
|
+
assets: [
|
|
10
|
+
{
|
|
11
|
+
name: "icons",
|
|
12
|
+
url: "https://www.figma.com/design/ElWWZIcOGFhiT06rzfIwRO/Design-System?node-id=11861-10071",
|
|
13
|
+
output: "src/assets/icons"
|
|
14
|
+
},
|
|
15
|
+
{
|
|
16
|
+
name: "illustrations",
|
|
17
|
+
url: "https://www.figma.com/design/ElWWZIcOGFhiT06rzfIwRO/Design-System?node-id=12345-67890",
|
|
18
|
+
output: "src/assets/illustrations"
|
|
19
|
+
}
|
|
20
|
+
]
|
|
21
|
+
},
|
|
22
|
+
|
|
23
|
+
tokensStudio: {
|
|
24
|
+
// Input directory containing design tokens
|
|
25
|
+
input: "./design-tokens",
|
|
26
|
+
|
|
27
|
+
// Default output file for transformations
|
|
28
|
+
output: "src/theme/tokens.json",
|
|
29
|
+
|
|
30
|
+
// Default transformer handler
|
|
31
|
+
handler: "./transforms/mui-transform.ts"
|
|
32
|
+
}
|
|
33
|
+
});
|
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MUI transformer for tokens-studio
|
|
3
|
+
* Transforms tokens exported with tokens-studio in Figma into
|
|
4
|
+
* a format that is easier to work with when using MUI.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import { mapValues, pick } from "remeda";
|
|
8
|
+
|
|
9
|
+
import { $IntentionalAny } from "@interactivethings/scripts/types";
|
|
10
|
+
import {
|
|
11
|
+
simplifyValues,
|
|
12
|
+
kebabCase,
|
|
13
|
+
mapEntries,
|
|
14
|
+
maybeParseToNumber,
|
|
15
|
+
maybeParseToPx,
|
|
16
|
+
makeResolver,
|
|
17
|
+
defineTransform,
|
|
18
|
+
type TokenStudioShadowValue,
|
|
19
|
+
mapKeysRecursively,
|
|
20
|
+
} from "@interactivethings/scripts/tokens-studio";
|
|
21
|
+
|
|
22
|
+
// Ideally those types should be imported from your theme's type definitions
|
|
23
|
+
// You should change those lines to match your actual theme structure
|
|
24
|
+
// @example
|
|
25
|
+
// ```
|
|
26
|
+
// import tokensStudioTokens from '../path/to/your/tokens-studio/tokens.json';
|
|
27
|
+
// type MUITokenData = typeof tokensStudioTokens
|
|
28
|
+
// ```
|
|
29
|
+
type MUITokenData = {
|
|
30
|
+
Base: $IntentionalAny;
|
|
31
|
+
Functional: $IntentionalAny;
|
|
32
|
+
Elevation: Record<
|
|
33
|
+
string,
|
|
34
|
+
{ value: TokenStudioShadowValue | TokenStudioShadowValue[] }
|
|
35
|
+
>;
|
|
36
|
+
Desktop: $IntentionalAny;
|
|
37
|
+
Mobile: $IntentionalAny;
|
|
38
|
+
fontFamilies: $IntentionalAny;
|
|
39
|
+
lineHeights: $IntentionalAny;
|
|
40
|
+
fontWeights: $IntentionalAny;
|
|
41
|
+
fontSize: $IntentionalAny;
|
|
42
|
+
letterSpacing: $IntentionalAny;
|
|
43
|
+
textDecoration: $IntentionalAny;
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
const renameColorKeys = (k: string) => {
|
|
47
|
+
return kebabCase(
|
|
48
|
+
k
|
|
49
|
+
.replace(/-[a-zA-Z0-9]+/, "")
|
|
50
|
+
.replace(" - ", " ")
|
|
51
|
+
.replace(",", "")
|
|
52
|
+
.replace(/^\d+\s+/, "")
|
|
53
|
+
);
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
const getPalette = (tokensData: MUITokenData) => {
|
|
57
|
+
const data = tokensData;
|
|
58
|
+
const colorKeys = ["Base", "Functional"] as const;
|
|
59
|
+
|
|
60
|
+
let palette = pick(data, colorKeys);
|
|
61
|
+
type Palette = typeof palette;
|
|
62
|
+
palette = mapValues(palette, simplifyValues);
|
|
63
|
+
const tpalette = mapKeysRecursively(palette, renameColorKeys) as unknown as {
|
|
64
|
+
base: Palette["Base"];
|
|
65
|
+
functional: Palette["Functional"];
|
|
66
|
+
};
|
|
67
|
+
palette = {
|
|
68
|
+
...tpalette.base,
|
|
69
|
+
...pick(tpalette, ["functional"]),
|
|
70
|
+
};
|
|
71
|
+
return palette;
|
|
72
|
+
};
|
|
73
|
+
|
|
74
|
+
const getTypography = (tokensData: MUITokenData) => {
|
|
75
|
+
const sizes = ["Desktop", "Mobile"] as const;
|
|
76
|
+
const res = {} as Record<string, $IntentionalAny>;
|
|
77
|
+
const resolve = makeResolver(tokensData, [
|
|
78
|
+
"fontFamilies",
|
|
79
|
+
"lineHeights",
|
|
80
|
+
"fontWeights",
|
|
81
|
+
"fontSize",
|
|
82
|
+
"letterSpacing",
|
|
83
|
+
"textDecoration",
|
|
84
|
+
] as const);
|
|
85
|
+
|
|
86
|
+
const cleanupTypographyFns = {
|
|
87
|
+
fontWeight: (x: string) => {
|
|
88
|
+
const lowered = x.toLowerCase();
|
|
89
|
+
if (lowered == "regular") {
|
|
90
|
+
return 400;
|
|
91
|
+
}
|
|
92
|
+
return lowered;
|
|
93
|
+
},
|
|
94
|
+
fontSize: maybeParseToNumber,
|
|
95
|
+
lineHeight: (x: string | number) => maybeParseToPx(maybeParseToNumber(x)),
|
|
96
|
+
paragraphSpacing: maybeParseToNumber,
|
|
97
|
+
letterSpacing: maybeParseToNumber,
|
|
98
|
+
};
|
|
99
|
+
|
|
100
|
+
const cleanupTypographyValue = (k: string, v: $IntentionalAny) => {
|
|
101
|
+
if (k in cleanupTypographyFns) {
|
|
102
|
+
return [
|
|
103
|
+
k,
|
|
104
|
+
cleanupTypographyFns[k as keyof typeof cleanupTypographyFns](v),
|
|
105
|
+
] as [string, $IntentionalAny];
|
|
106
|
+
} else {
|
|
107
|
+
return [k, v] as [string, $IntentionalAny];
|
|
108
|
+
}
|
|
109
|
+
};
|
|
110
|
+
|
|
111
|
+
for (const size of sizes) {
|
|
112
|
+
const typographies = tokensData[size];
|
|
113
|
+
for (const [typo, typoDataRaw] of Object.entries(typographies)) {
|
|
114
|
+
const typoData = typoDataRaw as { value: $IntentionalAny };
|
|
115
|
+
const typoKey = kebabCase(typo.toLowerCase());
|
|
116
|
+
res[typoKey] = res[typoKey] || {};
|
|
117
|
+
res[typoKey][size.toLowerCase()] = mapEntries(
|
|
118
|
+
mapValues(typoData.value, resolve),
|
|
119
|
+
cleanupTypographyValue
|
|
120
|
+
);
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
return res;
|
|
124
|
+
};
|
|
125
|
+
|
|
126
|
+
const getShadows = (tokenData: MUITokenData) => {
|
|
127
|
+
const transformShadow = (shadowData: TokenStudioShadowValue) => {
|
|
128
|
+
const { color, x, y, blur, spread } = shadowData;
|
|
129
|
+
return `${x}px ${y}px ${blur}px ${spread}px ${color}`;
|
|
130
|
+
};
|
|
131
|
+
|
|
132
|
+
const shadows = mapEntries(tokenData.Elevation, (k, v) => {
|
|
133
|
+
const shadowEntry = v as
|
|
134
|
+
| { value: TokenStudioShadowValue }
|
|
135
|
+
| { value: TokenStudioShadowValue[] };
|
|
136
|
+
return [
|
|
137
|
+
`${Number((k as string).replace("dp", "").replace("pd", ""))}`,
|
|
138
|
+
Array.isArray(shadowEntry.value)
|
|
139
|
+
? (shadowEntry.value as TokenStudioShadowValue[])
|
|
140
|
+
.map(transformShadow)
|
|
141
|
+
.join(", ")
|
|
142
|
+
: transformShadow(shadowEntry.value as TokenStudioShadowValue),
|
|
143
|
+
];
|
|
144
|
+
});
|
|
145
|
+
return shadows;
|
|
146
|
+
};
|
|
147
|
+
|
|
148
|
+
export const transform = defineTransform<MUITokenData>((input) => {
|
|
149
|
+
const palette = getPalette(input.tokenData);
|
|
150
|
+
const typography = getTypography(input.tokenData);
|
|
151
|
+
const shadows = getShadows(input.tokenData);
|
|
152
|
+
|
|
153
|
+
return {
|
|
154
|
+
palette,
|
|
155
|
+
typography,
|
|
156
|
+
shadows,
|
|
157
|
+
};
|
|
158
|
+
});
|
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tailwind transformer for tokens-studio
|
|
3
|
+
* Transforms tokens exported with tokens-studio in Figma into
|
|
4
|
+
* a format that is compatible with Tailwind CSS.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import { mapValues, pick } from "remeda";
|
|
8
|
+
import {
|
|
9
|
+
resolveReferences,
|
|
10
|
+
mapEntries,
|
|
11
|
+
flattenTokens,
|
|
12
|
+
defineTransform,
|
|
13
|
+
} from "@interactivethings/scripts/tokens-studio";
|
|
14
|
+
import { $IntentionalAny } from "../dist/types";
|
|
15
|
+
|
|
16
|
+
// Ideally those types should be imported from your theme's type definitions
|
|
17
|
+
// You should change those lines to match your actual theme structure
|
|
18
|
+
// @example
|
|
19
|
+
// ```
|
|
20
|
+
// import coreTokens from '../path/to/your/core/tokens.json';
|
|
21
|
+
// import functionalTokens from '../path/to/your/functional/tokens.json';
|
|
22
|
+
// type TailwindTokenData = {
|
|
23
|
+
// core: typeof coreTokens;
|
|
24
|
+
// functional: typeof functionalTokens;
|
|
25
|
+
// };
|
|
26
|
+
// ```
|
|
27
|
+
type TailwindTokenData = {
|
|
28
|
+
core: $IntentionalAny;
|
|
29
|
+
functional: $IntentionalAny;
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
export const transform = defineTransform<TailwindTokenData>((input) => {
|
|
33
|
+
const mergedTokens = input.tokenData;
|
|
34
|
+
|
|
35
|
+
const valueMap = new Map<string, string>();
|
|
36
|
+
resolveReferences(mergedTokens, valueMap);
|
|
37
|
+
|
|
38
|
+
const theme = {
|
|
39
|
+
colors: {
|
|
40
|
+
...pick(mergedTokens.core, [
|
|
41
|
+
"amber",
|
|
42
|
+
"blue",
|
|
43
|
+
"brand",
|
|
44
|
+
"cyan",
|
|
45
|
+
"emerald",
|
|
46
|
+
"fuchsia",
|
|
47
|
+
"green",
|
|
48
|
+
"indigo",
|
|
49
|
+
"light-blue",
|
|
50
|
+
"lime",
|
|
51
|
+
"midnight",
|
|
52
|
+
"monochrome",
|
|
53
|
+
"orange",
|
|
54
|
+
"pink",
|
|
55
|
+
"purple",
|
|
56
|
+
"red",
|
|
57
|
+
"rose",
|
|
58
|
+
"teal",
|
|
59
|
+
"violet",
|
|
60
|
+
"yellow",
|
|
61
|
+
]),
|
|
62
|
+
...pick(mergedTokens.functional, [
|
|
63
|
+
"primary",
|
|
64
|
+
"secondary",
|
|
65
|
+
"tertiary",
|
|
66
|
+
"error",
|
|
67
|
+
"success",
|
|
68
|
+
"warning",
|
|
69
|
+
"link",
|
|
70
|
+
"surface",
|
|
71
|
+
"on-surface",
|
|
72
|
+
"surface-inverted",
|
|
73
|
+
"on-surface-inverted",
|
|
74
|
+
"border",
|
|
75
|
+
"input",
|
|
76
|
+
"accent",
|
|
77
|
+
"qualitative",
|
|
78
|
+
"pathways",
|
|
79
|
+
]),
|
|
80
|
+
},
|
|
81
|
+
borderWidth: {
|
|
82
|
+
...mergedTokens.functional["border-width"],
|
|
83
|
+
},
|
|
84
|
+
borderRadius: {
|
|
85
|
+
...mergedTokens.functional["border-radius"],
|
|
86
|
+
},
|
|
87
|
+
fontSize: mergedTokens.core["font-size"],
|
|
88
|
+
fontWeight: mergedTokens.core["font-weight"],
|
|
89
|
+
lineHeight: mergedTokens.core["line-height"],
|
|
90
|
+
spacing: mergedTokens.functional.spacing,
|
|
91
|
+
};
|
|
92
|
+
|
|
93
|
+
const transformKey = (key: string, depth: number) => {
|
|
94
|
+
if (key.startsWith("on-")) {
|
|
95
|
+
if (depth === 1) {
|
|
96
|
+
return key.replace("on-", "foreground-");
|
|
97
|
+
} else {
|
|
98
|
+
return "foreground";
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
if (key === "default") {
|
|
102
|
+
return "DEFAULT";
|
|
103
|
+
}
|
|
104
|
+
return key;
|
|
105
|
+
};
|
|
106
|
+
|
|
107
|
+
const flattenedTheme = mapValues(theme, (x) =>
|
|
108
|
+
flattenTokens(x, 0, transformKey)
|
|
109
|
+
) as {
|
|
110
|
+
colors: Record<string, string>;
|
|
111
|
+
borderWidth: Record<string, string>;
|
|
112
|
+
borderRadius: Record<string, string>;
|
|
113
|
+
fontSize: Record<
|
|
114
|
+
"mobile-large" | "mobile-xxxlarge",
|
|
115
|
+
Record<string, number>
|
|
116
|
+
>;
|
|
117
|
+
fontWeight: Record<string, string>;
|
|
118
|
+
lineHeight: Record<
|
|
119
|
+
"mobile-large" | "mobile-xxxlarge",
|
|
120
|
+
Record<string, number>
|
|
121
|
+
>;
|
|
122
|
+
spacing: Record<string, string>;
|
|
123
|
+
};
|
|
124
|
+
|
|
125
|
+
const lineHeights = flattenedTheme.lineHeight;
|
|
126
|
+
const fontWeights = flattenedTheme.fontWeight;
|
|
127
|
+
|
|
128
|
+
const finalTheme = {
|
|
129
|
+
...flattenedTheme,
|
|
130
|
+
borderWidth: mapValues(flattenedTheme.borderWidth, (x) => `${x}px`),
|
|
131
|
+
borderRadius: mapValues(flattenedTheme.borderRadius, (x) => `${x}px`),
|
|
132
|
+
fontSize: mapEntries(
|
|
133
|
+
flattenedTheme.fontSize["mobile-large"],
|
|
134
|
+
(k: string, value) => {
|
|
135
|
+
return [
|
|
136
|
+
k.replace(",", ""),
|
|
137
|
+
[
|
|
138
|
+
`${value}px`,
|
|
139
|
+
{
|
|
140
|
+
lineHeight: lineHeights["mobile-large"][k]
|
|
141
|
+
? `${lineHeights["mobile-large"][k]}px`
|
|
142
|
+
: undefined,
|
|
143
|
+
fontWeight: fontWeights[k],
|
|
144
|
+
},
|
|
145
|
+
],
|
|
146
|
+
];
|
|
147
|
+
}
|
|
148
|
+
),
|
|
149
|
+
fontWeight: flattenedTheme.fontWeight,
|
|
150
|
+
lineHeight: mapEntries(
|
|
151
|
+
flattenedTheme.lineHeight["mobile-large"],
|
|
152
|
+
(k: string, value) => {
|
|
153
|
+
return [k.replace(",", ""), `${value}px`];
|
|
154
|
+
}
|
|
155
|
+
),
|
|
156
|
+
backgroundImage: {
|
|
157
|
+
"gradient-2":
|
|
158
|
+
"var(--Gradient-2, linear-gradient(135deg, var(--core-brand-electricblue500, #48A1C7) 20.83%, var(--core-brand-nocturne700, #336476) 87.96%))",
|
|
159
|
+
},
|
|
160
|
+
spacing: mapEntries(flattenedTheme.spacing, (k, v) => [
|
|
161
|
+
k.replace("spacing-", ""),
|
|
162
|
+
`${v}px`,
|
|
163
|
+
]),
|
|
164
|
+
};
|
|
165
|
+
|
|
166
|
+
return finalTheme;
|
|
167
|
+
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@interactivethings/scripts",
|
|
3
|
-
"version": "2.1
|
|
3
|
+
"version": "2.2.1",
|
|
4
4
|
"main": "dist/index.js",
|
|
5
5
|
"exports": {
|
|
6
6
|
".": "./dist/index.js",
|
|
@@ -36,7 +36,8 @@
|
|
|
36
36
|
"files": [
|
|
37
37
|
"dist",
|
|
38
38
|
"README.md",
|
|
39
|
-
"codemods"
|
|
39
|
+
"codemods",
|
|
40
|
+
"examples"
|
|
40
41
|
],
|
|
41
42
|
"dependencies": {
|
|
42
43
|
"@next/env": "^15.5.4",
|