CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-superset-ui--core

Core utilities and components for Apache Superset's frontend UI framework providing data visualization, formatting, and chart composition capabilities

Pending
Overview
Eval results
Files

ui-styling.mddocs/

UI & Styling

This module provides comprehensive styling infrastructure for Superset applications, including the theme system with Emotion integration, color scheme management, text dimension calculations, and layout utilities. It enables consistent styling across components with support for theming, color scales, and responsive design.

Overview

The UI & styling system is built around three core areas: the theme system powered by Emotion for CSS-in-JS styling, the color management system with support for categorical and sequential color schemes, and the dimension utilities for text measurement and layout calculations.

Theme System

Core Theme Integration { .api }

Emotion-based styling system with comprehensive theme support:

import { 
  ThemeProvider, 
  useTheme, 
  styled, 
  css,
  jsx,
  withTheme,
  SupersetTheme,
  SupersetThemeProps,
  supersetTheme,
  emotionCache,
  EmotionCacheProvider,
  createEmotionCache
} from '@superset-ui/core';

// Theme provider for React context
const ThemeProvider: React.ComponentType<{ theme: SupersetTheme; children: React.ReactNode }>;

// Hook to access theme context
function useTheme(): SupersetTheme;

// Styled components factory
const styled: typeof emotionStyled;

// CSS template literal function
const css: typeof emotionCss;

// JSX pragma for Emotion
const jsx: typeof emotionJsx;

// Higher-order component for theme access
const withTheme: typeof emotionWithTheme;

// Emotion cache providers
const EmotionCacheProvider: typeof CacheProvider;
function createEmotionCache(options?: { key?: string }): EmotionCache;

// Default emotion cache instance
const emotionCache: EmotionCache;

SupersetTheme Interface { .api }

Comprehensive theme structure with design tokens:

interface SupersetTheme {
  // Layout and spacing
  borderRadius: number;
  gridUnit: number;
  transitionTiming: number;
  
  // Color system
  colors: {
    text: {
      label: string;
      help: string;
    };
    primary: ColorScale;
    secondary: ColorScale;
    grayscale: ColorScale;
    error: ColorScale;
    warning: ColorScale;
    alert: ColorScale;
    success: ColorScale;
    info: ColorScale;
  };
  
  // Typography system
  typography: {
    families: {
      sansSerif: string;
      serif: string;
      monospace: string;
    };
    weights: {
      light: number;
      normal: number;
      medium: number;
      bold: number;
    };
    sizes: {
      xxs: number;
      xs: number;
      s: number;
      m: number;
      l: number;
      xl: number;
      xxl: number;
    };
  };
  
  // Opacity levels
  opacity: {
    light: string;
    mediumLight: string;
    mediumHeavy: string;
    heavy: string;
  };
  
  // Z-index management
  zIndex: {
    aboveDashboardCharts: number;
    dropdown: number;
    max: number;
  };
}

// Color scale structure
interface ColorScale {
  base: string;
  dark1: string;
  dark2: string;
  light1: string;
  light2: string;
  light3?: string;
  light4?: string;
  light5?: string;
}

// Component props interface for themed components
interface SupersetThemeProps {
  theme: SupersetTheme;
}

// Default theme instance
const supersetTheme: SupersetTheme;

Color Management

Color Scheme System { .api }

Comprehensive color scheme management for data visualization:

import { 
  ColorScheme,
  CategoricalScheme,
  SequentialScheme,
  CategoricalColorScale,
  getCategoricalSchemeRegistry,
  getSequentialSchemeRegistry,
  BRAND_COLOR
} from '@superset-ui/core';

// Base color scheme class
class ColorScheme {
  readonly id: string;
  readonly label: string;
  readonly colors: string[];
  readonly isDefault?: boolean;
  
  constructor(config: {
    id: string;
    label: string;
    colors: string[];
    isDefault?: boolean;
  });
  
  getColors(numColors?: number): string[];
}

// Categorical color scheme for discrete data
class CategoricalScheme extends ColorScheme {
  constructor(config: CategoricalSchemeConfig);
}

// Sequential color scheme for continuous data
class SequentialScheme extends ColorScheme {
  constructor(config: SequentialSchemeConfig);
}

// Categorical color scale for data mapping
class CategoricalColorScale {
  constructor(colors: string[], forced?: boolean);
  
