@pantoken/rust 0.1.0

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/README.md ADDED
@@ -0,0 +1,56 @@
1
+ # @pantoken/rust
2
+
3
+ Emit Instructure design tokens as Rust constants for the two mainstream native Rust GUIs. Colours
4
+ become the framework's colour type; dimensions become `f32` (px). Icons and non-colour/dimension
5
+ tokens are skipped.
6
+
7
+ | Format | Type | Framework |
8
+ | ------ | --------- | ------------------------------------- |
9
+ | `egui` | `Color32` | [egui](https://github.com/emilk/egui) |
10
+ | `iced` | `Color` | [iced](https://iced.rs) |
11
+
12
+ ## Install
13
+
14
+ ```sh
15
+ npm i @pantoken/rust
16
+ ```
17
+
18
+ ## Usage
19
+
20
+ ```ts
21
+ import { writeFileSync } from "node:fs";
22
+ import { generateRust } from "@pantoken/rust";
23
+
24
+ writeFileSync("tokens.rs", generateRust({ format: "egui", theme: "rebrand" }));
25
+ ```
26
+
27
+ Or via the CLI:
28
+
29
+ ```sh
30
+ pantoken generate rust --format egui --out tokens.rs
31
+ pantoken generate rust --format iced --out src/tokens.rs
32
+ ```
33
+
34
+ ## Output
35
+
36
+ A single Rust module of `pub const`s — one per colour and dimension token, `SCREAMING_SNAKE_CASE`,
37
+ prefixed with `use egui::Color32;` or `use iced::Color;` to match the chosen format. Web-rendered
38
+ Rust UIs (Tauri, Dioxus-web, Leptos, Yew) render to HTML/CSS — use `@pantoken/css` there, not this
39
+ package.
40
+
41
+ ## API
42
+
43
+ - **`generateRust(options?): string`** — emit Rust for a named theme (from the vendored
44
+ `@pantoken/tokens` IR). Returns the source string.
45
+ - **`toRust(tokens, options?): string`** — same, but for an explicit token IR.
46
+ - **`RustFormat`** — `"egui" | "iced"`.
47
+ - **`RustOptions`** — the `format` and `mode` options (`generateRust` also takes `theme`).
48
+
49
+ ## Related
50
+
51
+ - Uses `@pantoken/tokens` for the vendored token IR and `@pantoken/core` for the flattened Style
52
+ Dictionary values.
53
+
54
+ ## License
55
+
56
+ MIT
@@ -0,0 +1,55 @@
1
+ import { Mode } from "@pantoken/core";
2
+ import { Theme, Token } from "@pantoken/model";
3
+
4
+ //#region src/index.d.ts
5
+ /** The Rust GUI framework to target. */
6
+ type RustFormat = "egui" | "iced";
7
+ /** Options for {@link toRust} / {@link generateRust}. */
8
+ interface RustOptions {
9
+ /** The Rust GUI to target (default `"egui"`). */
10
+ format?: RustFormat;
11
+ /** Which `light-dark()` mode to resolve (default `"light"`). */
12
+ mode?: Mode;
13
+ }
14
+ /**
15
+ * Emit Rust constants for an explicit token IR.
16
+ *
17
+ * @param tokens - The IR.
18
+ * @param options - {@link RustOptions}.
19
+ * @returns The Rust source (a module of `pub const`s).
20
+ *
21
+ * @example egui (Color32), the default format
22
+ * ```ts
23
+ * import { toRust } from "@pantoken/rust";
24
+ * import { byTheme } from "@pantoken/tokens";
25
+ *
26
+ * const source = toRust(byTheme("rebrand"));
27
+ * // "use egui::Color32;\npub const COLOR_BACKGROUND_BRAND: Color32 = Color32::from_rgb(…);"
28
+ * ```
29
+ *
30
+ * @example iced (Color), dark mode
31
+ * ```ts
32
+ * import { toRust } from "@pantoken/rust";
33
+ * import { byTheme } from "@pantoken/tokens";
34
+ *
35
+ * const source = toRust(byTheme("rebrand"), { format: "iced", mode: "dark" });
36
+ * // "use iced::Color;\npub const COLOR_BACKGROUND_BRAND: Color = Color { r: …, g: …, b: …, a: … };"
37
+ * ```
38
+ */
39
+ declare function toRust(tokens: readonly Token[], options?: RustOptions): string;
40
+ /**
41
+ * Emit Rust constants for a named theme (using the vendored `@pantoken/tokens` IR).
42
+ *
43
+ * @example
44
+ * ```ts
45
+ * import { writeFileSync } from "node:fs";
46
+ * import { generateRust } from "@pantoken/rust";
47
+ *
48
+ * writeFileSync("tokens.rs", generateRust({ format: "egui", theme: "rebrand" }));
49
+ * ```
50
+ */
51
+ declare function generateRust(options?: RustOptions & {
52
+ theme?: Theme;
53
+ }): string;
54
+ //#endregion
55
+ export { RustFormat, RustOptions, generateRust as default, generateRust, toRust };
package/dist/index.mjs ADDED
@@ -0,0 +1,110 @@
1
+ import { toStyleDictionary } from "@pantoken/core";
2
+ import { byTheme } from "@pantoken/tokens";
3
+ import { parseHexColor } from "@pantoken/utils";
4
+ //#region src/index.ts
5
+ /**
6
+ * `@pantoken/rust` — emit Instructure design tokens as Rust constants for the two mainstream native
7
+ * Rust GUIs: **egui** (`Color32`) and **iced** (`Color`). Colours become the framework's colour
8
+ * type; dimensions become `f32` (px). Web-rendered Rust UIs (Tauri, Dioxus-web, Leptos, Yew) should
9
+ * use `@pantoken/css` instead.
10
+ *
11
+ * @module
12
+ * @experimental
13
+ */
14
+ function hexToRgb(hex) {
15
+ const c = parseHexColor(hex);
16
+ return c ? {
17
+ r: c.r,
18
+ g: c.g,
19
+ b: c.b,
20
+ a: Math.round(c.a * 255)
21
+ } : void 0;
22
+ }
23
+ function constName(tokenName) {
24
+ return tokenName.replace(/^--instui-/, "").replace(/-/g, "_").toUpperCase();
25
+ }
26
+ function dimension(value) {
27
+ const m = /^(-?\d*\.?\d+)(px|rem|em)?$/.exec(value.trim());
28
+ if (!m) return void 0;
29
+ return Number(m[1]) * (m[2] === "rem" || m[2] === "em" ? 16 : 1);
30
+ }
31
+ /** Format a number as a Rust `f32` literal (always with a decimal, so `1` → `1.0`). */
32
+ function f32lit(n) {
33
+ return Number.isInteger(n) ? `${n}.0` : `${n}`;
34
+ }
35
+ function colorLiteral(format, rgb) {
36
+ if (format === "egui") return {
37
+ ty: "Color32",
38
+ expr: rgb.a === 255 ? `Color32::from_rgb(${rgb.r}, ${rgb.g}, ${rgb.b})` : `Color32::from_rgba_unmultiplied(${rgb.r}, ${rgb.g}, ${rgb.b}, ${rgb.a})`
39
+ };
40
+ const c = (n) => f32lit(n / 255);
41
+ return {
42
+ ty: "Color",
43
+ expr: `Color { r: ${c(rgb.r)}, g: ${c(rgb.g)}, b: ${c(rgb.b)}, a: ${c(rgb.a)} }`
44
+ };
45
+ }
46
+ /**
47
+ * Emit Rust constants for an explicit token IR.
48
+ *
49
+ * @param tokens - The IR.
50
+ * @param options - {@link RustOptions}.
51
+ * @returns The Rust source (a module of `pub const`s).
52
+ *
53
+ * @example egui (Color32), the default format
54
+ * ```ts
55
+ * import { toRust } from "@pantoken/rust";
56
+ * import { byTheme } from "@pantoken/tokens";
57
+ *
58
+ * const source = toRust(byTheme("rebrand"));
59
+ * // "use egui::Color32;\npub const COLOR_BACKGROUND_BRAND: Color32 = Color32::from_rgb(…);"
60
+ * ```
61
+ *
62
+ * @example iced (Color), dark mode
63
+ * ```ts
64
+ * import { toRust } from "@pantoken/rust";
65
+ * import { byTheme } from "@pantoken/tokens";
66
+ *
67
+ * const source = toRust(byTheme("rebrand"), { format: "iced", mode: "dark" });
68
+ * // "use iced::Color;\npub const COLOR_BACKGROUND_BRAND: Color = Color { r: …, g: …, b: …, a: … };"
69
+ * ```
70
+ */
71
+ function toRust(tokens, options = {}) {
72
+ const format = options.format ?? "egui";
73
+ const dictionary = toStyleDictionary(tokens, options.mode ?? "light");
74
+ const lines = [
75
+ "// GENERATED by @pantoken/rust — do not edit by hand.",
76
+ "#![allow(dead_code)]",
77
+ format === "egui" ? "use egui::Color32;" : "use iced::Color;",
78
+ ""
79
+ ];
80
+ for (const [name, leaf] of Object.entries(dictionary)) {
81
+ const constant = constName(`--${name}`);
82
+ if (leaf.type === "color") {
83
+ const rgb = hexToRgb(leaf.value);
84
+ if (!rgb) continue;
85
+ const { ty, expr } = colorLiteral(format, rgb);
86
+ lines.push(`pub const ${constant}: ${ty} = ${expr};`);
87
+ } else if (leaf.type === "dimension" || leaf.type === "number") {
88
+ const n = dimension(leaf.value);
89
+ if (n === void 0) continue;
90
+ lines.push(`pub const ${constant}: f32 = ${f32lit(n)};`);
91
+ }
92
+ }
93
+ return `${lines.join("\n")}\n`;
94
+ }
95
+ /**
96
+ * Emit Rust constants for a named theme (using the vendored `@pantoken/tokens` IR).
97
+ *
98
+ * @example
99
+ * ```ts
100
+ * import { writeFileSync } from "node:fs";
101
+ * import { generateRust } from "@pantoken/rust";
102
+ *
103
+ * writeFileSync("tokens.rs", generateRust({ format: "egui", theme: "rebrand" }));
104
+ * ```
105
+ */
106
+ function generateRust(options = {}) {
107
+ return toRust(byTheme(options.theme ?? "rebrand"), options);
108
+ }
109
+ //#endregion
110
+ export { generateRust as default, generateRust, toRust };
package/package.json ADDED
@@ -0,0 +1,35 @@
1
+ {
2
+ "name": "@pantoken/rust",
3
+ "version": "0.1.0",
4
+ "description": "Emit Instructure design tokens as Rust constants for egui (Color32) or iced (Color).",
5
+ "license": "MIT",
6
+ "files": [
7
+ "dist"
8
+ ],
9
+ "type": "module",
10
+ "exports": {
11
+ ".": "./dist/index.mjs",
12
+ "./package.json": "./package.json"
13
+ },
14
+ "publishConfig": {
15
+ "access": "public"
16
+ },
17
+ "dependencies": {
18
+ "@pantoken/core": "0.1.0",
19
+ "@pantoken/model": "0.1.0",
20
+ "@pantoken/tokens": "0.1.0",
21
+ "@pantoken/utils": "0.1.0"
22
+ },
23
+ "devDependencies": {
24
+ "@types/node": "^24.13.3",
25
+ "typescript": "^6.0.3",
26
+ "vite": "npm:@voidzero-dev/vite-plus-core@0.2.4",
27
+ "vite-plus": "0.2.4"
28
+ },
29
+ "scripts": {
30
+ "build": "vp pack",
31
+ "dev": "vp pack --watch",
32
+ "test": "vp test",
33
+ "check": "vp check"
34
+ }
35
+ }