npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2025 – Pkg Stats / Ryan Hefner

@aisahub/bi-ui

v0.1.0

Published

Smart query form and chart component

Readme

aisahub-bi-ui

React component library for intelligent data visualization and query form management. Build AI-powered business intelligence interfaces with pre-built components for data upload, natural language queries, and interactive chart generation.

Features

  • Smart Query Forms - User input with optional file upload and chart type selection
  • 60+ Chart Types - Line, Bar, Pie, and Scatter charts with multiple subtypes
  • Multi-Chart Dashboard - Responsive grid layout with individual chart management
  • CSS Theme Variables - Full customization via CSS custom properties
  • TypeScript Support - Complete type definitions included
  • Next.js Compatible - Works with App Router and Pages Router
  • Accessible - ARIA attributes, keyboard navigation, and focus management

Installation

npm install aisahub-bi-ui
# or
yarn add aisahub-bi-ui

Peer Dependencies

npm install react react-dom @emotion/react @emotion/styled

| Package | Version | |---------|---------| | react | ^18.0.0 or ^19.0.0 | | react-dom | ^18.0.0 or ^19.0.0 | | @emotion/react | ^11.0.0 | | @emotion/styled | ^11.0.0 |

Quick Start

import {
  QueryForm,
  ChartDisplay,
  useChartData,
  PageHeader
} from 'aisahub-bi-ui';

function App() {
  const {
    chartOptions,
    isLoading,
    error,
    submitQuery,
    resetChart
  } = useChartData();

  const handleSubmit = (data) => {
    submitQuery(data, '/api/generate-chart');
  };

  return (
    <div>
      <PageHeader
        title="Data Visualization"
        subtitle="Describe what you want to visualize"
      />

      {!chartOptions ? (
        <QueryForm
          onSubmit={handleSubmit}
          isLoading={isLoading}
          error={error}
        />
      ) : (
        <ChartDisplay
          options={chartOptions}
          onReset={resetChart}
        />
      )}
    </div>
  );
}

API Configuration

The useChartData hook communicates with your backend API to generate charts. Configure the base URL when initializing:

// Default: http://localhost:8000
const { submitQuery } = useChartData();

// Custom base URL
const { submitQuery } = useChartData('https://your-api.com');

Request Format

The hook sends a FormData POST request with:

| Field | Type | Description | |-------|------|-------------| | userRequest | string | Natural language query (chart type appended if selected) | | dbDump | File (optional) | Uploaded data file (.sql, .csv, .json, .txt) |

Response Format

Your API should return:

{
  "echarts_config": { /* ECharts option object */ },
  "intent": {
    "intent_complete": true,
    "metrics": ["revenue", "sales"],
    "dimensions": ["month", "region"],
    "filters": {},
    "chart_type": "bar",
    "missing": [],
    "clarification_needed": ""
  }
}

When intent_complete is false, the clarification_needed field contains a question for the user, which can be displayed using the FeedbackForm component.

Custom Headers & Abort Signal

submitQuery(formData, '/api/chart', {
  headers: { 'Authorization': 'Bearer token' },
  signal: abortController.signal
});

Components

QueryForm

High-level query form with optional file upload and chart type selection.

<QueryForm
  onSubmit={(data) => handleSubmit(data)}
  isLoading={false}
  includeDbDump={true}
  includeChartTypeSelector={true}
  progress="Generating chart..."
  error={null}
/>

| Prop | Type | Default | Description | |------|------|---------|-------------| | onSubmit | (data: FormData) => void | required | Form submission handler | | isLoading | boolean | required | Shows loading state | | includeDbDump | boolean | false | Show file upload field | | includeChartTypeSelector | boolean | true | Show chart type selector | | progress | string | '' | Progress message during loading | | error | string \| null | null | Error message to display | | className | string | - | Container class | | classNames | BaseFormClassNames | - | Element-level classes |

ChartDisplay

Single chart viewer with reset functionality.

<ChartDisplay
  options={echartsOptions}
  onReset={() => setChartOptions(null)}
/>

| Prop | Type | Default | Description | |------|------|---------|-------------| | options | EChartsOption | required | ECharts configuration object | | onReset | () => void | required | Reset button handler | | className | string | - | Container class | | classNames | ChartDisplayClassNames | - | Element-level classes |

MultiChartDisplay

Dashboard with multiple charts in a responsive grid.

<MultiChartDisplay
  charts={[
    {
      id: '1',
      title: 'Revenue by Month',
      options: echartsOptions,
      size: 'medium',
      query: 'SELECT * FROM sales'
    }
  ]}
  onReset={() => setShowForm(true)}
  onDelete={(id) => removeChart(id)}
  title="Analytics Dashboard"
  columns={2}
/>

