Skip to content

Feature/component loading state#504

Merged
ankit-thesys merged 7 commits into
thesysdev:mainfrom
jeff-goodman:feature/component-loading-state
May 15, 2026
Merged

Feature/component loading state#504
ankit-thesys merged 7 commits into
thesysdev:mainfrom
jeff-goodman:feature/component-loading-state

Conversation

@jeff-goodman
Copy link
Copy Markdown
Contributor

@jeff-goodman jeff-goodman commented May 11, 2026

Closes #503

Summary

Genui apps with Query() calls render before tool data arrives, showing blank/empty UIs in an indeterminate loading state. This PR surfaces that loading state to components and adds skeleton placeholders so users see progress instead of nothing.

Changes

fix(openui-dashboard): remove server-side tool calls and add simulated tool latency

Refactors the chat route to use plain streaming (no runTools) so tool calls happen client-side via MCP rather than during LLM generation. Adds NEXT_PUBLIC_TOOL_DELAY_MS to mock tools for testing intermediate loading states.

feat(react-lang): add isQueryLoading to context for tracking in-flight queries

Adds isQueryLoading to OpenUIContextValue and exports a useIsQueryLoading() hook. Genui components can now distinguish between "waiting on data" and "no data exists."

feat(react-ui): add Skeleton component and loading state to Table

New Skeleton, SkeletonBar, and TableSkeleton components with theme-aware CSS variables. The genui Table now renders <TableSkeleton> while queries are in-flight and no rows exist yet.

docs: add useIsQueryLoading and Skeleton component documentation

Updates the react-lang API reference, renderer hooks list, and react-ui component docs with the new API surface.

Screenshot

Table skeleton during tool call loading state in examples/openui-dashboard:
Screenshot 2026-05-11 at 11 03 23 PM

Checklist

  • useIsQueryLoading() exported from @openuidev/react-lang
  • Skeleton / TableSkeleton exported from @openuidev/react-ui
  • Table genui component shows loading skeleton while queries fetch
  • All builds pass (react-ui, openui-dashboard)
  • Docs updated

…d tool latency

Remove tools from the runTools() call so the LLM only generates Query()
statements instead of executing tools server-side during generation.

Replace SSE streaming helper (sseResponseFromRunner) with a manual
ReadableStream that pipes plain create() chunks directly as SSE events
with an explicit data: [DONE] terminator.

Add NEXT_PUBLIC_TOOL_DELAY_MS env var so mock tool execute() functions
simulate network latency, surfacing intermediate loading states in the UI.
…t queries

Add isQueryLoading field to OpenUIContextValue and export a
useIsQueryLoading() hook so data-driven genui components can
detect when Query() calls are still fetching data via MCP.

Wire isQueryLoading from querySnapshot.__openui_loading in the
useOpenUIState hook, moving the variable before contextValue so it
is no longer referenced before declaration.
Add Skeleton, SkeletonBar, and TableSkeleton components with a
theme-aware opacity-pulse animation driven by CSS variables
(--openui-elevated-strong, --openui-border-default, --openui-radius-xs)
so the loading state is clearly visible against light and dark backgrounds.

Wire the genui-lib Table component to use useIsQueryLoading() and render
TableSkeleton when data is loading and no rows are present yet, using
deterministic widths for SSR hydration safety.
Add useIsQueryLoading() to the react-lang API reference and the
renderer hooks list alongside useIsStreaming.

Document Skeleton, TableSkeleton, and how the genui Table component
automatically uses them when isQueryLoading is true and no rows exist.
- Fix import ordering and ternary formatting in genui-lib Table
- Refactor Skeleton component from inline styles to SCSS classes per repo standards
- Add explanatory comment to .env.example for NEXT_PUBLIC_TOOL_DELAY_MS
- Add skeleton.scss with design tokens (cssUtils) and keyframe animation
- Add dependencies.ts per component structure rules
- Add Storybook stories for Skeleton and TableSkeleton
- Regenerate components/index.scss to forward Skeleton styles
…and wire into genui PieChart

Replace the narrow DonutChartSkeleton with a proper PieChartSkeleton that
mirrors the component library's variant/appearance model:

- variant: 'pie' | 'donut'
- appearance: 'circular' | 'semiCircular'

This ensures skeletons are visually consistent with the actual chart shapes
they replace, avoiding layout jumps when data arrives. It also demonstrates
WHY per-component loading state is needed (issue thesysdev#503): when multiple queries
run in parallel with different durations, each component should show its own
skeleton rather than relying on a global spinner.

Changes:
- Skeleton.tsx: PieChartSkeleton with variant/appearance/size props; use
  mutually exclusive class composition instead of overlapping modifiers
- skeleton.scss: CSS for all 4 shape combos using design tokens
  (-xl, -full)
- PieChart.ts: wire useIsQueryLoading -> PieChartSkeleton; expose
  'appearance' in genUI schema; remove unreachable skeleton branch;
  destructure variant/appearance at top of component
- Skeleton.stories.tsx: stories for all 4 variant/appearance combinations
- tools.ts: double get_error_breakdown delay for testing staggered loads
Copy link
Copy Markdown
Contributor

@ankit-thesys ankit-thesys left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks Good

@ankit-thesys ankit-thesys merged commit 8d3b31b into thesysdev:main May 15, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

useIsQueryLoading hook to support loading state for data driven components

2 participants