visualifyjs 2.5.3-2.dev → 3.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude/mem/TIMELINE.md +36 -0
- package/.claude/mem/notes/2026-02-11-3d-visualization-docs-fix-external-script-solution.md +24 -0
- package/.claude/mem/notes/2026-02-11-3d-visualization-docs-fix-session-summary.md +43 -0
- package/.claude/mem/notes/2026-02-11-cli-fix-editor-command-alias.md +26 -0
- package/.claude/mem/notes/2026-02-11-phase-3-developer-experience-completed.md +51 -0
- package/.claude/mem/notes/2026-02-11-phase-4-web-workers-implementation-complete.md +59 -0
- package/.claude/mem/notes/2026-02-11-visualify-phase-2-3d-visualization-complete.md +50 -0
- package/.claude/mem/notes/2026-02-11-visualify-phase-2-committed-ready-for-phase-3.md +33 -0
- package/.claude/mem/notes/2026-02-11-visualify-phase-3-complete-developer-experience.md +52 -0
- package/.claude/mem/notes/2026-02-11-visualify-repository-cleanup-complete.md +28 -0
- package/.claude/mem/notes/2026-02-18-codebase-cleanup-docsify-plugin-documentation.md +37 -0
- package/.claude/mem/notes/2026-02-19-css-grid-layout-fix-displaycontents-on-vcontroller.md +18 -0
- package/.claude/mem/notes/2026-02-19-docsify-plugin-fixes-latex-and-visualify-code-bloc.md +26 -0
- package/.claude/mem/notes/2026-02-19-page-mode-docs-update-decisions.md +23 -0
- package/.claude/mem/notes/2026-02-19-react-context-infinite-re-render-loop-fix-pattern.md +31 -0
- package/.claude/mem/notes/2026-02-19-version-300-bump-and-build-fixes.md +32 -0
- package/.claude/mem/notes/2026-02-19-visualify-build-deployment-architecture-bug-fixes.md +25 -0
- package/.claude/mem/notes/2026-02-19-visualify-dist-iife-self-contained-build-config.md +30 -0
- package/.claude/mem/notes/2026-02-19-visualify-infinite-loop-i18n-fixes.md +31 -0
- package/.claude/mem/notes/2026-02-19-visualify-v3-bundle-splitting-docs-restructuring.md +32 -0
- package/.claude/mem/notes/2026-02-20-bundle-externalization-final-architecture.md +29 -0
- package/.claude/mem/notes/2026-02-20-chromium-page-fix-unstable-keys-and-double-event-b.md +27 -0
- package/.claude/mem/notes/2026-02-20-console-cleanup-bundle-optimization-commit.md +20 -0
- package/.claude/mem/notes/2026-02-20-dotbio-dot-plot-fix-useeffect-dependency.md +21 -0
- package/.claude/mem/notes/2026-02-20-public-folder-cleanup-and-readme-rewrite.md +25 -0
- package/.claude/mem/notes/2026-02-20-v300-release-and-beta-channel-strategy.md +29 -0
- package/.claude/mem/notes/2026-02-20-visium-background-image-unknown-legend-fix.md +19 -0
- package/.claude/mem/notes/2026-02-20-visualify-cdn-loader-bundle-externalization.md +34 -0
- package/.claude/mem/sessions/session-2026-02-20-031524.md +54 -0
- package/.claude/settings.local.json +21 -0
- package/.github/workflows/static.yml.bak +51 -51
- package/.sisyphus/boulder.json +65 -0
- package/.sisyphus/plans/phase-4-advanced-optimizations.md +217 -0
- package/LICENSE +674 -674
- package/README.md +94 -59
- package/config-overrides.js +31 -31
- package/dist/stats.html +4949 -0
- package/dist/visualify-3d.esm.js +1 -0
- package/dist/visualify-3d.js +1 -0
- package/dist/visualify-core.esm.js +1 -0
- package/dist/visualify-core.js +1 -0
- package/dist/visualify-docs.esm.js +1 -0
- package/dist/visualify-docs.js +1 -0
- package/dist/visualify-loader.js +1 -0
- package/dist/visualify-pages.esm.js +1 -0
- package/dist/visualify-pages.js +1 -0
- package/dist/visualify-portal.esm.js +1 -0
- package/dist/visualify-portal.js +1 -0
- package/dist/visualify-shared.js +26571 -0
- package/dist/visualify.js +1 -188
- package/docs/CHANGELOG.md +148 -0
- package/docs/cli/commands.md +513 -0
- package/docs/configuration/visualify-json.md +474 -0
- package/docs/docs/3d-visualization.md +374 -0
- package/docs/docs/CLI.md +303 -34
- package/docs/docs/README.md +65 -65
- package/docs/docs/Rechart/bar.md +190 -190
- package/docs/docs/Rechart/funnel.md +241 -241
- package/docs/docs/Rechart/line.md +355 -355
- package/docs/docs/Rechart/pie.md +225 -225
- package/docs/docs/Rechart/radar.md +253 -253
- package/docs/docs/Rechart/scatter.md +298 -298
- package/docs/docs/_404.md +51 -51
- package/docs/docs/_coverpage.md +11 -11
- package/docs/docs/_sidebar.md +54 -44
- package/docs/docs/components/dotBio.md +87 -34
- package/docs/docs/components/echart.md +171 -82
- package/docs/docs/components/html.md +61 -34
- package/docs/docs/components/macaron.md +156 -145
- package/docs/docs/components/markdown.md +42 -0
- package/docs/docs/components/more.md +183 -142
- package/docs/docs/components/plotly.md +132 -62
- package/docs/docs/components/scatterL.md +171 -70
- package/docs/docs/components/visium.md +112 -57
- package/docs/docs/configuration.md +121 -121
- package/docs/docs/deploy.md +31 -31
- package/docs/docs/docsify-plugin.md +655 -0
- package/docs/docs/hmr.md +165 -0
- package/docs/docs/i18n.md +332 -0
- package/docs/docs/log.md +30 -9
- package/docs/docs/more-pages.md +23 -23
- package/docs/docs/quickstart.md +148 -124
- package/docs/docs/rechart-attributes.md +74 -74
- package/docs/docs/rechart-basic-usage.md +160 -162
- package/docs/docs/theme.md +5 -5
- package/docs/docs/typescript.md +306 -0
- package/docs/docs/visual-editor.md +359 -0
- package/docs/index.html +85 -71
- package/docs/manifest.json +23 -23
- package/docs/migration/v3-migration.md +392 -0
- package/docs/static/css/fluff-stuff.css +169 -169
- package/docs/static/css/font-awesome.min.css +4 -4
- package/docs/static/css/visualify.css +6 -25
- package/docs/static/js/3d-viz-examples.js +181 -0
- package/docs/static/js/configuration.js +630 -448
- package/docs/static/js/visualify.js +1 -188
- package/package.json +106 -84
- package/rollup.config.mjs +766 -76
- package/src/_css/404.css +115 -115
- package/src/_css/App.css +37 -37
- package/src/_css/autoSuggestion.css +26 -26
- package/src/_css/circular-progress.css +32 -32
- package/src/_css/index.css +36 -36
- package/src/_css/modern.css +350 -25
- package/src/_media/corner.svg +8 -8
- package/src/_media/download.svg +3 -3
- package/src/_media/logo.svg +14 -14
- package/src/_test/App.test.js +15 -15
- package/src/_utils/reportWebVitals.js +13 -13
- package/src/a11y/README.md +177 -0
- package/src/a11y/aria-labels.js +339 -0
- package/src/a11y/color-contrast.js +535 -0
- package/src/a11y/index.js +197 -0
- package/src/a11y/keyboard-nav.js +523 -0
- package/src/a11y/styles.css +165 -0
- package/src/cli/commands/dev.js +214 -0
- package/src/cli/commands/docs.js +521 -0
- package/src/cli/commands/edit.js +379 -0
- package/src/cli/commands/init.js +213 -0
- package/src/cli/commands/portal.js +236 -0
- package/src/cli/dev-server.js +530 -0
- package/src/cli/hmr.js +456 -0
- package/src/cli/index.js +180 -0
- package/src/cli/utils/config.js +207 -0
- package/src/cli/utils/logger.js +241 -0
- package/src/config/defaults.ts +122 -0
- package/src/config/index.ts +72 -0
- package/src/config/loader.ts +478 -0
- package/src/config/schema.ts +227 -0
- package/src/config/validator.ts +337 -0
- package/src/core/appContext.js +34 -27
- package/src/core/components/Bar.js +383 -0
- package/src/core/components/Bar3D.js +473 -0
- package/src/core/components/LargeDatasetChart.js +296 -0
- package/src/core/components/Line3D.js +310 -0
- package/src/core/components/Scatter.js +392 -188
- package/src/core/components/Scatter3D.js +455 -0
- package/src/core/components/ScatterBio.js +601 -572
- package/src/core/components/Surface3D.js +326 -0
- package/src/core/components/ThreeCustom.js +648 -0
- package/src/core/components/ThreeScene.js +459 -0
- package/src/core/components/VisiumPlot.js +191 -165
- package/src/core/components/browser.js +42 -42
- package/src/core/components/dotplot.js +413 -413
- package/src/core/components/html.js +29 -29
- package/src/core/components/list.js +178 -178
- package/src/core/components/macaron.js +206 -201
- package/src/core/components/markdown.js +56 -56
- package/src/core/components/parser.scatterBio.js +582 -587
- package/src/core/components/ratio.js +82 -80
- package/src/core/components/scatterL.js +206 -173
- package/src/core/components/searchbar.js +156 -131
- package/src/core/components/selection.js +310 -193
- package/src/core/components/timeline.js +236 -281
- package/src/core/components/visium.js +114 -97
- package/src/core/data-processor.js +413 -0
- package/src/core/fetch/condfetch.js +82 -82
- package/src/core/fetch/fetch.js +92 -92
- package/src/core/fetch/json.js +29 -29
- package/src/core/fetch/vfetch.js +42 -42
- package/src/core/hmr-client.js +724 -0
- package/src/core/liveEditor.js +44 -44
- package/src/core/modules/codeEditorWithPreview.js +104 -104
- package/src/core/modules/echarts/common.js +20 -20
- package/src/core/modules/echarts/gl.js +228 -0
- package/src/core/modules/echarts/presetHandler.js +41 -41
- package/src/core/modules/echarts/presets/esodev.chromium.js +172 -172
- package/src/core/modules/echarts/presets/esodev.codex.js +130 -130
- package/src/core/modules/echarts/presets/esodev.visium.js +123 -123
- package/src/core/modules/echarts/presets/mmtrbc.js +186 -186
- package/src/core/modules/echarts.js +70 -71
- package/src/core/modules/echartsUtils.js +43 -43
- package/src/core/modules/echartswitcher.js +227 -152
- package/src/core/modules/replotly/presetHandler.js +24 -24
- package/src/core/modules/replotly/presets/minimum.js +18 -18
- package/src/core/modules/replotly/presets/mmtrbc.dot.js +114 -114
- package/src/core/modules/replotly/presets/mmtrbc.violin.js +100 -100
- package/src/core/modules/replotly.js +74 -71
- package/src/core/modules/threejs/Camera.js +373 -0
- package/src/core/modules/threejs/Lighting.js +459 -0
- package/src/core/modules/threejs/Renderer.js +364 -0
- package/src/core/modules/threejs/Scene.js +266 -0
- package/src/core/modules/threejs/index.js +155 -0
- package/src/core/pages/404.js +50 -50
- package/src/core/pages/error.js +27 -27
- package/src/core/pages/jsonPage.js +62 -62
- package/src/core/pages/loading.js +44 -44
- package/src/core/parser/echart.data.js +204 -183
- package/src/core/parser/echart.features.js +125 -125
- package/src/core/parser/echart.general.js +147 -147
- package/src/core/parser/echart.hilbert.js +57 -57
- package/src/core/parser/echart.parser.js +210 -210
- package/src/core/parser/echart.series.js +67 -67
- package/src/core/parser/echart.types.js +76 -76
- package/src/core/parser/plotly.config.js +10 -10
- package/src/core/parser/plotly.data.js +132 -132
- package/src/core/parser/plotly.layout.js +9 -9
- package/src/core/parser/plotly.violin.js +18 -18
- package/src/core/recharts.js +361 -62
- package/src/core/router/alias.js +49 -49
- package/src/core/router/jsonRouter.js +31 -31
- package/src/core/themes/modern.js +32 -32
- package/src/core/themes/themeSelector.js +33 -33
- package/src/core/visualify.js +213 -47
- package/src/core/widgets/circularProgress.js +23 -23
- package/src/core/widgets/controller.js +116 -83
- package/src/core/widgets/errorBoundary.js +36 -36
- package/src/core/widgets/footer.js +185 -177
- package/src/core/widgets/header.js +238 -234
- package/src/core/widgets/layout/Grid.js +31 -31
- package/src/core/widgets/layout.js +36 -36
- package/src/core/widgets/mapping.js +56 -42
- package/src/core/workers/data-worker.js +349 -0
- package/src/core/workers/worker-pool.js +396 -0
- package/src/docsify/bundle.js +215 -0
- package/src/docsify/markdown.js +271 -0
- package/src/docsify/plugin.js +268 -0
- package/src/editor/README.md +172 -0
- package/src/editor/components/ChartBuilder.jsx +341 -0
- package/src/editor/components/ChartTypeSidebar.jsx +91 -0
- package/src/editor/components/Editor.jsx +367 -0
- package/src/editor/components/Preview.jsx +446 -0
- package/src/editor/components/PropertyPanel.jsx +468 -0
- package/src/editor/components/StatusBar.jsx +85 -0
- package/src/editor/context/EditorContext.js +248 -0
- package/src/editor/hooks/useDebounce.js +32 -0
- package/src/editor/index.js +315 -0
- package/src/editor/styles/editor.css +637 -0
- package/src/editor/utils/chartValidator.js +263 -0
- package/src/entries/charts3d.js +70 -0
- package/src/entries/core.js +78 -0
- package/src/entries/docs.js +154 -0
- package/src/entries/pages.js +93 -0
- package/src/entries/portal.js +204 -0
- package/src/entries/shared.js +50 -0
- package/src/i18n/formatters.js +455 -0
- package/src/i18n/index.js +169 -0
- package/src/i18n/locales/ar.json +137 -0
- package/src/i18n/locales/de.json +137 -0
- package/src/i18n/locales/en.json +137 -0
- package/src/i18n/locales/es.json +137 -0
- package/src/i18n/locales/he.json +137 -0
- package/src/i18n/locales/zh.json +137 -0
- package/src/i18n/rtl.css +183 -0
- package/src/index.js +82 -62
- package/src/loader.js +103 -0
- package/src/setupTests.js +5 -5
- package/tsconfig.json +51 -0
- package/types/charts.d.ts +569 -0
- package/types/components.d.ts +441 -0
- package/types/config.d.ts +199 -0
- package/types/index.d.ts +353 -0
|
@@ -1,33 +1,33 @@
|
|
|
1
|
-
/*
|
|
2
|
-
* @Author : Lihao leolihao@arizona.edu
|
|
3
|
-
* @Date : 2023-11-29 22:52:11
|
|
4
|
-
* @FilePath : /visualifyjs/src/core/themes/themeSelector.js
|
|
5
|
-
* @Description :
|
|
6
|
-
* Copyright (c) 2023 by Lihao (leolihao@arizona.edu), All Rights Reserved.
|
|
7
|
-
*/
|
|
8
|
-
import React from 'react';
|
|
9
|
-
import Modern from './modern';
|
|
10
|
-
|
|
11
|
-
function ThemeSelector({ theme, config, children }) {
|
|
12
|
-
switch (theme) {
|
|
13
|
-
case 'modern':
|
|
14
|
-
return (
|
|
15
|
-
<Modern
|
|
16
|
-
config={config}
|
|
17
|
-
children={children}
|
|
18
|
-
/>
|
|
19
|
-
);
|
|
20
|
-
// ... more cases as needed
|
|
21
|
-
default:
|
|
22
|
-
console.warn('Unsupported theme:', theme, 'using default theme');
|
|
23
|
-
// Fallback to default theme
|
|
24
|
-
return (
|
|
25
|
-
<Modern
|
|
26
|
-
config={config}
|
|
27
|
-
children={children}
|
|
28
|
-
/>
|
|
29
|
-
);
|
|
30
|
-
}
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
export default ThemeSelector;
|
|
1
|
+
/*
|
|
2
|
+
* @Author : Lihao leolihao@arizona.edu
|
|
3
|
+
* @Date : 2023-11-29 22:52:11
|
|
4
|
+
* @FilePath : /visualifyjs/src/core/themes/themeSelector.js
|
|
5
|
+
* @Description :
|
|
6
|
+
* Copyright (c) 2023 by Lihao (leolihao@arizona.edu), All Rights Reserved.
|
|
7
|
+
*/
|
|
8
|
+
import React from 'react';
|
|
9
|
+
import Modern from './modern';
|
|
10
|
+
|
|
11
|
+
function ThemeSelector({ theme, config, children }) {
|
|
12
|
+
switch (theme) {
|
|
13
|
+
case 'modern':
|
|
14
|
+
return (
|
|
15
|
+
<Modern
|
|
16
|
+
config={config}
|
|
17
|
+
children={children}
|
|
18
|
+
/>
|
|
19
|
+
);
|
|
20
|
+
// ... more cases as needed
|
|
21
|
+
default:
|
|
22
|
+
console.warn('Unsupported theme:', theme, 'using default theme');
|
|
23
|
+
// Fallback to default theme
|
|
24
|
+
return (
|
|
25
|
+
<Modern
|
|
26
|
+
config={config}
|
|
27
|
+
children={children}
|
|
28
|
+
/>
|
|
29
|
+
);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export default ThemeSelector;
|
package/src/core/visualify.js
CHANGED
|
@@ -1,47 +1,213 @@
|
|
|
1
|
-
/*
|
|
2
|
-
* @Author : Lihao leolihao@arizona.edu
|
|
3
|
-
* @Date : 2023-11-29 15:35:28
|
|
4
|
-
* @FilePath : /visualifyjs/src/core/visualify.js
|
|
5
|
-
* @Description :
|
|
6
|
-
* Copyright (c) 2023 by Lihao (leolihao@arizona.edu), All Rights Reserved.
|
|
7
|
-
*/
|
|
8
|
-
import React from 'react';
|
|
9
|
-
import ReactDOM from 'react-dom/client';
|
|
10
|
-
import ThemeSelector from './themes/themeSelector';
|
|
11
|
-
import JsonRouter from './router/jsonRouter';
|
|
12
|
-
import { VisualifyProvider } from './appContext';
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
const
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
1
|
+
/*
|
|
2
|
+
* @Author : Lihao leolihao@arizona.edu
|
|
3
|
+
* @Date : 2023-11-29 15:35:28
|
|
4
|
+
* @FilePath : /visualifyjs/src/core/visualify.js
|
|
5
|
+
* @Description :
|
|
6
|
+
* Copyright (c) 2023 by Lihao (leolihao@arizona.edu), All Rights Reserved.
|
|
7
|
+
*/
|
|
8
|
+
import React, { useEffect, useRef, useState } from 'react';
|
|
9
|
+
import ReactDOM from 'react-dom/client';
|
|
10
|
+
import ThemeSelector from './themes/themeSelector';
|
|
11
|
+
import JsonRouter from './router/jsonRouter';
|
|
12
|
+
import { VisualifyProvider, useAppContext } from './appContext';
|
|
13
|
+
import { initHMR, useHMR } from './hmr-client';
|
|
14
|
+
import { initializeI18n } from '../i18n';
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Global app state for HMR preservation
|
|
18
|
+
* @type {Object|null}
|
|
19
|
+
*/
|
|
20
|
+
let preservedAppState = null;
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Visualify root component with HMR support
|
|
24
|
+
* @param {Object} props - Component props
|
|
25
|
+
* @param {Object} props.config - Visualify configuration
|
|
26
|
+
* @param {Object} [props.initialState] - Preserved state from HMR
|
|
27
|
+
*/
|
|
28
|
+
function Visualify({ config, initialState }) {
|
|
29
|
+
// global variable
|
|
30
|
+
const { theme = 'modern' } = config;
|
|
31
|
+
const { setSharedData } = useAppContext();
|
|
32
|
+
const isFirstRender = useRef(true);
|
|
33
|
+
|
|
34
|
+
// Restore preserved state on mount
|
|
35
|
+
useEffect(() => {
|
|
36
|
+
if (initialState?.sharedData && isFirstRender.current) {
|
|
37
|
+
setSharedData(initialState.sharedData);
|
|
38
|
+
}
|
|
39
|
+
isFirstRender.current = false;
|
|
40
|
+
}, [initialState, setSharedData]);
|
|
41
|
+
|
|
42
|
+
// Setup HMR integration
|
|
43
|
+
useHMR({
|
|
44
|
+
configType: 'main',
|
|
45
|
+
onUpdate: (update) => {
|
|
46
|
+
console.log('[Visualify] Received config update:', update.file);
|
|
47
|
+
// Reload the page to apply new config
|
|
48
|
+
// In a more advanced implementation, we could hot-swap the config
|
|
49
|
+
if (update.config) {
|
|
50
|
+
window.location.reload();
|
|
51
|
+
}
|
|
52
|
+
},
|
|
53
|
+
onError: (error) => {
|
|
54
|
+
console.error('[Visualify] HMR error:', error.message);
|
|
55
|
+
},
|
|
56
|
+
preserveState: () => ({
|
|
57
|
+
sharedData: preservedAppState?.sharedData,
|
|
58
|
+
}),
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
return (
|
|
62
|
+
<JsonRouter config={config}>
|
|
63
|
+
<ThemeSelector
|
|
64
|
+
theme={theme}
|
|
65
|
+
config={config}
|
|
66
|
+
/>
|
|
67
|
+
</JsonRouter>
|
|
68
|
+
);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* State preservation wrapper component
|
|
73
|
+
* @param {Object} props - Component props
|
|
74
|
+
* @param {Object} props.config - Visualify configuration
|
|
75
|
+
*/
|
|
76
|
+
function VisualifyWithStatePreservation({ config }) {
|
|
77
|
+
const [currentConfig, setCurrentConfig] = useState(config);
|
|
78
|
+
const [initialState, setInitialState] = useState(null);
|
|
79
|
+
const { sharedData } = useAppContext();
|
|
80
|
+
|
|
81
|
+
// Preserve state before unloading
|
|
82
|
+
useEffect(() => {
|
|
83
|
+
const preserveState = () => {
|
|
84
|
+
preservedAppState = {
|
|
85
|
+
sharedData,
|
|
86
|
+
config: currentConfig,
|
|
87
|
+
timestamp: Date.now(),
|
|
88
|
+
};
|
|
89
|
+
};
|
|
90
|
+
|
|
91
|
+
window.addEventListener('beforeunload', preserveState);
|
|
92
|
+
return () => window.removeEventListener('beforeunload', preserveState);
|
|
93
|
+
}, [sharedData, currentConfig]);
|
|
94
|
+
|
|
95
|
+
// Handle HMR updates
|
|
96
|
+
useEffect(() => {
|
|
97
|
+
if (typeof window !== 'undefined' && window.__VISUALIFY_HMR__?.enabled) {
|
|
98
|
+
const hmrClient = initHMR();
|
|
99
|
+
|
|
100
|
+
if (hmrClient) {
|
|
101
|
+
// Register update handler for main config
|
|
102
|
+
const unsubscribe = hmrClient.onUpdate('main', (update) => {
|
|
103
|
+
console.log('[Visualify] Config update received:', update);
|
|
104
|
+
|
|
105
|
+
if (update.config) {
|
|
106
|
+
// Preserve current state
|
|
107
|
+
preservedAppState = { sharedData };
|
|
108
|
+
|
|
109
|
+
// Update config
|
|
110
|
+
setCurrentConfig(update.config);
|
|
111
|
+
setInitialState(preservedAppState);
|
|
112
|
+
}
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
return () => unsubscribe();
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
}, [sharedData]);
|
|
119
|
+
|
|
120
|
+
return (
|
|
121
|
+
<Visualify
|
|
122
|
+
config={currentConfig}
|
|
123
|
+
initialState={initialState}
|
|
124
|
+
/>
|
|
125
|
+
);
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
/**
|
|
129
|
+
* Create and render the Visualify application
|
|
130
|
+
* @param {Object} config - Application configuration
|
|
131
|
+
*/
|
|
132
|
+
function CreateApp(config) {
|
|
133
|
+
if (!config) throw new Error('Missing configuration.');
|
|
134
|
+
const el = document.querySelector(config.el || '#root');
|
|
135
|
+
if (!el) throw new Error('el not found. Please check your `el` option.');
|
|
136
|
+
|
|
137
|
+
// Initialize i18n before rendering any components that use useTranslation
|
|
138
|
+
initializeI18n(config.i18n || {});
|
|
139
|
+
|
|
140
|
+
// Store original config for HMR reloads
|
|
141
|
+
const originalConfig = { ...config };
|
|
142
|
+
|
|
143
|
+
// deletion used configuration
|
|
144
|
+
delete config.el;
|
|
145
|
+
delete config.mode;
|
|
146
|
+
|
|
147
|
+
const app = ReactDOM.createRoot(el);
|
|
148
|
+
|
|
149
|
+
// Initialize HMR client if enabled
|
|
150
|
+
if (typeof window !== 'undefined' && window.__VISUALIFY_HMR__?.enabled) {
|
|
151
|
+
initHMR();
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
// Render the app — VisualifyProvider must wrap everything that uses useAppContext
|
|
155
|
+
app.render(
|
|
156
|
+
<React.StrictMode>
|
|
157
|
+
<VisualifyProvider>
|
|
158
|
+
<VisualifyWithStatePreservation config={originalConfig} />
|
|
159
|
+
</VisualifyProvider>
|
|
160
|
+
</React.StrictMode>,
|
|
161
|
+
);
|
|
162
|
+
|
|
163
|
+
// Expose reload function for HMR
|
|
164
|
+
if (typeof window !== 'undefined') {
|
|
165
|
+
window.__VISUALIFY_RELOAD__ = (newConfig) => {
|
|
166
|
+
app.render(
|
|
167
|
+
<React.StrictMode>
|
|
168
|
+
<VisualifyProvider>
|
|
169
|
+
<VisualifyWithStatePreservation
|
|
170
|
+
config={newConfig || originalConfig}
|
|
171
|
+
/>
|
|
172
|
+
</VisualifyProvider>
|
|
173
|
+
</React.StrictMode>,
|
|
174
|
+
);
|
|
175
|
+
};
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
/**
|
|
180
|
+
* Reload the application with new configuration (for HMR)
|
|
181
|
+
* @param {Object} newConfig - New configuration object
|
|
182
|
+
* @param {Object} [preservedState] - State to preserve during reload
|
|
183
|
+
*/
|
|
184
|
+
export function reloadApp(newConfig, preservedState) {
|
|
185
|
+
if (typeof window !== 'undefined' && window.__VISUALIFY_RELOAD__) {
|
|
186
|
+
// Store preserved state globally
|
|
187
|
+
if (preservedState) {
|
|
188
|
+
preservedAppState = preservedState;
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
// Trigger reload
|
|
192
|
+
window.__VISUALIFY_RELOAD__(newConfig);
|
|
193
|
+
} else {
|
|
194
|
+
console.warn('[Visualify] Reload function not available');
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
/**
|
|
199
|
+
* Get the current preserved application state
|
|
200
|
+
* @returns {Object|null} The preserved state
|
|
201
|
+
*/
|
|
202
|
+
export function getPreservedState() {
|
|
203
|
+
return preservedAppState;
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
/**
|
|
207
|
+
* Clear the preserved application state
|
|
208
|
+
*/
|
|
209
|
+
export function clearPreservedState() {
|
|
210
|
+
preservedAppState = null;
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
export default CreateApp;
|
|
@@ -1,24 +1,24 @@
|
|
|
1
|
-
/*
|
|
2
|
-
* @Author : Lihao leolihao@arizona.edu
|
|
3
|
-
* @Date : 2023-12-23 13:24:11
|
|
4
|
-
* @FilePath : /visualifyjs/src/core/widgets/CircularProgress.js
|
|
5
|
-
* @Description :
|
|
6
|
-
* Copyright (c) 2023 by Lihao (leolihao@arizona.edu), All Rights Reserved.
|
|
7
|
-
*/
|
|
8
|
-
import React from 'react';
|
|
9
|
-
import PropTypes from 'prop-types';
|
|
10
|
-
import '../../_css/circular-progress.css';
|
|
11
|
-
|
|
12
|
-
function CircularProgress({ color }) {
|
|
13
|
-
return (
|
|
14
|
-
<div className='circular-progress'>
|
|
15
|
-
<div className={`spinner ${color}`} />
|
|
16
|
-
</div>
|
|
17
|
-
);
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
CircularProgress.propTypes = {
|
|
21
|
-
color: PropTypes.oneOf(['primary', 'secondary']),
|
|
22
|
-
};
|
|
23
|
-
|
|
1
|
+
/*
|
|
2
|
+
* @Author : Lihao leolihao@arizona.edu
|
|
3
|
+
* @Date : 2023-12-23 13:24:11
|
|
4
|
+
* @FilePath : /visualifyjs/src/core/widgets/CircularProgress.js
|
|
5
|
+
* @Description :
|
|
6
|
+
* Copyright (c) 2023 by Lihao (leolihao@arizona.edu), All Rights Reserved.
|
|
7
|
+
*/
|
|
8
|
+
import React from 'react';
|
|
9
|
+
import PropTypes from 'prop-types';
|
|
10
|
+
import '../../_css/circular-progress.css';
|
|
11
|
+
|
|
12
|
+
function CircularProgress({ color }) {
|
|
13
|
+
return (
|
|
14
|
+
<div className='circular-progress'>
|
|
15
|
+
<div className={`spinner ${color}`} />
|
|
16
|
+
</div>
|
|
17
|
+
);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
CircularProgress.propTypes = {
|
|
21
|
+
color: PropTypes.oneOf(['primary', 'secondary']),
|
|
22
|
+
};
|
|
23
|
+
|
|
24
24
|
export default CircularProgress;
|
|
@@ -1,83 +1,116 @@
|
|
|
1
|
-
/*
|
|
2
|
-
* @Author : Lihao leolihao@arizona.edu
|
|
3
|
-
* @Date : 2023-12-21 13:07:59
|
|
4
|
-
* @FilePath : /visualifyjs/src/core/widgets/controller.js
|
|
5
|
-
* @Description :
|
|
6
|
-
* Copyright (c) 2023 by Lihao (leolihao@arizona.edu), All Rights Reserved.
|
|
7
|
-
*/
|
|
8
|
-
import React from 'react';
|
|
9
|
-
import widgetMapping from './mapping';
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
const
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
|
|
1
|
+
/*
|
|
2
|
+
* @Author : Lihao leolihao@arizona.edu
|
|
3
|
+
* @Date : 2023-12-21 13:07:59
|
|
4
|
+
* @FilePath : /visualifyjs/src/core/widgets/controller.js
|
|
5
|
+
* @Description :
|
|
6
|
+
* Copyright (c) 2023 by Lihao (leolihao@arizona.edu), All Rights Reserved.
|
|
7
|
+
*/
|
|
8
|
+
import React, { useRef, useEffect } from 'react';
|
|
9
|
+
import widgetMapping from './mapping';
|
|
10
|
+
import { applyA11yStyles } from '../../a11y';
|
|
11
|
+
|
|
12
|
+
function Vcontroller({ components = [], layout, ariaLabel = 'Dashboard' }) {
|
|
13
|
+
const containerRef = useRef(null);
|
|
14
|
+
|
|
15
|
+
// Apply accessibility styles on mount
|
|
16
|
+
useEffect(() => {
|
|
17
|
+
applyA11yStyles();
|
|
18
|
+
}, []);
|
|
19
|
+
|
|
20
|
+
// ----------------------------------------------------------------------
|
|
21
|
+
// Iterate over the config array and render the components based on their type and position
|
|
22
|
+
// Use stable keys derived from component id/index to prevent unmount/remount on re-render
|
|
23
|
+
const Allcomponents = components.map((componentConfig, index) => {
|
|
24
|
+
const {
|
|
25
|
+
row = 1,
|
|
26
|
+
col = 1,
|
|
27
|
+
colspan = 1,
|
|
28
|
+
rowspan = 1,
|
|
29
|
+
debug = false,
|
|
30
|
+
} = componentConfig;
|
|
31
|
+
|
|
32
|
+
// Stable key: prefer component id, fall back to type+index
|
|
33
|
+
const stableKey = componentConfig.id || `${componentConfig.type}-${index}`;
|
|
34
|
+
|
|
35
|
+
const componentStyle =
|
|
36
|
+
layout === 'grid'
|
|
37
|
+
? {
|
|
38
|
+
gridColumn: `${col} / span ${colspan}`,
|
|
39
|
+
gridRow: `${row} / span ${rowspan}`,
|
|
40
|
+
border: debug ? '1px solid red' : 'none',
|
|
41
|
+
}
|
|
42
|
+
: {};
|
|
43
|
+
|
|
44
|
+
const Component = widgetMapping[componentConfig.type];
|
|
45
|
+
|
|
46
|
+
const componentAriaLabel = componentConfig.ariaLabel ||
|
|
47
|
+
`${componentConfig.type} widget ${index + 1} of ${components.length}`;
|
|
48
|
+
|
|
49
|
+
if (!Component) {
|
|
50
|
+
return (
|
|
51
|
+
<span
|
|
52
|
+
key={stableKey}
|
|
53
|
+
style={componentStyle}
|
|
54
|
+
role="alert"
|
|
55
|
+
aria-live="assertive">
|
|
56
|
+
Error: Component{' '}
|
|
57
|
+
<b style={{ color: 'red' }}>{componentConfig.type}</b> not
|
|
58
|
+
found.
|
|
59
|
+
</span>
|
|
60
|
+
);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
return React.cloneElement(<Component key={stableKey} />, {
|
|
64
|
+
style: componentStyle,
|
|
65
|
+
props: {
|
|
66
|
+
...componentConfig,
|
|
67
|
+
id: componentConfig.id || stableKey,
|
|
68
|
+
},
|
|
69
|
+
'aria-label': componentAriaLabel,
|
|
70
|
+
role: 'region',
|
|
71
|
+
});
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
return (
|
|
75
|
+
<div
|
|
76
|
+
ref={containerRef}
|
|
77
|
+
className="visualify-controller"
|
|
78
|
+
role="main"
|
|
79
|
+
aria-label={ariaLabel}
|
|
80
|
+
tabIndex={-1}
|
|
81
|
+
style={{ display: 'contents' }}
|
|
82
|
+
>
|
|
83
|
+
{/* Skip link for keyboard navigation */}
|
|
84
|
+
<a
|
|
85
|
+
href="#visualify-main-content"
|
|
86
|
+
className="sr-only sr-only-focusable"
|
|
87
|
+
style={{
|
|
88
|
+
position: 'absolute',
|
|
89
|
+
top: '-40px',
|
|
90
|
+
left: '0',
|
|
91
|
+
background: '#000',
|
|
92
|
+
color: '#fff',
|
|
93
|
+
padding: '8px 16px',
|
|
94
|
+
zIndex: 9999,
|
|
95
|
+
textDecoration: 'none',
|
|
96
|
+
transition: 'top 0.2s',
|
|
97
|
+
}}
|
|
98
|
+
onFocus={(e) => {
|
|
99
|
+
e.target.style.top = '0';
|
|
100
|
+
}}
|
|
101
|
+
onBlur={(e) => {
|
|
102
|
+
e.target.style.top = '-40px';
|
|
103
|
+
}}
|
|
104
|
+
>
|
|
105
|
+
Skip to main content
|
|
106
|
+
</a>
|
|
107
|
+
|
|
108
|
+
{/* Main content — display:contents makes grid items direct participants */}
|
|
109
|
+
<div id="visualify-main-content" className="visualify-components-container" style={{ display: 'contents' }}>
|
|
110
|
+
{Allcomponents}
|
|
111
|
+
</div>
|
|
112
|
+
</div>
|
|
113
|
+
);
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
export default Vcontroller;
|
|
@@ -1,36 +1,36 @@
|
|
|
1
|
-
/*
|
|
2
|
-
* @Author : Lihao leolihao@arizona.edu
|
|
3
|
-
* @Date : 2023-12-02 16:34:41
|
|
4
|
-
* @FilePath : /visualifyjs/src/core/widgets/errorBoundary.js
|
|
5
|
-
* @Description :
|
|
6
|
-
* Copyright (c) 2023 by Lihao (leolihao@arizona.edu), All Rights Reserved.
|
|
7
|
-
*/
|
|
8
|
-
import React from 'react';
|
|
9
|
-
|
|
10
|
-
class ErrorBoundary extends React.Component {
|
|
11
|
-
constructor(props) {
|
|
12
|
-
super(props);
|
|
13
|
-
this.state = { hasError: false, error: null };
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
static getDerivedStateFromError(error) {
|
|
17
|
-
// Update state so the next render will show the fallback UI.
|
|
18
|
-
return { hasError: true, error };
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
componentDidCatch(error, errorInfo) {
|
|
22
|
-
// You can also log the error to an error reporting service
|
|
23
|
-
console.error('Caught an error:', error, errorInfo);
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
render() {
|
|
27
|
-
if (this.state.hasError) {
|
|
28
|
-
// You can render any custom fallback UI
|
|
29
|
-
return <h1>Something went wrong: {this.state.error.message}</h1>;
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
return this.props.children;
|
|
33
|
-
}
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
export default ErrorBoundary;
|
|
1
|
+
/*
|
|
2
|
+
* @Author : Lihao leolihao@arizona.edu
|
|
3
|
+
* @Date : 2023-12-02 16:34:41
|
|
4
|
+
* @FilePath : /visualifyjs/src/core/widgets/errorBoundary.js
|
|
5
|
+
* @Description :
|
|
6
|
+
* Copyright (c) 2023 by Lihao (leolihao@arizona.edu), All Rights Reserved.
|
|
7
|
+
*/
|
|
8
|
+
import React from 'react';
|
|
9
|
+
|
|
10
|
+
class ErrorBoundary extends React.Component {
|
|
11
|
+
constructor(props) {
|
|
12
|
+
super(props);
|
|
13
|
+
this.state = { hasError: false, error: null };
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
static getDerivedStateFromError(error) {
|
|
17
|
+
// Update state so the next render will show the fallback UI.
|
|
18
|
+
return { hasError: true, error };
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
componentDidCatch(error, errorInfo) {
|
|
22
|
+
// You can also log the error to an error reporting service
|
|
23
|
+
console.error('Caught an error:', error, errorInfo);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
render() {
|
|
27
|
+
if (this.state.hasError) {
|
|
28
|
+
// You can render any custom fallback UI
|
|
29
|
+
return <h1>Something went wrong: {this.state.error.message}</h1>;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
return this.props.children;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export default ErrorBoundary;
|