| Prop | Type | Default | Description | |------|------|---------|-------------| | charts | ChartItem[] | required | Array of chart configurations | | onReset | () => void | required | "New Chart" button handler | | onDelete | (id: string) => void | required | Delete chart handler | | title | string | 'Dashboard' | Dashboard title | | columns | number | 2 | Grid column count | | className | string | - | Container class | | classNames | MultiChartDisplayClassNames | - | Element-level classes |

FeedbackForm

Form for AI clarification requests when intent is incomplete.

<FeedbackForm
  onSubmit={(data) => handleClarification(data)}
  isLoading={false}
  intent={intentData}
  includeDbDump={false}
/>

| Prop | Type | Default | Description | |------|------|---------|-------------| | onSubmit | (data: FormData) => void | required | Form submission handler | | isLoading | boolean | required | Shows loading state | | intent | Intent \| null | required | Intent object with clarification question | | includeDbDump | boolean | false | Show file upload field | | progress | string | '' | Progress message | | error | string \| null | null | Error message |

PageHeader

Customizable page header with title and subtitle.

<PageHeader
  title="Data Visualization Tool"
  subtitle="Upload your data and describe what you want to visualize"
/>

| Prop | Type | Default | Description | |------|------|---------|-------------| | title | string | 'Data Visualization Tool' | Main heading | | subtitle | string | 'Upload your data...' | Subheading text | | className | string | - | Container class | | classNames | PageHeaderClassNames | - | Element-level classes |

AnimatedModal

Accessible modal dialog with animations.

<AnimatedModal
  isOpen={showModal}
  onClose={() => setShowModal(false)}
  title="Chart Details"
>
  <p>Modal content here</p>
</AnimatedModal>

| Prop | Type | Default | Description | |------|------|---------|-------------| | isOpen | boolean | required | Controls visibility | | onClose | () => void | required | Close handler | | title | string | - | Modal title | | children | ReactNode | - | Modal content | | className | string | - | Modal container class | | classNames | AnimatedModalClassNames | - | Element-level classes |

LoadingDisplay

Animated loading spinner.

<LoadingDisplay />

ErrorDisplay

Error message with retry button.

<ErrorDisplay
  message="Failed to generate chart"
  onRetry={() => refetch()}
/>

| Prop | Type | Default | Description | |------|------|---------|-------------| | message | string | required | Error message text | | onRetry | () => void | - | Optional retry handler |

Hooks

useChartData

Hook for managing chart data submission and state.

const {
  chartOptions,      // EChartsOption | null
  isLoading,         // boolean
  error,             // string | null
  addChart,          // boolean
  setAddChart,       // Dispatch<SetStateAction<boolean>>
  isIntentComplete,  // boolean
  intent,            // Intent | null
  submitQuery,       // (data, url, options?) => Promise<void>
  resetChart,        // () => void
} = useChartData(baseURL?: string);

TypeScript Types

import type {
  FormData,
  ChartApiResponse,
  ChartItem,
  Intent,
  ChartCategory,
  UseChartDataReturn,
  SubmitQueryOptions,
  FileValidationConfig
} from 'aisahub-bi-ui';

// Chart categories
type ChartCategory = 'line' | 'bar' | 'pie' | 'scatter';

// Form data structure
interface FormData {
  user_request: string;
  db_dump: FileList | null;
  chart_type?: ChartCategory;
  chart_sub_type?: string;
}

// Chart item for dashboard
interface ChartItem {
  id: string;
  title: string;
  options: EChartsOption;
  size?: 'small' | 'medium' | 'large';
  query: string;
  isUpdating?: boolean;
  updateError?: string;
}

// Intent from API
interface Intent {
  intent_complete: boolean;
  metrics: string[];
  dimensions: string[];
  filters: object;
  chart_type: string;
  missing: string[];
  clarification_needed: string;
}

Theming

All components use CSS custom properties with the --bi- prefix. Override them in your global CSS:

:root {
  /* Primary colors */
  --bi-primary: hsl(222.2 47.4% 11.2%);
  --bi-primary-hover: hsl(222.2 47.4% 20%);
  --bi-primary-foreground: hsl(210 40% 98%);

  /* Background & Foreground */
  --bi-background: hsl(0 0% 100%);
  --bi-foreground: hsl(222.2 84% 4.9%);

  /* Semantic colors */
  --bi-success: hsl(142.1 76.2% 36.3%);
  --bi-error: hsl(0 84.2% 60.2%);
  --bi-destructive: hsl(0 84.2% 60.2%);

  /* Border & Input */
  --bi-border: hsl(214.3 31.8% 91.4%);
  --bi-input: hsl(214.3 31.8% 91.4%);
  --bi-ring: hsl(222.2 84% 4.9%);

  /* Muted colors */
  --bi-muted: hsl(210 40% 96.1%);
  --bi-muted-foreground: hsl(215.4 16.3% 46.9%);

  /* Card colors */
  --bi-card: hsl(0 0% 100%);
  --bi-card-foreground: hsl(222.2 84% 4.9%);

  /* Border radius */
  --bi-radius: 0.5rem;

  /* Typography */
  --bi-text-sm: 0.875rem;
  --bi-text-base: 1rem;
  --bi-text-lg: 1.125rem;
  --bi-font-sans: ui-sans-serif, system-ui, sans-serif;

  /* Shadows */
  --bi-shadow-sm: 0 1px 2px 0 rgba(0, 0, 0, 0.05);
  --bi-shadow-md: 0 4px 6px -1px rgba(0, 0, 0, 0.1);
  --bi-shadow-lg: 0 10px 15px -3px rgba(0, 0, 0, 0.1);

  /* Transitions */
  --bi-transition-fast: 150ms ease-in-out;
  --bi-transition-normal: 200ms ease-in-out;
}

