flexdesk 0.1.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/LICENSE +21 -0
- package/README.md +195 -0
- package/THIRD_PARTY_LICENSES.md +53 -0
- package/css/base.css +3439 -0
- package/css/flexdesk.css +5797 -0
- package/css/overrides.css +2349 -0
- package/css/reset.css +46 -0
- package/css/tokens.css +137 -0
- package/dist/charts.js +780 -0
- package/dist/charts.js.map +7 -0
- package/dist/chunk-3PHCPZHT.js +222 -0
- package/dist/chunk-3PHCPZHT.js.map +7 -0
- package/dist/chunk-CT4YXXLP.js +1770 -0
- package/dist/chunk-CT4YXXLP.js.map +7 -0
- package/dist/chunk-DRYCDMEG.js +2217 -0
- package/dist/chunk-DRYCDMEG.js.map +7 -0
- package/dist/chunk-DVU44T77.js +855 -0
- package/dist/chunk-DVU44T77.js.map +7 -0
- package/dist/chunk-FL5KFNQH.js +640 -0
- package/dist/chunk-FL5KFNQH.js.map +7 -0
- package/dist/chunk-FOOS3T5L.js +117 -0
- package/dist/chunk-FOOS3T5L.js.map +7 -0
- package/dist/chunk-JYWURG5T.js +32 -0
- package/dist/chunk-JYWURG5T.js.map +7 -0
- package/dist/chunk-TLZUUFOE.js +276 -0
- package/dist/chunk-TLZUUFOE.js.map +7 -0
- package/dist/chunk-UCJ2WD4D.js +625 -0
- package/dist/chunk-UCJ2WD4D.js.map +7 -0
- package/dist/chunk-WVFGV5FT.js +205 -0
- package/dist/chunk-WVFGV5FT.js.map +7 -0
- package/dist/core.js +1098 -0
- package/dist/core.js.map +7 -0
- package/dist/editor.js +1661 -0
- package/dist/editor.js.map +7 -0
- package/dist/flexdesk.css +5797 -0
- package/dist/host.js +132 -0
- package/dist/host.js.map +7 -0
- package/dist/reset.css +46 -0
- package/dist/tile_registry-6WZPTUZV.js +28 -0
- package/dist/tile_registry-6WZPTUZV.js.map +7 -0
- package/dist/tiles.js +2068 -0
- package/dist/tiles.js.map +7 -0
- package/dist/tokens.css +137 -0
- package/dist/widgets.js +5438 -0
- package/dist/widgets.js.map +7 -0
- package/dist/wm.js +4830 -0
- package/dist/wm.js.map +7 -0
- package/package.json +80 -0
- package/src/charts/chart_types.js +699 -0
- package/src/charts/data_series_plot_window.js +761 -0
- package/src/charts/downsample.js +119 -0
- package/src/charts/plot_config.js +176 -0
- package/src/charts/plot_popout_window.js +1560 -0
- package/src/charts/plotly_wrapper.js +432 -0
- package/src/core/event_bus.js +230 -0
- package/src/core/logging.js +300 -0
- package/src/core/settings.js +813 -0
- package/src/core/state_guard.js +382 -0
- package/src/core/state_guard_config.js +309 -0
- package/src/core/state_machine.js +258 -0
- package/src/editor/editor_pane.js +264 -0
- package/src/editor/monaco_editor_factory.js +449 -0
- package/src/editor/monaco_loader.js +74 -0
- package/src/editor/notebook_search.js +460 -0
- package/src/editor/notebook_tab_bar.js +456 -0
- package/src/editor/notebook_undo_manager.js +108 -0
- package/src/editor/split_pane_container.js +197 -0
- package/src/help/help_modal.js +409 -0
- package/src/help/help_registry.js +65 -0
- package/src/host/host.js +69 -0
- package/src/host/pywebview_host.js +133 -0
- package/src/tiles/config_schema.js +256 -0
- package/src/tiles/layout_persistence.js +662 -0
- package/src/tiles/tile_base.js +785 -0
- package/src/tiles/tile_grid.js +905 -0
- package/src/tiles/tile_registry.js +136 -0
- package/src/tiling/command_palette.js +328 -0
- package/src/tiling/content_registry.js +110 -0
- package/src/tiling/desktops.js +133 -0
- package/src/tiling/entity_sources.js +179 -0
- package/src/tiling/keymap.js +156 -0
- package/src/tiling/kind_taxonomy.js +172 -0
- package/src/tiling/landing_table.js +717 -0
- package/src/tiling/loading_overlay.js +33 -0
- package/src/tiling/nav_panel.js +142 -0
- package/src/tiling/page_factory.js +215 -0
- package/src/tiling/panel_keys.js +145 -0
- package/src/tiling/shell.js +437 -0
- package/src/tiling/tile_breadcrumb.js +222 -0
- package/src/tiling/tile_renderer.js +459 -0
- package/src/tiling/tile_tab_menu.js +340 -0
- package/src/tiling/tile_tree.js +880 -0
- package/src/tiling/wm.js +1352 -0
- package/src/ui/base/component_base.js +30 -0
- package/src/ui/base/controller_base.js +48 -0
- package/src/ui/base/page_base.js +102 -0
- package/src/ui/components/about_dialog.js +224 -0
- package/src/ui/components/action_dropdown.js +389 -0
- package/src/ui/components/attribute_list_editor.js +652 -0
- package/src/ui/components/autocomplete_field.js +732 -0
- package/src/ui/components/computing_status_window.js +81 -0
- package/src/ui/components/confirm_dialog.js +307 -0
- package/src/ui/components/context_menu.js +87 -0
- package/src/ui/components/data_table.js +2228 -0
- package/src/ui/components/detail_header.js +177 -0
- package/src/ui/components/drag_reorder.js +0 -0
- package/src/ui/components/gallery_picker.js +147 -0
- package/src/ui/components/inline_renamer.js +129 -0
- package/src/ui/components/managed_window.js +804 -0
- package/src/ui/components/modal.js +512 -0
- package/src/ui/components/notification_history.js +264 -0
- package/src/ui/components/slide_out_panel.js +185 -0
- package/src/ui/components/slider_field.js +122 -0
- package/src/ui/components/sortable_list.js +309 -0
- package/src/ui/components/table_state_store.js +81 -0
- package/src/ui/components/toast.js +59 -0
- package/src/ui/components/tree_view.js +460 -0
- package/src/ui/components/window_taskbar.js +143 -0
- package/src/ui/controllers/panel_state_machine.js +634 -0
- package/src/ui/controllers/window_chrome_controller.js +659 -0
- package/src/ui/notification_center.js +576 -0
- package/src/ui/utils/overlay_scrollbar.js +492 -0
- package/src/ui/utils/raf_resize_observer.js +31 -0
- package/src/ui/utils/tooltip_service.js +406 -0
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../src/tiles/config_schema.js", "../src/tiles/layout_persistence.js", "../src/tiles/tile_base.js", "../src/tiles/tile_grid.js", "../tiles.js"],
|
|
4
|
+
"sourcesContent": ["/**\n * config_schema.js\n *\n * Configuration schema definitions for widget types.\n * Defines field types, validation rules, and default values.\n */\n\n/**\n * Field type definitions for widget configuration.\n */\nexport const FieldTypes = {\n TEXT: 'text',\n NUMBER: 'number',\n CHECKBOX: 'checkbox',\n SELECT: 'select',\n MULTISELECT: 'multiselect',\n COLOR: 'color',\n RANGE: 'range'\n};\n\n/**\n * Validate a configuration value against its field schema.\n * @param {any} value - Value to validate\n * @param {Object} field - Field schema\n * @returns {{valid: boolean, error?: string}} Validation result\n */\nexport function validateField(value, field) {\n // Check required\n if (field.required && (value == null || value === '')) {\n return { valid: false, error: `${field.label} is required` };\n }\n\n // Type-specific validation\n switch (field.type) {\n case FieldTypes.NUMBER:\n case FieldTypes.RANGE:\n if (value != null && value !== '') {\n const num = parseFloat(value);\n if (isNaN(num)) {\n return { valid: false, error: `${field.label} must be a number` };\n }\n if (field.min != null && num < field.min) {\n return { valid: false, error: `${field.label} must be at least ${field.min}` };\n }\n if (field.max != null && num > field.max) {\n return { valid: false, error: `${field.label} must be at most ${field.max}` };\n }\n }\n break;\n\n case FieldTypes.SELECT:\n if (field.required && !value) {\n return { valid: false, error: `${field.label} must be selected` };\n }\n break;\n\n case FieldTypes.MULTISELECT:\n if (field.required && (!Array.isArray(value) || value.length === 0)) {\n return { valid: false, error: `${field.label} must have at least one selection` };\n }\n break;\n }\n\n return { valid: true };\n}\n\n/**\n * Validate an entire configuration object against a schema.\n * @param {Object} config - Configuration object\n * @param {Object} schema - Schema with fields array\n * @returns {{valid: boolean, errors: Object}} Validation result\n */\nexport function validateConfig(config, schema) {\n const errors = {};\n let valid = true;\n\n if (!schema?.fields) {\n return { valid: true, errors: {} };\n }\n\n schema.fields.forEach(field => {\n const result = validateField(config[field.key], field);\n if (!result.valid) {\n errors[field.key] = result.error;\n valid = false;\n }\n });\n\n return { valid, errors };\n}\n\n/**\n * Merge user config with defaults from schema.\n * @param {Object} config - User configuration\n * @param {Object} schema - Schema with fields array\n * @returns {Object} Merged configuration\n */\nexport function mergeWithDefaults(config, schema) {\n const result = { ...config };\n\n if (schema?.fields) {\n schema.fields.forEach(field => {\n if (result[field.key] === undefined && field.default !== undefined) {\n result[field.key] = field.default;\n }\n });\n }\n\n return result;\n}\n\n/**\n * Get options for a select/multiselect field.\n * Handles dynamic options (e.g., 'variables' which gets populated from data).\n * @param {Object} field - Field schema\n * @param {Object} data - Current data context\n * @returns {Array<{value: string, label: string}>} Options array\n */\nexport function getFieldOptions(field, data) {\n if (Array.isArray(field.options)) {\n return field.options;\n }\n\n // Dynamic options based on string identifier\n if (field.options === 'variables') {\n return getVariableOptions(data);\n }\n\n if (field.options === 'namespaces') {\n return getNamespaceOptions(data);\n }\n\n return [];\n}\n\n/**\n * Format a raw analytics variable key into a user-friendly display label.\n * Strips namespace prefixes, internal Godley patterns, and stock type suffixes.\n *\n * Examples:\n * \"Agriculture.__SimpleStocks__::arable_land[State]\" \u2192 \"arable_land\"\n * \"Population.population\" \u2192 \"population\"\n * \"Banks::Assets[Cash]\" \u2192 \"Assets / Cash\"\n * \"my_variable\" \u2192 \"my_variable\"\n *\n * @param {string} name - Raw variable key from analytics\n * @returns {string} Friendly display label\n */\nexport function formatVariableLabel(name) {\n if (!name) return '';\n let label = name;\n\n // Strip namespace prefix: \"Namespace.rest\" \u2192 \"rest\"\n const dotIdx = label.indexOf('.');\n if (dotIdx > 0) {\n label = label.slice(dotIdx + 1);\n }\n\n // Strip __SimpleStocks__:: or similar double-underscore sector prefixes\n label = label.replace(/^__\\w+__::/, '');\n\n // Handle Godley stock pattern: \"Sector::AccountType[Account]\" \u2192 \"AccountType / Account\"\n // But first strip [State] / [Rate] suffixes that are internal\n label = label.replace(/\\[State\\]$/i, '');\n label = label.replace(/\\[Rate\\]$/i, '');\n\n // Clean up trailing empty brackets or colons from stripping\n label = label.replace(/\\[\\]$/, '');\n\n // Replace :: with readable separator\n label = label.replace(/::/g, ' / ');\n\n // Replace single colons used as separators with underscore\n label = label.replace(/:/g, '_');\n\n // Clean up any double spaces or leading/trailing whitespace\n return label.replace(/\\s{2,}/g, ' ').trim();\n}\n\n/**\n * Get variable options from data.\n * @param {Object} data - Analytics data\n * @returns {Array<{value: string, label: string, category?: string}>} Variable options\n */\nexport function getVariableOptions(data) {\n const options = [];\n\n if (!data) return options;\n\n // Add stocks\n if (data.stocks) {\n Object.keys(data.stocks).forEach(name => {\n options.push({\n value: name,\n label: formatVariableLabel(name),\n category: 'Stocks'\n });\n });\n }\n\n // Add flows\n if (data.flows) {\n Object.keys(data.flows).forEach(name => {\n options.push({\n value: name,\n label: formatVariableLabel(name),\n category: 'Flows'\n });\n });\n }\n\n // Add indicators\n if (data.indicators) {\n Object.keys(data.indicators).forEach(name => {\n options.push({\n value: name,\n label: formatVariableLabel(name),\n category: 'Indicators'\n });\n });\n }\n\n return options;\n}\n\n/**\n * Extract unique namespace names from variable keys in data.\n * Stock keys follow the pattern \"Namespace.Sector::Type[Account]\".\n * @param {Object} data - Analytics data\n * @returns {Array<{value: string, label: string}>}\n */\nexport function getNamespaceOptions(data) {\n const namespaces = new Set();\n const sources = [data?.stocks, data?.flows, data?.indicators];\n for (const source of sources) {\n if (!source) continue;\n for (const key of Object.keys(source)) {\n const dotIdx = key.indexOf('.');\n if (dotIdx > 0) {\n namespaces.add(key.slice(0, dotIdx));\n }\n }\n }\n if (namespaces.size === 0) namespaces.add('Main');\n return Array.from(namespaces).sort().map(ns => ({ value: ns, label: ns }));\n}\n\nexport default {\n FieldTypes,\n validateField,\n validateConfig,\n mergeWithDefaults,\n getFieldOptions,\n getVariableOptions,\n formatVariableLabel\n};\n", "/**\n * layout_persistence.js \u2014 saved tile layouts, keyed by whatever the app keys them by.\n *\n * Three things used to make this un-shippable, and all three are now injected:\n *\n * 1. It wrote to `localStorage` under 'ecosim.results.layouts' and\n * 'ecosim.results.configs' \u2014 a LIBRARY scribbling on one application's storage\n * keys. The keys are the consumer's now, and EcoAgent passes its existing ones,\n * so not a single saved layout is orphaned.\n *\n * 2. It imported EcoAgent's TemplateRegistry to pick a starting layout. That is a\n * `resolveTemplate` callback now: hand it your context, get a layout back, or\n * return null and get an empty grid.\n *\n * 3. Everything was called `scenarioId`, 85 times. A tile layout is keyed by\n * SOMETHING \u2014 a scenario, a document, a user, a run \u2014 and the library does not\n * get an opinion about which. It is `contextId` now. This is a rename of\n * IDENTIFIERS only: the old name was never a stored string, just a key into the\n * stored object, so no persisted data changes shape.\n *\n * `storage` is any synchronous Storage-shaped object (getItem/setItem/removeItem).\n * It defaults to localStorage because that is what a browser has; it is not the Host,\n * because the Host is async and every caller of this class is not.\n */\n\nconst LAYOUT_VERSION = 3;\n\nconst DEFAULT_LAYOUTS_KEY = 'twm.tiles.layouts';\nconst DEFAULT_CONFIGS_KEY = 'twm.tiles.configs';\n\nexport class LayoutPersistence {\n constructor({\n storage = (typeof localStorage !== 'undefined' ? localStorage : null),\n layoutsKey = DEFAULT_LAYOUTS_KEY,\n configsKey = DEFAULT_CONFIGS_KEY,\n resolveTemplate = null,\n logger = null,\n } = {}) {\n this._cache = null;\n this._storage = storage;\n this._logger = logger;\n this._layoutsKey = layoutsKey;\n this._configsKey = configsKey;\n // (context) => layout | null. No resolver => no starting template.\n this._resolveTemplate = typeof resolveTemplate === 'function' ? resolveTemplate : null;\n }\n\n /**\n * Get layout for a specific context.\n * Falls back to template resolution when no saved layout exists.\n * @param {string} contextId - Whatever the app keys layouts by.\n * @param {Object} [context] - Passed opaquely to `resolveTemplate`.\n * @returns {Object} Layout object with tiles array\n */\n getLayout(contextId, context) {\n const all = this._loadAll();\n const layout = all[contextId];\n\n if (layout && layout.version === LAYOUT_VERSION) {\n return layout;\n }\n\n // Resolve a template based on context metadata\n const instantiated = this._resolveTemplate?.(context) ?? null;\n if (instantiated) {\n return {\n tiles: instantiated.tiles,\n version: LAYOUT_VERSION,\n templateId: instantiated.templateId,\n templateModified: false,\n };\n }\n\n // Final fallback: empty layout (should not happen \u2014 resolve always returns a default)\n return { tiles: [], version: LAYOUT_VERSION };\n }\n\n /**\n * Save layout for a specific context.\n * @param {string} contextId - Whatever the app keys layouts by.\n * @param {Array|Object} layout - Layout array or object with tiles property\n */\n saveLayout(contextId, layout) {\n const all = this._loadAll();\n\n // Handle both array (from TileGrid.getLayout) and object (with tiles property) formats\n const tilesArray = Array.isArray(layout) ? layout : (layout?.tiles || []);\n\n all[contextId] = {\n tiles: tilesArray,\n version: LAYOUT_VERSION,\n updatedAt: Date.now(),\n templateId: layout?.templateId || all[contextId]?.templateId || null,\n templateModified: layout?.templateModified ?? true,\n };\n\n this._saveAll(all);\n this._logger?.info?.(`[LayoutPersistence] Saved layout for context ${contextId}`);\n }\n\n /**\n * Delete layout for a specific context.\n * @param {string} contextId - Whatever the app keys layouts by.\n */\n deleteLayout(contextId) {\n const all = this._loadAll();\n\n if (all[contextId]) {\n delete all[contextId];\n this._saveAll(all);\n this._logger?.info?.(`[LayoutPersistence] Deleted layout for context ${contextId}`);\n }\n }\n\n /**\n * Reset a layout by re-resolving the best-matching template.\n *\n * With no `resolveTemplate` supplied, \"reset\" means \"empty grid\" \u2014 which is the\n * honest answer for a library that has no templates. The previous code called\n * `TemplateRegistry.instantiate()` unconditionally and read `.tiles` off the\n * result, so a null resolver here would have been a TypeError.\n *\n * @param {string} contextId - Whatever the app keys layouts by.\n * @param {Object} [context] - Passed opaquely to `resolveTemplate`.\n * @returns {Object} The resolved layout (empty if nothing resolves).\n */\n resetLayout(contextId, context) {\n const instantiated = this._resolveTemplate?.(context) ?? null;\n const layout = {\n tiles: instantiated?.tiles ?? [],\n version: LAYOUT_VERSION,\n templateId: instantiated?.templateId ?? null,\n templateModified: false,\n };\n this.saveLayout(contextId, layout);\n return layout;\n }\n\n /**\n * Check if a context has a saved layout.\n * @param {string} contextId - Whatever the app keys layouts by.\n * @returns {boolean}\n */\n hasLayout(contextId) {\n const all = this._loadAll();\n return !!all[contextId];\n }\n\n /**\n * Get all context IDs with saved layouts.\n * @returns {Array<string>}\n */\n getAllContextIds() {\n const all = this._loadAll();\n return Object.keys(all);\n }\n\n /**\n * Export all layouts as JSON string.\n * @returns {string}\n */\n exportAll() {\n const all = this._loadAll();\n return JSON.stringify(all, null, 2);\n }\n\n /**\n * Import layouts from JSON string.\n * @param {string} json - JSON string of layouts\n * @param {boolean} [merge=false] - Whether to merge with existing or replace\n */\n importAll(json, merge = false) {\n try {\n const imported = JSON.parse(json);\n\n if (merge) {\n const existing = this._loadAll();\n this._saveAll({ ...existing, ...imported });\n } else {\n this._saveAll(imported);\n }\n\n this._cache = null;\n this._logger?.info?.('[LayoutPersistence] Imported layouts');\n } catch (err) {\n console.error('[LayoutPersistence] Failed to import layouts:', err);\n }\n }\n\n /**\n * Clear all saved layouts.\n */\n clearAll() {\n try {\n this._storage?.removeItem(this._layoutsKey);\n this._cache = null;\n this._logger?.info?.('[LayoutPersistence] Cleared all layouts');\n } catch (err) {\n console.error('[LayoutPersistence] Failed to clear layouts:', err);\n }\n }\n\n /**\n * Load all layouts from storage.\n * @returns {Object}\n * @private\n */\n _loadAll() {\n if (this._cache) {\n return this._cache;\n }\n\n try {\n const raw = this._storage?.getItem(this._layoutsKey);\n if (raw) {\n this._cache = JSON.parse(raw);\n return this._cache;\n }\n } catch (err) {\n console.error('[LayoutPersistence] Failed to load layouts:', err);\n }\n\n this._cache = {};\n return this._cache;\n }\n\n /**\n * Save all layouts to storage.\n * @param {Object} data\n * @private\n */\n _saveAll(data) {\n try {\n this._storage?.setItem(this._layoutsKey, JSON.stringify(data));\n this._cache = data;\n } catch (err) {\n console.error('[LayoutPersistence] Failed to save layouts:', err);\n\n // If quota exceeded, try to clear old entries\n if (err.name === 'QuotaExceededError') {\n this._pruneOldLayouts(data);\n }\n }\n }\n\n /**\n * Remove oldest layouts to free up space.\n * @param {Object} data\n * @private\n */\n _pruneOldLayouts(data) {\n const entries = Object.entries(data);\n\n // Sort by updatedAt, oldest first\n entries.sort((a, b) => (a[1].updatedAt || 0) - (b[1].updatedAt || 0));\n\n // Remove oldest 25%\n const removeCount = Math.ceil(entries.length * 0.25);\n for (let i = 0; i < removeCount; i++) {\n delete data[entries[i][0]];\n }\n\n // Try saving again\n try {\n this._storage?.setItem(this._layoutsKey, JSON.stringify(data));\n this._cache = data;\n this._logger?.warn?.('[LayoutPersistence] Pruned old layouts due to quota');\n } catch (err) {\n console.error('[LayoutPersistence] Still cannot save after pruning:', err);\n }\n }\n\n /**\n * Get the template ID associated with a saved layout.\n * @param {string} contextId - Whatever the app keys layouts by.\n * @returns {string|null} Template ID or null\n */\n getTemplateId(contextId) {\n const all = this._loadAll();\n return all[contextId]?.templateId || null;\n }\n\n /**\n * Check if the user has modified the layout since the template was applied.\n * @param {string} contextId - Whatever the app keys layouts by.\n * @returns {boolean}\n */\n isTemplateModified(contextId) {\n const all = this._loadAll();\n return all[contextId]?.templateModified ?? false;\n }\n\n // =========================================================================\n // NAMED CONFIGURATION MANAGEMENT\n // =========================================================================\n\n /**\n * Get all saved configurations for a context.\n * @param {string} contextId - Whatever the app keys layouts by.\n * @returns {Object} { activeId: string, configs: { id: { name, tiles, createdAt } } }\n */\n getConfigurations(contextId) {\n const all = this._loadConfigs();\n const contextConfigs = all[contextId];\n\n if (contextConfigs && Object.keys(contextConfigs.configs || {}).length > 0) {\n return contextConfigs;\n }\n\n // Return empty structure\n return {\n activeId: null,\n configs: {}\n };\n }\n\n /**\n * Save the current layout as a named configuration.\n * Names are enforced to be unique - duplicates get \"(2)\", \"(3)\", etc. suffix.\n * @param {string} contextId - Whatever the app keys layouts by.\n * @param {string} name - Configuration name\n * @param {Array|Object} layout - Layout to save\n * @param {Object} [options] - Additional options\n * @param {string} [options.templateId] - Template ID that generated this layout\n * @returns {string} The new configuration ID\n */\n saveConfiguration(contextId, name, layout, options) {\n const all = this._loadConfigs();\n\n if (!all[contextId]) {\n all[contextId] = { activeId: null, configs: {} };\n }\n\n // Ensure unique name\n const uniqueName = this._getUniqueName(all[contextId].configs, name);\n\n const configId = `config-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;\n const tilesArray = Array.isArray(layout) ? layout : (layout?.tiles || []);\n\n all[contextId].configs[configId] = {\n name: uniqueName,\n tiles: tilesArray,\n version: LAYOUT_VERSION,\n createdAt: Date.now(),\n templateId: options?.templateId || null,\n };\n\n // Set as active if it's the first one\n if (!all[contextId].activeId) {\n all[contextId].activeId = configId;\n }\n\n this._saveConfigs(all);\n this._logger?.info?.(`[LayoutPersistence] Saved configuration \"${uniqueName}\" for context ${contextId}`);\n\n return configId;\n }\n\n /**\n * Generate a unique name by appending (2), (3), etc. if name already exists.\n * @param {Object} configs - Existing configurations object\n * @param {string} name - Desired name\n * @returns {string} Unique name\n * @private\n */\n _getUniqueName(configs, name) {\n if (!configs) return name;\n\n const existingNames = new Set(Object.values(configs).map(c => c.name));\n\n if (!existingNames.has(name)) {\n return name;\n }\n\n // Find next available number\n let counter = 2;\n let candidate = `${name} (${counter})`;\n while (existingNames.has(candidate)) {\n counter++;\n candidate = `${name} (${counter})`;\n }\n\n return candidate;\n }\n\n /**\n * Load a specific configuration.\n * @param {string} contextId - Whatever the app keys layouts by.\n * @param {string} configId - Configuration ID\n * @returns {Object|null} Configuration layout or null if not found\n */\n loadConfiguration(contextId, configId) {\n const all = this._loadConfigs();\n const config = all[contextId]?.configs?.[configId];\n\n if (config) {\n // Update active config\n all[contextId].activeId = configId;\n this._saveConfigs(all);\n return config;\n }\n\n return null;\n }\n\n /**\n * Delete a saved configuration.\n * @param {string} contextId - Whatever the app keys layouts by.\n * @param {string} configId - Configuration ID\n * @returns {boolean} True if deleted, false if not found\n */\n deleteConfiguration(contextId, configId) {\n const all = this._loadConfigs();\n\n if (!all[contextId]?.configs?.[configId]) {\n return false;\n }\n\n delete all[contextId].configs[configId];\n\n // Update active if deleted\n if (all[contextId].activeId === configId) {\n const remaining = Object.keys(all[contextId].configs);\n all[contextId].activeId = remaining.length > 0 ? remaining[0] : null;\n }\n\n this._saveConfigs(all);\n this._logger?.info?.(`[LayoutPersistence] Deleted configuration ${configId} for context ${contextId}`);\n\n return true;\n }\n\n /**\n * Update an existing configuration's layout (without creating a new ID).\n * @param {string} contextId - Whatever the app keys layouts by.\n * @param {string} configId - Configuration ID\n * @param {Array|Object} layout - New layout to save\n * @returns {boolean} True if updated, false if not found\n */\n updateConfiguration(contextId, configId, layout) {\n const all = this._loadConfigs();\n\n if (!all[contextId]?.configs?.[configId]) {\n return false;\n }\n\n const tilesArray = Array.isArray(layout) ? layout : (layout?.tiles || []);\n\n all[contextId].configs[configId].tiles = tilesArray;\n all[contextId].configs[configId].version = LAYOUT_VERSION;\n all[contextId].configs[configId].updatedAt = Date.now();\n\n this._saveConfigs(all);\n return true;\n }\n\n /**\n * Update the templateId on an existing configuration.\n * @param {string} contextId - Whatever the app keys layouts by.\n * @param {string} configId - Configuration ID\n * @param {string} templateId - New template ID\n * @returns {boolean} True if updated, false if not found\n */\n updateConfigurationTemplateId(contextId, configId, templateId) {\n const all = this._loadConfigs();\n\n if (!all[contextId]?.configs?.[configId]) {\n return false;\n }\n\n all[contextId].configs[configId].templateId = templateId;\n this._saveConfigs(all);\n return true;\n }\n\n /**\n * Rename a configuration.\n * Names are enforced to be unique - duplicates get \"(2)\", \"(3)\", etc. suffix.\n * @param {string} contextId - Whatever the app keys layouts by.\n * @param {string} configId - Configuration ID\n * @param {string} newName - New name\n * @returns {string|false} The actual name used (may differ if duplicate), or false if not found\n */\n renameConfiguration(contextId, configId, newName) {\n const all = this._loadConfigs();\n\n if (!all[contextId]?.configs?.[configId]) {\n return false;\n }\n\n // Get configs excluding the one being renamed for uniqueness check\n const otherConfigs = {};\n Object.entries(all[contextId].configs).forEach(([id, config]) => {\n if (id !== configId) {\n otherConfigs[id] = config;\n }\n });\n\n const uniqueName = this._getUniqueName(otherConfigs, newName);\n all[contextId].configs[configId].name = uniqueName;\n this._saveConfigs(all);\n\n return uniqueName;\n }\n\n /**\n * Get the active configuration for a context.\n * @param {string} contextId - Whatever the app keys layouts by.\n * @returns {Object|null} { id, name, tiles } or null\n */\n getActiveConfiguration(contextId) {\n const all = this._loadConfigs();\n const contextConfigs = all[contextId];\n\n if (!contextConfigs?.activeId) {\n return null;\n }\n\n const activeConfig = contextConfigs.configs[contextConfigs.activeId];\n if (activeConfig) {\n return {\n id: contextConfigs.activeId,\n ...activeConfig\n };\n }\n\n return null;\n }\n\n /**\n * Set the active configuration.\n * @param {string} contextId - Whatever the app keys layouts by.\n * @param {string} configId - Configuration ID\n */\n setActiveConfiguration(contextId, configId) {\n const all = this._loadConfigs();\n\n if (all[contextId]?.configs?.[configId]) {\n all[contextId].activeId = configId;\n this._saveConfigs(all);\n }\n }\n\n /**\n * List all configurations for a context.\n * @param {string} contextId - Whatever the app keys layouts by.\n * @returns {Array} Array of { id, name, createdAt, isActive }\n */\n listConfigurations(contextId) {\n const all = this._loadConfigs();\n const contextConfigs = all[contextId];\n\n if (!contextConfigs?.configs) {\n return [];\n }\n\n return Object.entries(contextConfigs.configs).map(([id, config]) => ({\n id,\n name: config.name,\n createdAt: config.createdAt,\n isActive: id === contextConfigs.activeId\n })).sort((a, b) => (b.createdAt || 0) - (a.createdAt || 0));\n }\n\n /**\n * Get the template set fingerprint for a context.\n * Used to detect when templates have changed and configs need regeneration.\n * @param {string} contextId\n * @returns {string|null}\n */\n getTemplateSetId(contextId) {\n const all = this._loadConfigs();\n return all[contextId]?.templateSetId || null;\n }\n\n /**\n * Store the template set fingerprint for a context.\n * @param {string} contextId\n * @param {string} templateSetId\n */\n setTemplateSetId(contextId, templateSetId) {\n const all = this._loadConfigs();\n if (!all[contextId]) {\n all[contextId] = { activeId: null, configs: {} };\n }\n all[contextId].templateSetId = templateSetId;\n this._saveConfigs(all);\n }\n\n /**\n * Delete ALL configurations for a context.\n * @param {string} contextId\n */\n clearConfigurations(contextId) {\n const all = this._loadConfigs();\n delete all[contextId];\n this._saveConfigs(all);\n }\n\n /**\n * Load all configurations from storage.\n * @returns {Object}\n * @private\n */\n _loadConfigs() {\n try {\n const raw = this._storage?.getItem(this._configsKey);\n if (raw) {\n return JSON.parse(raw);\n }\n } catch (err) {\n console.error('[LayoutPersistence] Failed to load configurations:', err);\n }\n return {};\n }\n\n /**\n * Save all configurations to storage.\n * @param {Object} data\n * @private\n */\n _saveConfigs(data) {\n try {\n this._storage?.setItem(this._configsKey, JSON.stringify(data));\n } catch (err) {\n console.error('[LayoutPersistence] Failed to save configurations:', err);\n }\n }\n}\n\n// Singleton instance\nlet instance = null;\nlet _options = {};\n\n/**\n * Configure the singleton BEFORE anything reads it. Call once, at boot.\n *\n * The first cut let `getLayoutPersistence(options)` configure it lazily \u2014 whoever\n * called first won. That is a trap with teeth: if ANY code path had reached the\n * store before the dashboard did, the singleton would have been built with the\n * library's generic defaults, and the app would have read\n * 'twm.tiles.layouts' instead of 'ecosim.results.layouts' \u2014 an empty store. Every\n * saved dashboard a user had ever built would have silently vanished, with no\n * error, and no captured view would show it because the pixel gate runs on a\n * fresh template that has no saved layouts to lose.\n *\n * Configure once, at boot, where the ordering is not in question.\n */\nexport function configureLayoutPersistence(options = {}) {\n _options = options;\n instance = null; // rebuild on next get\n}\n\n/** @returns {LayoutPersistence} */\nexport function getLayoutPersistence() {\n if (!instance) {\n instance = new LayoutPersistence(_options);\n }\n return instance;\n}\n\nexport default LayoutPersistence;\n", "/**\n * tile_base.js\n *\n * Base class for all dashboard widget tiles.\n * Provides common lifecycle management, tile chrome (header, config button),\n * and abstract methods for subclass implementation.\n */\n\nimport { openRawTracesWindow } from '../charts/plot_popout_window.js';\nimport { formatVariableLabel } from './config_schema.js';\n// The host is INJECTED, not fetched from a global.\n//\n// This imported `appHost()` from ui/js/ecoagent/app_host.js \u2014 a tile reaching into\n// the application to find out how to save a file. The framework is injection-only;\n// the app may have a root host provider, but the library does not get to know about\n// it. Its only use was to back \"Expand\" -> Export CSV/PNG, and a tile without a host\n// falls back to a Blob download, which is exactly what the host contract promises.\n\nexport class TileBase {\n /** @type {string} Widget type identifier - override in subclass */\n static TYPE = 'base';\n\n /** @type {string} Display title - override in subclass */\n static TITLE = 'Widget';\n\n /** @type {{w: number, h: number}} Default grid size - override in subclass */\n static DEFAULT_SIZE = { w: 4, h: 3 };\n\n /** @type {{minW: number, minH: number, maxW: number, maxH: number}} Size constraints */\n static SIZE_CONSTRAINTS = { minW: 2, minH: 2, maxW: 12, maxH: 8 };\n\n /** @type {boolean} Whether widget can be expanded to a separate window - override in subclass */\n static EXPANDABLE = false;\n\n /** @type {boolean} Whether widget supports scenario comparison overlay - override in subclass */\n static SUPPORTS_COMPARISON = false;\n\n /**\n * @param {Object} options\n * @param {string} options.id - Unique tile identifier\n * @param {Object} options.grid - Parent TileGrid instance\n * @param {Object} [options.eventBus] - Event bus for cross-component communication\n * @param {Object} [options.config] - Widget-specific configuration\n * @param {boolean} [options.headless] - If true, mount without tile chrome (header, controls)\n */\n constructor({ id, grid, eventBus = null, config = {}, readonly = false,\n headless = false, host = null, stateGuard = null }) {\n this.host = host;\n // `window.__ECOSIM_JS_NEW__?.stateGuard` \u2014 an application's global, reached for\n // by a tile. The StateGuard is a FRAMEWORK service (@flexdesk/core); the INSTANCE is\n // the application's, and it is handed down through the grid. No guard => the\n // dataset writes happen directly, which is what the optional chain already did.\n this.stateGuard = stateGuard;\n this.id = id;\n this.grid = grid;\n this.eventBus = eventBus;\n this.config = { ...this.getDefaultConfig(), ...config };\n this.readonly = readonly;\n this.headless = headless;\n this.element = null;\n this.contentElement = null;\n this.chartInstance = null;\n this.data = null;\n /** @type {Object|null} Unfiltered analytics data for cross-namespace variable resolution */\n this.fullData = null;\n this._disposed = false;\n /** @type {Map<string, {name: string, analytics: Object, color: string}>|null} */\n this.comparisonData = null;\n }\n\n /**\n * Set comparison data for overlay rendering.\n * Only meaningful for widgets where SUPPORTS_COMPARISON = true.\n * @param {Map<string, Object>|null} comparisonData\n */\n setComparisonData(comparisonData) {\n this.comparisonData = comparisonData;\n if (this.data && this.contentElement) {\n this.render(this.data);\n }\n }\n\n /**\n * Format a raw analytics variable key into a user-friendly display label.\n * Strips namespace prefixes, internal Godley patterns, and stock type suffixes.\n * @param {string} name - Raw variable key\n * @returns {string} Friendly display label\n */\n formatLabel(name) {\n return formatVariableLabel(name);\n }\n\n /**\n * Look up the unit string for a variable from analytics metadata.\n * Checks stocks, flows, and indicators for unit metadata.\n * @param {string} varName - Variable name\n * @returns {string|null} Unit string or null\n */\n getVariableUnit(varName) {\n if (!varName || !this.data) return null;\n const sources = [this.data.stocks, this.data.flows, this.data.indicators];\n for (const source of sources) {\n const varData = source?.[varName];\n if (varData?.unit) return varData.unit;\n }\n return null;\n }\n\n /**\n * Look up a variable across stocks, flows, and indicators.\n * If the variable is not found, returns the first available variable\n * and updates the config key so the widget self-heals.\n * @param {Object} data - Analytics data\n * @param {string} configKey - Config property name (e.g. 'variable', 'xVariable')\n * @returns {{varData: any, varName: string}|null} Resolved data or null if no data at all\n */\n resolveVariable(data, configKey = 'variable') {\n const varName = this.config[configKey];\n if (varName) {\n // Try exact name first\n const varData = data.stocks?.[varName]\n || data.indicators?.[varName]\n || data.flows?.[varName];\n if (varData) return { varData, varName };\n\n // Try without namespace prefix (e.g. \"Population.population\" \u2192 \"population\")\n const dotIdx = varName.indexOf('.');\n if (dotIdx >= 0) {\n const bare = varName.slice(dotIdx + 1);\n const bareData = data.stocks?.[bare]\n || data.indicators?.[bare]\n || data.flows?.[bare];\n if (bareData) return { varData: bareData, varName: bare };\n }\n\n // Reverse lookup: bare name \u2192 namespace-prefixed key\n // e.g. \"population\" matches \"Population.population\" in MC data\n if (dotIdx < 0) {\n const suffix = `.${varName}`;\n for (const source of [data.stocks, data.indicators, data.flows]) {\n if (!source) continue;\n const match = Object.keys(source).find(k => k.endsWith(suffix));\n if (match) return { varData: source[match], varName: match };\n }\n }\n\n // Try unfiltered data (variable may be in a different namespace)\n if (this.fullData && this.fullData !== data) {\n const fullVarData = this.fullData.stocks?.[varName]\n || this.fullData.indicators?.[varName]\n || this.fullData.flows?.[varName];\n if (fullVarData) return { varData: fullVarData, varName };\n\n // Also try bare name against unfiltered data\n if (dotIdx >= 0) {\n const bare = varName.slice(dotIdx + 1);\n const fullBareData = this.fullData.stocks?.[bare]\n || this.fullData.indicators?.[bare]\n || this.fullData.flows?.[bare];\n if (fullBareData) return { varData: fullBareData, varName: bare };\n }\n\n // Reverse lookup against unfiltered data\n if (dotIdx < 0) {\n const suffix = `.${varName}`;\n for (const source of [this.fullData.stocks, this.fullData.indicators, this.fullData.flows]) {\n if (!source) continue;\n const match = Object.keys(source).find(k => k.endsWith(suffix));\n if (match) return { varData: source[match], varName: match };\n }\n }\n }\n }\n\n // Configured variable not found \u2014 auto-select the first available\n const sources = [data.stocks, data.indicators, data.flows];\n for (const source of sources) {\n if (!source) continue;\n const keys = Object.keys(source);\n if (keys.length > 0) {\n this.config[configKey] = keys[0];\n return { varData: source[keys[0]], varName: keys[0] };\n }\n }\n\n return null;\n }\n\n /**\n * Find a variable by name in data, trying exact match then suffix match.\n * Does NOT auto-fallback to first available variable.\n * @param {Object} data - Analytics data with stocks/indicators/flows\n * @param {string} varName - Variable name (bare or namespace-prefixed)\n * @returns {{varData: any, varName: string}|null}\n */\n static findVariable(data, varName) {\n if (!data || !varName) return null;\n for (const source of [data.stocks, data.indicators, data.flows]) {\n if (!source) continue;\n if (source[varName]) return { varData: source[varName], varName };\n }\n // Reverse lookup: bare \"population\" \u2192 \"Population.population\"\n const dotIdx = varName.indexOf('.');\n if (dotIdx < 0) {\n const suffix = `.${varName}`;\n for (const source of [data.stocks, data.indicators, data.flows]) {\n if (!source) continue;\n const match = Object.keys(source).find(k => k.endsWith(suffix));\n if (match) return { varData: source[match], varName: match };\n }\n } else {\n // Strip prefix: \"Population.population\" \u2192 \"population\"\n const bare = varName.slice(dotIdx + 1);\n for (const source of [data.stocks, data.indicators, data.flows]) {\n if (!source) continue;\n if (source[bare]) return { varData: source[bare], varName: bare };\n }\n }\n return null;\n }\n\n /**\n * Get default configuration for this widget type.\n * Override in subclass.\n * @returns {Object} Default config object\n */\n getDefaultConfig() {\n return {};\n }\n\n /**\n * Get configuration schema for the config modal.\n * Override in subclass.\n * @returns {Object} Schema definition\n */\n getConfigSchema() {\n return { fields: [] };\n }\n\n /**\n * Render widget content with data.\n * Override in subclass.\n * @param {Object} data - Analytics data\n */\n render(data) {\n throw new Error('TileBase.render() must be implemented by subclass');\n }\n\n /**\n * Mount the tile into the container.\n * @param {HTMLElement} container - Parent container\n */\n mount(container) {\n if (this._disposed) return;\n\n this.element = document.createElement('div');\n this.element.className = `tile${this.readonly ? ' tile--readonly' : ''}`;\n\n // Use StateGuard bypass if available to set dataset properties\n const stateGuard = this.stateGuard;\n const setDataset = () => {\n this.element.dataset.tileId = this.id;\n this.element.dataset.tileType = this.constructor.TYPE;\n };\n if (stateGuard?.executeWithBypass) {\n stateGuard.executeWithBypass('tile-mount', setDataset);\n } else {\n setDataset();\n }\n\n if (this.headless) {\n // Headless mode: content only, no header/controls (for embedding in notebook cells)\n this.contentElement = document.createElement('div');\n this.contentElement.className = 'tile-content';\n this.element.appendChild(this.contentElement);\n } else {\n // Build tile chrome (header + content area)\n this._buildChrome();\n }\n\n container.appendChild(this.element);\n }\n\n /**\n * Update the widget with new data and/or config.\n * @param {Object} [data] - New analytics data\n * @param {Object} [config] - New config values to merge\n */\n update(data, config) {\n if (this._disposed) return;\n\n if (config) {\n const prevDocs = (this.config?.docs || '').trim();\n this.config = { ...this.config, ...config };\n const nextDocs = (this.config?.docs || '').trim();\n // Keep the header's info-button in sync with the docs state\n if (this.element && !this.headless && prevDocs !== nextDocs) {\n this._syncInfoButton();\n }\n }\n\n if (data !== undefined) {\n this.data = data;\n }\n\n if (this.data && this.contentElement) {\n this.render(this.data);\n }\n }\n\n /** Add, update, or remove the info (\u24D8) button in the header to match current docs state. */\n _syncInfoButton() {\n const header = this.element?.querySelector('.tile-header');\n const controls = header?.querySelector('.tile-controls');\n if (!controls) return;\n const docs = (this.config?.docs || '').trim();\n let btn = controls.querySelector('.tile-info-btn');\n if (docs) {\n if (!btn) {\n btn = document.createElement('button');\n btn.className = 'tile-info-btn twm-has-tooltip';\n btn.type = 'button';\n btn.tabIndex = -1;\n btn.style.cssText = 'background:transparent;border:none;padding:2px;color:rgba(255,255,255,0.55);cursor:help;display:inline-flex;align-items:center;justify-content:center;';\n btn.setAttribute('data-tooltip-placement', 'bottom');\n btn.setAttribute('data-tooltip-max-width', '420px');\n btn.innerHTML = '<span class=\"material-symbols-outlined\" style=\"font-size:18px;\">info</span>';\n btn.addEventListener('click', (e) => e.stopPropagation());\n const anchor = controls.querySelector('.tile-expand-btn')\n ?? controls.querySelector('.tile-remove-btn');\n if (anchor) controls.insertBefore(btn, anchor);\n else controls.appendChild(btn);\n }\n btn.setAttribute('data-tooltip', docs);\n } else if (btn) {\n btn.remove();\n }\n }\n\n /**\n * Clean up resources and remove from DOM.\n */\n dispose() {\n if (this._disposed) return;\n this._disposed = true;\n\n // Close expand window if open\n if (this._expandWindow?.isVisible) {\n this._expandWindow.close();\n }\n this._expandWindow = null;\n\n // Destroy chart instance if exists\n if (this.chartInstance) {\n this.chartInstance.destroy();\n this.chartInstance = null;\n }\n\n // Remove from DOM\n if (this.element && this.element.parentNode) {\n this.element.parentNode.removeChild(this.element);\n }\n\n this.element = null;\n this.contentElement = null;\n this.data = null;\n this.fullData = null;\n }\n\n /**\n * Build the tile chrome (header, content area, resize handles).\n * @private\n */\n _buildChrome() {\n // Header with drag handle and controls\n const header = document.createElement('div');\n header.className = 'tile-header';\n\n // Build controls HTML - expand button only if widget is expandable\n const expandBtnHtml = this.constructor.EXPANDABLE\n ? `<button class=\"tile-expand-btn twm-has-tooltip\" data-tooltip=\"Open in window\">\n <span class=\"material-symbols-outlined\">open_in_new</span>\n </button>`\n : '';\n\n // Info button \u2014 only shown if config.docs has text. Uses the\n // standard has-tooltip system so the docs appear as a hover tooltip\n // (auto-positioned) instead of a click-to-open popover.\n const docs = (this.config?.docs || '').trim();\n const infoBtnHtml = docs\n ? `<button class=\"tile-info-btn twm-has-tooltip\" type=\"button\" tabindex=\"-1\"\n data-tooltip=\"${this.#escapeAttr(docs)}\"\n data-tooltip-placement=\"bottom\"\n data-tooltip-max-width=\"420px\"\n style=\"background:transparent;border:none;padding:2px;color:rgba(255,255,255,0.55);cursor:help;display:inline-flex;align-items:center;justify-content:center;\">\n <span class=\"material-symbols-outlined\" style=\"font-size:18px;\">info</span>\n </button>`\n : '';\n\n if (this.readonly) {\n // Read-only mode: no drag handle, no menu, no remove button\n header.innerHTML = `\n <span class=\"tile-title\">${this.constructor.TITLE}</span>\n <div class=\"tile-controls\">\n ${infoBtnHtml}\n ${expandBtnHtml}\n </div>\n `;\n } else {\n header.innerHTML = `\n <span class=\"tile-drag-handle twm-has-tooltip\" data-tooltip=\"Drag to reposition\">\n <span class=\"material-symbols-outlined\">drag_indicator</span>\n </span>\n <span class=\"tile-title\">${this.constructor.TITLE}</span>\n <div class=\"tile-controls\">\n <button class=\"tile-config-btn twm-has-tooltip\" data-tooltip=\"Configure\">\n <span class=\"material-symbols-outlined\">settings</span>\n </button>\n <div class=\"tile-menu-wrapper\">\n <button class=\"tile-menu-btn twm-has-tooltip\" data-tooltip=\"More actions\">\n <span class=\"material-symbols-outlined\">more_vert</span>\n </button>\n <div class=\"tile-menu-dropdown\" hidden>\n <button class=\"tile-menu-item\" data-action=\"add-to-documentation\" style=\"${this.config?.sourceCellId && this.grid?.documentationCellIds?.has(this.config.sourceCellId) ? 'display:none' : ''}\">\n <span class=\"material-symbols-outlined\">post_add</span>\n <span>Add to Documentation</span>\n </button>\n <button class=\"tile-menu-item\" data-action=\"show-in-documentation\" style=\"${this.config?.sourceCellId && this.grid?.documentationCellIds?.has(this.config.sourceCellId) ? '' : 'display:none'}\">\n <span class=\"material-symbols-outlined\">description</span>\n <span>Show in Documentation</span>\n </button>\n </div>\n </div>\n ${infoBtnHtml}\n ${expandBtnHtml}\n <button class=\"tile-remove-btn twm-has-tooltip\" data-tooltip=\"Remove widget\">\n <span class=\"material-symbols-outlined\">close</span>\n </button>\n </div>\n `;\n }\n\n // Expand button handler\n const expandBtn = header.querySelector('.tile-expand-btn');\n expandBtn?.addEventListener('click', (e) => {\n e.stopPropagation();\n this._onExpandClick();\n });\n\n // Info button is purely decorative \u2014 the docs are shown by the global\n // tooltip service via data-tooltip. Stop click-propagation so clicks\n // don't open the config panel, and make the button unfocusable.\n const infoBtn = header.querySelector('.tile-info-btn');\n infoBtn?.addEventListener('click', (e) => e.stopPropagation());\n\n if (!this.readonly) {\n // Config opens ONLY via the explicit cogwheel button \u2014 not a\n // title or content click, which fired the config panel too\n // eagerly (e.g. when you just wanted to read or pan the chart).\n const configBtn = header.querySelector('.tile-config-btn');\n configBtn?.addEventListener('click', (e) => {\n e.stopPropagation();\n this._onConfigClick();\n });\n\n // \"...\" menu button + dropdown\n const menuBtn = header.querySelector('.tile-menu-btn');\n const menuDropdown = header.querySelector('.tile-menu-dropdown');\n if (menuBtn && menuDropdown) {\n menuBtn.addEventListener('click', (e) => {\n e.stopPropagation();\n const isOpen = !menuDropdown.hidden;\n menuDropdown.hidden = !menuDropdown.hidden;\n if (!isOpen) {\n // Close on outside click\n const closeMenu = (ev) => {\n if (!menuDropdown.contains(ev.target) && ev.target !== menuBtn) {\n menuDropdown.hidden = true;\n document.removeEventListener('pointerdown', closeMenu, true);\n }\n };\n // Delay to avoid immediate close from the same click\n requestAnimationFrame(() => {\n document.addEventListener('pointerdown', closeMenu, true);\n });\n }\n });\n menuDropdown.querySelector('[data-action=\"add-to-documentation\"]')?.addEventListener('click', (e) => {\n e.stopPropagation();\n menuDropdown.hidden = true;\n this.eventBus?.emit?.('tile:add-to-documentation', {\n tileType: this.constructor.TYPE,\n config: { ...this.config },\n });\n });\n menuDropdown.querySelector('[data-action=\"show-in-documentation\"]')?.addEventListener('click', (e) => {\n e.stopPropagation();\n menuDropdown.hidden = true;\n if (this.config?.sourceCellId) {\n this.eventBus?.emit?.('tile:show-in-documentation', {\n sourceCellId: this.config.sourceCellId,\n });\n }\n });\n }\n\n const removeBtn = header.querySelector('.tile-remove-btn');\n removeBtn?.addEventListener('click', (e) => {\n e.stopPropagation();\n this._onRemoveClick();\n });\n }\n\n // Content area. Clicking the content no longer opens config \u2014 that\n // moved to the explicit cogwheel button in the header so chart\n // interaction (pan/zoom/hover) doesn't trip the config panel.\n this.contentElement = document.createElement('div');\n this.contentElement.className = 'tile-content';\n\n this.element.appendChild(header);\n this.element.appendChild(this.contentElement);\n\n if (!this.readonly) {\n // Resize handle (bottom-right)\n const resizeHandle = document.createElement('div');\n resizeHandle.className = 'tile-resize-handle se';\n resizeHandle.innerHTML = '<span class=\"material-symbols-outlined\">drag_handle</span>';\n this.element.appendChild(resizeHandle);\n\n // Context menu for \"Add to Documentation\" etc.\n this.element.addEventListener('contextmenu', (e) => {\n e.preventDefault();\n e.stopPropagation();\n this.eventBus?.emit?.('tile:context-menu', {\n tileId: this.id,\n tileType: this.constructor.TYPE,\n tileTitle: this.constructor.TITLE,\n config: { ...this.config },\n clientX: e.clientX,\n clientY: e.clientY,\n });\n });\n }\n }\n\n /**\n * Handle config button click \u2014 highlight tile and emit config request.\n * @private\n */\n _onConfigClick() {\n // Deselect all sibling tiles, then select this one\n this.element?.closest('.tile-grid')\n ?.querySelectorAll('.tile.tile--selected')\n .forEach(el => el.classList.remove('tile--selected'));\n this.element?.classList.add('tile--selected');\n\n // Emit event for grid/dashboard to show config panel\n this.eventBus?.emit?.('tile:config-request', {\n tileId: this.id,\n tileType: this.constructor.TYPE,\n config: this.config,\n schema: this.getConfigSchema()\n });\n\n // Also dispatch DOM event for alternative handling\n this.element?.dispatchEvent(new CustomEvent('tile:config-request', {\n bubbles: true,\n detail: {\n tileId: this.id,\n tileType: this.constructor.TYPE,\n config: this.config,\n schema: this.getConfigSchema()\n }\n }));\n }\n\n /**\n * Handle remove button click.\n * @param {Event} [event] - Original click event\n * @private\n */\n _onRemoveClick(event) {\n const removeBtn = this.element?.querySelector('.tile-remove-btn');\n\n // Only dispatch DOM event - let the dashboard handle confirmation\n this.element?.dispatchEvent(new CustomEvent('tile:remove-request', {\n bubbles: true,\n detail: {\n tileId: this.id,\n anchorElement: removeBtn\n }\n }));\n }\n\n /**\n * Set the title displayed in the header.\n * @param {string} title - New title text\n */\n setTitle(title) {\n const titleEl = this.element?.querySelector('.tile-title');\n if (titleEl) {\n titleEl.textContent = title;\n }\n }\n\n /**\n * Show loading state in content area.\n */\n showLoading() {\n if (this.contentElement) {\n this.contentElement.innerHTML = `\n <div class=\"tile-loading\">\n <span class=\"material-symbols-outlined spinning\">progress_activity</span>\n <span>Loading...</span>\n </div>\n `;\n }\n }\n\n /**\n * Show empty state in content area.\n * @param {string} [message] - Custom message\n */\n showEmpty(message = 'No data available') {\n if (this.contentElement) {\n this.contentElement.innerHTML = `\n <div class=\"tile-empty\">\n <span class=\"material-symbols-outlined\">inbox</span>\n <span>${message}</span>\n </div>\n `;\n }\n }\n\n /**\n * Show error state in content area.\n * @param {string} [message] - Error message\n */\n showError(message = 'Failed to load data') {\n if (this.contentElement) {\n this.contentElement.innerHTML = `\n <div class=\"twm-tile-error\">\n <span class=\"material-symbols-outlined\">error</span>\n <span>${message}</span>\n </div>\n `;\n }\n }\n\n /**\n * Format a number for display.\n * @param {number} value - Number to format\n * @param {number} [decimals=2] - Decimal places\n * @returns {string} Formatted string\n */\n formatNumber(value, decimals = 2) {\n if (value == null || !Number.isFinite(value)) return '\u2014';\n\n const abs = Math.abs(value);\n if (abs >= 1e9) {\n return (value / 1e9).toFixed(1) + 'B';\n } else if (abs >= 1e6) {\n return (value / 1e6).toFixed(1) + 'M';\n } else if (abs >= 1e3) {\n return (value / 1e3).toFixed(1) + 'K';\n } else if (abs < 0.01 && abs > 0) {\n return value.toExponential(decimals);\n }\n return value.toFixed(decimals);\n }\n\n /**\n * Get available variables from data for config dropdowns.\n * @param {Object} data - Analytics data\n * @returns {Array<{value: string, label: string}>} Variable options\n */\n getAvailableVariables(data) {\n if (!data) return [];\n\n const variables = [];\n\n // Add stocks\n if (data.stocks) {\n Object.keys(data.stocks).forEach(name => {\n variables.push({ value: name, label: name, category: 'Stocks' });\n });\n }\n\n // Add flows\n if (data.flows) {\n Object.keys(data.flows).forEach(name => {\n variables.push({ value: name, label: name, category: 'Flows' });\n });\n }\n\n // Add indicators\n if (data.indicators) {\n Object.keys(data.indicators).forEach(name => {\n variables.push({ value: name, label: name, category: 'Indicators' });\n });\n }\n\n return variables;\n }\n\n // =========================================================================\n // EXPAND WINDOW FUNCTIONALITY\n // Reuses PlotPopoutWindow's patterns and CSS classes\n // =========================================================================\n\n /**\n * Handle expand button click.\n * @private\n */\n _onExpandClick() {\n if (!this.constructor.EXPANDABLE) return;\n\n const expandData = this.getExpandData();\n if (!expandData) {\n console.warn(`[TileBase] No expand data from widget ${this.id}`);\n return;\n }\n\n this._openExpandWindow(expandData);\n }\n\n /**\n * Get data for the expanded window.\n * Override in subclass for expandable widgets.\n * @returns {Object|null} { title, traces, layout, tableHeaders, tableRows }\n */\n getExpandData() {\n return null;\n }\n\n /**\n * Open the expand window with plot and data tabs.\n * Delegates to openRawTracesWindow (PlotPopoutWindow module) which\n * provides proper toolbar layout, download buttons, and data table.\n * @param {Object} expandData - Data from getExpandData()\n * @private\n */\n async _openExpandWindow(expandData) {\n if (this._expandWindow?.isVisible) {\n this._expandWindow.bringToFront();\n return;\n }\n\n this._expandWindow = await openRawTracesWindow({\n host: this.host,\n id: `tile-expand-${this.id}`,\n title: expandData.title || this.constructor.TITLE,\n traces: expandData.traces,\n layout: expandData.layout,\n frames: expandData.frames,\n tableHeaders: expandData.tableHeaders,\n tableRows: expandData.tableRows,\n services: { eventBus: this.eventBus },\n });\n }\n\n /**\n * Escape a string for safe insertion into an HTML attribute.\n * @private\n */\n #escapeAttr(s) {\n return String(s ?? '').replace(/[&<>\"']/g, c => ({\n '&':'&','<':'<','>':'>','\"':'"',\"'\":'''\n }[c]));\n }\n\n /**\n * Show toast notification via eventBus.\n * @private\n */\n _notify(title, message, severity = 'info') {\n this.eventBus?.emit?.('toast:show', {\n title,\n message,\n type: severity,\n });\n }\n}\n\nexport default TileBase;\n", "/**\n * tile_grid.js\n *\n * Core draggable tile grid system.\n * Manages a 12-column CSS grid with drag-and-drop repositioning and resize functionality.\n */\n\nimport { createWidget, getWidgetCatalog } from './tile_registry.js';\nimport { ActionDropdown } from '../ui/components/action_dropdown.js';\n\nexport class TileGrid {\n /**\n * @param {Object} options\n * @param {HTMLElement} options.container - Container element for the grid\n * @param {number} [options.columns=12] - Number of grid columns\n * @param {number} [options.rowHeight=80] - Height of each grid row in pixels\n * @param {number} [options.gap=16] - Gap between tiles in pixels\n * @param {Object} [options.eventBus] - Event bus for cross-component communication\n * @param {boolean} [options.showToolbar=true] - Whether to show built-in toolbar\n * @param {Function} [options.onLayoutChange] - Callback when layout changes\n * @param {Function} [options.onAddWidget] - Callback for add widget action\n * @param {Function} [options.onResetLayout] - Callback for reset layout action\n * @param {Function} [options.onExport] - Callback for export action\n */\n constructor({ container, columns = 12, rowHeight = 80, gap = 16, eventBus = null,\n showToolbar = true, readonly = false, onLayoutChange, onBeforeLayoutChange,\n onAddWidget, onResetLayout, onExport,\n // Handed down to every tile. TileBase used to import appHost() from\n // ui/js/ecoagent/ to back Expand -> Export CSV/PNG; a grid that has\n // no host simply gets the Blob-download fallback the host contract\n // promises. It is not an error to have none.\n host = null, stateGuard = null }) {\n this.host = host;\n this.stateGuard = stateGuard;\n this.container = container;\n this.columns = columns;\n this.rowHeight = rowHeight;\n this.gap = gap;\n this.eventBus = eventBus;\n this.showToolbar = showToolbar;\n this.readonly = readonly;\n this._onLayoutChangeCallback = onLayoutChange;\n this._onBeforeLayoutChangeCallback = onBeforeLayoutChange;\n this._onAddWidgetCallback = onAddWidget;\n this._onResetLayoutCallback = onResetLayout;\n this._onExportCallback = onExport;\n\n /** @type {Map<string, import('./tile_base.js').TileBase>} */\n this.tiles = new Map();\n\n /** @type {Array<{id: string, x: number, y: number, w: number, h: number}>} */\n this.layout = [];\n\n /** @type {Set<string>|null} IDs of documentation cells (for \"Show in Documentation\" visibility) */\n this.documentationCellIds = null;\n\n this.gridElement = null;\n this.data = null;\n this.fullData = null;\n\n // Drag state\n this._dragState = null;\n this._resizeState = null;\n this._ghostElement = null;\n\n // Bound handlers for cleanup\n this._boundOnPointerMove = this._onPointerMove.bind(this);\n this._boundOnPointerUp = this._onPointerUp.bind(this);\n\n this._init();\n }\n\n /**\n * Initialize the grid container.\n * @private\n */\n _init() {\n // Create grid element\n this.gridElement = document.createElement('div');\n this.gridElement.className = 'tile-grid';\n this.gridElement.style.setProperty('--grid-columns', this.columns);\n this.gridElement.style.setProperty('--grid-row-height', `${this.rowHeight}px`);\n this.gridElement.style.setProperty('--grid-gap', `${this.gap}px`);\n\n // Add grid to container\n this.container.innerHTML = '';\n this.container.appendChild(this.gridElement);\n\n // Add toolbar (can be disabled for external toolbar)\n if (this.showToolbar) {\n this._buildToolbar();\n }\n\n // Listen for tile events\n this.gridElement.addEventListener('tile:config-request', this._onTileConfigRequest.bind(this));\n this.gridElement.addEventListener('tile:remove-request', this._onTileRemoveRequest.bind(this));\n\n // Global pointer events for drag/resize\n document.addEventListener('pointermove', this._boundOnPointerMove);\n document.addEventListener('pointerup', this._boundOnPointerUp);\n }\n\n /**\n * Build the dashboard bottom toolbar with add widget dropdown.\n * @private\n */\n _buildToolbar() {\n const toolbar = document.createElement('div');\n toolbar.className = 'tile-grid-toolbar tile-grid-toolbar--bottom';\n this._toolbarElement = toolbar;\n\n toolbar.innerHTML = `\n <div class=\"toolbar-group toolbar-group--main\">\n <div class=\"add-widget-container\">\n <button class=\"toolbar-btn add-widget-btn twm-has-tooltip\" data-tooltip=\"Add widget\">\n <span class=\"material-symbols-outlined\">add</span>\n <span>Add Widget</span>\n <span class=\"material-symbols-outlined dropdown-arrow\">expand_less</span>\n </button>\n </div>\n <button class=\"toolbar-btn reset-layout-btn twm-has-tooltip\" data-tooltip=\"Reset to default layout\">\n <span class=\"material-symbols-outlined\">restart_alt</span>\n <span class=\"btn-text\">Reset</span>\n </button>\n <button class=\"toolbar-btn export-btn twm-has-tooltip\" data-tooltip=\"Export report\">\n <span class=\"material-symbols-outlined\">download</span>\n <span class=\"btn-text\">Export</span>\n </button>\n </div>\n `;\n\n // Create add-widget dropdown via ActionDropdown\n const addBtn = toolbar.querySelector('.add-widget-btn');\n const catalog = getWidgetCatalog();\n this._addWidgetDropdown = new ActionDropdown({\n trigger: addBtn,\n options: catalog.map(w => ({ type: w.type, label: w.title, icon: w.icon, description: w.description })),\n onSelect: (opt) => this._addWidgetFromDropdown(opt.type),\n className: 'add-widget-dropdown-menu'\n });\n\n toolbar.querySelector('.reset-layout-btn')?.addEventListener('click', () => this._resetLayout());\n toolbar.querySelector('.export-btn')?.addEventListener('click', () => this._exportReport());\n\n // Insert after grid element (at bottom)\n this.container.appendChild(toolbar);\n }\n\n /**\n * Add a widget from the dropdown selection.\n * @param {string} type - Widget type\n * @private\n */\n _addWidgetFromDropdown(type) {\n import('./tile_registry.js').then(({ getWidget }) => {\n const WidgetClass = getWidget(type);\n if (WidgetClass) {\n const size = WidgetClass.DEFAULT_SIZE || { w: 4, h: 3 };\n const pos = this.findNextPosition(size.w, size.h);\n this.addTile(type, { ...pos, ...size });\n }\n });\n }\n\n /**\n * Add a tile to the grid.\n * @param {string} type - Widget type\n * @param {Object} position - Grid position {x, y, w, h}\n * @param {Object} [config] - Widget configuration\n * @param {string} [id] - Optional tile ID (generated if not provided)\n * @returns {import('./tile_base.js').TileBase | null} The created tile or null\n */\n addTile(type, position, config = {}, id = null) {\n const tileId = id || `tile-${Date.now()}-${Math.random().toString(36).slice(2, 7)}`;\n\n const tile = createWidget(type, {\n id: tileId,\n grid: this,\n eventBus: this.eventBus,\n config,\n readonly: this.readonly,\n host: this.host,\n stateGuard: this.stateGuard,\n });\n\n if (!tile) return null;\n\n // Add to layout\n const layoutEntry = {\n id: tileId,\n type,\n x: position.x,\n y: position.y,\n w: position.w,\n h: position.h,\n config\n };\n this.layout.push(layoutEntry);\n\n // Store tile instance\n this.tiles.set(tileId, tile);\n\n // Mount to grid\n tile.mount(this.gridElement);\n this._applyTilePosition(tile, layoutEntry);\n\n // Setup drag handles\n this._setupTileDragHandlers(tile);\n\n // Render with current data if available\n if (this.data) {\n tile.fullData = this.fullData;\n tile.update(this.data);\n }\n\n // Emit layout changed\n this._emitLayoutChanged();\n\n return tile;\n }\n\n /**\n * Remove a tile from the grid.\n * @param {string} tileId - Tile ID to remove\n */\n removeTile(tileId) {\n const tile = this.tiles.get(tileId);\n if (!tile) return;\n\n tile.dispose();\n this.tiles.delete(tileId);\n\n // Remove from layout\n this.layout = this.layout.filter(l => l.id !== tileId);\n\n this._emitLayoutChanged();\n }\n\n /**\n * Update all tiles with new data.\n * @param {Object} data - Analytics data\n */\n setData(data) {\n this.data = data;\n this.tiles.forEach(tile => {\n tile.fullData = this.fullData;\n tile.update(data);\n });\n }\n\n /**\n * Get current layout.\n * @returns {Array} Layout array\n */\n getLayout() {\n return this.layout.map(l => ({\n id: l.id,\n type: l.type,\n x: l.x,\n y: l.y,\n w: l.w,\n h: l.h,\n config: this.tiles.get(l.id)?.config || l.config\n }));\n }\n\n /**\n * Set layout and rebuild tiles.\n * @param {Array|Object} layout - Layout array or object with tiles property\n */\n setLayout(layout) {\n // Clear existing tiles\n this.tiles.forEach(tile => tile.dispose());\n this.tiles.clear();\n this.layout = [];\n\n // Clear grid content (keep toolbar)\n this.gridElement.innerHTML = '';\n\n // Handle both array and object with tiles property\n const tilesArray = Array.isArray(layout) ? layout : (layout?.tiles || []);\n\n // Rebuild from layout\n tilesArray.forEach(item => {\n this.addTile(item.type, {\n x: item.x,\n y: item.y,\n w: item.w,\n h: item.h\n }, item.config, item.id);\n });\n }\n\n /**\n * Apply CSS grid position to a tile element.\n * @param {import('./tile_base.js').TileBase} tile\n * @param {{x: number, y: number, w: number, h: number}} position\n * @private\n */\n _applyTilePosition(tile, position) {\n if (!tile.element) return;\n\n tile.element.style.gridColumn = `${position.x + 1} / span ${position.w}`;\n tile.element.style.gridRow = `${position.y + 1} / span ${position.h}`;\n }\n\n /**\n * Setup drag and resize handlers for a tile.\n * @param {import('./tile_base.js').TileBase} tile\n * @private\n */\n _setupTileDragHandlers(tile) {\n if (!tile.element || this.readonly) return;\n\n const dragHandle = tile.element.querySelector('.tile-drag-handle');\n const resizeHandle = tile.element.querySelector('.tile-resize-handle');\n\n // Drag handle\n if (dragHandle) {\n dragHandle.addEventListener('pointerdown', (e) => this._onDragStart(tile, e));\n }\n\n // Resize handle\n if (resizeHandle) {\n resizeHandle.addEventListener('pointerdown', (e) => this._onResizeStart(tile, e));\n }\n }\n\n /**\n * Handle drag start.\n * @param {import('./tile_base.js').TileBase} tile\n * @param {PointerEvent} e\n * @private\n */\n _onDragStart(tile, e) {\n e.preventDefault();\n e.stopPropagation();\n\n const rect = tile.element.getBoundingClientRect();\n const gridRect = this.gridElement.getBoundingClientRect();\n\n const layoutItem = this.layout.find(l => l.id === tile.id);\n if (!layoutItem) return;\n\n // Notify before mutation so caller can snapshot current state\n this._emitBeforeLayoutChange();\n\n this._dragState = {\n tile,\n tileId: tile.id,\n startX: e.clientX,\n startY: e.clientY,\n startGridX: layoutItem.x,\n startGridY: layoutItem.y,\n tileRect: rect,\n gridRect,\n w: layoutItem.w,\n h: layoutItem.h\n };\n\n tile.element.classList.add('dragging');\n\n // Create ghost element\n this._createGhost(rect);\n }\n\n /**\n * Handle resize start.\n * @param {import('./tile_base.js').TileBase} tile\n * @param {PointerEvent} e\n * @private\n */\n _onResizeStart(tile, e) {\n e.preventDefault();\n e.stopPropagation();\n\n const layoutItem = this.layout.find(l => l.id === tile.id);\n if (!layoutItem) return;\n\n const gridRect = this.gridElement.getBoundingClientRect();\n const cellWidth = (gridRect.width - (this.columns - 1) * this.gap) / this.columns;\n\n // Notify before mutation so caller can snapshot current state\n this._emitBeforeLayoutChange();\n\n this._resizeState = {\n tile,\n tileId: tile.id,\n startX: e.clientX,\n startY: e.clientY,\n startW: layoutItem.w,\n startH: layoutItem.h,\n gridRect,\n cellWidth,\n x: layoutItem.x,\n y: layoutItem.y\n };\n\n tile.element.classList.add('resizing');\n }\n\n /**\n * Handle pointer move (drag/resize).\n * @param {PointerEvent} e\n * @private\n */\n _onPointerMove(e) {\n if (this._dragState) {\n this._onDragMove(e);\n } else if (this._resizeState) {\n this._onResizeMove(e);\n }\n }\n\n /**\n * Handle drag move.\n * @param {PointerEvent} e\n * @private\n */\n _onDragMove(e) {\n const state = this._dragState;\n if (!state) return;\n\n const dx = e.clientX - state.startX;\n const dy = e.clientY - state.startY;\n\n // Calculate cell dimensions\n const gridRect = state.gridRect;\n const cellWidth = (gridRect.width - (this.columns - 1) * this.gap) / this.columns;\n const cellHeight = this.rowHeight;\n\n // Calculate new grid position\n const deltaGridX = Math.round(dx / (cellWidth + this.gap));\n const deltaGridY = Math.round(dy / (cellHeight + this.gap));\n\n let newX = state.startGridX + deltaGridX;\n let newY = state.startGridY + deltaGridY;\n\n // Clamp to grid bounds\n newX = Math.max(0, Math.min(newX, this.columns - state.w));\n newY = Math.max(0, newY);\n\n // Update ghost position\n if (this._ghostElement) {\n const ghostLeft = newX * (cellWidth + this.gap);\n const ghostTop = newY * (cellHeight + this.gap);\n this._ghostElement.style.transform = `translate(${ghostLeft}px, ${ghostTop}px)`;\n this._ghostElement.style.width = `${state.w * cellWidth + (state.w - 1) * this.gap}px`;\n this._ghostElement.style.height = `${state.h * cellHeight + (state.h - 1) * this.gap}px`;\n }\n\n // Store pending position\n state.pendingX = newX;\n state.pendingY = newY;\n }\n\n /**\n * Handle resize move.\n * @param {PointerEvent} e\n * @private\n */\n _onResizeMove(e) {\n const state = this._resizeState;\n if (!state) return;\n\n const dx = e.clientX - state.startX;\n const dy = e.clientY - state.startY;\n\n // Calculate new size in grid cells\n const deltaW = Math.round(dx / (state.cellWidth + this.gap));\n const deltaH = Math.round(dy / (this.rowHeight + this.gap));\n\n let newW = state.startW + deltaW;\n let newH = state.startH + deltaH;\n\n // Get constraints\n const tileClass = state.tile.constructor;\n const constraints = tileClass.SIZE_CONSTRAINTS || { minW: 2, minH: 2, maxW: 12, maxH: 8 };\n\n // Apply constraints\n newW = Math.max(constraints.minW, Math.min(newW, constraints.maxW));\n newH = Math.max(constraints.minH, Math.min(newH, constraints.maxH));\n\n // Don't exceed grid width\n newW = Math.min(newW, this.columns - state.x);\n\n // Live update tile size\n state.tile.element.style.gridColumn = `${state.x + 1} / span ${newW}`;\n state.tile.element.style.gridRow = `${state.y + 1} / span ${newH}`;\n\n state.pendingW = newW;\n state.pendingH = newH;\n }\n\n /**\n * Handle pointer up (end drag/resize).\n * @param {PointerEvent} e\n * @private\n */\n _onPointerUp(e) {\n if (this._dragState) {\n this._onDragEnd();\n } else if (this._resizeState) {\n this._onResizeEnd();\n }\n }\n\n /**\n * Handle drag end.\n * @private\n */\n _onDragEnd() {\n const state = this._dragState;\n if (!state) return;\n\n state.tile.element.classList.remove('dragging');\n this._removeGhost();\n\n // Update layout if position changed\n if (state.pendingX !== undefined && state.pendingY !== undefined) {\n const layoutItem = this.layout.find(l => l.id === state.tileId);\n if (layoutItem) {\n layoutItem.x = state.pendingX;\n layoutItem.y = state.pendingY;\n this._applyTilePosition(state.tile, layoutItem);\n\n // Resolve overlaps - push other tiles down\n this._resolveOverlaps(state.tileId);\n\n this._emitLayoutChanged();\n }\n }\n\n this._dragState = null;\n }\n\n /**\n * Handle resize end.\n * @private\n */\n _onResizeEnd() {\n const state = this._resizeState;\n if (!state) return;\n\n state.tile.element.classList.remove('resizing');\n\n // Update layout if size changed\n if (state.pendingW !== undefined && state.pendingH !== undefined) {\n const layoutItem = this.layout.find(l => l.id === state.tileId);\n if (layoutItem) {\n layoutItem.w = state.pendingW;\n layoutItem.h = state.pendingH;\n\n // Resolve overlaps - push other tiles down\n this._resolveOverlaps(state.tileId);\n\n this._emitLayoutChanged();\n\n // Re-render tile content for new size\n if (this.data) {\n state.tile.fullData = this.fullData;\n state.tile.update(this.data);\n }\n }\n }\n\n this._resizeState = null;\n }\n\n /**\n * Check if two layout items overlap.\n * @param {Object} a - First layout item {x, y, w, h}\n * @param {Object} b - Second layout item {x, y, w, h}\n * @returns {boolean}\n * @private\n */\n _tilesOverlap(a, b) {\n return !(\n a.x + a.w <= b.x ||\n b.x + b.w <= a.x ||\n a.y + a.h <= b.y ||\n b.y + b.h <= a.y\n );\n }\n\n /**\n * Resolve overlaps by pushing tiles down.\n * @param {string} sourceTileId - The tile that was resized/moved\n * @private\n */\n _resolveOverlaps(sourceTileId) {\n const sourceItem = this.layout.find(l => l.id === sourceTileId);\n if (!sourceItem) return;\n\n // Sort tiles by y position (top to bottom), then by x\n const otherTiles = this.layout\n .filter(l => l.id !== sourceTileId)\n .sort((a, b) => a.y - b.y || a.x - b.x);\n\n let hasChanges = true;\n let iterations = 0;\n const maxIterations = 100; // Prevent infinite loops\n\n while (hasChanges && iterations < maxIterations) {\n hasChanges = false;\n iterations++;\n\n for (const item of otherTiles) {\n if (this._tilesOverlap(sourceItem, item)) {\n // Push this tile down to be below the source tile\n const newY = sourceItem.y + sourceItem.h;\n if (item.y !== newY) {\n item.y = newY;\n hasChanges = true;\n\n // Apply the new position visually\n const tile = this.tiles.get(item.id);\n if (tile) {\n this._applyTilePosition(tile, item);\n }\n }\n }\n }\n\n // Check for cascading overlaps among the moved tiles\n for (let i = 0; i < otherTiles.length; i++) {\n for (let j = i + 1; j < otherTiles.length; j++) {\n if (this._tilesOverlap(otherTiles[i], otherTiles[j])) {\n // Push the lower-index tile (earlier in sort order) doesn't need to move\n // Push the higher one down\n const pusher = otherTiles[i];\n const pushed = otherTiles[j];\n const newY = pusher.y + pusher.h;\n if (pushed.y < newY && this._tilesOverlap(pusher, pushed)) {\n pushed.y = newY;\n hasChanges = true;\n\n const tile = this.tiles.get(pushed.id);\n if (tile) {\n this._applyTilePosition(tile, pushed);\n }\n }\n }\n }\n }\n }\n\n // Compact the layout - remove vertical gaps\n this._compactLayout();\n }\n\n /**\n * Compact the layout by removing vertical gaps.\n * @private\n */\n _compactLayout() {\n // Sort tiles by y position\n const sortedTiles = [...this.layout].sort((a, b) => a.y - b.y || a.x - b.x);\n\n for (const item of sortedTiles) {\n // Try to move up as far as possible\n let newY = 0;\n\n while (newY < item.y) {\n const testPosition = { ...item, y: newY };\n\n // Check for overlaps with tiles above this one\n let hasOverlap = false;\n for (const other of this.layout) {\n if (other.id === item.id) continue;\n if (this._tilesOverlap(testPosition, other)) {\n hasOverlap = true;\n // Move below this overlapping tile\n newY = other.y + other.h;\n break;\n }\n }\n\n if (!hasOverlap) {\n break;\n }\n }\n\n if (newY < item.y) {\n item.y = newY;\n const tile = this.tiles.get(item.id);\n if (tile) {\n this._applyTilePosition(tile, item);\n }\n }\n }\n }\n\n /**\n * Create ghost element for drag preview.\n * @param {DOMRect} rect - Original tile rect\n * @private\n */\n _createGhost(rect) {\n this._ghostElement = document.createElement('div');\n this._ghostElement.className = 'tile-ghost';\n this.gridElement.appendChild(this._ghostElement);\n }\n\n /**\n * Remove ghost element.\n * @private\n */\n _removeGhost() {\n if (this._ghostElement) {\n this._ghostElement.remove();\n this._ghostElement = null;\n }\n }\n\n /**\n * Find next available position for a new tile.\n * @param {number} w - Width in cells\n * @param {number} h - Height in cells\n * @returns {{x: number, y: number}}\n */\n findNextPosition(w, h) {\n // Build occupancy grid\n const maxY = Math.max(...this.layout.map(l => l.y + l.h), 0);\n const occupied = new Set();\n\n this.layout.forEach(l => {\n for (let x = l.x; x < l.x + l.w; x++) {\n for (let y = l.y; y < l.y + l.h; y++) {\n occupied.add(`${x},${y}`);\n }\n }\n });\n\n // Find first available position\n for (let y = 0; y <= maxY + 1; y++) {\n for (let x = 0; x <= this.columns - w; x++) {\n let fits = true;\n for (let dx = 0; dx < w && fits; dx++) {\n for (let dy = 0; dy < h && fits; dy++) {\n if (occupied.has(`${x + dx},${y + dy}`)) {\n fits = false;\n }\n }\n }\n if (fits) {\n return { x, y };\n }\n }\n }\n\n // Default: place at bottom\n return { x: 0, y: maxY + 1 };\n }\n\n /**\n * Handle tile config request.\n * @param {CustomEvent} e\n * @private\n */\n _onTileConfigRequest(e) {\n const { tileId, tileType, config, schema } = e.detail;\n this.eventBus?.emit?.('grid:config-modal-show', {\n tileId,\n tileType,\n config,\n schema,\n variables: this.data ? this._getVariableList() : [],\n onSave: (newConfig) => {\n const tile = this.tiles.get(tileId);\n if (tile) {\n tile.fullData = this.fullData;\n tile.update(this.data, newConfig);\n // Update layout config\n const layoutItem = this.layout.find(l => l.id === tileId);\n if (layoutItem) {\n layoutItem.config = newConfig;\n }\n this._emitLayoutChanged();\n }\n }\n });\n }\n\n /**\n * Handle tile remove request.\n * Note: Let the event bubble up to the dashboard which handles confirmation.\n * @param {CustomEvent} e\n * @private\n */\n _onTileRemoveRequest(e) {\n // Don't auto-remove - let event bubble up to dashboard\n // Dashboard shows a confirm dialog before calling removeTile()\n // Do NOT stop propagation - dashboard listener needs to receive this event\n }\n\n /**\n * Get list of available variables from data.\n * @returns {Array<{value: string, label: string}>}\n * @private\n */\n _getVariableList() {\n if (!this.data) return [];\n\n const variables = [];\n if (this.data.stocks) {\n Object.keys(this.data.stocks).forEach(name => {\n variables.push({ value: name, label: name });\n });\n }\n if (this.data.indicators) {\n Object.keys(this.data.indicators).forEach(name => {\n variables.push({ value: name, label: name });\n });\n }\n return variables;\n }\n\n /**\n * Show add widget menu.\n * @private\n */\n _showAddWidgetMenu() {\n this.eventBus?.emit?.('grid:add-widget-menu-show', {\n onSelect: (type) => {\n const { getWidget } = require('./tile_registry.js');\n const WidgetClass = getWidget(type);\n if (WidgetClass) {\n const size = WidgetClass.DEFAULT_SIZE || { w: 4, h: 3 };\n const pos = this.findNextPosition(size.w, size.h);\n this.addTile(type, { ...pos, ...size });\n }\n }\n });\n }\n\n /**\n * Reset to default layout.\n * @private\n */\n _resetLayout() {\n this.eventBus?.emit?.('grid:reset-layout-confirm', {\n onConfirm: () => {\n this.eventBus?.emit?.('grid:layout-reset-requested');\n }\n });\n }\n\n /**\n * Export report.\n * @private\n */\n _exportReport() {\n this.eventBus?.emit?.('grid:export-requested', {\n gridElement: this.gridElement,\n layout: this.getLayout()\n });\n }\n\n /**\n * Notify that a layout mutation is about to begin (drag/resize start).\n * @private\n */\n _emitBeforeLayoutChange() {\n if (typeof this._onBeforeLayoutChangeCallback === 'function') {\n this._onBeforeLayoutChangeCallback(this.getLayout());\n }\n }\n\n /**\n * Emit layout changed event and call the onLayoutChange callback.\n * @private\n */\n _emitLayoutChanged() {\n const layout = this.getLayout();\n this.eventBus?.emit?.('grid:layout-changed', { layout });\n\n // Call the callback if provided (used by ResultsTileDashboard for autosave)\n if (typeof this._onLayoutChangeCallback === 'function') {\n this._onLayoutChangeCallback(layout);\n }\n }\n\n /**\n * Clean up resources.\n */\n dispose() {\n document.removeEventListener('pointermove', this._boundOnPointerMove);\n document.removeEventListener('pointerup', this._boundOnPointerUp);\n\n this._addWidgetDropdown?.destroy();\n this._addWidgetDropdown = null;\n\n this.tiles.forEach(tile => tile.dispose());\n this.tiles.clear();\n this.layout = [];\n\n if (this.gridElement) {\n this.gridElement.remove();\n this.gridElement = null;\n }\n }\n}\n\nexport default TileGrid;\n", "/**\n * @flexdesk/tiles \u2014 A draggable, resizable widget grid: the tile base class, the grid, the\n * widget registry, and layout persistence.\n *\n * It stores layouts under keys YOU choose and resolves starting templates\n * through a callback YOU supply. It has no opinion about what a layout is\n * keyed by.\n *\n * GENERATED by scripts/gen_barrels.py. Do not hand-edit.\n *\n * 5 modules.\n */\n\nexport * from './src/tiles/config_schema.js';\nexport * from './src/tiles/layout_persistence.js';\nexport * from './src/tiles/tile_base.js';\nexport * from './src/tiles/tile_grid.js';\nexport * from './src/tiles/tile_registry.js';\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": ["getWidget"]
|
|
7
|
+
}
|
package/dist/tokens.css
ADDED
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
/* ════════════════════════════════════════════════════════════════════
|
|
2
|
+
tokens.css — single source of truth for design tokens.
|
|
3
|
+
|
|
4
|
+
Loaded before every other stylesheet (see index.html). All other
|
|
5
|
+
stylesheets must reference these variables instead of writing
|
|
6
|
+
literal values.
|
|
7
|
+
|
|
8
|
+
Phase 1 contract: defining these tokens must not change the visible
|
|
9
|
+
UI. Each value is chosen to match what the existing CSS already
|
|
10
|
+
resolves to today — either the value of a dominant literal in use,
|
|
11
|
+
or the fallback that page-prefixed aliases (--config-*, --sm-*, …)
|
|
12
|
+
already evaluate to via `var(--ghost, #fallback)`.
|
|
13
|
+
|
|
14
|
+
See docs/UX_HARMONIZATION.md for the harmonization plan.
|
|
15
|
+
──────────────────────────────────────────────────────────────────── */
|
|
16
|
+
|
|
17
|
+
:root {
|
|
18
|
+
|
|
19
|
+
/* ── Spacing scale ─────────────────────────────────────────────
|
|
20
|
+
8-step scale derived from observed gap/padding usage.
|
|
21
|
+
Top-of-cluster values: 8 (237), 6 (165), 4 (148), 12 (93). */
|
|
22
|
+
--space-xxs: 2px;
|
|
23
|
+
--space-xs: 4px;
|
|
24
|
+
--space-sm: 6px;
|
|
25
|
+
--space-md: 8px;
|
|
26
|
+
--space-lg: 12px;
|
|
27
|
+
--space-xl: 16px;
|
|
28
|
+
--space-2xl: 24px;
|
|
29
|
+
--space-3xl: 32px;
|
|
30
|
+
|
|
31
|
+
/* ── Border radius ─────────────────────────────────────────────
|
|
32
|
+
3-step scale + special tokens for circles and pills. */
|
|
33
|
+
--radius-sm: 4px;
|
|
34
|
+
--radius-md: 6px;
|
|
35
|
+
--radius-lg: 8px;
|
|
36
|
+
--radius-pill: 999px;
|
|
37
|
+
--radius-circle: 50%;
|
|
38
|
+
|
|
39
|
+
/* ── Typography ─────────────────────────────────────────────── */
|
|
40
|
+
--font-family-sans: system-ui, -apple-system, BlinkMacSystemFont,
|
|
41
|
+
'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell,
|
|
42
|
+
'Open Sans', 'Helvetica Neue', sans-serif;
|
|
43
|
+
--font-family-mono: ui-monospace, 'SF Mono', 'Consolas', 'Monaco', monospace;
|
|
44
|
+
|
|
45
|
+
/* 6-step scale: top-of-cluster sizes only. */
|
|
46
|
+
--font-size-xs: 11px;
|
|
47
|
+
--font-size-sm: 12px; /* body default */
|
|
48
|
+
--font-size-md: 13px;
|
|
49
|
+
--font-size-lg: 14px;
|
|
50
|
+
--font-size-xl: 16px;
|
|
51
|
+
--font-size-2xl: 18px;
|
|
52
|
+
|
|
53
|
+
--font-weight-regular: 400;
|
|
54
|
+
--font-weight-medium: 500;
|
|
55
|
+
--font-weight-semibold: 600; /* dominant in codebase */
|
|
56
|
+
--font-weight-bold: 700;
|
|
57
|
+
|
|
58
|
+
--line-height-tight: 1.2;
|
|
59
|
+
--line-height-normal: 1.5;
|
|
60
|
+
--line-height-relaxed: 1.7;
|
|
61
|
+
|
|
62
|
+
/* ── Surfaces (background hierarchy) ────────────────────────────
|
|
63
|
+
Values match the most-frequent gray literals in use today. */
|
|
64
|
+
--surface-0: #1e1e1e; /* page / tab background (103 uses) */
|
|
65
|
+
--surface-1: #252526; /* cards, panels (56 uses) */
|
|
66
|
+
--surface-2: #2d2d2d; /* elevated, hover bg (107 uses) */
|
|
67
|
+
--surface-3: #3c3c3c; /* form-control bg (240 uses) */
|
|
68
|
+
--surface-app: #121212; /* application chrome (root) */
|
|
69
|
+
--surface-well: #0d0d0d; /* recessed wells / sunken areas */
|
|
70
|
+
|
|
71
|
+
/* ── Borders ────────────────────────────────────────────────── */
|
|
72
|
+
--border-subtle: #2a2a2a; /* dividers within cards (174 uses) */
|
|
73
|
+
--border-default: #303030; /* card / panel borders (ghost-global fallback) */
|
|
74
|
+
--border-strong: #383838; /* emphasized borders (--layout-border-default value) */
|
|
75
|
+
|
|
76
|
+
/* ── Text ───────────────────────────────────────────────────── */
|
|
77
|
+
--text-primary: #e0e0e0; /* primary body text */
|
|
78
|
+
--text-secondary: #cccccc; /* lighter secondary (e.g. tree-view rows) */
|
|
79
|
+
--text-body: #d4d4d4; /* base.css body default — between primary & secondary */
|
|
80
|
+
--text-muted: #888888; /* de-facto canonical muted gray (268+ literal uses) */
|
|
81
|
+
--text-dim: #666666;
|
|
82
|
+
--text-bright: #ffffff;
|
|
83
|
+
|
|
84
|
+
/* ── Accent / brand ─────────────────────────────────────────────
|
|
85
|
+
Two accent values exist in the codebase today:
|
|
86
|
+
#0e639c (used by all --primary-color fallbacks, deep blue)
|
|
87
|
+
#007acc (used by --layout-accent, brighter VS Code blue)
|
|
88
|
+
Phase 5 will pick one. For Phase 1 we keep both wired. */
|
|
89
|
+
--accent: #0e639c;
|
|
90
|
+
--accent-hover: #1177bb;
|
|
91
|
+
--accent-bright: #007acc; /* --layout-accent value */
|
|
92
|
+
|
|
93
|
+
/* ── Semantic colors ───────────────────────────────────────── */
|
|
94
|
+
--color-success: #3fb950;
|
|
95
|
+
--color-warning: #ff9800;
|
|
96
|
+
--color-danger: #c74e4e;
|
|
97
|
+
--color-danger-hover: #d85858;
|
|
98
|
+
--color-info: #2196f3;
|
|
99
|
+
|
|
100
|
+
/* ── Surface state overlays ────────────────────────────────── */
|
|
101
|
+
--state-hover: rgba(255, 255, 255, 0.05);
|
|
102
|
+
--state-active: rgba(255, 255, 255, 0.08);
|
|
103
|
+
--state-selected: rgba(0, 122, 204, 0.15);
|
|
104
|
+
|
|
105
|
+
/* ── Shadows / elevation ──────────────────────────────────── */
|
|
106
|
+
--shadow-sm: 0 1px 3px rgba(0, 0, 0, 0.3);
|
|
107
|
+
--shadow-md: 0 4px 12px rgba(0, 0, 0, 0.4);
|
|
108
|
+
--shadow-lg: 0 8px 24px rgba(0, 0, 0, 0.5);
|
|
109
|
+
--shadow-glow: 0 0 2px rgba(0, 122, 204, 0.3);
|
|
110
|
+
|
|
111
|
+
/* ── Z-index layers ───────────────────────────────────────── */
|
|
112
|
+
--z-base: 0;
|
|
113
|
+
--z-sticky: 10;
|
|
114
|
+
--z-dropdown: 100;
|
|
115
|
+
--z-popover: 200;
|
|
116
|
+
--z-modal: 1000;
|
|
117
|
+
--z-toast: 10000;
|
|
118
|
+
|
|
119
|
+
/* ── Transitions ──────────────────────────────────────────── */
|
|
120
|
+
--transition-fast: 120ms ease;
|
|
121
|
+
--transition-normal: 150ms ease; /* dominant duration in codebase */
|
|
122
|
+
--transition-slow: 300ms ease;
|
|
123
|
+
|
|
124
|
+
|
|
125
|
+
/* ── Layout-semantic tokens (page / section / tab-bar) ──────
|
|
126
|
+
Named for their purpose, not their value. Used by chrome
|
|
127
|
+
rules in main_new.css and a handful of page-specific files. */
|
|
128
|
+
--layout-pad-h: var(--space-2xl); /* 24px — page horizontal padding */
|
|
129
|
+
--layout-pad-section: var(--space-xl); /* 16px — internal section / card spacing */
|
|
130
|
+
--layout-tab-bar-pad-left: 22px; /* aligns first tab icon with title */
|
|
131
|
+
--layout-radius: var(--radius-lg); /* 8px — large container radius */
|
|
132
|
+
|
|
133
|
+
/* Ghost-global aliases (--panel-bg, --primary-color, --border-color,
|
|
134
|
+
--panel-surface, --panel-header-bg, --primary-color-hover) removed
|
|
135
|
+
in Phase 7 — all page CSS now references canonical tokens
|
|
136
|
+
directly. */
|
|
137
|
+
}
|