From 81f310e05550c43678125e9a0b02a2e89cb32434 Mon Sep 17 00:00:00 2001 From: william garrity Date: Tue, 10 Feb 2026 20:31:20 -0500 Subject: [PATCH 1/6] feat(DataVis): add React wrapper component for wcdatavis library Integrate MIE's imperative wcdatavis data visualization/grid library into the mieweb-ui React component system with full design system support. ## New Component: DataVis - DataVis.tsx: Declarative React wrapper around wcdatavis Source, ComputedView, and Grid classes. Supports multiple data source types (HTTP, JSON/array via local bridging), lifecycle management (mount, update, destroy), loading/error/empty states, and forwarded refs. - datavis-theme.css: 1,300+ lines of CSS overrides mapping every hardcoded wcdatavis color to --mieweb-* design tokens. Covers grid shell, title bar, toolbar, table headers/rows/footer, control panels, buttons, context menus, jQuery UI dialogs, column config windows, SumoSelect dropdowns, tooltips, scrollbars, and print styles. Includes responsive, high-contrast, and reduced-motion media queries. - index.ts: Public exports for DataVis, dataVisVariants, and all TypeScript interfaces (DataVisProps, DataVisSourceConfig, etc.) - wcdatavis.d.ts: Ambient type declarations for both 'wcdatavis' (v2.x unscoped) and '@mieweb/wcdatavis' (v3.x scoped) packages, plus CSS module declarations. ## Vite/Storybook Integration - wcdatavis-shim.js: ESM shim that resolves the broken Perspective export in wcdatavis's index.js. Loads jQuery as a global first, then jQuery UI + contextmenu + SumoSelect + Flatpickr as side-effects, then re-exports Source, ComputedView, Grid, Graph, and Prefs. - jquery-global.js: Sets window.jQuery/$ before jQuery UI loads. Also patches console.warn BEFORE wcdatavis modules evaluate to suppress benign warnings (MirageView naming, column validation) that are bound via Function.prototype.bind at import time. - .storybook/main.ts: Added viteFinal config with Vite aliases - bare 'wcdatavis' and '@mieweb/wcdatavis' resolve to our shim; jQuery plugins resolved from wcdatavis's nested node_modules. Added optimizeDeps includes for wcdatavis source files. - .storybook/preview-head.html: Added FontAwesome 4.7 CDN link (required by wcdatavis grid icons). - .storybook/preview.tsx: Refactored brand style injection to use separate light/dark CSS variable blocks with a semanticVarBlock() helper, fixing dark mode propagation to inline .dark wrappers. ## Stories (DataVis.stories.tsx) 15 stories covering all component features: - Default (HTTP/Iris dataset), JsonData, CardVariant - SmallSize, LargeSize (density presets) - Loading, CustomLoading (loading states) - BrandBlueHive, BrandMieWeb, BrandEnterpriseHealth (multi-brand) - DarkMode, LightDarkComparison (theme modes) - WithCallbacks (onGridReady, onDataLoaded, onError) - ErrorState, CustomErrorMessage (error handling using unsupported_source_type instead of invalid HTTP URLs to avoid network errors in the console) ## Package Configuration - package.json: Added wcdatavis as a devDependency (file: link), @mieweb/wcdatavis and font-awesome as optional peerDependencies. - eslint.config.js: Added MutationObserver to browser globals; added config block for DataVis .js shim files with window/console globals. ## Console Error Cleanup Resolved all wcdatavis console noise: - MirageView 'Providing a name for this' warnings: suppressed via console.warn patch in jquery-global.js (runs before module load, captured by bind) - 'Unable to validate column configuration' warnings: same approach - HTTP/AJAX errors from invalid URLs in stories: replaced with clean unsupported_source_type trigger - AbortError noise: eliminated by removing network requests from error state stories --- .storybook/main.ts | 43 + .storybook/preview-head.html | 8 + .storybook/preview.tsx | 59 +- eslint.config.js | 11 + package-lock.json | 55 +- package.json | 11 +- src/components/DataVis/DataVis.stories.tsx | 422 ++++++ src/components/DataVis/DataVis.tsx | 632 +++++++++ src/components/DataVis/datavis-theme.css | 1373 ++++++++++++++++++++ src/components/DataVis/index.ts | 8 + src/components/DataVis/jquery-global.js | 25 + src/components/DataVis/wcdatavis-shim.js | 39 + src/components/DataVis/wcdatavis.d.ts | 90 ++ src/index.ts | 1 + 14 files changed, 2753 insertions(+), 24 deletions(-) create mode 100644 src/components/DataVis/DataVis.stories.tsx create mode 100644 src/components/DataVis/DataVis.tsx create mode 100644 src/components/DataVis/datavis-theme.css create mode 100644 src/components/DataVis/index.ts create mode 100644 src/components/DataVis/jquery-global.js create mode 100644 src/components/DataVis/wcdatavis-shim.js create mode 100644 src/components/DataVis/wcdatavis.d.ts diff --git a/.storybook/main.ts b/.storybook/main.ts index f592219f..5302b6da 100644 --- a/.storybook/main.ts +++ b/.storybook/main.ts @@ -1,4 +1,5 @@ import type { StorybookConfig } from '@storybook/react-vite'; +import path from 'path'; const config: StorybookConfig = { stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'], @@ -16,6 +17,48 @@ const config: StorybookConfig = { reactDocgen: 'react-docgen-typescript', }, staticDirs: ['./public'], + viteFinal: async (config) => { + // wcdatavis nested dependency root + const wcdatavisNodeModules = path.resolve(process.cwd(), 'node_modules/wcdatavis/node_modules'); + + // Use our shim that works around the broken Perspective export in wcdatavis index.js + // and ensures Vite uses ESM exports instead of the "browser" field (window.MIE globals). + // Only alias the EXACT bare specifier 'wcdatavis', not 'wcdatavis/src/...' sub-paths. + config.resolve = config.resolve || {}; + const existingAliases = Array.isArray(config.resolve.alias) + ? config.resolve.alias + : Object.entries(config.resolve.alias || {}).map(([find, replacement]) => ({ find, replacement })); + config.resolve.alias = [ + ...existingAliases, + { + find: /^wcdatavis$/, + replacement: path.resolve(process.cwd(), 'src/components/DataVis/wcdatavis-shim.js'), + }, + { + find: /^@mieweb\/wcdatavis$/, + replacement: path.resolve(process.cwd(), 'src/components/DataVis/wcdatavis-shim.js'), + }, + // Resolve wcdatavis's jQuery plugins from its nested node_modules so they + // extend the same jQuery instance the source files import + { find: /^jquery-ui(.*)$/, replacement: path.join(wcdatavisNodeModules, 'jquery-ui$1') }, + { find: /^jquery-contextmenu$/, replacement: path.join(wcdatavisNodeModules, 'jquery-contextmenu') }, + { find: /^sumoselect$/, replacement: path.join(wcdatavisNodeModules, 'sumoselect') }, + { find: /^flatpickr$/, replacement: path.join(wcdatavisNodeModules, 'flatpickr') }, + { find: /^jquery$/, replacement: path.join(wcdatavisNodeModules, 'jquery') }, + ]; + + // Pre-bundle wcdatavis and its jQuery plugins + config.optimizeDeps = config.optimizeDeps || {}; + config.optimizeDeps.include = [ + ...(config.optimizeDeps.include || []), + 'wcdatavis/src/source.js', + 'wcdatavis/src/computed_view.js', + 'wcdatavis/src/grid.js', + 'wcdatavis/src/graph.js', + 'wcdatavis/src/prefs.js', + ]; + return config; + }, }; export default config; diff --git a/.storybook/preview-head.html b/.storybook/preview-head.html index a98e03b2..f3a7dea1 100644 --- a/.storybook/preview-head.html +++ b/.storybook/preview-head.html @@ -1,3 +1,11 @@ + + +