Dark Mode

.dark {
  --bi-background: hsl(222.2 84% 4.9%);
  --bi-foreground: hsl(210 40% 98%);
  --bi-card: hsl(222.2 84% 4.9%);
  --bi-card-foreground: hsl(210 40% 98%);
  --bi-border: hsl(217.2 32.6% 17.5%);
  --bi-muted: hsl(217.2 32.6% 17.5%);
  --bi-muted-foreground: hsl(215 20.2% 65.1%);
}

Chart Types Reference

Line Charts (15 subtypes)

| Value | Label | |-------|-------| | line-simple | Basic Line | | line-smooth | Smoothed Line | | area-basic | Basic Area | | line-stack | Stacked Line | | area-stack | Stacked Area | | area-stack-gradient | Gradient Stacked Area | | line-step | Step Line | | line-marker | Line with Markers | | line-gradient | Line Gradient | | line-style | Line Style | | area-pieces | Area Pieces | | line-log | Log Axis | | line-polar | Polar Line | | bump-chart | Bump Chart | | confidence-band | Confidence Band |

Bar Charts (14 subtypes)

| Value | Label | |-------|-------| | bar-simple | Basic Bar | | bar-stack | Stacked Bar | | bar-y-category | Horizontal Bar | | bar-waterfall | Waterfall | | bar-gradient | Gradient Bar | | bar-negative | Negative Values | | bar-label-rotation | Label Rotation | | bar-y-category-stack | Horizontal Stacked | | bar-polar-stack | Polar Stacked | | bar-race | Bar Race | | bar-background | Bar with Background | | mix-line-bar | Mixed Line & Bar | | bar-drilldown | Drilldown | | polar-roundCap | Rounded Polar |

Pie Charts (13 subtypes)

| Value | Label | |-------|-------| | pie-simple | Basic Pie | | pie-doughnut | Doughnut | | pie-roseType | Nightingale | | pie-half-donut | Half Doughnut | | pie-nest | Nested Pies | | pie-borderRadius | Rounded Doughnut | | pie-padAngle | Padded Pie | | pie-pattern | Textured Pie | | pie-legend | Scrollable Legend | | pie-rich-text | Rich Text Label | | pie-labelLine-adjust | Label Line Adjust | | pie-custom | Custom Pie | | pie-roseType-simple | Simple Nightingale |

Scatter Charts (12 subtypes)

| Value | Label | |-------|-------| | scatter-simple | Basic Scatter | | scatter-effect | Effect Scatter | | scatter-weight | Bubble | | bubble-gradient | Gradient Bubble | | scatter-punchCard | Punch Card | | scatter-single-axis | Single Axis | | scatter-linear-regression | Linear Regression | | scatter-exponential-regression | Exponential Regression | | scatter-clustering | Clustering | | scatter-anscombe-quartet | Anscombe Quartet | | scatter-aqi-color | AQI Color | | scatter-matrix | Scatter Matrix |

Next.js Integration

App Router

All components include the 'use client' directive and work out of the box:

// app/dashboard/page.tsx
import { QueryForm, ChartDisplay, useChartData } from 'aisahub-bi-ui';

export default function DashboardPage() {
  // Components are already client components
  return <Dashboard />;
}

With Server Components

Wrap the library components in a client component:

// components/ChartWidget.tsx
'use client';

import { QueryForm, useChartData } from 'aisahub-bi-ui';

export function ChartWidget() {
  const { submitQuery, isLoading } = useChartData();
  return <QueryForm onSubmit={submitQuery} isLoading={isLoading} />;
}

Accessibility

  • Semantic HTML: Proper heading hierarchy, form labels, and landmarks
  • ARIA attributes: aria-label, aria-describedby, aria-invalid, aria-live
  • Keyboard navigation: Full Tab support, Escape to close modals
  • Focus management: Focus trapping in modals, focus restoration on close
  • Screen reader support: Loading announcements via aria-live regions

License

ISC

Author

Geared AI