  getColor(key: string): string;
  setColor(key: string, color: string): this;
  getColorMap(): { [key: string]: string };
  copy(): CategoricalColorScale;
}

// Registry access functions
function getCategoricalSchemeRegistry(): RegistryWithDefaultKey<CategoricalScheme>;
function getSequentialSchemeRegistry(): RegistryWithDefaultKey<SequentialScheme>;

// Brand color constant
const BRAND_COLOR = '#00A699';

Color Namespace Management { .api }

Advanced color management with namespaces for consistent color assignment:

import { CategoricalColorNamespace, getSharedLabelColor } from '@superset-ui/core';

// Categorical color namespace utilities
namespace CategoricalColorNamespace {
  function getNamespace(namespace?: string): CategoricalColorScale;
  function getScale(schemeId?: string, namespace?: string): CategoricalColorScale;
  function setColor(key: string, color: string, namespace?: string): void;
  function getColor(key: string, schemeId?: string, namespace?: string): string;
}

// Shared label color management
function getSharedLabelColor(): SharedLabelColor;

class SharedLabelColor {
  getColorMap(scheme?: string, namespace?: string): { [key: string]: string };
  addSlice(label: string, color: string, scheme?: string, namespace?: string): void;
  removeSlice(label: string, scheme?: string, namespace?: string): void;
  clear(scheme?: string, namespace?: string): void;
}

Text and Layout Utilities

Text Dimension Calculation { .api }

Utilities for measuring text dimensions and calculating font sizes:

import { 
  getTextDimension,
  getMultipleTextDimensions,
  computeMaxFontSize,
  Dimension,
  TextStyle
} from '@superset-ui/core';

// Single text measurement
function getTextDimension(config: {
  text: string;
  style?: TextStyle;
}): Dimension;

// Multiple text measurements (more efficient for batch operations)
function getMultipleTextDimensions(config: {
  texts: string[];
  style?: TextStyle;
}): Dimension[];

// Calculate maximum font size that fits constraints
function computeMaxFontSize(config: {
  text: string;
  idealFontSize: number;
  maxWidth: number;
  maxHeight: number;
  style?: TextStyle;
}): number;

// Dimension interface
interface Dimension {
  width: number;
  height: number;
}

// Text style configuration
interface TextStyle {
  fontSize?: string | number;
  fontFamily?: string;
  fontWeight?: string | number;
  fontStyle?: string;
  letterSpacing?: string | number;
  lineHeight?: string | number;
}

Layout Utilities { .api }

Utilities for margin handling and CSS length parsing:

import { mergeMargin, parseLength, Margin } from '@superset-ui/core';

// Merge margin objects with proper handling of undefined values
function mergeMargin(...margins: (Partial<Margin> | undefined)[]): Margin;

// Parse CSS length values to numeric values
function parseLength(input: string | number): number;

// Margin interface
interface Margin {
  top: number;
  right: number;
  bottom: number;
  left: number;
}

Usage Examples

Basic Theme Setup

import React from 'react';
import { 
  ThemeProvider, 
  supersetTheme, 
  emotionCache,
  EmotionCacheProvider 
} from '@superset-ui/core';

// App-level theme setup
const App: React.FC = ({ children }) => (
  <EmotionCacheProvider value={emotionCache}>
    <ThemeProvider theme={supersetTheme}>
      {children}
    </ThemeProvider>
  </EmotionCacheProvider>
);

// Custom theme configuration
const customTheme = {
  ...supersetTheme,
  colors: {
    ...supersetTheme.colors,
    primary: {
      ...supersetTheme.colors.primary,
      base: '#FF6B6B'  // Custom primary color
    }
  }
};

Styled Components with Theme

import React from 'react';
import { styled, useTheme, css } from '@superset-ui/core';

// Basic styled component with theme access
const StyledButton = styled.button`
  background-color: ${({ theme }) => theme.colors.primary.base};
  color: ${({ theme }) => theme.colors.grayscale.light5};
  border: none;
  border-radius: ${({ theme }) => theme.borderRadius}px;
  padding: ${({ theme }) => theme.gridUnit * 2}px ${({ theme }) => theme.gridUnit * 4}px;
  font-family: ${({ theme }) => theme.typography.families.sansSerif};
  font-size: ${({ theme }) => theme.typography.sizes.m}px;
  font-weight: ${({ theme }) => theme.typography.weights.medium};
  transition: all ${({ theme }) => theme.transitionTiming}s ease;
  
  &:hover {
    background-color: ${({ theme }) => theme.colors.primary.dark1};
  }
  
  &:disabled {
    opacity: ${({ theme }) => theme.opacity.mediumHeavy};
    cursor: not-allowed;
  }
`;

