@gtcx/theme 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.
@@ -0,0 +1,40 @@
1
+ /**
2
+ * @module config-provider
3
+ *
4
+ * Root provider for GTCX theming. Wraps Ant Design's `ConfigProvider` with
5
+ * GTCX tokens and ensures all descendants receive the correct theme.
6
+ *
7
+ * Per ADR-0002: All styling flows from GTCX tokens via ConfigProvider.
8
+ * Platform apps should wrap their root with this provider.
9
+ */
10
+ import { ConfigProvider } from 'antd';
11
+ import React from 'react';
12
+ import { type ThemeMode, type ThemeDensity, type TokensOverride } from './create-theme';
13
+ export interface GtcxConfigProviderProps {
14
+ /** Light or dark mode. Defaults to `'light'`. */
15
+ mode?: ThemeMode;
16
+ /** Comfortable or compact density. Defaults to `'comfortable'`. */
17
+ density?: ThemeDensity;
18
+ /** Deep-merged token overrides. Must be a stable reference or memoized. */
19
+ tokensOverride?: TokensOverride;
20
+ /** Layout direction. Defaults to `'ltr'`. */
21
+ direction?: 'ltr' | 'rtl';
22
+ /** Ant Design locale object for i18n. */
23
+ locale?: React.ComponentProps<typeof ConfigProvider>['locale'];
24
+ children: React.ReactNode;
25
+ }
26
+ /**
27
+ * Root GTCX theme provider.
28
+ *
29
+ * @example
30
+ * ```tsx
31
+ * <GtcxConfigProvider mode="dark" density="compact">
32
+ * <App />
33
+ * </GtcxConfigProvider>
34
+ * ```
35
+ */
36
+ export declare function GtcxConfigProvider({ mode, density, tokensOverride, direction, locale, children, }: GtcxConfigProviderProps): React.ReactElement;
37
+ export declare namespace GtcxConfigProvider {
38
+ var displayName: string;
39
+ }
40
+ //# sourceMappingURL=config-provider.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config-provider.d.ts","sourceRoot":"","sources":["../src/config-provider.tsx"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAE,cAAc,EAAO,MAAM,MAAM,CAAC;AAC3C,OAAO,KAAyC,MAAM,OAAO,CAAC;AAE9D,OAAO,EAEL,KAAK,SAAS,EACd,KAAK,YAAY,EACjB,KAAK,cAAc,EACpB,MAAM,gBAAgB,CAAC;AAExB,MAAM,WAAW,uBAAuB;IACtC,iDAAiD;IACjD,IAAI,CAAC,EAAE,SAAS,CAAC;IACjB,mEAAmE;IACnE,OAAO,CAAC,EAAE,YAAY,CAAC;IACvB,2EAA2E;IAC3E,cAAc,CAAC,EAAE,cAAc,CAAC;IAChC,6CAA6C;IAC7C,SAAS,CAAC,EAAE,KAAK,GAAG,KAAK,CAAC;IAC1B,yCAAyC;IACzC,MAAM,CAAC,EAAE,KAAK,CAAC,cAAc,CAAC,OAAO,cAAc,CAAC,CAAC,QAAQ,CAAC,CAAC;IAC/D,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC;CAC3B;AAED;;;;;;;;;GASG;AACH,wBAAgB,kBAAkB,CAAC,EACjC,IAAc,EACd,OAAuB,EACvB,cAAc,EACd,SAAiB,EACjB,MAAM,EACN,QAAQ,GACT,EAAE,uBAAuB,GAAG,KAAK,CAAC,YAAY,CA2B9C;yBAlCe,kBAAkB"}
@@ -0,0 +1,61 @@
1
+ /**
2
+ * @module create-theme
3
+ *
4
+ * Creates Ant Design v5 {@link ThemeConfig} objects from GTCX semantic tokens.
5
+ * This is the single bridge between the GTCX token system and Ant Design's
6
+ * theming engine.
7
+ *
8
+ * Key design decisions:
9
+ * - Deep merges `tokensOverride` so nested objects (like `colors.primary`)
10
+ * don't blow away sibling keys.
11
+ * - Maps ~80% of Ant Design's seed, alias, and component tokens.
12
+ * - Supports light/dark modes via `theme.darkAlgorithm`.
13
+ * - Supports compact density via `theme.compactAlgorithm`.
14
+ */
15
+ import { type SemanticColors, type SemanticSpacing, type SemanticTypography, type SemanticRadii, type SemanticShadows, type SemanticLayout } from '@gtcx/tokens';
16
+ import type { ThemeConfig } from 'antd';
17
+ export type ThemeMode = 'light' | 'dark';
18
+ export type ThemeDensity = 'comfortable' | 'compact';
19
+ type Widen<T> = T extends string ? string : T extends number ? number : T extends boolean ? boolean : T;
20
+ type DeepPartial<T> = {
21
+ [K in keyof T]?: T[K] extends object ? DeepPartial<T[K]> : Widen<T[K]>;
22
+ };
23
+ export interface TokensOverride {
24
+ colors?: DeepPartial<SemanticColors>;
25
+ spacing?: DeepPartial<SemanticSpacing>;
26
+ typography?: DeepPartial<SemanticTypography>;
27
+ radii?: DeepPartial<SemanticRadii>;
28
+ shadows?: DeepPartial<SemanticShadows>;
29
+ layout?: DeepPartial<SemanticLayout>;
30
+ }
31
+ export interface CreateAntdThemeOptions {
32
+ /** Light or dark mode. Defaults to `'light'`. */
33
+ mode?: ThemeMode;
34
+ /** Comfortable (default) or compact density. */
35
+ density?: ThemeDensity;
36
+ /** Deep-merged overrides for semantic tokens. */
37
+ tokensOverride?: TokensOverride;
38
+ }
39
+ /**
40
+ * Creates an Ant Design {@link ThemeConfig} from GTCX semantic tokens.
41
+ *
42
+ * @example
43
+ * ```ts
44
+ * // Light mode (default)
45
+ * const theme = createAntdTheme();
46
+ *
47
+ * // Dark mode
48
+ * const dark = createAntdTheme({ mode: 'dark' });
49
+ *
50
+ * // Compact density
51
+ * const compact = createAntdTheme({ density: 'compact' });
52
+ *
53
+ * // Override specific tokens without losing siblings
54
+ * const custom = createAntdTheme({
55
+ * tokensOverride: { colors: { primary: '#ff0000' } },
56
+ * });
57
+ * ```
58
+ */
59
+ export declare function createAntdTheme(options?: CreateAntdThemeOptions): ThemeConfig;
60
+ export {};
61
+ //# sourceMappingURL=create-theme.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"create-theme.d.ts","sourceRoot":"","sources":["../src/create-theme.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,EAWL,KAAK,cAAc,EACnB,KAAK,eAAe,EACpB,KAAK,kBAAkB,EACvB,KAAK,aAAa,EAClB,KAAK,eAAe,EACpB,KAAK,cAAc,EACpB,MAAM,cAAc,CAAC;AAEtB,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,MAAM,CAAC;AAMxC,MAAM,MAAM,SAAS,GAAG,OAAO,GAAG,MAAM,CAAC;AACzC,MAAM,MAAM,YAAY,GAAG,aAAa,GAAG,SAAS,CAAC;AAErD,KAAK,KAAK,CAAC,CAAC,IAAI,CAAC,SAAS,MAAM,GAC5B,MAAM,GACN,CAAC,SAAS,MAAM,GACd,MAAM,GACN,CAAC,SAAS,OAAO,GACf,OAAO,GACP,CAAC,CAAC;AACV,KAAK,WAAW,CAAC,CAAC,IAAI;KACnB,CAAC,IAAI,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,SAAS,MAAM,GAAG,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;CACvE,CAAC;AAEF,MAAM,WAAW,cAAc;IAC7B,MAAM,CAAC,EAAE,WAAW,CAAC,cAAc,CAAC,CAAC;IACrC,OAAO,CAAC,EAAE,WAAW,CAAC,eAAe,CAAC,CAAC;IACvC,UAAU,CAAC,EAAE,WAAW,CAAC,kBAAkB,CAAC,CAAC;IAC7C,KAAK,CAAC,EAAE,WAAW,CAAC,aAAa,CAAC,CAAC;IACnC,OAAO,CAAC,EAAE,WAAW,CAAC,eAAe,CAAC,CAAC;IACvC,MAAM,CAAC,EAAE,WAAW,CAAC,cAAc,CAAC,CAAC;CACtC;AAED,MAAM,WAAW,sBAAsB;IACrC,iDAAiD;IACjD,IAAI,CAAC,EAAE,SAAS,CAAC;IACjB,gDAAgD;IAChD,OAAO,CAAC,EAAE,YAAY,CAAC;IACvB,iDAAiD;IACjD,cAAc,CAAC,EAAE,cAAc,CAAC;CACjC;AAsDD;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAgB,eAAe,CAAC,OAAO,GAAE,sBAA2B,GAAG,WAAW,CA6LjF"}
package/dist/index.cjs ADDED
@@ -0,0 +1,167 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/index.ts
21
+ var index_exports = {};
22
+ __export(index_exports, {
23
+ GtcxConfigProvider: () => GtcxConfigProvider,
24
+ createAntdTheme: () => createAntdTheme,
25
+ getAntThemeForPlatform: () => getAntThemeForPlatform,
26
+ getPlatformTheme: () => getPlatformTheme,
27
+ platformThemes: () => platformThemes
28
+ });
29
+ module.exports = __toCommonJS(index_exports);
30
+
31
+ // src/createAntdTheme.ts
32
+ var import_tokens = require("@gtcx/tokens");
33
+ function createAntdTheme(options = {}) {
34
+ const { mode = "light" } = options;
35
+ const tokens = { ...import_tokens.semanticTokens, ...options.tokensOverride };
36
+ const baseTheme = {
37
+ token: {
38
+ colorPrimary: tokens.colors.primary,
39
+ colorSuccess: tokens.colors.success,
40
+ colorWarning: tokens.colors.warning,
41
+ colorError: tokens.colors.error,
42
+ colorInfo: tokens.colors.info,
43
+ colorLink: tokens.colors.link,
44
+ colorLinkHover: tokens.colors.linkHover,
45
+ colorText: tokens.colors.textPrimary,
46
+ colorTextSecondary: tokens.colors.textSecondary,
47
+ colorTextTertiary: tokens.colors.textMuted,
48
+ colorBgContainer: tokens.colors.bgSurface,
49
+ colorBgLayout: tokens.colors.bgPage,
50
+ colorBorder: tokens.colors.border,
51
+ colorBorderSecondary: tokens.colors.borderLight,
52
+ borderRadius: tokens.radii.component,
53
+ fontFamily: tokens.typography.fontFamily,
54
+ fontFamilyCode: tokens.typography.fontFamilyCode,
55
+ fontSize: tokens.typography.body.md.fontSize,
56
+ lineHeight: tokens.typography.body.md.lineHeight,
57
+ boxShadow: tokens.shadows.card,
58
+ boxShadowSecondary: tokens.shadows.dropdown
59
+ },
60
+ components: {
61
+ Layout: {
62
+ headerBg: tokens.colors.bgHeader,
63
+ headerHeight: tokens.layout.headerHeight,
64
+ siderBg: tokens.colors.bgSidebar,
65
+ bodyBg: tokens.colors.bgPage
66
+ },
67
+ Menu: {
68
+ itemBg: "transparent",
69
+ itemSelectedBg: tokens.colors.primaryBg,
70
+ itemSelectedColor: tokens.colors.primary,
71
+ itemHoverBg: tokens.colors.bgSurfaceHover,
72
+ itemHeight: 36,
73
+ itemMarginInline: 8,
74
+ itemPaddingInline: 12,
75
+ itemBorderRadius: 6,
76
+ groupTitleColor: tokens.colors.textMuted,
77
+ groupTitleFontSize: 11,
78
+ groupTitleLineHeight: 16
79
+ },
80
+ Button: {
81
+ borderRadius: tokens.radii.button
82
+ },
83
+ Card: {
84
+ borderRadiusLG: tokens.radii.card
85
+ },
86
+ Input: {
87
+ borderRadius: tokens.radii.input
88
+ }
89
+ }
90
+ };
91
+ if (mode === "dark") {
92
+ return {
93
+ ...baseTheme,
94
+ algorithm: void 0
95
+ // TODO: implement dark mode algorithm
96
+ };
97
+ }
98
+ return baseTheme;
99
+ }
100
+
101
+ // src/GtcxConfigProvider.tsx
102
+ var import_react = require("react");
103
+ var import_antd = require("antd");
104
+ var import_jsx_runtime = require("react/jsx-runtime");
105
+ function GtcxConfigProvider({
106
+ mode = "light",
107
+ tokensOverride,
108
+ direction = "ltr",
109
+ children
110
+ }) {
111
+ const theme = (0, import_react.useMemo)(
112
+ () => createAntdTheme({ mode, tokensOverride }),
113
+ [mode, tokensOverride]
114
+ );
115
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_antd.ConfigProvider, { theme, direction, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_antd.App, { children }) });
116
+ }
117
+
118
+ // src/platform-themes.ts
119
+ var import_tokens2 = require("@gtcx/tokens");
120
+ var platformThemes = {
121
+ crx: {
122
+ platform: "crx",
123
+ colors: import_tokens2.platformColors.crx,
124
+ spacing: import_tokens2.platformSpacing.crx
125
+ },
126
+ sgx: {
127
+ platform: "sgx",
128
+ colors: import_tokens2.platformColors.sgx,
129
+ spacing: import_tokens2.platformSpacing.sgx
130
+ },
131
+ agx: {
132
+ platform: "agx",
133
+ colors: import_tokens2.platformColors.agx,
134
+ spacing: import_tokens2.platformSpacing.agx
135
+ }
136
+ };
137
+ var getPlatformTheme = (platform) => platformThemes[platform];
138
+ function getAntThemeForPlatform(platform) {
139
+ const theme = platformThemes[platform];
140
+ return {
141
+ token: {
142
+ colorPrimary: theme.colors.primary,
143
+ colorInfo: import_tokens2.colorPrimitives.info[500],
144
+ colorSuccess: import_tokens2.colorPrimitives.success[500],
145
+ colorWarning: import_tokens2.colorPrimitives.warning[500],
146
+ colorError: import_tokens2.colorPrimitives.error[500],
147
+ borderRadius: 8,
148
+ fontFamily: "Inter, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif"
149
+ },
150
+ components: {
151
+ Button: {
152
+ paddingInline: theme.spacing.basePadding
153
+ },
154
+ Card: {
155
+ paddingLG: theme.spacing.basePadding + 8
156
+ }
157
+ }
158
+ };
159
+ }
160
+ // Annotate the CommonJS export names for ESM import in node:
161
+ 0 && (module.exports = {
162
+ GtcxConfigProvider,
163
+ createAntdTheme,
164
+ getAntThemeForPlatform,
165
+ getPlatformTheme,
166
+ platformThemes
167
+ });
@@ -0,0 +1,58 @@
1
+ import { ThemeConfig } from 'antd';
2
+ import { semanticTokens, Platform } from '@gtcx/tokens';
3
+ export { Platform } from '@gtcx/tokens';
4
+ import * as react_jsx_runtime from 'react/jsx-runtime';
5
+ import React from 'react';
6
+
7
+ type ThemeMode = 'light' | 'dark';
8
+ interface CreateAntdThemeOptions {
9
+ mode?: ThemeMode;
10
+ tokensOverride?: Partial<typeof semanticTokens>;
11
+ }
12
+ /**
13
+ * Creates an Ant Design theme config from GTCX semantic tokens.
14
+ * Follows ADR-0002: use ConfigProvider as primary customization mechanism.
15
+ */
16
+ declare function createAntdTheme(options?: CreateAntdThemeOptions): ThemeConfig;
17
+
18
+ interface GtcxConfigProviderProps {
19
+ mode?: ThemeMode;
20
+ tokensOverride?: Partial<typeof semanticTokens>;
21
+ direction?: 'ltr' | 'rtl';
22
+ children: React.ReactNode;
23
+ }
24
+ /**
25
+ * Root provider for GTCX theming.
26
+ * Wraps Ant Design ConfigProvider with GTCX tokens.
27
+ *
28
+ * Per ADR-0002: All styling flows from GTCX tokens via ConfigProvider.
29
+ * Platform apps should wrap their root with this provider.
30
+ */
31
+ declare function GtcxConfigProvider({ mode, tokensOverride, direction, children, }: GtcxConfigProviderProps): react_jsx_runtime.JSX.Element;
32
+
33
+ /**
34
+ * Platform-specific Ant Design theme generators for CRX, SGX, and AGX.
35
+ */
36
+
37
+ interface PlatformTheme {
38
+ platform: Platform;
39
+ colors: {
40
+ primary: string;
41
+ secondary: string;
42
+ accent: string;
43
+ gradient: string;
44
+ };
45
+ spacing: {
46
+ density: string;
47
+ basePadding: number;
48
+ baseGap: number;
49
+ };
50
+ }
51
+ declare const platformThemes: Record<Platform, PlatformTheme>;
52
+ declare const getPlatformTheme: (platform: Platform) => PlatformTheme;
53
+ /**
54
+ * Generate an Ant Design theme config for a specific platform.
55
+ */
56
+ declare function getAntThemeForPlatform(platform: Platform): ThemeConfig;
57
+
58
+ export { type CreateAntdThemeOptions, GtcxConfigProvider, type GtcxConfigProviderProps, type PlatformTheme, type ThemeMode, createAntdTheme, getAntThemeForPlatform, getPlatformTheme, platformThemes };
@@ -0,0 +1,6 @@
1
+ export { createAntdTheme } from './create-theme';
2
+ export type { ThemeMode, ThemeDensity, CreateAntdThemeOptions, TokensOverride, } from './create-theme';
3
+ export { GtcxConfigProvider } from './config-provider';
4
+ export type { GtcxConfigProviderProps } from './config-provider';
5
+ export { useGtcxTheme } from './use-gtcx-theme';
6
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AACjD,YAAY,EACV,SAAS,EACT,YAAY,EACZ,sBAAsB,EACtB,cAAc,GACf,MAAM,gBAAgB,CAAC;AAExB,OAAO,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AACvD,YAAY,EAAE,uBAAuB,EAAE,MAAM,mBAAmB,CAAC;AAEjE,OAAO,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,228 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/index.ts
21
+ var index_exports = {};
22
+ __export(index_exports, {
23
+ GtcxConfigProvider: () => GtcxConfigProvider,
24
+ createAntdTheme: () => createAntdTheme,
25
+ useGtcxTheme: () => useGtcxTheme
26
+ });
27
+ module.exports = __toCommonJS(index_exports);
28
+
29
+ // src/create-theme.ts
30
+ var import_tokens = require("@gtcx/tokens");
31
+ var import_antd = require("antd");
32
+ function deepMerge(base, override) {
33
+ if (typeof base !== "object" || base === null || typeof override !== "object" || override === null) {
34
+ return override ?? base;
35
+ }
36
+ const result = { ...base };
37
+ for (const key of Object.keys(override)) {
38
+ const overrideVal = override[key];
39
+ const baseVal = base[key];
40
+ if (overrideVal !== null && overrideVal !== void 0 && typeof overrideVal === "object" && !Array.isArray(overrideVal) && typeof baseVal === "object" && baseVal !== null && !Array.isArray(baseVal)) {
41
+ result[key] = deepMerge(baseVal, overrideVal);
42
+ } else if (overrideVal !== void 0) {
43
+ result[key] = overrideVal;
44
+ }
45
+ }
46
+ return result;
47
+ }
48
+ function createAntdTheme(options = {}) {
49
+ const { mode = "light", density = "comfortable" } = options;
50
+ const base = {
51
+ colors: { ...import_tokens.semanticColors },
52
+ spacing: { ...import_tokens.semanticSpacing },
53
+ typography: { ...import_tokens.semanticTypography },
54
+ radii: { ...import_tokens.semanticRadii },
55
+ shadows: { ...import_tokens.semanticShadows },
56
+ layout: { ...import_tokens.semanticLayout }
57
+ };
58
+ const tokens = options.tokensOverride ? {
59
+ colors: options.tokensOverride.colors ? deepMerge(base.colors, options.tokensOverride.colors) : base.colors,
60
+ spacing: options.tokensOverride.spacing ? deepMerge(base.spacing, options.tokensOverride.spacing) : base.spacing,
61
+ typography: options.tokensOverride.typography ? deepMerge(base.typography, options.tokensOverride.typography) : base.typography,
62
+ radii: options.tokensOverride.radii ? deepMerge(base.radii, options.tokensOverride.radii) : base.radii,
63
+ shadows: options.tokensOverride.shadows ? deepMerge(base.shadows, options.tokensOverride.shadows) : base.shadows,
64
+ layout: options.tokensOverride.layout ? deepMerge(base.layout, options.tokensOverride.layout) : base.layout
65
+ } : base;
66
+ const colors = mode === "dark" ? { ...tokens.colors, ...import_tokens.darkSemanticColors } : tokens.colors;
67
+ const algorithms = [];
68
+ if (mode === "dark") {
69
+ algorithms.push(import_antd.theme.darkAlgorithm);
70
+ }
71
+ if (density === "compact") {
72
+ algorithms.push(import_antd.theme.compactAlgorithm);
73
+ }
74
+ const config = {
75
+ // Algorithm
76
+ ...algorithms.length === 1 ? { algorithm: algorithms[0] } : algorithms.length > 1 ? { algorithm: algorithms } : {},
77
+ // Seed + alias tokens
78
+ token: {
79
+ // Colors — seed
80
+ colorPrimary: colors.primary,
81
+ colorSuccess: colors.success,
82
+ colorWarning: colors.warning,
83
+ colorError: colors.error,
84
+ colorInfo: colors.info,
85
+ colorLink: colors.link,
86
+ colorLinkHover: colors.linkHover,
87
+ // Colors — text
88
+ colorText: colors.textPrimary,
89
+ colorTextSecondary: colors.textSecondary,
90
+ colorTextTertiary: colors.textTertiary,
91
+ colorTextQuaternary: colors.textMuted,
92
+ // Colors — backgrounds
93
+ colorBgBase: colors.bgPage,
94
+ colorBgContainer: colors.bgSurface,
95
+ colorBgLayout: colors.bgPage,
96
+ colorBgElevated: colors.bgSurface,
97
+ // Colors — borders
98
+ colorBorder: colors.border,
99
+ colorBorderSecondary: colors.borderLight,
100
+ // Typography
101
+ fontFamily: tokens.typography.fontFamily,
102
+ fontFamilyCode: tokens.typography.fontFamilyCode,
103
+ fontSize: tokens.typography.body.md.fontSize,
104
+ lineHeight: tokens.typography.body.md.lineHeight,
105
+ // Border radius — seed
106
+ borderRadius: tokens.radii.component,
107
+ // Shadows
108
+ boxShadow: tokens.shadows.card,
109
+ boxShadowSecondary: tokens.shadows.dropdown,
110
+ boxShadowTertiary: tokens.shadows.modal,
111
+ // Focus
112
+ controlOutlineWidth: import_tokens.focusPrimitives.ringWidth,
113
+ // Opacity
114
+ opacityLoading: import_tokens.opacityPrimitives.loading,
115
+ // Spacing — Ant Design seed tokens
116
+ sizeUnit: 4,
117
+ sizeStep: 4,
118
+ // Motion
119
+ motionUnit: 0.1,
120
+ // Z-index
121
+ zIndexBase: 0,
122
+ zIndexPopupBase: 1e3,
123
+ // Control height
124
+ controlHeight: 36
125
+ },
126
+ // Component-level token overrides
127
+ components: {
128
+ Layout: {
129
+ headerBg: colors.bgHeader,
130
+ headerHeight: tokens.layout.headerHeight,
131
+ siderBg: colors.bgSidebar,
132
+ bodyBg: colors.bgPage
133
+ },
134
+ Menu: {
135
+ itemBg: "transparent",
136
+ itemSelectedBg: colors.primaryBg,
137
+ itemSelectedColor: colors.primary,
138
+ itemHoverBg: colors.bgSurfaceHover,
139
+ itemHeight: 36,
140
+ itemMarginInline: 8,
141
+ itemPaddingInline: 12,
142
+ itemBorderRadius: import_tokens.borderRadiusPrimitives.md,
143
+ groupTitleColor: colors.textMuted,
144
+ groupTitleFontSize: tokens.typography.caption.fontSize - 1,
145
+ groupTitleLineHeight: 16
146
+ },
147
+ Button: {
148
+ borderRadius: tokens.radii.button,
149
+ paddingInline: tokens.spacing.component.button.paddingX,
150
+ fontWeight: tokens.typography.button.md.fontWeight
151
+ },
152
+ Card: {
153
+ borderRadiusLG: tokens.radii.card,
154
+ paddingLG: tokens.spacing.component.card.padding
155
+ },
156
+ Input: {
157
+ borderRadius: tokens.radii.input,
158
+ paddingInline: tokens.spacing.component.input.paddingX
159
+ },
160
+ Table: {
161
+ cellPaddingBlock: tokens.spacing.component.table.cellPadding,
162
+ cellPaddingInline: tokens.spacing.component.table.cellPadding,
163
+ headerBg: colors.bgSurfaceHover,
164
+ headerColor: colors.textSecondary,
165
+ borderColor: colors.borderLight,
166
+ rowHoverBg: colors.bgSurfaceHover
167
+ },
168
+ Modal: {
169
+ paddingLG: tokens.spacing.component.modal.padding,
170
+ borderRadiusLG: tokens.radii.card
171
+ },
172
+ Form: {
173
+ itemMarginBottom: tokens.spacing.component.form.fieldGap,
174
+ labelFontSize: tokens.typography.body.sm.fontSize
175
+ },
176
+ Typography: {
177
+ fontFamilyCode: tokens.typography.fontFamilyCode
178
+ },
179
+ Tag: {
180
+ borderRadiusSM: tokens.radii.tag
181
+ }
182
+ }
183
+ };
184
+ return config;
185
+ }
186
+
187
+ // src/config-provider.tsx
188
+ var import_antd2 = require("antd");
189
+ var import_react = require("react");
190
+ function GtcxConfigProvider({
191
+ mode = "light",
192
+ density = "comfortable",
193
+ tokensOverride,
194
+ direction = "ltr",
195
+ locale,
196
+ children
197
+ }) {
198
+ const overrideRef = (0, import_react.useRef)(tokensOverride);
199
+ const overrideJson = JSON.stringify(tokensOverride);
200
+ const prevJson = (0, import_react.useRef)(overrideJson);
201
+ if (overrideJson !== prevJson.current) {
202
+ overrideRef.current = tokensOverride;
203
+ prevJson.current = overrideJson;
204
+ }
205
+ const theme = (0, import_react.useMemo)(
206
+ () => createAntdTheme({ mode, density, tokensOverride: overrideRef.current }),
207
+ [mode, density, overrideJson]
208
+ );
209
+ return (0, import_react.createElement)(
210
+ import_antd2.ConfigProvider,
211
+ { theme, direction, locale },
212
+ (0, import_react.createElement)(import_antd2.App, null, children)
213
+ );
214
+ }
215
+ GtcxConfigProvider.displayName = "GtcxConfigProvider";
216
+
217
+ // src/use-gtcx-theme.ts
218
+ var import_antd3 = require("antd");
219
+ function useGtcxTheme() {
220
+ const { token } = import_antd3.theme.useToken();
221
+ return { token };
222
+ }
223
+ // Annotate the CommonJS export names for ESM import in node:
224
+ 0 && (module.exports = {
225
+ GtcxConfigProvider,
226
+ createAntdTheme,
227
+ useGtcxTheme
228
+ });
package/dist/index.mjs ADDED
@@ -0,0 +1,210 @@
1
+ // src/create-theme.ts
2
+ import {
3
+ semanticColors,
4
+ semanticSpacing,
5
+ semanticTypography,
6
+ semanticRadii,
7
+ semanticShadows,
8
+ semanticLayout,
9
+ darkSemanticColors,
10
+ borderRadiusPrimitives,
11
+ opacityPrimitives,
12
+ focusPrimitives
13
+ } from "@gtcx/tokens";
14
+ import { theme as antdTheme } from "antd";
15
+ function deepMerge(base, override) {
16
+ if (typeof base !== "object" || base === null || typeof override !== "object" || override === null) {
17
+ return override ?? base;
18
+ }
19
+ const result = { ...base };
20
+ for (const key of Object.keys(override)) {
21
+ const overrideVal = override[key];
22
+ const baseVal = base[key];
23
+ if (overrideVal !== null && overrideVal !== void 0 && typeof overrideVal === "object" && !Array.isArray(overrideVal) && typeof baseVal === "object" && baseVal !== null && !Array.isArray(baseVal)) {
24
+ result[key] = deepMerge(baseVal, overrideVal);
25
+ } else if (overrideVal !== void 0) {
26
+ result[key] = overrideVal;
27
+ }
28
+ }
29
+ return result;
30
+ }
31
+ function createAntdTheme(options = {}) {
32
+ const { mode = "light", density = "comfortable" } = options;
33
+ const base = {
34
+ colors: { ...semanticColors },
35
+ spacing: { ...semanticSpacing },
36
+ typography: { ...semanticTypography },
37
+ radii: { ...semanticRadii },
38
+ shadows: { ...semanticShadows },
39
+ layout: { ...semanticLayout }
40
+ };
41
+ const tokens = options.tokensOverride ? {
42
+ colors: options.tokensOverride.colors ? deepMerge(base.colors, options.tokensOverride.colors) : base.colors,
43
+ spacing: options.tokensOverride.spacing ? deepMerge(base.spacing, options.tokensOverride.spacing) : base.spacing,
44
+ typography: options.tokensOverride.typography ? deepMerge(base.typography, options.tokensOverride.typography) : base.typography,
45
+ radii: options.tokensOverride.radii ? deepMerge(base.radii, options.tokensOverride.radii) : base.radii,
46
+ shadows: options.tokensOverride.shadows ? deepMerge(base.shadows, options.tokensOverride.shadows) : base.shadows,
47
+ layout: options.tokensOverride.layout ? deepMerge(base.layout, options.tokensOverride.layout) : base.layout
48
+ } : base;
49
+ const colors = mode === "dark" ? { ...tokens.colors, ...darkSemanticColors } : tokens.colors;
50
+ const algorithms = [];
51
+ if (mode === "dark") {
52
+ algorithms.push(antdTheme.darkAlgorithm);
53
+ }
54
+ if (density === "compact") {
55
+ algorithms.push(antdTheme.compactAlgorithm);
56
+ }
57
+ const config = {
58
+ // Algorithm
59
+ ...algorithms.length === 1 ? { algorithm: algorithms[0] } : algorithms.length > 1 ? { algorithm: algorithms } : {},
60
+ // Seed + alias tokens
61
+ token: {
62
+ // Colors — seed
63
+ colorPrimary: colors.primary,
64
+ colorSuccess: colors.success,
65
+ colorWarning: colors.warning,
66
+ colorError: colors.error,
67
+ colorInfo: colors.info,
68
+ colorLink: colors.link,
69
+ colorLinkHover: colors.linkHover,
70
+ // Colors — text
71
+ colorText: colors.textPrimary,
72
+ colorTextSecondary: colors.textSecondary,
73
+ colorTextTertiary: colors.textTertiary,
74
+ colorTextQuaternary: colors.textMuted,
75
+ // Colors — backgrounds
76
+ colorBgBase: colors.bgPage,
77
+ colorBgContainer: colors.bgSurface,
78
+ colorBgLayout: colors.bgPage,
79
+ colorBgElevated: colors.bgSurface,
80
+ // Colors — borders
81
+ colorBorder: colors.border,
82
+ colorBorderSecondary: colors.borderLight,
83
+ // Typography
84
+ fontFamily: tokens.typography.fontFamily,
85
+ fontFamilyCode: tokens.typography.fontFamilyCode,
86
+ fontSize: tokens.typography.body.md.fontSize,
87
+ lineHeight: tokens.typography.body.md.lineHeight,
88
+ // Border radius — seed
89
+ borderRadius: tokens.radii.component,
90
+ // Shadows
91
+ boxShadow: tokens.shadows.card,
92
+ boxShadowSecondary: tokens.shadows.dropdown,
93
+ boxShadowTertiary: tokens.shadows.modal,
94
+ // Focus
95
+ controlOutlineWidth: focusPrimitives.ringWidth,
96
+ // Opacity
97
+ opacityLoading: opacityPrimitives.loading,
98
+ // Spacing — Ant Design seed tokens
99
+ sizeUnit: 4,
100
+ sizeStep: 4,
101
+ // Motion
102
+ motionUnit: 0.1,
103
+ // Z-index
104
+ zIndexBase: 0,
105
+ zIndexPopupBase: 1e3,
106
+ // Control height
107
+ controlHeight: 36
108
+ },
109
+ // Component-level token overrides
110
+ components: {
111
+ Layout: {
112
+ headerBg: colors.bgHeader,
113
+ headerHeight: tokens.layout.headerHeight,
114
+ siderBg: colors.bgSidebar,
115
+ bodyBg: colors.bgPage
116
+ },
117
+ Menu: {
118
+ itemBg: "transparent",
119
+ itemSelectedBg: colors.primaryBg,
120
+ itemSelectedColor: colors.primary,
121
+ itemHoverBg: colors.bgSurfaceHover,
122
+ itemHeight: 36,
123
+ itemMarginInline: 8,
124
+ itemPaddingInline: 12,
125
+ itemBorderRadius: borderRadiusPrimitives.md,
126
+ groupTitleColor: colors.textMuted,
127
+ groupTitleFontSize: tokens.typography.caption.fontSize - 1,
128
+ groupTitleLineHeight: 16
129
+ },
130
+ Button: {
131
+ borderRadius: tokens.radii.button,
132
+ paddingInline: tokens.spacing.component.button.paddingX,
133
+ fontWeight: tokens.typography.button.md.fontWeight
134
+ },
135
+ Card: {
136
+ borderRadiusLG: tokens.radii.card,
137
+ paddingLG: tokens.spacing.component.card.padding
138
+ },
139
+ Input: {
140
+ borderRadius: tokens.radii.input,
141
+ paddingInline: tokens.spacing.component.input.paddingX
142
+ },
143
+ Table: {
144
+ cellPaddingBlock: tokens.spacing.component.table.cellPadding,
145
+ cellPaddingInline: tokens.spacing.component.table.cellPadding,
146
+ headerBg: colors.bgSurfaceHover,
147
+ headerColor: colors.textSecondary,
148
+ borderColor: colors.borderLight,
149
+ rowHoverBg: colors.bgSurfaceHover
150
+ },
151
+ Modal: {
152
+ paddingLG: tokens.spacing.component.modal.padding,
153
+ borderRadiusLG: tokens.radii.card
154
+ },
155
+ Form: {
156
+ itemMarginBottom: tokens.spacing.component.form.fieldGap,
157
+ labelFontSize: tokens.typography.body.sm.fontSize
158
+ },
159
+ Typography: {
160
+ fontFamilyCode: tokens.typography.fontFamilyCode
161
+ },
162
+ Tag: {
163
+ borderRadiusSM: tokens.radii.tag
164
+ }
165
+ }
166
+ };
167
+ return config;
168
+ }
169
+
170
+ // src/config-provider.tsx
171
+ import { ConfigProvider, App } from "antd";
172
+ import { useMemo, useRef, createElement } from "react";
173
+ function GtcxConfigProvider({
174
+ mode = "light",
175
+ density = "comfortable",
176
+ tokensOverride,
177
+ direction = "ltr",
178
+ locale,
179
+ children
180
+ }) {
181
+ const overrideRef = useRef(tokensOverride);
182
+ const overrideJson = JSON.stringify(tokensOverride);
183
+ const prevJson = useRef(overrideJson);
184
+ if (overrideJson !== prevJson.current) {
185
+ overrideRef.current = tokensOverride;
186
+ prevJson.current = overrideJson;
187
+ }
188
+ const theme = useMemo(
189
+ () => createAntdTheme({ mode, density, tokensOverride: overrideRef.current }),
190
+ [mode, density, overrideJson]
191
+ );
192
+ return createElement(
193
+ ConfigProvider,
194
+ { theme, direction, locale },
195
+ createElement(App, null, children)
196
+ );
197
+ }
198
+ GtcxConfigProvider.displayName = "GtcxConfigProvider";
199
+
200
+ // src/use-gtcx-theme.ts
201
+ import { theme as antdTheme2 } from "antd";
202
+ function useGtcxTheme() {
203
+ const { token } = antdTheme2.useToken();
204
+ return { token };
205
+ }
206
+ export {
207
+ GtcxConfigProvider,
208
+ createAntdTheme,
209
+ useGtcxTheme
210
+ };
@@ -0,0 +1,33 @@
1
+ /**
2
+ * @module platform-themes
3
+ *
4
+ * Pre-built theme configs for each GTCX exchange platform.
5
+ * These compose platform-specific token overrides with the base
6
+ * semantic theme to produce ready-to-use Ant Design ThemeConfig objects.
7
+ */
8
+ import { type Platform } from '@gtcx/tokens';
9
+ import type { ThemeConfig } from 'antd';
10
+ export interface PlatformTheme {
11
+ platform: Platform;
12
+ colors: {
13
+ primary: string;
14
+ secondary: string;
15
+ accent: string;
16
+ gradient: string;
17
+ };
18
+ spacing: {
19
+ density: string;
20
+ basePadding: number;
21
+ baseGap: number;
22
+ };
23
+ }
24
+ export declare const platformThemes: Record<Platform, PlatformTheme>;
25
+ /** Get the platform theme descriptor for a given platform. */
26
+ export declare const getPlatformTheme: (platform: Platform) => PlatformTheme;
27
+ /**
28
+ * Generate an Ant Design theme config for a specific platform.
29
+ *
30
+ * Uses semantic token references instead of hardcoded values.
31
+ */
32
+ export declare function getAntThemeForPlatform(platform: Platform): ThemeConfig;
33
+ //# sourceMappingURL=platform-themes.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"platform-themes.d.ts","sourceRoot":"","sources":["../src/platform-themes.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAML,KAAK,QAAQ,EACd,MAAM,cAAc,CAAC;AACtB,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,MAAM,CAAC;AAExC,MAAM,WAAW,aAAa;IAC5B,QAAQ,EAAE,QAAQ,CAAC;IACnB,MAAM,EAAE;QACN,OAAO,EAAE,MAAM,CAAC;QAChB,SAAS,EAAE,MAAM,CAAC;QAClB,MAAM,EAAE,MAAM,CAAC;QACf,QAAQ,EAAE,MAAM,CAAC;KAClB,CAAC;IACF,OAAO,EAAE;QACP,OAAO,EAAE,MAAM,CAAC;QAChB,WAAW,EAAE,MAAM,CAAC;QACpB,OAAO,EAAE,MAAM,CAAC;KACjB,CAAC;CACH;AAED,eAAO,MAAM,cAAc,EAAE,MAAM,CAAC,QAAQ,EAAE,aAAa,CAgB1D,CAAC;AAEF,8DAA8D;AAC9D,eAAO,MAAM,gBAAgB,GAAI,UAAU,QAAQ,KAAG,aAAyC,CAAC;AAEhG;;;;GAIG;AACH,wBAAgB,sBAAsB,CAAC,QAAQ,EAAE,QAAQ,GAAG,WAAW,CAqBtE"}
@@ -0,0 +1,23 @@
1
+ /**
2
+ * @module use-gtcx-theme
3
+ *
4
+ * React hook for accessing the resolved Ant Design theme token
5
+ * within the GTCX context. Thin wrapper around `antd`'s `theme.useToken()`.
6
+ */
7
+ import type { GlobalToken } from 'antd/es/theme/interface';
8
+ /**
9
+ * Access the resolved Ant Design theme token from the nearest
10
+ * `GtcxConfigProvider` (or `ConfigProvider`).
11
+ *
12
+ * @example
13
+ * ```tsx
14
+ * function MyComponent() {
15
+ * const { token } = useGtcxTheme();
16
+ * return <div style={{ color: token.colorPrimary }}>Themed</div>;
17
+ * }
18
+ * ```
19
+ */
20
+ export declare function useGtcxTheme(): {
21
+ token: GlobalToken;
22
+ };
23
+ //# sourceMappingURL=use-gtcx-theme.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"use-gtcx-theme.d.ts","sourceRoot":"","sources":["../src/use-gtcx-theme.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAC;AAE3D;;;;;;;;;;;GAWG;AACH,wBAAgB,YAAY,IAAI;IAAE,KAAK,EAAE,WAAW,CAAA;CAAE,CAGrD"}
package/package.json ADDED
@@ -0,0 +1,42 @@
1
+ {
2
+ "name": "@gtcx/theme",
3
+ "version": "0.1.0",
4
+ "description": "GTCX Ant Design theme integration — maps tokens to ThemeConfig, provides GtcxConfigProvider",
5
+ "main": "dist/index.cjs",
6
+ "module": "dist/index.js",
7
+ "types": "dist/index.d.ts",
8
+ "exports": {
9
+ ".": {
10
+ "types": "./dist/index.d.ts",
11
+ "import": "./dist/index.js",
12
+ "require": "./dist/index.cjs"
13
+ }
14
+ },
15
+ "sideEffects": false,
16
+ "scripts": {
17
+ "build": "tsup && tsc --emitDeclarationOnly --declaration --outDir dist",
18
+ "dev": "tsup src/index.ts --format esm,cjs --dts --watch",
19
+ "lint": "eslint src/",
20
+ "typecheck": "tsc --noEmit",
21
+ "test": "vitest run"
22
+ },
23
+ "dependencies": {
24
+ "@gtcx/tokens": "workspace:*",
25
+ "antd": "^5.12.0"
26
+ },
27
+ "peerDependencies": {
28
+ "react": "^18.0.0 || ^19.0.0"
29
+ },
30
+ "devDependencies": {
31
+ "@types/react": "^18.0.0",
32
+ "tsup": "^8.0.0",
33
+ "typescript": "^5.0.0"
34
+ },
35
+ "files": [
36
+ "dist",
37
+ "README.md"
38
+ ],
39
+ "publishConfig": {
40
+ "access": "public"
41
+ }
42
+ }