# All files / src/utils grackleHostStyleVariables.ts

98.16% Statements 107/109
75% Branches 3/4
100% Functions 1/1
98.16% Lines 107/109

Press n or j to go to the next uncovered block, b, p or k for the previous block.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135

    1x
    1x
    1x
    1x
    1x
    1x
    1x
    1x
    1x
    1x
    1x
    1x
    1x
    1x
    1x
    1x
    1x
    1x
    1x
    1x
    1x
    1x
    1x
    1x
    1x
    1x
    1x
    1x
    1x
    1x
    1x
    1x
    1x
    1x
    1x
    1x
    1x
    1x
    1x
    1x
    1x
    1x
    1x
    1x
    1x
    1x
    1x
    1x
    1x
    1x
    1x
    1x
    1x
    1x
    1x
    1x
    1x
    1x
    1x
    1x
    1x
    1x
    1x
    1x
    1x
    1x
    1x
    1x
    1x
    1x
    1x
    1x
    1x
    1x
    1x
    1x
    1x
    1x

    1x
    1x
    1x
    1x
    1x
    1x
    1x
    1x
    1x
    1x
    1x
    1x
    1x
    1x
    1x
    1x

    1x
    2x
    2x

    2x
    2x
    2x
    28x
    28x
    2x
    2x
    28x
    2x
    2x
     import type { McpUiStyles } from "@modelcontextprotocol/ext-apps";

    /**
     * MCP Apps widgets consume a fixed, standard set of CSS custom properties
     * (`--color-*`, `--font-*`, `--border-radius-*`, `--shadow-*`). Grackle's own
     * theme tokens live under different names (`--bg-*`, `--text-*`, `--radius-*`) in
     * `src/styles/theme.scss`. This module exposes Grackle's current theme to widgets
     * under the MCP-standard names so a widget renders coherently inside the host.
     *
     * `McpUiStyles` requires the complete variable set, so we seed from the standard
     * theme-adaptive defaults (verbatim from modelcontextprotocol/ext-apps
     * examples/basic-host/src/host-styles.ts, commit 9a37ad7) and override the subset
     * we can source from Grackle's live theme.
     */

    /** Complete MCP-standard default style variables (theme-adaptive via `light-dark()`). */
    const DEFAULT_MCP_STYLES: McpUiStyles = {
      "--color-background-primary": "light-dark(#ffffff, #1a1a1a)",
      "--color-background-secondary": "light-dark(#f5f5f5, #2d2d2d)",
      "--color-background-tertiary": "light-dark(#e5e5e5, #404040)",
      "--color-background-inverse": "light-dark(#1a1a1a, #ffffff)",
      "--color-background-ghost": "light-dark(rgba(255,255,255,0), rgba(26,26,26,0))",
      "--color-background-info": "light-dark(#eff6ff, #1e3a5f)",
      "--color-background-danger": "light-dark(#fef2f2, #7f1d1d)",
      "--color-background-success": "light-dark(#f0fdf4, #14532d)",
      "--color-background-warning": "light-dark(#fefce8, #713f12)",
      "--color-background-disabled": "light-dark(rgba(255,255,255,0.5), rgba(26,26,26,0.5))",
      "--color-text-primary": "light-dark(#1f2937, #f3f4f6)",
      "--color-text-secondary": "light-dark(#6b7280, #9ca3af)",
      "--color-text-tertiary": "light-dark(#9ca3af, #6b7280)",
      "--color-text-inverse": "light-dark(#f3f4f6, #1f2937)",
      "--color-text-ghost": "light-dark(rgba(107,114,128,0.5), rgba(156,163,175,0.5))",
      "--color-text-info": "light-dark(#1d4ed8, #60a5fa)",
      "--color-text-danger": "light-dark(#b91c1c, #f87171)",
      "--color-text-success": "light-dark(#15803d, #4ade80)",
      "--color-text-warning": "light-dark(#a16207, #fbbf24)",
      "--color-text-disabled": "light-dark(rgba(31,41,55,0.5), rgba(243,244,246,0.5))",
      "--color-border-primary": "light-dark(#e5e7eb, #404040)",
      "--color-border-secondary": "light-dark(#d1d5db, #525252)",
      "--color-border-tertiary": "light-dark(#f3f4f6, #374151)",
      "--color-border-inverse": "light-dark(rgba(255,255,255,0.3), rgba(0,0,0,0.3))",
      "--color-border-ghost": "light-dark(rgba(229,231,235,0), rgba(64,64,64,0))",
      "--color-border-info": "light-dark(#93c5fd, #1e40af)",
      "--color-border-danger": "light-dark(#fca5a5, #991b1b)",
      "--color-border-success": "light-dark(#86efac, #166534)",
      "--color-border-warning": "light-dark(#fde047, #854d0e)",
      "--color-border-disabled": "light-dark(rgba(229,231,235,0.5), rgba(64,64,64,0.5))",
      "--color-ring-primary": "light-dark(#3b82f6, #60a5fa)",
      "--color-ring-secondary": "light-dark(#6b7280, #9ca3af)",
      "--color-ring-inverse": "light-dark(#ffffff, #1f2937)",
      "--color-ring-info": "light-dark(#2563eb, #3b82f6)",
      "--color-ring-danger": "light-dark(#dc2626, #ef4444)",
      "--color-ring-success": "light-dark(#16a34a, #22c55e)",
      "--color-ring-warning": "light-dark(#ca8a04, #eab308)",
      "--font-sans": "system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif",
      "--font-mono": "ui-monospace, 'SF Mono', Monaco, 'Cascadia Code', monospace",
      "--font-weight-normal": "400",
      "--font-weight-medium": "500",
      "--font-weight-semibold": "600",
      "--font-weight-bold": "700",
      "--font-text-xs-size": "0.75rem",
      "--font-text-sm-size": "0.875rem",
      "--font-text-md-size": "1rem",
      "--font-text-lg-size": "1.125rem",
      "--font-heading-xs-size": "0.75rem",
      "--font-heading-sm-size": "0.875rem",
      "--font-heading-md-size": "1rem",
      "--font-heading-lg-size": "1.25rem",
      "--font-heading-xl-size": "1.5rem",
      "--font-heading-2xl-size": "1.875rem",
      "--font-heading-3xl-size": "2.25rem",
      "--font-text-xs-line-height": "1.4",
      "--font-text-sm-line-height": "1.4",
      "--font-text-md-line-height": "1.5",
      "--font-text-lg-line-height": "1.5",
      "--font-heading-xs-line-height": "1.4",
      "--font-heading-sm-line-height": "1.4",
      "--font-heading-md-line-height": "1.4",
      "--font-heading-lg-line-height": "1.3",
      "--font-heading-xl-line-height": "1.25",
      "--font-heading-2xl-line-height": "1.2",
      "--font-heading-3xl-line-height": "1.1",
      "--border-radius-xs": "2px",
      "--border-radius-sm": "4px",
      "--border-radius-md": "6px",
      "--border-radius-lg": "8px",
      "--border-radius-xl": "12px",
      "--border-radius-full": "9999px",
      "--border-width-regular": "1px",
      "--shadow-hairline": "0 1px 2px 0 rgba(0, 0, 0, 0.05)",
      "--shadow-sm": "0 1px 3px 0 rgba(0, 0, 0, 0.1), 0 1px 2px -1px rgba(0, 0, 0, 0.1)",
      "--shadow-md": "0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -2px rgba(0, 0, 0, 0.1)",
      "--shadow-lg": "0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -4px rgba(0, 0, 0, 0.1)",
    };

    /** MCP-standard variable name -> Grackle theme token to read its value from. */
    const GRACKLE_TOKEN_BY_MCP_NAME: Readonly<Record<string, string>> = {
      "--color-background-primary": "--bg-base",
      "--color-background-secondary": "--bg-surface",
      "--color-background-tertiary": "--bg-elevated",
      "--color-text-primary": "--text-primary",
      "--color-text-secondary": "--text-secondary",
      "--color-text-tertiary": "--text-tertiary",
      "--color-border-primary": "--border-primary",
      "--color-border-secondary": "--border-subtle",
      "--font-sans": "--font-sans",
      "--font-mono": "--font-mono",
      "--border-radius-sm": "--radius-sm",
      "--border-radius-md": "--radius-md",
      "--border-radius-lg": "--radius-lg",
      "--border-radius-full": "--radius-full",
    };

    /**
     * Build the MCP-standard style-variable map from Grackle's live theme, falling
     * back to theme-adaptive defaults for any token that cannot be read.
     *
     * @returns Style variables suitable for `hostContext.styles.variables`.
     */
    export function grackleHostStyleVariables(): McpUiStyles {
      const out: McpUiStyles = { ...DEFAULT_MCP_STYLES };
      if (typeof window === "undefined" || typeof document === "undefined") {
        return out;
      }
      const computed: CSSStyleDeclaration = window.getComputedStyle(document.documentElement);
      const writable: Record<string, string> = out as Record<string, string>;
      for (const [mcpName, grackleToken] of Object.entries(GRACKLE_TOKEN_BY_MCP_NAME)) {
        const value: string = computed.getPropertyValue(grackleToken).trim();
        if (value) {
          writable[mcpName] = value;
        }
      }
      return out;
    }