// Component using theme hook
const ThemedCard: React.FC<{ children: React.ReactNode }> = ({ children }) => {
  const theme = useTheme();
  
  return (
    <div
      css={css`
        background: ${theme.colors.grayscale.light5};
        border: 1px solid ${theme.colors.grayscale.light2};
        border-radius: ${theme.borderRadius}px;
        padding: ${theme.gridUnit * 4}px;
        box-shadow: 0 ${theme.gridUnit}px ${theme.gridUnit * 3}px ${theme.colors.grayscale.light2};
      `}
    >
      {children}
    </div>
  );
};

Color Scheme Usage

import { 
  getCategoricalSchemeRegistry,
  CategoricalColorNamespace,
  CategoricalColorScale 
} from '@superset-ui/core';

// Register custom color scheme
const customColors = ['#FF6B6B', '#4ECDC4', '#45B7D1', '#FFA07A', '#98D8C8'];
const customScheme = new CategoricalScheme({
  id: 'custom',
  label: 'Custom Colors',
  colors: customColors
});

getCategoricalSchemeRegistry().registerValue('custom', customScheme);

// Use color scale for data visualization
const createColorScale = (data: string[]) => {
  const scale = CategoricalColorNamespace.getScale('custom', 'myChart');
  
  // Assign colors to data categories
  data.forEach(category => {
    CategoricalColorNamespace.getColor(category, 'custom', 'myChart');
  });
  
  return scale;
};

// Get colors for chart data
const chartData = ['Category A', 'Category B', 'Category C'];
const colorScale = createColorScale(chartData);
const colors = chartData.map(category => colorScale.getColor(category));

Text Measurement and Font Sizing

import { 
  getTextDimension, 
  computeMaxFontSize,
  getMultipleTextDimensions 
} from '@superset-ui/core';

// Measure single text element
const textDimension = getTextDimension({
  text: 'Chart Title',
  style: {
    fontSize: 16,
    fontFamily: 'Inter, Arial, sans-serif',
    fontWeight: 'bold'
  }
});

console.log(`Text size: ${textDimension.width} x ${textDimension.height}`);

// Calculate optimal font size for container
const optimalFontSize = computeMaxFontSize({
  text: 'Long chart title that needs to fit',
  idealFontSize: 18,
  maxWidth: 200,
  maxHeight: 30,
  style: {
    fontFamily: 'Inter, Arial, sans-serif',
    fontWeight: 'bold'
  }
});

// Batch text measurement for better performance
const labels = ['Label 1', 'Label 2', 'Label 3', 'Very Long Label Name'];
const labelDimensions = getMultipleTextDimensions({
  texts: labels,
  style: { fontSize: 12, fontFamily: 'Inter' }
});

// Find maximum width for layout calculations
const maxLabelWidth = Math.max(...labelDimensions.map(d => d.width));

Advanced Styling Patterns

import { styled, css, useTheme } from '@superset-ui/core';

// Conditional styling based on props
interface CardProps {
  variant?: 'primary' | 'secondary' | 'danger';
  size?: 'small' | 'medium' | 'large';
}

const StyledCard = styled.div<CardProps>`
  ${({ theme }) => css`
    border-radius: ${theme.borderRadius}px;
    padding: ${theme.gridUnit * 2}px;
    font-family: ${theme.typography.families.sansSerif};
    transition: all ${theme.transitionTiming}s ease;
  `}
  
  ${({ theme, variant = 'primary' }) => {
    const colorMap = {
      primary: theme.colors.primary,
      secondary: theme.colors.secondary,
      danger: theme.colors.error
    };
    
    const colors = colorMap[variant];
    
    return css`
      background-color: ${colors.light4};
      border: 1px solid ${colors.light2};
      color: ${colors.dark2};
    `;
  }}
  
  ${({ theme, size = 'medium' }) => {
    const sizeMap = {
      small: theme.gridUnit * 2,
      medium: theme.gridUnit * 4, 
      large: theme.gridUnit * 6
    };
    
    return css`
      padding: ${sizeMap[size]}px;
      font-size: ${theme.typography.sizes[size === 'small' ? 's' : size === 'large' ? 'l' : 'm']}px;
    `;
  }}
`;

