fix: Added lazy icon loading, users now select which icons they want loaded in, by default only the isoflow ones get loaded in, users can quickly change this, or disable this behaviour, this results in much faster loads. Fixes #79

This commit is contained in:
stan
2025-10-18 16:47:22 +01:00
parent 755f33ccba
commit e0462f6bbd
200 changed files with 925 additions and 4281 deletions

10
package-lock.json generated
View File

@@ -1,12 +1,12 @@
{
"name": "fossflow-monorepo",
"version": "1.1.0",
"version": "1.5.0",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "fossflow-monorepo",
"version": "1.1.0",
"version": "1.5.0",
"workspaces": [
"packages/*"
],
@@ -20908,7 +20908,7 @@
}
},
"packages/fossflow-app": {
"version": "1.1.0",
"version": "1.5.0",
"dependencies": {
"@isoflow/isopacks": "^0.0.10",
"fossflow": "^1.1.0",
@@ -20931,7 +20931,7 @@
}
},
"packages/fossflow-backend": {
"version": "1.1.0",
"version": "1.5.0",
"dependencies": {
"cors": "^2.8.5",
"dotenv": "^16.6.1",
@@ -20944,7 +20944,7 @@
},
"packages/fossflow-lib": {
"name": "fossflow",
"version": "1.1.0",
"version": "1.5.0",
"license": "MIT",
"dependencies": {
"@emotion/react": "^11.14.0",

View File

@@ -2,10 +2,6 @@ import { useState, useEffect, useRef } from 'react';
import { Isoflow } from 'fossflow';
import { flattenCollections } from '@isoflow/isopacks/dist/utils';
import isoflowIsopack from '@isoflow/isopacks/dist/isoflow';
import awsIsopack from '@isoflow/isopacks/dist/aws';
import gcpIsopack from '@isoflow/isopacks/dist/gcp';
import azureIsopack from '@isoflow/isopacks/dist/azure';
import kubernetesIsopack from '@isoflow/isopacks/dist/kubernetes';
import { useTranslation } from 'react-i18next';
import { DiagramData, mergeDiagramData, extractSavableData } from './diagramUtils';
import { StorageManager } from './StorageManager';
@@ -13,15 +9,11 @@ import { DiagramManager } from './components/DiagramManager';
import { storageManager } from './services/storageService';
import ChangeLanguage from './components/ChangeLanguage';
import { allLocales } from 'fossflow';
import { useIconPackManager, IconPackName } from './services/iconPackManager';
import './App.css';
const icons = flattenCollections([
isoflowIsopack,
awsIsopack,
azureIsopack,
gcpIsopack,
kubernetesIsopack
]);
// Load core isoflow icons (always loaded)
const coreIcons = flattenCollections([isoflowIsopack]);
interface SavedDiagram {
@@ -33,6 +25,9 @@ interface SavedDiagram {
}
function App() {
// Initialize icon pack manager with core icons
const iconPackManager = useIconPackManager(coreIcons);
const [diagrams, setDiagrams] = useState<SavedDiagram[]>([]);
const [currentDiagram, setCurrentDiagram] = useState<SavedDiagram | null>(null);
const [diagramName, setDiagramName] = useState('');
@@ -67,7 +62,7 @@ function App() {
try {
const data = JSON.parse(lastOpenedData);
const importedIcons = (data.icons || []).filter((icon: any) => icon.collection === 'imported');
const mergedIcons = [...icons, ...importedIcons];
const mergedIcons = [...coreIcons, ...importedIcons];
return {
...data,
icons: mergedIcons,
@@ -78,11 +73,11 @@ function App() {
console.error('Failed to load last opened data:', e);
}
}
// Default state if no saved data
return {
title: 'Untitled Diagram',
icons: icons,
icons: coreIcons,
colors: defaultColors,
items: [],
views: [],
@@ -97,6 +92,17 @@ function App() {
}).catch(console.error);
}, []);
// Update diagramData when loaded icons change
useEffect(() => {
setDiagramData(prev => ({
...prev,
icons: [
...iconPackManager.loadedIcons,
...(prev.icons || []).filter(icon => icon.collection === 'imported')
]
}));
}, [iconPackManager.loadedIcons]);
// Load diagrams from localStorage on component mount
useEffect(() => {
const savedDiagrams = localStorage.getItem('fossflow-diagrams');
@@ -216,14 +222,17 @@ function App() {
}
};
const loadDiagram = (diagram: SavedDiagram) => {
const loadDiagram = async (diagram: SavedDiagram) => {
if (hasUnsavedChanges && !window.confirm(t('alert.unsavedChanges'))) {
return;
}
// Merge imported icons with default icon set
// Auto-detect and load required icon packs
await iconPackManager.loadPacksForDiagram(diagram.data.items || []);
// Merge imported icons with loaded icon set
const importedIcons = (diagram.data.icons || []).filter((icon: any) => icon.collection === 'imported');
const mergedIcons = [...icons, ...importedIcons];
const mergedIcons = [...iconPackManager.loadedIcons, ...importedIcons];
const dataWithIcons = {
...diagram.data,
icons: mergedIcons
@@ -257,14 +266,14 @@ function App() {
};
const newDiagram = () => {
const message = hasUnsavedChanges
const message = hasUnsavedChanges
? t('alert.unsavedChangesExport')
: t('alert.createNewDiagram');
if (window.confirm(message)) {
const emptyDiagram: DiagramData = {
title: 'Untitled Diagram',
icons: icons, // Always include full icon set
icons: iconPackManager.loadedIcons, // Use currently loaded icons
colors: defaultColors,
items: [],
views: [],
@@ -276,7 +285,7 @@ function App() {
setCurrentModel(emptyDiagram); // Reset current model too
setFossflowKey(prev => prev + 1); // Force re-render of FossFLOW
setHasUnsavedChanges(false);
// Clear last opened
localStorage.removeItem('fossflow-last-opened');
localStorage.removeItem('fossflow-last-opened-data');
@@ -355,7 +364,7 @@ function App() {
};
const handleDiagramManagerLoad = (id: string, data: any) => {
const handleDiagramManagerLoad = async (id: string, data: any) => {
console.log(`App: handleDiagramManagerLoad called for diagram ${id}`);
/**
@@ -379,6 +388,9 @@ function App() {
const loadedIcons = data.icons || [];
console.log(`App: Server sent ${loadedIcons.length} icons`);
// Auto-detect and load required icon packs
await iconPackManager.loadPacksForDiagram(data.items || []);
// Strategy: Check if server has ALL icons (both default and imported)
// Server storage now saves ALL icons, so we should use them directly
// For backward compatibility with old saves, we detect and merge
@@ -395,10 +407,10 @@ function App() {
finalIcons = loadedIcons;
} else {
// Old format: Server only saved imported icons
// Merge imported icons with current default icons
// Merge imported icons with currently loaded icon packs
const importedIcons = loadedIcons.filter((icon: any) => icon.collection === 'imported');
finalIcons = [...icons, ...importedIcons];
console.log(`App: Old format detected. Merged ${importedIcons.length} imported icons with ${icons.length} defaults = ${finalIcons.length} total`);
finalIcons = [...iconPackManager.loadedIcons, ...importedIcons];
console.log(`App: Old format detected. Merged ${importedIcons.length} imported icons with ${iconPackManager.loadedIcons.length} defaults = ${finalIcons.length} total`);
}
const mergedData: DiagramData = {
@@ -444,12 +456,12 @@ function App() {
// Auto-save functionality
useEffect(() => {
if (!currentModel || !hasUnsavedChanges || !currentDiagram) return;
const autoSaveTimer = setTimeout(() => {
// Include imported icons in auto-save
const importedIcons = (currentModel?.icons || diagramData.icons || [])
.filter(icon => icon.collection === 'imported');
const savedData = {
title: diagramName || currentDiagram.name,
icons: importedIcons, // Save imported icons in auto-save
@@ -458,17 +470,17 @@ function App() {
views: currentModel.views || [],
fitToScreen: true
};
const updatedDiagram: SavedDiagram = {
...currentDiagram,
data: savedData,
updatedAt: new Date().toISOString()
};
setDiagrams(prevDiagrams =>
setDiagrams(prevDiagrams =>
prevDiagrams.map(d => d.id === currentDiagram.id ? updatedDiagram : d)
);
// Update last opened data
try {
localStorage.setItem('fossflow-last-opened-data', JSON.stringify(savedData));
@@ -482,9 +494,9 @@ function App() {
}
}
}, 5000); // Auto-save after 5 seconds of changes
return () => clearTimeout(autoSaveTimer);
}, [currentModel, hasUnsavedChanges, currentDiagram, diagramName, icons]);
}, [currentModel, hasUnsavedChanges, currentDiagram, diagramName]);
// Warn before closing if there are unsaved changes
useEffect(() => {
@@ -547,12 +559,19 @@ function App() {
</div>
<div className="fossflow-container">
<Isoflow
<Isoflow
key={fossflowKey}
initialData={diagramData}
onModelUpdated={handleModelUpdated}
editorMode="EDITABLE"
locale={allLocales[i18n.language as keyof typeof allLocales]}
iconPackManager={{
lazyLoadingEnabled: iconPackManager.lazyLoadingEnabled,
onToggleLazyLoading: iconPackManager.toggleLazyLoading,
packInfo: Object.values(iconPackManager.packInfo),
enabledPacks: iconPackManager.enabledPacks,
onTogglePack: iconPackManager.togglePack
}}
/>
</div>

View File

@@ -0,0 +1,267 @@
import { useState, useEffect, useCallback } from 'react';
import { flattenCollections } from '@isoflow/isopacks/dist/utils';
// Available icon packs (excluding core isoflow which is always loaded)
export type IconPackName = 'aws' | 'gcp' | 'azure' | 'kubernetes';
export interface IconPackInfo {
name: IconPackName;
displayName: string;
loaded: boolean;
loading: boolean;
error: string | null;
iconCount: number;
}
export interface IconPackManagerState {
lazyLoadingEnabled: boolean;
enabledPacks: IconPackName[];
packInfo: Record<IconPackName, IconPackInfo>;
loadedIcons: any[];
}
// localStorage keys
const LAZY_LOADING_KEY = 'fossflow-lazy-loading-enabled';
const ENABLED_PACKS_KEY = 'fossflow-enabled-icon-packs';
// Pack metadata
const PACK_METADATA: Record<IconPackName, string> = {
aws: 'AWS Icons',
gcp: 'Google Cloud Icons',
azure: 'Azure Icons',
kubernetes: 'Kubernetes Icons'
};
// Load preferences from localStorage
export const loadLazyLoadingPreference = (): boolean => {
const stored = localStorage.getItem(LAZY_LOADING_KEY);
return stored === null ? true : stored === 'true'; // Default to true
};
export const saveLazyLoadingPreference = (enabled: boolean): void => {
localStorage.setItem(LAZY_LOADING_KEY, String(enabled));
};
export const loadEnabledPacks = (): IconPackName[] => {
const stored = localStorage.getItem(ENABLED_PACKS_KEY);
if (!stored) return [];
try {
return JSON.parse(stored) as IconPackName[];
} catch {
return [];
}
};
export const saveEnabledPacks = (packs: IconPackName[]): void => {
localStorage.setItem(ENABLED_PACKS_KEY, JSON.stringify(packs));
};
// Dynamic pack loader
export const loadIconPack = async (packName: IconPackName): Promise<any> => {
switch (packName) {
case 'aws':
return (await import('@isoflow/isopacks/dist/aws')).default;
case 'gcp':
return (await import('@isoflow/isopacks/dist/gcp')).default;
case 'azure':
return (await import('@isoflow/isopacks/dist/azure')).default;
case 'kubernetes':
return (await import('@isoflow/isopacks/dist/kubernetes')).default;
default:
throw new Error(`Unknown icon pack: ${packName}`);
}
};
// React hook for managing icon packs
export const useIconPackManager = (coreIcons: any[]) => {
const [lazyLoadingEnabled, setLazyLoadingEnabled] = useState<boolean>(() =>
loadLazyLoadingPreference()
);
const [enabledPacks, setEnabledPacks] = useState<IconPackName[]>(() =>
loadEnabledPacks()
);
const [packInfo, setPackInfo] = useState<Record<IconPackName, IconPackInfo>>(() => {
const info: Record<string, IconPackInfo> = {};
const packNames: IconPackName[] = ['aws', 'gcp', 'azure', 'kubernetes'];
packNames.forEach(name => {
info[name] = {
name,
displayName: PACK_METADATA[name],
loaded: false,
loading: false,
error: null,
iconCount: 0
};
});
return info as Record<IconPackName, IconPackInfo>;
});
const [loadedIcons, setLoadedIcons] = useState<any[]>(coreIcons);
const [loadedPackData, setLoadedPackData] = useState<Record<IconPackName, any>>({} as Record<IconPackName, any>);
// Load a specific pack
const loadPack = useCallback(async (packName: IconPackName) => {
// Already loaded?
if (packInfo[packName].loaded || packInfo[packName].loading) {
return;
}
// Set loading state
setPackInfo(prev => ({
...prev,
[packName]: { ...prev[packName], loading: true, error: null }
}));
try {
const pack = await loadIconPack(packName);
const flattenedIcons = flattenCollections([pack]);
// Store the loaded pack data
setLoadedPackData(prev => ({
...prev,
[packName]: pack
}));
// Update pack info
setPackInfo(prev => ({
...prev,
[packName]: {
...prev[packName],
loaded: true,
loading: false,
iconCount: flattenedIcons.length,
error: null
}
}));
// Add icons to the loaded icons array
setLoadedIcons(prev => [...prev, ...flattenedIcons]);
return flattenedIcons;
} catch (error) {
console.error(`Failed to load ${packName} icon pack:`, error);
setPackInfo(prev => ({
...prev,
[packName]: {
...prev[packName],
loading: false,
error: error instanceof Error ? error.message : 'Failed to load pack'
}
}));
throw error;
}
}, [packInfo]);
// Enable/disable a pack
const togglePack = useCallback(async (packName: IconPackName, enabled: boolean) => {
if (enabled) {
// Add to enabled packs
const newEnabledPacks = [...enabledPacks, packName];
setEnabledPacks(newEnabledPacks);
saveEnabledPacks(newEnabledPacks);
// Load the pack
await loadPack(packName);
} else {
// Remove from enabled packs
const newEnabledPacks = enabledPacks.filter(p => p !== packName);
setEnabledPacks(newEnabledPacks);
saveEnabledPacks(newEnabledPacks);
// Remove icons from loaded icons
// We need to rebuild the icons array from core + enabled packs
const newIcons = [coreIcons];
for (const pack of newEnabledPacks) {
if (loadedPackData[pack]) {
newIcons.push(flattenCollections([loadedPackData[pack]]));
}
}
setLoadedIcons(newIcons.flat());
}
}, [enabledPacks, loadPack, coreIcons, loadedPackData]);
// Toggle lazy loading
const toggleLazyLoading = useCallback((enabled: boolean) => {
setLazyLoadingEnabled(enabled);
saveLazyLoadingPreference(enabled);
}, []);
// Load all packs (for when lazy loading is disabled)
const loadAllPacks = useCallback(async () => {
const allPacks: IconPackName[] = ['aws', 'gcp', 'azure', 'kubernetes'];
for (const pack of allPacks) {
if (!packInfo[pack].loaded && !packInfo[pack].loading) {
await loadPack(pack);
}
}
}, [packInfo, loadPack]);
// Auto-detect required packs from diagram data
const loadPacksForDiagram = useCallback(async (diagramItems: any[]) => {
if (!diagramItems || diagramItems.length === 0) return;
// Extract unique collections from diagram items
const collections = new Set<string>();
diagramItems.forEach(item => {
if (item.icon?.collection) {
collections.add(item.icon.collection);
}
});
// Load any missing packs
const packsToLoad: IconPackName[] = [];
collections.forEach(collection => {
if (collection !== 'isoflow' && collection !== 'imported') {
const packName = collection as IconPackName;
if (['aws', 'gcp', 'azure', 'kubernetes'].includes(packName)) {
if (!packInfo[packName].loaded && !packInfo[packName].loading) {
packsToLoad.push(packName);
}
}
}
});
// Load required packs
for (const pack of packsToLoad) {
await loadPack(pack);
// Also add to enabled packs
if (!enabledPacks.includes(pack)) {
const newEnabledPacks = [...enabledPacks, pack];
setEnabledPacks(newEnabledPacks);
saveEnabledPacks(newEnabledPacks);
}
}
}, [packInfo, enabledPacks, loadPack]);
// Initialize: Load enabled packs or all packs depending on lazy loading setting
useEffect(() => {
const initialize = async () => {
if (!lazyLoadingEnabled) {
// Load all packs immediately
await loadAllPacks();
} else {
// Load only enabled packs
for (const pack of enabledPacks) {
if (!packInfo[pack].loaded && !packInfo[pack].loading) {
await loadPack(pack);
}
}
}
};
initialize();
}, []); // Only run once on mount
return {
lazyLoadingEnabled,
enabledPacks,
packInfo,
loadedIcons,
togglePack,
toggleLazyLoading,
loadAllPacks,
loadPacksForDiagram,
isPackEnabled: (packName: IconPackName) => enabledPacks.includes(packName)
};
};

View File

@@ -1,19 +0,0 @@
import { IsoflowProps } from './types';
export declare const Isoflow: (props: IsoflowProps) => import("react/jsx-runtime").JSX.Element;
declare const useIsoflow: () => {
Model: {
get: () => import("./types").ModelStoreWithHistory;
set: (model: Partial<import("./types").Model>, skipHistory?: boolean) => void;
undo: () => boolean;
redo: () => boolean;
canUndo: () => boolean;
canRedo: () => boolean;
saveToHistory: () => void;
clearHistory: () => void;
};
uiState: import("./types").UiStateActions;
rendererEl: HTMLDivElement | null;
};
export { useIsoflow };
export * from './standaloneExports';
export default Isoflow;

View File

@@ -1,8 +0,0 @@
import React from 'react';
import { Coords } from '../../types';
interface Props {
tile: Coords;
radius?: number;
}
export declare const Circle: ({ tile, radius, ...rest }: Props & React.SVGProps<SVGCircleElement>) => import("react/jsx-runtime").JSX.Element;
export {};

View File

@@ -1,5 +0,0 @@
import { MuiColorInputProps } from 'mui-color-input';
interface Props extends Omit<MuiColorInputProps, 'ref'> {
}
export declare const ColorPicker: ({ value, onChange }: Props) => import("react/jsx-runtime").JSX.Element;
export {};

View File

@@ -1,6 +0,0 @@
interface Props {
onChange: (color: string) => void;
activeColor?: string;
}
export declare const ColorSelector: ({ onChange, activeColor }: Props) => import("react/jsx-runtime").JSX.Element;
export {};

View File

@@ -1,7 +0,0 @@
import React from 'react';
export type Props = {
hex: string;
isActive?: boolean;
onClick: React.MouseEventHandler<HTMLButtonElement> | undefined;
};
export declare const ColorSwatch: ({ hex, onClick, isActive }: Props) => import("react/jsx-runtime").JSX.Element;

View File

@@ -1 +0,0 @@
export declare const ConnectorEmptySpaceTooltip: () => import("react/jsx-runtime").JSX.Element | null;

View File

@@ -1,6 +0,0 @@
import React from 'react';
interface Props {
toolMenuRef?: React.RefObject<HTMLElement>;
}
export declare const ConnectorHintTooltip: ({ toolMenuRef }: Props) => import("react/jsx-runtime").JSX.Element | null;
export {};

View File

@@ -1 +0,0 @@
export declare const ConnectorRerouteTooltip: () => import("react/jsx-runtime").JSX.Element | null;

View File

@@ -1 +0,0 @@
export declare const ConnectorSettings: () => import("react/jsx-runtime").JSX.Element;

View File

@@ -1,13 +0,0 @@
import { Coords } from '../../types';
interface MenuItemI {
label: string;
onClick: () => void;
}
interface Props {
onClose: () => void;
position: Coords;
anchorEl?: HTMLElement;
menuItems: MenuItemI[];
}
export declare const ContextMenu: ({ onClose, position, anchorEl, menuItems }: Props) => import("react/jsx-runtime").JSX.Element;
export {};

View File

@@ -1,5 +0,0 @@
interface Props {
anchorEl?: HTMLElement;
}
export declare const ContextMenuManager: ({ anchorEl }: Props) => import("react/jsx-runtime").JSX.Element | null;
export {};

View File

@@ -1 +0,0 @@
export declare const Cursor: () => import("react/jsx-runtime").JSX.Element;

View File

@@ -1 +0,0 @@
export declare const DebugUtils: () => import("react/jsx-runtime").JSX.Element;

View File

@@ -1,6 +0,0 @@
interface Props {
title: string;
value: string | number;
}
export declare const LineItem: ({ title, value }: Props) => import("react/jsx-runtime").JSX.Element;
export {};

View File

@@ -1 +0,0 @@
export declare const SizeIndicator: () => import("react/jsx-runtime").JSX.Element;

View File

@@ -1,5 +0,0 @@
interface Props {
value: string;
}
export declare const Value: ({ value }: Props) => import("react/jsx-runtime").JSX.Element;
export {};

View File

@@ -1,7 +0,0 @@
import { Coords } from '../../types';
interface Props {
iconId: string;
tile: Coords;
}
export declare const DragAndDrop: ({ iconId, tile }: Props) => import("react/jsx-runtime").JSX.Element;
export {};

View File

@@ -1,6 +0,0 @@
interface Props {
quality?: number;
onClose: () => void;
}
export declare const ExportImageDialog: ({ onClose, quality }: Props) => import("react/jsx-runtime").JSX.Element;
export {};

View File

@@ -1 +0,0 @@
export declare const FreehandLasso: () => import("react/jsx-runtime").JSX.Element | null;

View File

@@ -1,6 +0,0 @@
import { SxProps } from '@mui/material';
interface Props {
sx?: SxProps;
}
export declare const Gradient: ({ sx }: Props) => import("react/jsx-runtime").JSX.Element;
export {};

View File

@@ -1 +0,0 @@
export declare const Grid: () => import("react/jsx-runtime").JSX.Element;

View File

@@ -1 +0,0 @@
export declare const HelpDialog: () => import("react/jsx-runtime").JSX.Element;

View File

@@ -1 +0,0 @@
export declare const HotkeySettings: () => import("react/jsx-runtime").JSX.Element;

View File

@@ -1,12 +0,0 @@
import React from 'react';
import { TooltipProps } from '@mui/material/Tooltip';
interface Props {
name: string;
Icon: React.ReactNode;
isActive?: boolean;
onClick: (e: React.MouseEvent<HTMLButtonElement>) => void;
tooltipPosition?: TooltipProps['placement'];
disabled?: boolean;
}
export declare const IconButton: ({ name, Icon, onClick, isActive, disabled, tooltipPosition }: Props) => import("react/jsx-runtime").JSX.Element;
export {};

View File

@@ -1 +0,0 @@
export declare const ImportHintTooltip: () => import("react/jsx-runtime").JSX.Element | null;

View File

@@ -1,15 +0,0 @@
import { Coords } from '../../types';
interface Props {
from: Coords;
to: Coords;
origin?: Coords;
fill?: string;
cornerRadius?: number;
stroke?: {
width: number;
color: string;
dashArray?: string;
};
}
export declare const IsoTileArea: ({ from, to, fill, cornerRadius, stroke }: Props) => import("react/jsx-runtime").JSX.Element;
export {};

View File

@@ -1,5 +0,0 @@
interface Props {
id: string;
}
export declare const ConnectorControls: ({ id }: Props) => import("react/jsx-runtime").JSX.Element | null;
export {};

View File

@@ -1,9 +0,0 @@
import { Icon as IconI } from '../../../types';
interface Props {
icon: IconI;
onClick?: () => void;
onMouseDown?: () => void;
onDoubleClick?: () => void;
}
export declare const Icon: ({ icon, onClick, onMouseDown, onDoubleClick }: Props) => import("react/jsx-runtime").JSX.Element;
export {};

View File

@@ -1,10 +0,0 @@
import { Icon as IconI } from '../../../types';
interface Props {
id?: string;
icons: IconI[];
onClick?: (icon: IconI) => void;
onMouseDown?: (icon: IconI) => void;
isExpanded: boolean;
}
export declare const IconCollection: ({ id, icons, onClick, onMouseDown, isExpanded: _isExpanded }: Props) => import("react/jsx-runtime").JSX.Element;
export {};

View File

@@ -1,11 +0,0 @@
import { Icon as IconI } from '../../../types';
interface Props {
icons: IconI[];
onMouseDown?: (icon: IconI) => void;
onClick?: (icon: IconI) => void;
onDoubleClick?: (icon: IconI) => void;
hoveredIndex?: number;
onHover?: (index: number) => void;
}
export declare const IconGrid: ({ icons, onMouseDown, onClick, onDoubleClick, hoveredIndex, onHover }: Props) => import("react/jsx-runtime").JSX.Element;
export {};

View File

@@ -1 +0,0 @@
export declare const IconSelectionControls: () => import("react/jsx-runtime").JSX.Element;

View File

@@ -1,8 +0,0 @@
import { IconCollectionStateWithIcons, Icon } from '../../../types';
interface Props {
iconCategories: IconCollectionStateWithIcons[];
onClick?: (icon: Icon) => void;
onMouseDown?: (icon: Icon) => void;
}
export declare const Icons: ({ iconCategories, onClick, onMouseDown }: Props) => import("react/jsx-runtime").JSX.Element;
export {};

View File

@@ -1,6 +0,0 @@
interface Props {
value: string;
onChange: (value: string) => void;
}
export declare const Searchbox: ({ value, onChange }: Props) => import("react/jsx-runtime").JSX.Element;
export {};

View File

@@ -1 +0,0 @@
export declare const ItemControlsManager: () => import("react/jsx-runtime").JSX.Element;

View File

@@ -1,5 +0,0 @@
interface Props {
id: string;
}
export declare const NodeControls: ({ id }: Props) => import("react/jsx-runtime").JSX.Element | null;
export {};

View File

@@ -1,13 +0,0 @@
import { ModelItem, ViewItem } from '../../../../types';
export type NodeUpdates = {
model: Partial<ModelItem>;
view: Partial<ViewItem>;
};
interface Props {
node: ViewItem;
onModelItemUpdated: (updates: Partial<ModelItem>) => void;
onViewItemUpdated: (updates: Partial<ViewItem>) => void;
onDeleted: () => void;
}
export declare const NodeSettings: ({ node, onModelItemUpdated, onViewItemUpdated, onDeleted }: Props) => import("react/jsx-runtime").JSX.Element | null;
export {};

View File

@@ -1,8 +0,0 @@
import { Icon } from '../../../types';
interface Props {
onIconSelected: (icon: Icon) => void;
onClose?: () => void;
currentIconId?: string;
}
export declare const QuickIconSelector: ({ onIconSelected, onClose, currentIconId }: Props) => import("react/jsx-runtime").JSX.Element;
export {};

View File

@@ -1,5 +0,0 @@
interface Props {
id: string;
}
export declare const RectangleControls: ({ id }: Props) => import("react/jsx-runtime").JSX.Element | null;
export {};

View File

@@ -1,5 +0,0 @@
interface Props {
id: string;
}
export declare const TextBoxControls: ({ id }: Props) => import("react/jsx-runtime").JSX.Element | null;
export {};

View File

@@ -1,7 +0,0 @@
import React from 'react';
interface Props {
header?: React.ReactNode;
children: React.ReactNode;
}
export declare const ControlsContainer: ({ header, children }: Props) => import("react/jsx-runtime").JSX.Element;
export {};

View File

@@ -1,5 +0,0 @@
interface Props {
onClick: () => void;
}
export declare const DeleteButton: ({ onClick }: Props) => import("react/jsx-runtime").JSX.Element;
export {};

View File

@@ -1,5 +0,0 @@
interface Props {
title: string;
}
export declare const Header: ({ title }: Props) => import("react/jsx-runtime").JSX.Element;
export {};

View File

@@ -1,9 +0,0 @@
import React from 'react';
import { SxProps } from '@mui/material';
interface Props {
children: React.ReactNode;
title?: string;
sx?: SxProps;
}
export declare const Section: ({ children, sx, title }: Props) => import("react/jsx-runtime").JSX.Element;
export {};

View File

@@ -1,8 +0,0 @@
import { SxProps } from '@mui/material';
interface Props {
isExpanded: boolean;
onClick: () => void;
sx?: SxProps;
}
export declare const ExpandButton: ({ isExpanded, onClick, sx }: Props) => import("react/jsx-runtime").JSX.Element;
export {};

View File

@@ -1,6 +0,0 @@
import { Props as LabelProps } from './Label';
type Props = Omit<LabelProps, 'maxHeight'> & {
onToggleExpand?: (isExpanded: boolean) => void;
};
export declare const ExpandableLabel: ({ children, onToggleExpand, ...rest }: Props) => import("react/jsx-runtime").JSX.Element;
export {};

View File

@@ -1,12 +0,0 @@
import React from 'react';
import { SxProps } from '@mui/material';
export interface Props {
labelHeight?: number;
maxWidth: number;
maxHeight?: number;
expandDirection?: 'CENTER' | 'BOTTOM';
children: React.ReactNode;
sx?: SxProps;
showLine?: boolean;
}
export declare const Label: ({ children, maxWidth, maxHeight, expandDirection, labelHeight, sx, showLine }: Props) => import("react/jsx-runtime").JSX.Element;

View File

@@ -1 +0,0 @@
export declare const Lasso: () => import("react/jsx-runtime").JSX.Element | null;

View File

@@ -1,6 +0,0 @@
import React from 'react';
interface Props {
toolMenuRef?: React.RefObject<HTMLElement>;
}
export declare const LassoHintTooltip: ({ toolMenuRef }: Props) => import("react/jsx-runtime").JSX.Element | null;
export {};

View File

@@ -1,8 +0,0 @@
import { CircularProgressProps } from '@mui/material';
interface Props {
size?: number;
color?: CircularProgressProps['color'];
isInline?: boolean;
}
export declare const Loader: ({ size, color, isInline }: Props) => import("react/jsx-runtime").JSX.Element;
export {};

View File

@@ -1 +0,0 @@
export declare const MainMenu: () => import("react/jsx-runtime").JSX.Element | null;

View File

@@ -1,8 +0,0 @@
import React from 'react';
export interface Props {
onClick?: () => void;
Icon?: React.ReactNode;
children: string | React.ReactNode;
disabled?: boolean;
}
export declare const MenuItem: ({ onClick, Icon, children, disabled }: Props) => import("react/jsx-runtime").JSX.Element;

View File

@@ -1,10 +0,0 @@
import React from 'react';
interface Props {
value?: string;
onChange?: (value: string) => void;
readOnly?: boolean;
height?: number;
styles?: React.CSSProperties;
}
export declare const MarkdownEditor: ({ value, onChange, readOnly, height, styles }: Props) => import("react/jsx-runtime").JSX.Element;
export {};

View File

@@ -1 +0,0 @@
export declare const PanSettings: () => import("react/jsx-runtime").JSX.Element;

View File

@@ -1,2 +0,0 @@
import { RendererProps } from '../../types/rendererProps';
export declare const Renderer: ({ showGrid, backgroundColor }: RendererProps) => import("react/jsx-runtime").JSX.Element;

View File

@@ -1,10 +0,0 @@
import React from 'react';
import { SxProps } from '@mui/material';
interface Props {
children?: React.ReactNode;
order?: number;
sx?: SxProps;
disableAnimation?: boolean;
}
export declare const SceneLayer: ({ children, order, sx, disableAnimation }: Props) => import("react/jsx-runtime").JSX.Element;
export {};

View File

@@ -1,6 +0,0 @@
import { useScene } from '../../../hooks/useScene';
interface Props {
connector: ReturnType<typeof useScene>['connectors'][0];
}
export declare const ConnectorLabel: ({ connector: sceneConnector }: Props) => import("react/jsx-runtime").JSX.Element;
export {};

View File

@@ -1,6 +0,0 @@
import { useScene } from '../../../hooks/useScene';
interface Props {
connectors: ReturnType<typeof useScene>['connectors'];
}
export declare const ConnectorLabels: ({ connectors }: Props) => import("react/jsx-runtime").JSX.Element;
export {};

View File

@@ -1,7 +0,0 @@
import { useScene } from '../../../hooks/useScene';
interface Props {
connector: ReturnType<typeof useScene>['connectors'][0];
isSelected?: boolean;
}
export declare const Connector: ({ connector: _connector, isSelected }: Props) => import("react/jsx-runtime").JSX.Element | null;
export {};

View File

@@ -1,6 +0,0 @@
import type { useScene } from '../../../hooks/useScene';
interface Props {
connectors: ReturnType<typeof useScene>['connectors'];
}
export declare const Connectors: ({ connectors }: Props) => import("react/jsx-runtime").JSX.Element;
export {};

View File

@@ -1,7 +0,0 @@
interface Props {
url: string;
scale?: number;
onImageLoaded?: () => void;
}
export declare const IsometricIcon: ({ url, scale, onImageLoaded }: Props) => import("react/jsx-runtime").JSX.Element;
export {};

View File

@@ -1,6 +0,0 @@
import { Icon } from '../../../../../types';
interface Props {
icon: Icon;
}
export declare const NonIsometricIcon: ({ icon }: Props) => import("react/jsx-runtime").JSX.Element;
export {};

View File

@@ -1,7 +0,0 @@
import { ViewItem } from '../../../../types';
interface Props {
node: ViewItem;
order: number;
}
export declare const Node: ({ node, order }: Props) => import("react/jsx-runtime").JSX.Element | null;
export {};

View File

@@ -1,6 +0,0 @@
import { ViewItem } from '../../../types';
interface Props {
nodes: ViewItem[];
}
export declare const Nodes: ({ nodes }: Props) => import("react/jsx-runtime").JSX.Element;
export {};

View File

@@ -1,4 +0,0 @@
import { useScene } from '../../../hooks/useScene';
type Props = ReturnType<typeof useScene>['rectangles'][0];
export declare const Rectangle: ({ from, to, color: colorId, customColor }: Props) => import("react/jsx-runtime").JSX.Element | null;
export {};

View File

@@ -1,6 +0,0 @@
import { useScene } from '../../../hooks/useScene';
interface Props {
rectangles: ReturnType<typeof useScene>['rectangles'];
}
export declare const Rectangles: ({ rectangles }: Props) => import("react/jsx-runtime").JSX.Element;
export {};

View File

@@ -1,6 +0,0 @@
import { useScene } from '../../../hooks/useScene';
interface Props {
textBox: ReturnType<typeof useScene>['textBoxes'][0];
}
export declare const TextBox: ({ textBox }: Props) => import("react/jsx-runtime").JSX.Element;
export {};

View File

@@ -1,6 +0,0 @@
import { useScene } from '../../../hooks/useScene';
interface Props {
textBoxes: ReturnType<typeof useScene>['textBoxes'];
}
export declare const TextBoxes: ({ textBoxes }: Props) => import("react/jsx-runtime").JSX.Element;
export {};

View File

@@ -1 +0,0 @@
export declare const SettingsDialog: () => import("react/jsx-runtime").JSX.Element;

View File

@@ -1,9 +0,0 @@
import React from 'react';
import { Size } from '../../types';
type Props = React.SVGProps<SVGSVGElement> & {
children: React.ReactNode;
style?: React.CSSProperties;
viewboxSize?: Size;
};
export declare const Svg: ({ children, style, viewboxSize, ...rest }: Props) => import("react/jsx-runtime").JSX.Element;
export {};

View File

@@ -1 +0,0 @@
export declare const ToolMenu: () => import("react/jsx-runtime").JSX.Element;

View File

@@ -1,5 +0,0 @@
interface Props {
id: string;
}
export declare const NodeTransformControls: ({ id }: Props) => import("react/jsx-runtime").JSX.Element | null;
export {};

View File

@@ -1,5 +0,0 @@
interface Props {
id: string;
}
export declare const RectangleTransformControls: ({ id }: Props) => import("react/jsx-runtime").JSX.Element | null;
export {};

View File

@@ -1,5 +0,0 @@
interface Props {
id: string;
}
export declare const TextBoxTransformControls: ({ id }: Props) => import("react/jsx-runtime").JSX.Element | null;
export {};

View File

@@ -1,7 +0,0 @@
import { Coords } from '../../types';
interface Props {
position: Coords;
onMouseDown: () => void;
}
export declare const TransformAnchor: ({ position, onMouseDown }: Props) => import("react/jsx-runtime").JSX.Element;
export {};

View File

@@ -1,8 +0,0 @@
import { Coords, AnchorPosition } from '../../types';
interface Props {
from: Coords;
to: Coords;
onAnchorMouseDown?: (anchorPosition: AnchorPosition) => void;
}
export declare const TransformControls: ({ from, to, onAnchorMouseDown }: Props) => import("react/jsx-runtime").JSX.Element;
export {};

View File

@@ -1 +0,0 @@
export declare const TransformControlsManager: () => import("react/jsx-runtime").JSX.Element | null;

View File

@@ -1,9 +0,0 @@
import React from 'react';
import { SxProps } from '@mui/material';
interface Props {
children: React.ReactNode;
sx?: SxProps;
style?: React.CSSProperties;
}
export declare const UiElement: ({ children, sx, style }: Props) => import("react/jsx-runtime").JSX.Element;
export {};

View File

@@ -1 +0,0 @@
export declare const UiOverlay: () => import("react/jsx-runtime").JSX.Element;

View File

@@ -1 +0,0 @@
export declare const ZoomControls: () => import("react/jsx-runtime").JSX.Element;

View File

@@ -1 +0,0 @@
export declare const ZoomSettings: () => import("react/jsx-runtime").JSX.Element;

View File

@@ -1,48 +0,0 @@
import { Size, InitialData, MainMenuOptions, Icon, Connector, TextBox, ViewItem, View, Rectangle, Colors } from './types';
export declare const UNPROJECTED_TILE_SIZE = 100;
export declare const TILE_PROJECTION_MULTIPLIERS: Size;
export declare const PROJECTED_TILE_SIZE: {
width: number;
height: number;
};
export declare const DEFAULT_COLOR: Colors[0];
export declare const DEFAULT_FONT_FAMILY = "Roboto, Arial, sans-serif";
export declare const VIEW_DEFAULTS: Required<Omit<View, 'id' | 'description' | 'lastUpdated'>>;
export declare const VIEW_ITEM_DEFAULTS: Required<Omit<ViewItem, 'id' | 'tile'>>;
export declare const CONNECTOR_DEFAULTS: Required<Omit<Connector, 'id' | 'color'>>;
export declare const CONNECTOR_SEARCH_OFFSET: {
x: number;
y: number;
};
export declare const TEXTBOX_DEFAULTS: Required<Omit<TextBox, 'id' | 'tile'>>;
export declare const TEXTBOX_PADDING = 0.2;
export declare const TEXTBOX_FONT_WEIGHT = "bold";
export declare const RECTANGLE_DEFAULTS: Required<Omit<Rectangle, 'id' | 'from' | 'to' | 'color'>>;
export declare const ZOOM_INCREMENT = 0.2;
export declare const MIN_ZOOM = 0.2;
export declare const MAX_ZOOM = 1;
export declare const TRANSFORM_ANCHOR_SIZE = 30;
export declare const TRANSFORM_CONTROLS_COLOR = "#0392ff";
export declare const INITIAL_DATA: InitialData;
export declare const INITIAL_UI_STATE: {
zoom: number;
scroll: {
position: {
x: number;
y: number;
};
offset: {
x: number;
y: number;
};
};
};
export declare const INITIAL_SCENE_STATE: {
connectors: {};
textBoxes: {};
};
export declare const MAIN_MENU_OPTIONS: MainMenuOptions;
export declare const DEFAULT_ICON: Icon;
export declare const DEFAULT_LABEL_HEIGHT = 20;
export declare const PROJECT_BOUNDING_BOX_PADDING = 3;
export declare const MARKDOWN_EMPTY_VALUE = "<p><br></p>";

View File

@@ -1,13 +0,0 @@
export type HotkeyProfile = 'qwerty' | 'smnrct' | 'none';
export interface HotkeyMapping {
select: string | null;
pan: string | null;
addItem: string | null;
rectangle: string | null;
connector: string | null;
text: string | null;
lasso: string | null;
freehandLasso: string | null;
}
export declare const HOTKEY_PROFILES: Record<HotkeyProfile, HotkeyMapping>;
export declare const DEFAULT_HOTKEY_PROFILE: HotkeyProfile;

View File

@@ -1,12 +0,0 @@
export interface PanSettings {
middleClickPan: boolean;
rightClickPan: boolean;
ctrlClickPan: boolean;
altClickPan: boolean;
emptyAreaClickPan: boolean;
arrowKeysPan: boolean;
wasdPan: boolean;
ijklPan: boolean;
keyboardPanSpeed: number;
}
export declare const DEFAULT_PAN_SETTINGS: PanSettings;

View File

@@ -1,4 +0,0 @@
export interface ZoomSettings {
zoomToCursor: boolean;
}
export declare const DEFAULT_ZOOM_SETTINGS: ZoomSettings;

View File

@@ -1 +0,0 @@
export declare const BasicEditor: () => import("react/jsx-runtime").JSX.Element;

View File

@@ -1 +0,0 @@
export declare const DebugTools: () => import("react/jsx-runtime").JSX.Element;

View File

@@ -1 +0,0 @@
export declare const ReadonlyMode: () => import("react/jsx-runtime").JSX.Element;

View File

@@ -1 +0,0 @@
export declare const Examples: () => import("react/jsx-runtime").JSX.Element;

View File

@@ -1,4 +0,0 @@
import { Colors, Icons, InitialData } from '../Isoflow';
export declare const colors: Colors;
export declare const icons: Icons;
export declare const initialData: InitialData;

View File

@@ -1,2 +0,0 @@
import { Colors } from '../types';
export declare const colors: Colors;

View File

@@ -1,2 +0,0 @@
import { Model } from '../types';
export declare const icons: Model['icons'];

View File

@@ -1,2 +0,0 @@
import { Model } from '../types';
export declare const model: Model;

View File

@@ -1,2 +0,0 @@
import { Model } from '../types';
export declare const modelItems: Model['items'];

View File

@@ -1,2 +0,0 @@
import { Model } from '../types';
export declare const views: Model['views'];

View File

@@ -1,4 +0,0 @@
export declare const useColor: (colorId?: string) => {
value: string;
id: string;
} | null;

View File

@@ -1,35 +0,0 @@
export declare const useConnector: (id: string) => {
path: import("../types").ConnectorPath;
id: string;
anchors: {
id: string;
ref: {
item?: string | undefined;
anchor?: string | undefined;
tile?: {
x: number;
y: number;
} | undefined;
};
}[];
description: string;
color?: string | undefined;
customColor: string;
startLabel: string;
endLabel: string;
startLabelHeight: number;
centerLabelHeight: number;
endLabelHeight: number;
labels: {
id: string;
text: string;
position: number;
height?: number | undefined;
line?: "1" | "2" | undefined;
showLine?: boolean | undefined;
}[];
width: number;
style: "SOLID" | "DOTTED" | "DASHED";
lineType: "SINGLE" | "DOUBLE" | "DOUBLE_WITH_CIRCLE";
showArrow: boolean;
} | null;

View File

@@ -1,10 +0,0 @@
import { Size, Coords } from '../types';
export declare const useDiagramUtils: () => {
getUnprojectedBounds: () => Size & Coords;
getVisualBounds: () => Size & Coords;
fitToView: () => Promise<void>;
getFitToViewParams: (viewportSize: Size) => {
zoom: number;
scroll: Coords;
};
};

Some files were not shown because too many files have changed in this diff Show More