@gainsight-hub/design-tokens 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,305 @@
1
+ # @gainsight-hub/design-tokens
2
+
3
+ Design tokens for the Gainsight Community Hub — CSS custom properties, TypeScript constants, JSON, and a Tailwind v3 preset.
4
+
5
+ ## Install
6
+
7
+ ```bash
8
+ npm install @gainsight-hub/design-tokens
9
+ ```
10
+
11
+ ---
12
+
13
+ ## Quick start
14
+
15
+ Import `styles.css` once at your app entry point. That's it for most apps.
16
+
17
+ ```js
18
+ // main.js / main.ts
19
+ import "@gainsight-hub/design-tokens/styles.css";
20
+ ```
21
+
22
+ Then use tokens anywhere via CSS custom properties:
23
+
24
+ ```css
25
+ .button {
26
+ background: var(--color-action-primary-default);
27
+ color: var(--color-content-inverse);
28
+ border-radius: var(--button-radius);
29
+ }
30
+ ```
31
+
32
+ ---
33
+
34
+ ## CSS custom properties
35
+
36
+ ### Base (light theme)
37
+
38
+ Defines all tokens as CSS custom properties on `:root`. This is the default light theme.
39
+
40
+ ```js
41
+ import "@gainsight-hub/design-tokens/styles.css";
42
+ ```
43
+
44
+ ### All themes bundled
45
+
46
+ Includes the base tokens plus all theme overrides in a single file. Use this if you want to switch themes at runtime without loading additional stylesheets.
47
+
48
+ ```js
49
+ import "@gainsight-hub/design-tokens/themes.css";
50
+ ```
51
+
52
+ ### Individual themes
53
+
54
+ Load only the theme you need on top of `styles.css`:
55
+
56
+ ```js
57
+ import "@gainsight-hub/design-tokens/styles.css";
58
+ import "@gainsight-hub/design-tokens/themes/dark.css";
59
+ ```
60
+
61
+ Available themes:
62
+
63
+ | Import path | Description |
64
+ |---|---|
65
+ | `@gainsight-hub/design-tokens/themes/dark.css` | Gainsight dark mode |
66
+ | `@gainsight-hub/design-tokens/themes/legacy.css` | Legacy variable aliases |
67
+ | `@gainsight-hub/design-tokens/themes/mui.css` | Material UI overrides |
68
+ | `@gainsight-hub/design-tokens/themes/antd.css` | Ant Design overrides |
69
+ | `@gainsight-hub/design-tokens/themes/spectrum.css` | Adobe Spectrum overrides |
70
+
71
+ ### Theme switching at runtime
72
+
73
+ All CSS custom properties can be scoped and overridden at any level:
74
+
75
+ ```css
76
+ /* Scope to a data attribute */
77
+ [data-theme="dark"] {
78
+ --color-surface-page: #161618;
79
+ --color-content-default: #f4f5f7;
80
+ }
81
+
82
+ /* Scope to a tenant / white-label */
83
+ [data-tenant="acme"] {
84
+ --color-action-primary-default: #e63946;
85
+ --button-primary-background-default: #e63946;
86
+ }
87
+ ```
88
+
89
+ ---
90
+
91
+ ## TypeScript / JavaScript
92
+
93
+ Import typed token constants directly. All exports are fully typed via the bundled `tokens.d.ts`.
94
+
95
+ ```ts
96
+ import {
97
+ ColorActionPrimaryDefault,
98
+ ColorSurfacePage,
99
+ RadiusFull,
100
+ } from "@gainsight-hub/design-tokens";
101
+
102
+ // Use in JS logic — e.g. canvas drawing, charting libs
103
+ ctx.fillStyle = ColorActionPrimaryDefault; // "#0C66E4"
104
+ ```
105
+
106
+ ---
107
+
108
+ ## Tailwind v3
109
+
110
+ ### Step 1 — Import the CSS variables
111
+
112
+ The Tailwind preset generates utility classes that reference CSS custom properties. Import `styles.css` so those variables are defined on the page.
113
+
114
+ ```js
115
+ // main.js / main.ts
116
+ import "@gainsight-hub/design-tokens/styles.css";
117
+ ```
118
+
119
+ ### Step 2 — Add the preset to your Tailwind config
120
+
121
+ **ESM** (Vite, Next.js, modern setups):
122
+
123
+ ```js
124
+ // tailwind.config.js
125
+ import preset from "@gainsight-hub/design-tokens/tailwind";
126
+
127
+ export default {
128
+ content: ["./src/**/*.{html,js,ts,jsx,tsx}"],
129
+ presets: [preset],
130
+ };
131
+ ```
132
+
133
+ **CJS** (older Tailwind v3 configs):
134
+
135
+ ```js
136
+ // tailwind.config.cjs
137
+ const preset = require("@gainsight-hub/design-tokens/tailwind");
138
+
139
+ module.exports = {
140
+ content: ["./src/**/*.{html,js,ts,jsx,tsx}"],
141
+ presets: [preset],
142
+ };
143
+ ```
144
+
145
+ ### Step 3 — Use token-based utility classes
146
+
147
+ ```html
148
+ <!-- Colors -->
149
+ <div class="bg-action-primary text-content-inverse">Primary button</div>
150
+ <div class="bg-surface-default text-content-default">Card</div>
151
+ <div class="bg-status-success-bold text-content-inverse">Success badge</div>
152
+
153
+ <!-- Spacing -->
154
+ <div class="p-spacing-200 gap-spacing-100">Layout</div>
155
+
156
+ <!-- Border radius -->
157
+ <div class="rounded-radius-100">Small</div>
158
+ <div class="rounded-radius-full">Pill / avatar</div>
159
+
160
+ <!-- Typography -->
161
+ <p class="text-sm leading-normal font-medium">Body text</p>
162
+
163
+ <!-- Shadows -->
164
+ <div class="shadow-elevation-1">Raised card</div>
165
+ ```
166
+
167
+ Color token naming — the `-default` suffix collapses into the base class:
168
+
169
+ | Tailwind class | CSS variable |
170
+ |---|---|
171
+ | `bg-action-primary` | `var(--color-action-primary-default)` |
172
+ | `bg-action-primary-hover` | `var(--color-action-primary-hover)` |
173
+ | `bg-surface-page` | `var(--color-surface-page)` |
174
+ | `text-content-subtle` | `var(--color-content-subtle)` |
175
+ | `border-line-default` | `var(--color-line-default)` |
176
+
177
+ > **Why import both `styles.css` and the preset?**
178
+ > `styles.css` defines the CSS custom property values. The preset generates utility classes that reference those variables with `var(--token-name)`. The preset alone produces no colors — it needs the variables defined on the page. This separation enables runtime theming: change a CSS variable at any scope and every Tailwind class using that token updates automatically, with no rebuild.
179
+
180
+ ---
181
+
182
+ ## Component tokens (CSS Modules)
183
+
184
+ For component internals, use CSS Modules with `var()` directly:
185
+
186
+ ```css
187
+ /* Button.module.css */
188
+ .root {
189
+ background: var(--button-primary-background-default);
190
+ color: var(--button-primary-label-default);
191
+ border-radius: var(--button-radius);
192
+ padding: var(--space-100) var(--space-200);
193
+ }
194
+
195
+ .root:hover {
196
+ background: var(--button-primary-background-hover);
197
+ }
198
+ ```
199
+
200
+ ```tsx
201
+ // Button.tsx
202
+ import styles from "./Button.module.css";
203
+
204
+ export function Button({ children }: { children: React.ReactNode }) {
205
+ return <button className={styles.root}>{children}</button>;
206
+ }
207
+ ```
208
+
209
+ ---
210
+
211
+ ## JSON
212
+
213
+ Raw token values as nested JSON. Useful for tooling, build scripts, or non-web targets (e.g. React Native, Figma plugins).
214
+
215
+ ```js
216
+ import tokens from "@gainsight-hub/design-tokens/tokens.json" with { type: "json" };
217
+
218
+ const primary = tokens.color.action.primary.default.value; // "#0C66E4"
219
+ const gutter = tokens.space.layout.gutter.value; // "12px"
220
+ ```
221
+
222
+ ## Token catalog
223
+
224
+ Structured catalog with resolved values, descriptions, alias chains, and legacy mappings. Used by the design portal and design tooling.
225
+
226
+ ```js
227
+ import catalog from "@gainsight-hub/design-tokens/token-catalog.json" with { type: "json" };
228
+
229
+ // 224 tokens with cssVar, path, type, value, description, references, legacyMapping
230
+ catalog.all.forEach(token => console.log(token.cssVar, token.value));
231
+ ```
232
+
233
+ ## Runtime theme switching
234
+
235
+ Switch the active theme at runtime — no page reload required. `applyThemeConfig` lazy-loads the theme CSS on first use via `import.meta.url`, so only the themes you actually activate are fetched.
236
+
237
+ ```js
238
+ import "@gainsight-hub/design-tokens/styles.css"; // load base tokens first
239
+ import { applyThemeConfig } from "@gainsight-hub/design-tokens";
240
+
241
+ // Switch to dark mode
242
+ await applyThemeConfig("gainsight-dark");
243
+
244
+ // Dark mode + custom brand color override
245
+ await applyThemeConfig("gainsight-dark", { "--theme-brand-700": "#FF6600" });
246
+
247
+ // Restore default light theme
248
+ await applyThemeConfig("gainsight-light");
249
+ ```
250
+
251
+ Available theme IDs: `gainsight-light` (default), `dark`, `legacy`, `mui`, `antd`, `spectrum`.
252
+
253
+ ---
254
+
255
+ ## Available exports
256
+
257
+ | Import | Description |
258
+ |---|---|
259
+ | `@gainsight-hub/design-tokens` | `applyThemeConfig` + TypeScript/JS named constants |
260
+ | `@gainsight-hub/design-tokens/styles.css` | CSS custom properties — base light theme |
261
+ | `@gainsight-hub/design-tokens/themes.css` | CSS custom properties — all themes bundled |
262
+ | `@gainsight-hub/design-tokens/themes/*` | Individual theme overrides (load on top of `styles.css`) |
263
+ | `@gainsight-hub/design-tokens/tailwind` | Tailwind v3 preset (ESM + CJS) |
264
+ | `@gainsight-hub/design-tokens/tokens.json` | Nested JSON — raw token values |
265
+ | `@gainsight-hub/design-tokens/token-catalog.json` | Full catalog with resolved values, descriptions, alias chains |
266
+
267
+ ---
268
+
269
+ ## Package structure
270
+
271
+ ```
272
+ packages/design-tokens/
273
+ ├── src/ Token source files (Style Dictionary format)
274
+ │ ├── primitive/ Raw scales — color, space, radius, font, shadow
275
+ │ ├── semantic/ Semantic roles — action, surface, content, line, status
276
+ │ └── component/ Component tokens — button, card, feed, navigation, widget
277
+ ├── config/ Style Dictionary config and custom formats
278
+ │ └── themes/ Theme override definitions
279
+ ├── migration/ Legacy variable mapping tools
280
+ ├── build.js Build entry point
281
+ └── dist/ Published output (generated, do not edit)
282
+ ├── index.js Root entry — applyThemeConfig + token constants
283
+ ├── index.d.ts TypeScript declarations for root entry
284
+ ├── applyTheme.js Runtime theme switcher (lazy CSS loading)
285
+ ├── applyTheme.d.ts TypeScript declarations for applyThemeConfig
286
+ ├── tokens.js JS named constants
287
+ ├── tokens.d.ts TypeScript declarations for token constants
288
+ ├── styles.css CSS custom properties (base light theme)
289
+ ├── themes.css All themes combined (styles.css + all theme overrides)
290
+ ├── tokens.json Nested JSON
291
+ ├── token-catalog.json Full token catalog
292
+ ├── tailwind.preset.mjs Tailwind preset (ESM)
293
+ ├── tailwind.preset.cjs Tailwind preset (CJS)
294
+ └── themes/ Individual theme CSS files
295
+ ```
296
+
297
+ ## Building and publishing
298
+
299
+ ```bash
300
+ # Build from the monorepo root
301
+ turbo run build --filter=@gainsight-hub/design-tokens
302
+
303
+ # Publish
304
+ npm publish --access public -w packages/design-tokens
305
+ ```
@@ -0,0 +1,14 @@
1
+ // Auto-generated — do not edit manually.
2
+
3
+ /**
4
+ * Switches the active theme at runtime. Lazy-loads the theme CSS on first use.
5
+ * Import styles.css first to establish the default light theme.
6
+ *
7
+ * @param themeId Theme to activate ("gainsight-dark", "legacy", "theme-mui", …).
8
+ * Pass "gainsight-light" to restore the default.
9
+ * @param overrides Optional CSS variable overrides applied on top of the base theme.
10
+ */
11
+ export declare function applyThemeConfig(
12
+ themeId: string,
13
+ overrides?: Record<string, string>,
14
+ ): Promise<void>;
@@ -0,0 +1,66 @@
1
+ // Auto-generated — do not edit manually.
2
+ const THEME_CSS_URLS = {
3
+ "dark": new URL("./themes/dark.css", import.meta.url).href,
4
+ "legacy": new URL("./themes/legacy.css", import.meta.url).href,
5
+ "mui": new URL("./themes/mui.css", import.meta.url).href,
6
+ "antd": new URL("./themes/antd.css", import.meta.url).href,
7
+ "spectrum": new URL("./themes/spectrum.css", import.meta.url).href,
8
+ };
9
+
10
+ const STYLE_ID = "__gs-theme-overrides";
11
+ const _loaded = new Set();
12
+
13
+ function loadCss(url) {
14
+ if (_loaded.has(url)) return Promise.resolve();
15
+ return new Promise((resolve, reject) => {
16
+ const link = document.createElement("link");
17
+ link.rel = "stylesheet";
18
+ link.href = url;
19
+ link.onload = () => { _loaded.add(url); resolve(); };
20
+ link.onerror = () => reject(new Error("Failed to load theme CSS: " + url));
21
+ document.head.appendChild(link);
22
+ });
23
+ }
24
+
25
+ function injectOverrides(overrides) {
26
+ const css = Object.entries(overrides).map(([k, v]) => " " + k + ": " + v + ";").join("\n");
27
+ let el = document.getElementById(STYLE_ID);
28
+ if (!el) { el = document.createElement("style"); el.id = STYLE_ID; document.head.appendChild(el); }
29
+ el.textContent = ":root {\n" + css + "\n}";
30
+ }
31
+
32
+ function removeOverrides() {
33
+ document.getElementById(STYLE_ID)?.remove();
34
+ }
35
+
36
+ /**
37
+ * Switches the active theme at runtime.
38
+ *
39
+ * @param {string} themeId - Theme to activate. Use "gainsight-light" to restore the default.
40
+ * @param {Record<string,string>} [overrides] - Optional CSS variable overrides applied on top.
41
+ * @returns {Promise<void>}
42
+ *
43
+ * @example
44
+ * import { applyThemeConfig } from "@gainsight-hub/design-tokens";
45
+ *
46
+ * await applyThemeConfig("gainsight-dark");
47
+ * await applyThemeConfig("gainsight-dark", { "--theme-brand-700": "#FF6600" });
48
+ * await applyThemeConfig("gainsight-light"); // restore default
49
+ */
50
+ export async function applyThemeConfig(themeId, overrides = {}) {
51
+ const cssUrl = THEME_CSS_URLS[themeId];
52
+
53
+ if (!cssUrl) {
54
+ // Default / light theme — remove any active theme attribute
55
+ document.documentElement.removeAttribute("data-theme");
56
+ } else {
57
+ await loadCss(cssUrl);
58
+ document.documentElement.setAttribute("data-theme", themeId);
59
+ }
60
+
61
+ if (Object.keys(overrides).length === 0) {
62
+ removeOverrides();
63
+ } else {
64
+ injectOverrides(overrides);
65
+ }
66
+ }
@@ -0,0 +1,3 @@
1
+ // Auto-generated — do not edit manually.
2
+ export * from "./tokens.js";
3
+ export { applyThemeConfig } from "./applyTheme.js";
package/dist/index.js ADDED
@@ -0,0 +1,3 @@
1
+ // Auto-generated — do not edit manually.
2
+ export * from "./tokens.js";
3
+ export { applyThemeConfig } from "./applyTheme.js";