// Dynamic styling with CSS variables
const DynamicStyledComponent = styled.div`
  ${({ theme }) => {
    // Set CSS custom properties from theme
    return css`
      --primary-color: ${theme.colors.primary.base};
      --secondary-color: ${theme.colors.secondary.base};
      --border-radius: ${theme.borderRadius}px;
      --grid-unit: ${theme.gridUnit}px;
      
      background: var(--primary-color);
      border-radius: var(--border-radius);
      padding: calc(var(--grid-unit) * 2);
      
      .nested-element {
        background: var(--secondary-color);
        margin: var(--grid-unit);
      }
    `;
  }}
`;

Responsive Design with Theme

import { styled, css } from '@superset-ui/core';

// Responsive breakpoints (not in theme but commonly used)
const breakpoints = {
  xs: '0px',
  sm: '576px',
  md: '768px',
  lg: '992px',
  xl: '1200px'
};

const media = {
  xs: `@media (min-width: ${breakpoints.xs})`,
  sm: `@media (min-width: ${breakpoints.sm})`,
  md: `@media (min-width: ${breakpoints.md})`,
  lg: `@media (min-width: ${breakpoints.lg})`,
  xl: `@media (min-width: ${breakpoints.xl})`
};

// Responsive styled component
const ResponsiveGrid = styled.div`
  ${({ theme }) => css`
    display: grid;
    gap: ${theme.gridUnit * 2}px;
    padding: ${theme.gridUnit * 2}px;
    
    ${media.xs} {
      grid-template-columns: 1fr;
    }
    
    ${media.sm} {
      grid-template-columns: repeat(2, 1fr);
    }
    
    ${media.md} {
      grid-template-columns: repeat(3, 1fr);
    }
    
    ${media.lg} {
      grid-template-columns: repeat(4, 1fr);
    }
  `}
`;

Color Utilities and Helpers

import { 
  CategoricalColorNamespace, 
  getSharedLabelColor,
  BRAND_COLOR 
} from '@superset-ui/core';

// Shared color management across dashboard
const labelColorManager = getSharedLabelColor();

// Add colors for specific data labels
labelColorManager.addSlice('Sales', '#FF6B6B', 'd3Category10', 'dashboard_1');
labelColorManager.addSlice('Marketing', '#4ECDC4', 'd3Category10', 'dashboard_1');

// Get consistent colors across charts
const getConsistentColor = (label: string, namespace: string) => {
  return CategoricalColorNamespace.getColor(label, 'd3Category10', namespace);
};

// Clear colors when dashboard changes
const clearDashboardColors = (namespace: string) => {
  labelColorManager.clear('d3Category10', namespace);
};

// Use brand color for primary elements
const brandButton = styled.button`
  background-color: ${BRAND_COLOR};
  color: white;
`;

Layout Margin Utilities

import { mergeMargin, parseLength } from '@superset-ui/core';

// Merge multiple margin configurations
const baseMargin = { top: 10, right: 15, bottom: 10, left: 15 };
const titleMargin = { top: 20, bottom: 5 };
const finalMargin = mergeMargin(baseMargin, titleMargin);
// Result: { top: 20, right: 15, bottom: 5, left: 15 }

// Parse CSS length values
const numericValue1 = parseLength('16px');    // 16
const numericValue2 = parseLength('1.5em');   // Converted to pixels based on context
const numericValue3 = parseLength(20);        // 20

// Calculate responsive margins
const calculateResponsiveMargin = (baseSize: number) => {
  const sm = parseLength(`${baseSize * 0.5}px`);
  const md = parseLength(`${baseSize}px`);
  const lg = parseLength(`${baseSize * 1.5}px`);
  
  return { sm, md, lg };
};

Related Documentation

  • Core Models & Utilities - Registry system for color schemes
  • Data Formatting - Formatter integration with styling
  • Plugin System - Chart component styling
  • Dashboard Components - Dashboard layout and styling

Install with Tessl CLI

npx tessl i tessl/npm-superset-ui--core

docs

core-models.md

dashboard.md

data-connection.md

data-formatting.md

index.md

plugin-system.md

translation.md

ui-styling.md

validation-math.md

tile.json