@ibis-design/css 0.8.2 → 0.9.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.
@@ -178,7 +178,11 @@ module.exports = {
178
178
  },
179
179
  color: {
180
180
  default: "var(--border-color-default)",
181
+ subtle: "var(--border-color-subtle)",
182
+ strong: "var(--border-color-strong)",
181
183
  focus: "var(--border-color-focus)",
184
+ disabled: "var(--border-color-disabled)",
185
+ emphasis: "var(--border-color-emphasis)",
182
186
  button: "var(--border-color-button)"
183
187
  }
184
188
  },
@@ -248,9 +252,44 @@ module.exports = {
248
252
  green: "var(--color-green)",
249
253
  red: "var(--color-red)",
250
254
  orange: "var(--color-orange)",
255
+ surface: {
256
+ default: "var(--color-surface-default)",
257
+ muted: "var(--color-surface-muted)",
258
+ subtle: "var(--color-surface-subtle)",
259
+ elevated: "var(--color-surface-elevated)",
260
+ inverse: "var(--color-surface-inverse)",
261
+ disabled: "var(--color-surface-disabled)",
262
+ page: "var(--color-surface-page)"
263
+ },
251
264
  text: {
252
265
  primary: "var(--color-text-primary)",
253
- inverse: "var(--color-text-inverse)"
266
+ secondary: "var(--color-text-secondary)",
267
+ muted: "var(--color-text-muted)",
268
+ disabled: "var(--color-text-disabled)",
269
+ inverse: "var(--color-text-inverse)",
270
+ onPrimary: "var(--color-text-on-primary)",
271
+ onMuted: "var(--color-text-on-muted)"
272
+ },
273
+ interactive: {
274
+ primary: {
275
+ bgSelected: "var(--color-interactive-primary-bg-selected)",
276
+ bgHover: "var(--color-interactive-primary-bg-hover)",
277
+ fg: "var(--color-interactive-primary-fg)",
278
+ fgDisabled: "var(--color-interactive-primary-fg-disabled)",
279
+ bgEmphasized: "var(--color-interactive-primary-bg-emphasized)",
280
+ borderSelected: "var(--color-interactive-primary-border-selected)",
281
+ indicator: "var(--color-interactive-primary-indicator)",
282
+ bgDisabled: "var(--color-interactive-primary-bg-disabled)",
283
+ fgOnDisabled: "var(--color-interactive-primary-fg-on-disabled)",
284
+ bgMenuHover: "var(--color-interactive-primary-bg-menu-hover)",
285
+ bgMenuSelected: "var(--color-interactive-primary-bg-menu-selected)",
286
+ bgMenuSelectedHover: "var(--color-interactive-primary-bg-menu-selected-hover)",
287
+ trackOn: "var(--color-interactive-primary-track-on)",
288
+ trackOff: "var(--color-interactive-primary-track-off)"
289
+ },
290
+ neutral: {
291
+ bgHover: "var(--color-interactive-neutral-bg-hover)"
292
+ }
254
293
  },
255
294
  toaster: {
256
295
  default: "var(--color-toaster-default)",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ibis-design/css",
3
- "version": "0.8.2",
3
+ "version": "0.9.0",
4
4
  "description": "Design tokens, CSS variables, and Tailwind preset for the IBIS design system.",
5
5
  "type": "module",
6
6
  "exports": {
@@ -13,14 +13,16 @@
13
13
  "./ibis/tailwind.preset": "./dist/tailwind.preset.js",
14
14
  "./alchemy/tailwind.preset": "./dist/tailwind.preset.js",
15
15
  "./components/*": "./dist/components/*",
16
- "./tailwind.theme": "./dist/tailwind.theme.js"
16
+ "./tailwind.theme": "./dist/tailwind.theme.js",
17
+ "./theme": "./src/lib/set-theme.ts"
17
18
  },
18
19
  "files": [
19
- "dist"
20
+ "dist",
21
+ "src/lib"
20
22
  ],
21
23
  "scripts": {
22
- "build": "tsx src/scripts/build.ts && tsx src/scripts/validate-themes.ts",
23
- "validate": "tsx src/scripts/validate-themes.ts",
24
+ "build": "tsx src/scripts/build.ts && tsx src/scripts/validate-themes.ts && tsx src/scripts/validate-component-tokens.ts",
25
+ "validate": "tsx src/scripts/validate-themes.ts && tsx src/scripts/validate-component-tokens.ts",
24
26
  "prepublishOnly": "npm run build"
25
27
  },
26
28
  "devDependencies": {
@@ -0,0 +1,20 @@
1
+ /**
2
+ * @param blocks - Formatted CSS blocks from Style Dictionary (one per global/theme layer).
3
+ * @returns Full design-tokens stylesheet with header comment.
4
+ */
5
+ export const assembleDesignTokensStylesheet = (blocks: string[]): string => {
6
+ const body = blocks
7
+ .map((block) => block.trim())
8
+ .filter(Boolean)
9
+ .join("\n\n");
10
+
11
+ return `/**
12
+ * Do not edit directly. Generated by @ibis-design/css build.
13
+ * Set data-brand (ib | alc) and data-color-mode (light | dark) on <html>,
14
+ * or use setTheme() from @ibis-design/css/theme.
15
+ * :root holds global tokens; :root + [data-brand="ib"][data-color-mode="light"] is the default theme overlay.
16
+ */
17
+
18
+ ${body}
19
+ `;
20
+ };
@@ -0,0 +1,73 @@
1
+ import {
2
+ DEFAULT_BRAND,
3
+ DEFAULT_COLOR_MODE,
4
+ type BrandId,
5
+ type ColorModeId,
6
+ toThemeId,
7
+ type ThemeId,
8
+ } from "./themes.ts";
9
+
10
+ export {
11
+ DEFAULT_BRAND,
12
+ DEFAULT_COLOR_MODE,
13
+ DEFAULT_THEME_ID,
14
+ parseThemeId,
15
+ toThemeId,
16
+ type BrandId,
17
+ type ColorModeId,
18
+ type ThemeId,
19
+ } from "./themes.ts";
20
+
21
+ export type ThemeOptions = {
22
+ brand?: BrandId;
23
+ colorMode?: ColorModeId;
24
+ };
25
+
26
+ const isBrandId = (value: string): value is BrandId => value === "ib" || value === "alc";
27
+
28
+ const isColorModeId = (value: string): value is ColorModeId =>
29
+ value === "light" || value === "dark";
30
+
31
+ /**
32
+ * Applies brand and color mode to `document.documentElement` for CSS token switching.
33
+ *
34
+ * @param options - Brand and color mode; defaults to Ibis light
35
+ * @example
36
+ * setTheme({ brand: 'alc', colorMode: 'dark' });
37
+ */
38
+ export const setTheme = (options: ThemeOptions = {}): ThemeId => {
39
+ const brand = options.brand ?? DEFAULT_BRAND;
40
+ const colorMode = options.colorMode ?? DEFAULT_COLOR_MODE;
41
+
42
+ if (typeof document !== "undefined") {
43
+ const root = document.documentElement;
44
+ root.dataset.brand = brand;
45
+ root.dataset.colorMode = colorMode;
46
+ delete root.dataset.theme;
47
+ }
48
+
49
+ return toThemeId(brand, colorMode);
50
+ };
51
+
52
+ /**
53
+ * Reads the active brand and color mode from the document root.
54
+ *
55
+ * @returns Current brand and color mode, or defaults when not in a browser
56
+ */
57
+ export const getTheme = (): { brand: BrandId; colorMode: ColorModeId; themeId: ThemeId } => {
58
+ if (typeof document === "undefined") {
59
+ return {
60
+ brand: DEFAULT_BRAND,
61
+ colorMode: DEFAULT_COLOR_MODE,
62
+ themeId: toThemeId(DEFAULT_BRAND, DEFAULT_COLOR_MODE),
63
+ };
64
+ }
65
+
66
+ const brandRaw = document.documentElement.dataset.brand;
67
+ const modeRaw = document.documentElement.dataset.colorMode;
68
+
69
+ const brand = brandRaw && isBrandId(brandRaw) ? brandRaw : DEFAULT_BRAND;
70
+ const colorMode = modeRaw && isColorModeId(modeRaw) ? modeRaw : DEFAULT_COLOR_MODE;
71
+
72
+ return { brand, colorMode, themeId: toThemeId(brand, colorMode) };
73
+ };
@@ -0,0 +1,74 @@
1
+ export type BrandId = "ib" | "alc";
2
+
3
+ export type ColorModeId = "light" | "dark";
4
+
5
+ /** Composite theme id used for Style Dictionary source files and RN JSON exports. */
6
+ export type ThemeId = `${BrandId}-${ColorModeId}`;
7
+
8
+ export type ThemeDefinition = {
9
+ id: ThemeId;
10
+ brand: BrandId;
11
+ colorMode: ColorModeId;
12
+ /** Selector passed to Style Dictionary css/variables `options.selector`. */
13
+ cssSelector: string;
14
+ };
15
+
16
+ const themeSelector = (brand: BrandId, colorMode: ColorModeId): string =>
17
+ `[data-brand="${brand}"][data-color-mode="${colorMode}"]`;
18
+
19
+ export const THEMES: ThemeDefinition[] = [
20
+ {
21
+ id: "ib-light",
22
+ brand: "ib",
23
+ colorMode: "light",
24
+ cssSelector: ':root, [data-brand="ib"][data-color-mode="light"]',
25
+ },
26
+ {
27
+ id: "ib-dark",
28
+ brand: "ib",
29
+ colorMode: "dark",
30
+ cssSelector: themeSelector("ib", "dark"),
31
+ },
32
+ {
33
+ id: "alc-light",
34
+ brand: "alc",
35
+ colorMode: "light",
36
+ cssSelector: themeSelector("alc", "light"),
37
+ },
38
+ {
39
+ id: "alc-dark",
40
+ brand: "alc",
41
+ colorMode: "dark",
42
+ cssSelector: themeSelector("alc", "dark"),
43
+ },
44
+ ];
45
+
46
+ export const DEFAULT_BRAND: BrandId = "ib";
47
+
48
+ export const DEFAULT_COLOR_MODE: ColorModeId = "light";
49
+
50
+ export const DEFAULT_THEME_ID: ThemeId = `${DEFAULT_BRAND}-${DEFAULT_COLOR_MODE}`;
51
+
52
+ /**
53
+ * @param brand - Ibis or Alchemy
54
+ * @param colorMode - Light or dark
55
+ * @returns Composite theme id for token JSON / RN export filenames
56
+ */
57
+ export const toThemeId = (brand: BrandId, colorMode: ColorModeId): ThemeId =>
58
+ `${brand}-${colorMode}`;
59
+
60
+ /**
61
+ * @param themeId - Composite id such as `ib-dark`
62
+ * @returns Brand and color mode parsed from the id
63
+ * @throws When the id is not a valid theme id
64
+ */
65
+ export const parseThemeId = (themeId: string): { brand: BrandId; colorMode: ColorModeId } => {
66
+ const match = /^(ib|alc)-(light|dark)$/.exec(themeId);
67
+ if (!match?.[1] || !match[2]) {
68
+ throw new Error(`Invalid theme id: ${themeId}`);
69
+ }
70
+ return {
71
+ brand: match[1] as BrandId,
72
+ colorMode: match[2] as ColorModeId,
73
+ };
74
+ };