@microsoft/fabric-visuals-core
v1.1.0
Published
Core library for Fabric Apps - Analytics — data utilities, design tokens, and configuration
Readme
@microsoft/fabric-visuals-core
Foundational shared types, data utilities, format helpers, and design tokens for the Fabric Apps - Analytics visualization stack.
Quick Reference
Package:
@microsoft/fabric-visuals-corePurpose: Shared types, data utilities, format helpers, and design tokens for the Fabric Apps visualization stack. Use when: You needDataTable,ColumnDef, design tokens, data filtering/aggregation, or VBA format conversion. This is a required dependency for both@microsoft/fabric-visualsand@microsoft/fabric-datagrid. Do NOT use when: You want to render charts (use@microsoft/fabric-visuals) or data grids (use@microsoft/fabric-datagrid) — those packages re-export what they need. Key exports:DataTable,ColumnDef,VisualTheme,filterRows,aggregate,groupBy,convertVbaFormat,formatValue,tokens,spacing,injectDesignTokensPeer dependencies: None Install:npm install @microsoft/fabric-visuals-core
Ecosystem Context
@microsoft/fabric-visuals-core is the lowest-level shared package in the visualization ecosystem.
@microsoft/fabric-visuals-core
├─ shared by @microsoft/fabric-visuals
└─ shared by @microsoft/fabric-datagridIt defines the common contracts and helpers that sibling packages build on:
@microsoft/fabric-visuals-core— shared types, formatting, filtering, aggregation, theming, and design tokens@microsoft/fabric-visuals— visualization components built on those shared contracts@microsoft/fabric-datagrid— grid/table components built on the same data and formatting model
Installation
npm install @microsoft/fabric-visuals-corePublic API
All exports below come from src/index.ts.
Data Types
export interface ColumnDef {
readonly name: string;
readonly displayName?: string;
readonly format?: string;
}export interface DataTable {
readonly columns: ColumnDef[];
readonly rows: unknown[][];
}Data Utilities
export function convertDataTableToRows(input: DataTable): Record<string, unknown>[]export function isDataTable(input: unknown): input is DataTableFiltering
export function filterRows(
table: DataTable,
predicate: (row: unknown[], columns: readonly ColumnDef[]) => boolean,
): DataTableexport function getUniqueColumnValues(table: DataTable, columnName: string): unknown[]export function sliceRows(table: DataTable, start: number, end?: number): DataTableAggregation
export type AggregationFn = 'sum' | 'min' | 'max' | 'average' | 'count'export interface AggregationSpec {
readonly column?: string;
readonly fn: AggregationFn;
readonly as?: string;
}export function aggregate(table: DataTable, spec: AggregationSpec): number | undefinedexport function groupBy(
table: DataTable,
groupColumns: string[],
aggregations: AggregationSpec[],
): DataTableFormat Conversion and Value Formatting
export interface VbaFormatResult {
readonly type: 'number' | 'time';
readonly d3Format: string;
}export function convertVbaFormat(vbaFormat: string): VbaFormatResultexport function vbaToD3Format(vbaFormat: string): stringexport function vbaToD3TimeFormat(vbaFormat: string): stringexport function formatValue(
value: unknown,
vbaFormat: string | undefined,
options?: { locale?: string },
): unknownDesign Tokens and Theming
export const spacing: {
readonly none: '0';
readonly xxs: '2px';
readonly xs: '4px';
readonly sNudge: '6px';
readonly s: '8px';
readonly mNudge: '10px';
readonly m: '12px';
readonly l: '16px';
readonly xl: '20px';
readonly xxl: '24px';
readonly xxxl: '32px';
}export const fontSize: {
readonly 100: '10px';
readonly 200: '12px';
readonly 300: '14px';
readonly 400: '16px';
readonly 500: '20px';
readonly 600: '24px';
readonly hero700: '28px';
readonly hero800: '32px';
readonly hero900: '40px';
readonly hero1000: '68px';
}export const lineHeight: {
readonly 100: '14px';
readonly 200: '16px';
readonly 300: '20px';
readonly 400: '22px';
readonly 500: '28px';
readonly 600: '32px';
readonly hero700: '36px';
readonly hero800: '40px';
readonly hero900: '52px';
readonly hero1000: '92px';
}export const fontWeight: {
readonly regular: 400;
readonly medium: 500;
readonly semibold: 600;
readonly bold: 700;
}export const fontFamily: {
readonly heading: "'Segoe UI', 'Segoe UI Web (West European)', -apple-system, BlinkMacSystemFont, Roboto, 'Helvetica Neue', sans-serif";
readonly base: "'Segoe UI', 'Segoe UI Web (West European)', -apple-system, BlinkMacSystemFont, Roboto, 'Helvetica Neue', sans-serif";
readonly monospace: "Consolas, 'Courier New', Courier, monospace";
readonly numeric: "Bahnschrift, 'Segoe UI', 'Segoe UI Web (West European)', -apple-system, BlinkMacSystemFont, Roboto, 'Helvetica Neue', sans-serif";
}export const iconSize: {
readonly 100: '12px';
readonly 200: '16px';
readonly 300: '20px';
readonly 400: '24px';
readonly 500: '28px';
readonly 600: '32px';
readonly 700: '48px';
}export const borderRadius: {
readonly none: '0';
readonly small: '2px';
readonly medium: '4px';
readonly large: '6px';
readonly xLarge: '8px';
readonly '2xl': '12px';
readonly '3xl': '16px';
readonly '4xl': '24px';
readonly '5xl': '32px';
readonly '6xl': '40px';
readonly circular: '9999px';
}export function injectDesignTokens(): booleanexport interface VisualTheme {
foreground: string;
foregroundSecondary: string;
brandForeground: string;
brandBackground: string;
background: string;
backgroundSecondary: string;
backgroundHover: string;
stroke: string;
typography?: {
heading?: { family?: string; size?: number; weight?: number; style?: string };
label?: { family?: string; size?: number; weight?: number; style?: string };
};
spacing?: {
cellPadding?: string;
};
border?: {
width?: number;
radius?: string;
};
}export function readCssTheme(element?: Element): VisualThemeexport const CSS_VAR_BY_THEME_KEY: {
readonly foreground: '--color-foreground';
readonly background: '--color-card';
readonly stroke: '--color-border';
readonly foregroundSecondary: '--color-muted-foreground';
readonly backgroundSecondary: '--color-muted';
readonly backgroundHover: '--color-hover';
readonly brandBackground: '--color-brand';
readonly brandForeground: '--color-brand-foreground';
}export function cssThemeChanged(a: VisualTheme, b: VisualTheme): booleanexport const lightThemeColors: VisualThemeexport const darkThemeColors: VisualThemeDesign Token Type Helpers
export type SpacingToken = keyof typeof spacingexport type FontSizeToken = keyof typeof fontSizeexport type LineHeightToken = keyof typeof lineHeightexport type FontWeightToken = keyof typeof fontWeightexport type FontFamilyToken = keyof typeof fontFamilyexport type IconSizeToken = keyof typeof iconSizeexport type BorderRadiusToken = keyof typeof borderRadiusexport type DesignToken = keyof typeof tokensKey Constraints & Gotchas
Format strings are VBA/ECMA-376, not d3
// ✅ DO: Use VBA/ECMA-376 format strings in ColumnDef.format
const col: ColumnDef = { name: 'sales', format: '$#,##0.00' };
// ❌ DON'T: Use d3 format strings in ColumnDef.format
const col: ColumnDef = { name: 'sales', format: '$,.2f' };
// ✅ DO: Convert when a downstream API needs d3 format
const d3Fmt = vbaToD3Format('$#,##0.00'); // '$,.2f'Column names from Fabric SDK omit single quotes around table names
// ✅ DO: Use the exact column name returned by the Fabric SDK
const key = 'Product Category[EnglishProductCategoryName]';
// ❌ DON'T: Use DAX-style quoted table names
const key = "'Product Category'[EnglishProductCategoryName]";DataTable uses column-major schema with row-major values
// ✅ DO: Align row values to the columns array by index
const table: DataTable = {
columns: [{ name: 'region' }, { name: 'sales' }],
rows: [['West', 1200], ['East', 900]], // row[0] = 'region', row[1] = 'sales'
};Aggregation behavior
- ✅ DO: Expect
countto ignore thecolumnproperty and count all rows. - ✅ DO: Expect
sumto return0for empty or missing numeric input. - ✅ DO: Expect
min,max, andaverageto returnundefinedfor empty or missing numeric input. - ✅ DO: Expect non-numeric and
nullvalues to be skipped by numeric aggregations.
SSR and DOM safety
- ✅ DO: Handle
injectDesignTokens()returningfalsewhen nodocumentis available or when tokens were already injected. - ✅ DO: Expect
readCssTheme()to fall back tolightThemeColorswhendocumentis unavailable.
Immutability
- ✅ DO: Treat
filterRows(),sliceRows(),aggregate(), andgroupBy()as non-mutating helpers. - ✅ DO: Expect
convertDataTableToRows()to fill missing entries withnull.
Token access
- ✅ DO: Use raw token objects such as
spacingandfontSizewhen you need literal values. - ❌ DON'T: Assume
tokensexposes literals; it exposes CSSvar(...)references.
Minimal Usage Examples
import { aggregate, convertDataTableToRows, filterRows, formatValue, injectDesignTokens, type DataTable } from '@microsoft/fabric-visuals-core';
const table: DataTable = { columns: [{ name: 'region' }, { name: 'sales', format: '$#,##0.00' }], rows: [['West', 1200]] };
const rows = convertDataTableToRows(table);
const westOnly = filterRows(table, (row) => row[0] === 'West');
const total = aggregate(table, { column: 'sales', fn: 'sum' });
const label = formatValue(1200, '$#,##0.00');
injectDesignTokens();import { convertVbaFormat, vbaToD3Format, vbaToD3TimeFormat } from '@microsoft/fabric-visuals-core';
convertVbaFormat('$#,##0.00'); // { type: 'number', d3Format: '$,.2f' }
vbaToD3Format('0.00%'); // '.2%'
vbaToD3TimeFormat('yyyy-mm-dd'); // '%Y-%m-%d'import { spacing, tokens, lightThemeColors, readCssTheme } from '@microsoft/fabric-visuals-core';
spacing.s; // '8px'
tokens.spacingS; // 'var(--spacing-s)'
lightThemeColors.stroke; // '#e0e0e0'
readCssTheme();Trademarks
This project may contain trademarks or logos for projects, products, or services. Authorized use of Microsoft trademarks or logos is subject to and must follow Microsoft's Trademark & Brand Guidelines. Use of Microsoft trademarks or logos in modified versions of this project must not cause confusion or imply Microsoft sponsorship. Any use of third-party trademarks or logos are subject to those third-party's policies.
Security
Microsoft takes the security of our software products and services seriously, which includes all source code repositories in our GitHub organizations.
Please do not report security vulnerabilities through public GitHub issues.
For security reporting information, locations, contact information, and policies, please review the latest guidance for Microsoft repositories at https://aka.ms/SECURITY.md.
Code of conduct
We as members, contributors, and leaders pledge to make participation in our community a harassment-free experience for everyone, regardless of age, body size, visible or invisible disability, ethnicity, sex characteristics, gender identity and expression, level of experience, education, socio-economic status, nationality, personal appearance, race, caste, color, religion, or sexual identity and orientation.
We pledge to act and interact in ways that contribute to an open, welcoming, diverse, inclusive, and healthy community.
