@databricks/appkit-ui 0.61.1 → 0.62.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.
Files changed (115) hide show
  1. package/CLAUDE.md +1 -0
  2. package/dist/cli/commands/codemod/index.js.map +1 -1
  3. package/dist/cli/commands/codemod/on-plugins-ready.js.map +1 -1
  4. package/dist/cli/commands/docs.js.map +1 -1
  5. package/dist/cli/commands/doctor/bundle.js.map +1 -1
  6. package/dist/cli/commands/doctor/index.js.map +1 -1
  7. package/dist/cli/commands/doctor/report.js.map +1 -1
  8. package/dist/cli/commands/doctor/resolve-targets.js.map +1 -1
  9. package/dist/cli/commands/doctor/run.js.map +1 -1
  10. package/dist/cli/commands/generate-types.js.map +1 -1
  11. package/dist/cli/commands/lint.js.map +1 -1
  12. package/dist/cli/commands/plugin/add-resource/add-resource.js.map +1 -1
  13. package/dist/cli/commands/plugin/create/create.js.map +1 -1
  14. package/dist/cli/commands/plugin/create/prompt-resource.js.map +1 -1
  15. package/dist/cli/commands/plugin/create/scaffold.js.map +1 -1
  16. package/dist/cli/commands/plugin/index.js.map +1 -1
  17. package/dist/cli/commands/plugin/list/list.js.map +1 -1
  18. package/dist/cli/commands/plugin/promote/promote.js.map +1 -1
  19. package/dist/cli/commands/plugin/sync/sync.js.map +1 -1
  20. package/dist/cli/commands/plugin/validate/validate-manifest.js.map +1 -1
  21. package/dist/cli/commands/plugin/validate/validate.js.map +1 -1
  22. package/dist/cli/commands/registry/add.js.map +1 -1
  23. package/dist/cli/commands/registry/client.js.map +1 -1
  24. package/dist/cli/commands/registry/config-writer.js.map +1 -1
  25. package/dist/cli/commands/registry/env-reconcile.js.map +1 -1
  26. package/dist/cli/commands/registry/env-writer.js.map +1 -1
  27. package/dist/cli/commands/registry/index.js.map +1 -1
  28. package/dist/cli/commands/registry/info.js.map +1 -1
  29. package/dist/cli/commands/registry/list.js.map +1 -1
  30. package/dist/cli/commands/registry/requirements.js.map +1 -1
  31. package/dist/cli/commands/registry/server-register.js.map +1 -1
  32. package/dist/cli/commands/registry/workspace-picker.js.map +1 -1
  33. package/dist/cli/commands/setup.js.map +1 -1
  34. package/dist/cli/index.js.map +1 -1
  35. package/dist/js/arrow/arrow-client.d.ts.map +1 -1
  36. package/dist/js/arrow/arrow-client.js.map +1 -1
  37. package/dist/react/charts/area/index.d.ts.map +1 -1
  38. package/dist/react/charts/area/index.js.map +1 -1
  39. package/dist/react/charts/bar/index.d.ts.map +1 -1
  40. package/dist/react/charts/bar/index.js.map +1 -1
  41. package/dist/react/charts/base.d.ts.map +1 -1
  42. package/dist/react/charts/base.js +1 -1
  43. package/dist/react/charts/base.js.map +1 -1
  44. package/dist/react/charts/heatmap/index.d.ts.map +1 -1
  45. package/dist/react/charts/heatmap/index.js.map +1 -1
  46. package/dist/react/charts/line/index.d.ts.map +1 -1
  47. package/dist/react/charts/line/index.js.map +1 -1
  48. package/dist/react/charts/normalize.d.ts.map +1 -1
  49. package/dist/react/charts/normalize.js.map +1 -1
  50. package/dist/react/charts/pie/index.d.ts.map +1 -1
  51. package/dist/react/charts/pie/index.js.map +1 -1
  52. package/dist/react/charts/radar/index.d.ts.map +1 -1
  53. package/dist/react/charts/radar/index.js.map +1 -1
  54. package/dist/react/charts/scatter/index.d.ts.map +1 -1
  55. package/dist/react/charts/scatter/index.js.map +1 -1
  56. package/dist/react/charts/theme.d.ts.map +1 -1
  57. package/dist/react/charts/theme.js.map +1 -1
  58. package/dist/react/charts/wrapper.d.ts.map +1 -1
  59. package/dist/react/charts/wrapper.js.map +1 -1
  60. package/dist/react/file-browser/directory-list.d.ts.map +1 -1
  61. package/dist/react/file-browser/directory-list.js.map +1 -1
  62. package/dist/react/file-browser/file-breadcrumb.d.ts.map +1 -1
  63. package/dist/react/file-browser/file-breadcrumb.js.map +1 -1
  64. package/dist/react/file-browser/file-entry.d.ts.map +1 -1
  65. package/dist/react/file-browser/file-entry.js.map +1 -1
  66. package/dist/react/file-browser/file-preview-panel.d.ts.map +1 -1
  67. package/dist/react/file-browser/file-preview-panel.js.map +1 -1
  68. package/dist/react/file-browser/new-folder-input.d.ts.map +1 -1
  69. package/dist/react/file-browser/new-folder-input.js.map +1 -1
  70. package/dist/react/genie/genie-chat-input.d.ts.map +1 -1
  71. package/dist/react/genie/genie-chat-input.js.map +1 -1
  72. package/dist/react/genie/genie-chat-message-list.d.ts.map +1 -1
  73. package/dist/react/genie/genie-chat-message-list.js.map +1 -1
  74. package/dist/react/genie/genie-chat-message.d.ts.map +1 -1
  75. package/dist/react/genie/genie-chat-message.js.map +1 -1
  76. package/dist/react/genie/genie-query-visualization.d.ts.map +1 -1
  77. package/dist/react/genie/genie-query-visualization.js.map +1 -1
  78. package/dist/react/genie/use-genie-chat.d.ts.map +1 -1
  79. package/dist/react/genie/use-genie-chat.js.map +1 -1
  80. package/dist/react/hooks/types.d.ts.map +1 -1
  81. package/dist/react/hooks/use-agent-chat.d.ts.map +1 -1
  82. package/dist/react/hooks/use-agent-chat.js.map +1 -1
  83. package/dist/react/hooks/use-ai-search-query.d.ts.map +1 -1
  84. package/dist/react/hooks/use-ai-search-query.js.map +1 -1
  85. package/dist/react/hooks/use-analytics-query.d.ts.map +1 -1
  86. package/dist/react/hooks/use-analytics-query.js.map +1 -1
  87. package/dist/react/hooks/use-analytics-warehouse-status.js.map +1 -1
  88. package/dist/react/hooks/use-chart-data.d.ts.map +1 -1
  89. package/dist/react/hooks/use-chart-data.js.map +1 -1
  90. package/dist/react/hooks/use-metric-view.d.ts.map +1 -1
  91. package/dist/react/hooks/use-metric-view.js.map +1 -1
  92. package/dist/react/hooks/use-plugin-config.d.ts.map +1 -1
  93. package/dist/react/hooks/use-plugin-config.js.map +1 -1
  94. package/dist/react/hooks/use-serving-invoke.d.ts.map +1 -1
  95. package/dist/react/hooks/use-serving-invoke.js.map +1 -1
  96. package/dist/react/hooks/use-serving-stream.d.ts.map +1 -1
  97. package/dist/react/hooks/use-serving-stream.js.map +1 -1
  98. package/dist/react/resource-status-indicator.d.ts.map +1 -1
  99. package/dist/react/resource-status-indicator.js.map +1 -1
  100. package/dist/react/table/data-table.d.ts.map +1 -1
  101. package/dist/react/table/data-table.js.map +1 -1
  102. package/dist/react/table/table-wrapper.js.map +1 -1
  103. package/dist/react/ui-variants/variants.d.ts.map +1 -1
  104. package/dist/react/ui-variants/variants.js.map +1 -1
  105. package/dist/schemas/manifest.d.ts.map +1 -1
  106. package/dist/schemas/manifest.js.map +1 -1
  107. package/dist/schemas/metric-fqn.js.map +1 -1
  108. package/dist/shared/src/plugin.d.ts.map +1 -1
  109. package/dist/styles.css +0 -3
  110. package/dist/workspace-client/legacy.js.map +1 -1
  111. package/dist/workspace-client/types.d.ts.map +1 -1
  112. package/docs/plugins/testing.md +245 -0
  113. package/llms.txt +1 -0
  114. package/package.json +1 -1
  115. package/sbom.cdx.json +1 -1
@@ -1 +1 @@
1
- {"version":3,"file":"base.d.ts","names":[],"sources":["../../../src/react/charts/base.tsx"],"mappings":";;;;UAiHiB,cAAA;;EAEf,IAAA,EAAM,SAAA;EAFS;EAIf,SAAA,EAAW,SAAA;;EAEX,IAAA;EAFW;EAIX,IAAA;EAee;EAbf,WAAA,GAAc,WAAA;EAmDG;EAjDjB,MAAA;EA6DqC;EA3DrC,KAAA;EAZA;EAcA,UAAA;EAZA;;;;;;EAmBA,YAAA,GAAe,iBAAA;EATf;EAWA,MAAA;EAFA;EAIA,UAAA;EAFA;EAIA,MAAA;EAAA;EAEA,OAAA;EAEA;EAAA,UAAA;EAIA;EAFA,QAAA;EAMA;EAJA,WAAA;EAQA;EANA,UAAA;EAoBA;EAlBA,aAAA;EAoBA;EAlBA,QAAA;EAoBA;EAlBA,GAAA;EA4BsB;EA1BtB,GAAA;EA4BA;;;AAWF;;;;;;;;EA3BE,OAAA,GAAU,MAAA;EAkCV;EAhCA,cAAA,GAAiB,mBAAA;EAkCjB;EAhCA,SAAA;EAkCA;;;;;;;;;EAxBA,WAAA,IAAe,KAAA,EAAO,eAAA;EAkCtB;EAhCA,QAAA;AAAA;;;;;iBAWc,SAAA,CAAA;EACd,IAAA;EACA,SAAA;EACA,IAAA;EACA,IAAA;EACA,WAAA;EACA,MAAA;EACA,KAAA;EACA,UAAA;EACA,YAAA;EACA,MAAA,EAAQ,YAAA;EACR,UAAA;EACA,MAAA;EACA,OAAA;EACA,UAAA;EACA,QAAA;EACA,WAAA;EACA,UAAA;EACA,aAAA;EACA,QAAA;EACA,GAAA;EACA,GAAA;EACA,OAAA,EAAS,aAAA;EACT,cAAA;EACA,SAAA;EACA,WAAA;EACA;AAAA,GACC,cAAA,GAAc,kBAAA,CAAA,GAAA,CAAA,OAAA"}
1
+ {"version":3,"file":"base.d.ts","names":[],"sources":["../../../src/react/charts/base.tsx"],"mappings":";;;;UAkHiB,cAAA;;EAEf,IAAA,EAAM,SAAA;EAFS;EAIf,SAAA,EAAW,SAAA;;EAEX,IAAA;EAFW;EAIX,IAAA;EAee;EAbf,WAAA,GAAc,WAAA;EAmDG;EAjDjB,MAAA;EA6DqC;EA3DrC,KAAA;EAZA;EAcA,UAAA;EAZA;;;;;;EAmBA,YAAA,GAAe,iBAAA;EATf;EAWA,MAAA;EAFA;EAIA,UAAA;EAFA;EAIA,MAAA;EAAA;EAEA,OAAA;EAEA;EAAA,UAAA;EAIA;EAFA,QAAA;EAMA;EAJA,WAAA;EAQA;EANA,UAAA;EAoBA;EAlBA,aAAA;EAoBA;EAlBA,QAAA;EAoBA;EAlBA,GAAA;EA4BsB;EA1BtB,GAAA;EA4BA;;;AAWF;;;;;;;;EA3BE,OAAA,GAAU,MAAA;EAkCV;EAhCA,cAAA,GAAiB,mBAAA;EAkCjB;EAhCA,SAAA;EAkCA;;;;;;;;;EAxBA,WAAA,IAAe,KAAA,EAAO,eAAA;EAkCtB;EAhCA,QAAA;AAAA;;;;;iBAWc,SAAA,CAAA;EACd,IAAA;EACA,SAAA;EACA,IAAA;EACA,IAAA;EACA,WAAA;EACA,MAAA;EACA,KAAA;EACA,UAAA;EACA,YAAA;EACA,MAAA,EAAQ,YAAA;EACR,UAAA;EACA,MAAA;EACA,OAAA;EACA,UAAA;EACA,QAAA;EACA,WAAA;EACA,UAAA;EACA,aAAA;EACA,QAAA;EACA,GAAA;EACA,GAAA;EACA,OAAA,EAAS,aAAA;EACT,cAAA;EACA,SAAA;EACA,WAAA;EACA;AAAA,GACC,cAAA,GAAc,kBAAA,CAAA,GAAA,CAAA,OAAA"}
@@ -2,12 +2,12 @@ import { mapToDatum } from "./utils.js";
2
2
  import { normalizeChartData, normalizeHeatmapData } from "./normalize.js";
3
3
  import { applySelectionEmphasis, buildCartesianOption, buildHeatmapOption, buildHorizontalBarOption, buildPieOption, buildRadarOption } from "./options.js";
4
4
  import { useChartUITokens, useThemeColors } from "./theme.js";
5
+ import ReactEChartsCore from "echarts-for-react/esm/core";
5
6
  import { BarChart, HeatmapChart, LineChart, PieChart, RadarChart, ScatterChart } from "echarts/charts";
6
7
  import { GridComponent, LegendComponent, TitleComponent, TooltipComponent, VisualMapComponent } from "echarts/components";
7
8
  import * as echarts from "echarts/core";
8
9
  import { LegacyGridContainLabel } from "echarts/features";
9
10
  import { CanvasRenderer } from "echarts/renderers";
10
- import ReactEChartsCore from "echarts-for-react/esm/core";
11
11
  import { useCallback, useMemo, useRef } from "react";
12
12
  import { jsx } from "react/jsx-runtime";
13
13
 
@@ -1 +1 @@
1
- {"version":3,"file":"base.js","names":[],"sources":["../../../src/react/charts/base.tsx"],"sourcesContent":["// Type-only import: erased at compile time, does not pull the full echarts\n// bundle in. The `ECharts` type is used for the stored ECharts instance ref.\nimport type { ECharts } from \"echarts\";\nimport {\n BarChart,\n HeatmapChart,\n LineChart,\n PieChart,\n RadarChart,\n ScatterChart,\n} from \"echarts/charts\";\nimport {\n GridComponent,\n LegendComponent,\n TitleComponent,\n TooltipComponent,\n VisualMapComponent,\n} from \"echarts/components\";\nimport * as echarts from \"echarts/core\";\nimport { LegacyGridContainLabel } from \"echarts/features\";\nimport { CanvasRenderer } from \"echarts/renderers\";\n// Import the ESM core build, not `echarts-for-react/lib/core` (CJS). The package\n// has no `exports` map, so `/lib/core` resolves to the literal CommonJS file\n// whose default export is `module.exports`; under ESM default-import interop a\n// consumer's bundler hands back the whole `{ default, __esModule }` object rather\n// than the component, so `<ReactEChartsCore/>` renders an object and React throws\n// \"Element type is invalid\". `esm/core` is real ESM with a true `export default`.\nimport ReactEChartsCore from \"echarts-for-react/esm/core\";\nimport { useCallback, useMemo, useRef } from \"react\";\nimport { normalizeChartData, normalizeHeatmapData } from \"./normalize\";\nimport {\n applySelectionEmphasis,\n buildCartesianOption,\n buildHeatmapOption,\n buildHorizontalBarOption,\n buildPieOption,\n buildRadarOption,\n type OptionBuilderContext,\n} from \"./options\";\nimport { useChartUITokens, useThemeColors } from \"./theme\";\nimport type {\n ChartBaseProps,\n ChartClickDatum,\n ChartColorPalette,\n ChartData,\n ChartType,\n ChartValueFormatter,\n Orientation,\n} from \"./types\";\nimport { mapToDatum } from \"./utils\";\n\n// ============================================================================\n// ECharts Registration (modular imports for tree-shaking)\n// ============================================================================\n// Only the chart types and components used by the option builders in\n// `options.ts` are registered. Importing from `echarts/core` instead of the\n// full `echarts` entry keeps unused chart types (graph, sankey, gauge, ...)\n// out of consumer bundles.\n//\n// If you add a new chart type or use a new ECharts feature (e.g. dataZoom,\n// toolbox, markLine), register it here. Consumers passing custom `options`\n// that need extra features can register them in their own app via\n// `import { use } from \"echarts/core\"`.\n//\n// Note: tooltip-driven axisPointer is bundled with `TooltipComponent`, so no\n// explicit AxisPointerComponent registration is needed.\n//\n// This `use()` call must stay co-located in the same module as `BaseChart`:\n// `package.json#sideEffects` declares JS modules side-effect free, so moving\n// registration to a separate import-for-side-effect module would let bundlers\n// drop it during tree-shaking.\necharts.use([\n // Series types used by the option builders\n LineChart, // line + area charts (area = line with areaStyle)\n BarChart, // bar + horizontal bar charts\n PieChart, // pie + donut charts\n ScatterChart,\n HeatmapChart,\n RadarChart,\n // Components referenced by built options\n TitleComponent, // `title`\n TooltipComponent, // `tooltip`\n LegendComponent, // `legend`\n GridComponent, // `grid` / `xAxis` / `yAxis`\n VisualMapComponent, // `visualMap` (heatmap color scale)\n // Features\n LegacyGridContainLabel, // `grid.containLabel` (cartesian option builder)\n // Renderer (BaseChart always renders with `renderer: \"canvas\"`)\n CanvasRenderer,\n]);\n\n// ============================================================================\n// Palette Selection\n// ============================================================================\n\n/**\n * Determines the appropriate color palette for a chart type.\n * - Heatmaps use sequential (low → high intensity)\n * - All other charts use categorical (distinct categories)\n */\nfunction getDefaultPalette(chartType: ChartType): ChartColorPalette {\n switch (chartType) {\n case \"heatmap\":\n return \"sequential\";\n default:\n return \"categorical\";\n }\n}\n\n// ============================================================================\n// Component Props\n// ============================================================================\n\nexport interface BaseChartProps {\n /** Chart data (Arrow Table or JSON array) - format is auto-detected */\n data: ChartData;\n /** Chart type */\n chartType: ChartType;\n /** X-axis field key (auto-detected from schema if not provided) */\n xKey?: string;\n /** Y-axis field key(s) (auto-detected from schema if not provided) */\n yKey?: string | string[];\n /** Chart orientation @default \"vertical\" */\n orientation?: Orientation;\n /** Chart height in pixels @default 300 */\n height?: number;\n /** Chart title */\n title?: string;\n /** Show legend @default true */\n showLegend?: boolean;\n /**\n * Color palette to use. Auto-selected based on chart type if not specified.\n * - \"categorical\": Distinct colors for different categories (bar, pie, line)\n * - \"sequential\": Gradient for magnitude (heatmap)\n * - \"diverging\": Two-tone for positive/negative (correlation)\n */\n colorPalette?: ChartColorPalette;\n /** Custom colors (overrides colorPalette) */\n colors?: string[];\n /** Show data point symbols (line/area charts) @default false */\n showSymbol?: boolean;\n /** Smooth line curves (line/area charts) @default true */\n smooth?: boolean;\n /** Stack series @default false */\n stacked?: boolean;\n /** Symbol size for scatter charts @default 8 */\n symbolSize?: number;\n /** Show area fill for radar charts @default true */\n showArea?: boolean;\n /** Inner radius for pie/donut (0-100) @default 0 */\n innerRadius?: number;\n /** Show labels on pie/donut slices @default true */\n showLabels?: boolean;\n /** Label position for pie/donut @default \"outside\" */\n labelPosition?: \"outside\" | \"inside\" | \"center\";\n /** Y-axis field key for heatmap (the row dimension) */\n yAxisKey?: string;\n /** Min value for heatmap color scale */\n min?: number;\n /** Max value for heatmap color scale */\n max?: number;\n /**\n * Additional ECharts options to merge.\n *\n * Only the built-in feature set is registered by this package, so options\n * referencing extra ECharts features (`dataZoom`, `toolbox`, `markLine`,\n * `markArea`, `graphic`, `dataset`, top-level `axisPointer`, ...) require\n * registering them in your app via `import { use } from \"echarts/core\"`.\n * This only works when your `echarts` resolves to the same module\n * instance/version as this package's (the registry is a singleton;\n * duplicate echarts copies won't share registrations).\n */\n options?: Record<string, unknown>;\n /** Formats measure values. See {@link ChartBaseProps.valueFormatter}. */\n valueFormatter?: ChartValueFormatter;\n /** Additional CSS classes */\n className?: string;\n /**\n * Fired when a data element (bar, slice, point) is clicked. Fire-and-forget:\n * the return value is ignored (async handlers are fine — the chart never awaits).\n * The handler receives a normalized {@link ChartClickDatum}.\n *\n * Pointer-only: charts render to <canvas>, so this does not fire for keyboard\n * users. Provide a keyboard-accessible equivalent (e.g. a table row action) for\n * the same action.\n */\n onDataClick?: (datum: ChartClickDatum) => void;\n /** Controlled selection by category name. See {@link ChartBaseProps.selected}. */\n selected?: string | string[];\n}\n\n// ============================================================================\n// Base Chart Component\n// ============================================================================\n\n/**\n * Base chart component that handles both Arrow and JSON data.\n * Renders using ECharts for consistent output across both formats.\n */\nexport function BaseChart({\n data,\n chartType,\n xKey,\n yKey,\n orientation,\n height = 300,\n title,\n showLegend = true,\n colorPalette,\n colors: customColors,\n showSymbol = false,\n smooth = true,\n stacked = false,\n symbolSize = 8,\n showArea = true,\n innerRadius = 0,\n showLabels = true,\n labelPosition = \"outside\",\n yAxisKey,\n min,\n max,\n options: customOptions,\n valueFormatter,\n className,\n onDataClick,\n selected,\n}: BaseChartProps) {\n // Determine the appropriate color palette based on chart type\n const resolvedPalette = colorPalette ?? getDefaultPalette(chartType);\n const themeColors = useThemeColors(resolvedPalette);\n const colors = customColors ?? themeColors;\n\n const ui = useChartUITokens();\n\n // Handler presence enables line interaction and gates events. Tracking the\n // boolean keeps inline handler identities from rebuilding chart options.\n const interactive = !!onDataClick;\n\n // Keep the latest handler in a ref so `onEvents` can call the current\n // `onDataClick` without listing it as a dependency (see `onEvents` below).\n const onDataClickRef = useRef(onDataClick);\n onDataClickRef.current = onDataClick;\n\n // Store ECharts instance directly to avoid stale ref issues on unmount\n const echartsInstanceRef = useRef<ECharts | null>(null);\n\n // Callback ref pattern: captures the ECharts instance when ReactECharts mounts\n // This ensures we always have a stable reference to the actual instance\n const chartRefCallback = useCallback((node: ReactEChartsCore | null) => {\n // Dispose previous instance if component is being replaced\n if (\n echartsInstanceRef.current &&\n !echartsInstanceRef.current.isDisposed()\n ) {\n echartsInstanceRef.current.dispose();\n }\n\n // Store the new instance\n if (node) {\n echartsInstanceRef.current = node.getEchartsInstance();\n } else {\n // Component unmounting - dispose the stored instance\n if (\n echartsInstanceRef.current &&\n !echartsInstanceRef.current.isDisposed()\n ) {\n echartsInstanceRef.current.dispose();\n }\n echartsInstanceRef.current = null;\n }\n }, []);\n\n // Memoize data normalization\n const normalized = useMemo(\n () =>\n chartType === \"heatmap\"\n ? normalizeHeatmapData(data, xKey, yAxisKey, yKey)\n : normalizeChartData(data, xKey, yKey, orientation),\n [data, xKey, yKey, yAxisKey, orientation, chartType],\n );\n\n // Memoize option building\n const option = useMemo(() => {\n const { xData, yFields, xField, chartType: detectedChartType } = normalized;\n\n if (xData.length === 0) return null;\n\n // Determine chart mode first (needed to handle yDataMap)\n const isHeatmap = chartType === \"heatmap\";\n\n // Heatmaps use heatmapData instead of yDataMap\n // For other charts, yDataMap is required\n const yDataMap = \"yDataMap\" in normalized ? normalized.yDataMap : {};\n\n const baseCtx: OptionBuilderContext = {\n xData,\n yDataMap,\n yFields,\n colors,\n title,\n showLegend,\n xField,\n ui,\n valueFormatter,\n };\n const isPie = chartType === \"pie\" || chartType === \"donut\";\n const isRadar = chartType === \"radar\";\n const isHorizontal =\n !isPie &&\n !isRadar &&\n !isHeatmap &&\n (orientation === \"horizontal\" ||\n (detectedChartType === \"categorical\" &&\n !orientation &&\n chartType === \"bar\"));\n const isTimeSeries =\n detectedChartType === \"timeseries\" &&\n !isHorizontal &&\n !isRadar &&\n !isHeatmap;\n\n // Build option based on chart type\n let opt: Record<string, unknown>;\n\n if (isHeatmap && \"yAxisData\" in normalized && \"heatmapData\" in normalized) {\n const heatmapNorm = normalized as {\n yAxisData: (string | number)[];\n heatmapData: [number, number, number][];\n min: number;\n max: number;\n } & typeof normalized;\n opt = buildHeatmapOption({\n ...baseCtx,\n yAxisData: heatmapNorm.yAxisData,\n heatmapData: heatmapNorm.heatmapData,\n min: min ?? heatmapNorm.min,\n max: max ?? heatmapNorm.max,\n showLabels,\n });\n } else if (isRadar) {\n opt = buildRadarOption(baseCtx, showArea);\n } else if (isPie) {\n opt = buildPieOption(\n baseCtx,\n chartType as \"pie\" | \"donut\",\n innerRadius,\n showLabels,\n labelPosition,\n );\n } else if (isHorizontal) {\n opt = buildHorizontalBarOption(baseCtx, stacked);\n } else {\n opt = buildCartesianOption({\n ...baseCtx,\n chartType,\n isTimeSeries,\n stacked,\n smooth,\n showSymbol,\n symbolSize,\n interactive,\n });\n }\n\n // Apply selection after custom options; empty selection is a no-op.\n const merged = customOptions ? { ...opt, ...customOptions } : opt;\n return applySelectionEmphasis(merged, selected);\n }, [\n normalized,\n colors,\n ui,\n title,\n showLegend,\n chartType,\n orientation,\n innerRadius,\n showLabels,\n labelPosition,\n stacked,\n smooth,\n showSymbol,\n symbolSize,\n showArea,\n min,\n max,\n customOptions,\n valueFormatter,\n selected,\n interactive,\n ]);\n\n // Heatmap data uses axis indexes; preserve labels for click results instead\n // of exposing those raw positions.\n const axisLabels = useMemo(\n () => ({\n xLabels: normalized.xData,\n yLabels:\n \"yAxisData\" in normalized\n ? (normalized.yAxisData as (string | number)[])\n : undefined,\n }),\n [normalized],\n );\n\n // `onEvents` must not re-subscribe when the data changes (e.g. each SSE tick).\n const axisLabelsRef = useRef(axisLabels);\n axisLabelsRef.current = axisLabels;\n\n // Memoize by handler presence because echarts-for-react re-subscribes whenever\n // `onEvents` changes, while callers commonly pass a new inline callback on\n // every render. This also avoids churn during frequently changing data such\n // as SSE ticks.\n const onEvents = useMemo(\n () =>\n interactive\n ? {\n click: (params: unknown, instance: ECharts) => {\n const result = onDataClickRef.current?.(\n mapToDatum(params, axisLabelsRef.current, instance),\n ) as void | Promise<void>;\n if (\n result &&\n typeof (result as Promise<void>).then === \"function\"\n ) {\n (result as Promise<void>).catch(() => {});\n }\n },\n }\n : undefined,\n [interactive],\n );\n\n if (!option) {\n return (\n <div className=\"flex items-center justify-center h-full text-muted-foreground\">\n No data\n </div>\n );\n }\n\n return (\n <ReactEChartsCore\n ref={chartRefCallback}\n echarts={echarts}\n option={option}\n style={{ height }}\n className={className}\n opts={{ renderer: \"canvas\" }}\n notMerge={false}\n lazyUpdate={true}\n onEvents={onEvents}\n />\n );\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"base.js","names":[],"sources":["../../../src/react/charts/base.tsx"],"sourcesContent":["// Type-only import: erased at compile time, does not pull the full echarts\n// bundle in. The `ECharts` type is used for the stored ECharts instance ref.\nimport type { ECharts } from \"echarts\";\n// Import the ESM core build, not `echarts-for-react/lib/core` (CJS). The package\n// has no `exports` map, so `/lib/core` resolves to the literal CommonJS file\n// whose default export is `module.exports`; under ESM default-import interop a\n// consumer's bundler hands back the whole `{ default, __esModule }` object rather\n// than the component, so `<ReactEChartsCore/>` renders an object and React throws\n// \"Element type is invalid\". `esm/core` is real ESM with a true `export default`.\nimport ReactEChartsCore from \"echarts-for-react/esm/core\";\nimport {\n BarChart,\n HeatmapChart,\n LineChart,\n PieChart,\n RadarChart,\n ScatterChart,\n} from \"echarts/charts\";\nimport {\n GridComponent,\n LegendComponent,\n TitleComponent,\n TooltipComponent,\n VisualMapComponent,\n} from \"echarts/components\";\nimport * as echarts from \"echarts/core\";\nimport { LegacyGridContainLabel } from \"echarts/features\";\nimport { CanvasRenderer } from \"echarts/renderers\";\nimport { useCallback, useMemo, useRef } from \"react\";\n\nimport { normalizeChartData, normalizeHeatmapData } from \"./normalize\";\nimport {\n applySelectionEmphasis,\n buildCartesianOption,\n buildHeatmapOption,\n buildHorizontalBarOption,\n buildPieOption,\n buildRadarOption,\n type OptionBuilderContext,\n} from \"./options\";\nimport { useChartUITokens, useThemeColors } from \"./theme\";\nimport type {\n ChartBaseProps,\n ChartClickDatum,\n ChartColorPalette,\n ChartData,\n ChartType,\n ChartValueFormatter,\n Orientation,\n} from \"./types\";\nimport { mapToDatum } from \"./utils\";\n\n// ============================================================================\n// ECharts Registration (modular imports for tree-shaking)\n// ============================================================================\n// Only the chart types and components used by the option builders in\n// `options.ts` are registered. Importing from `echarts/core` instead of the\n// full `echarts` entry keeps unused chart types (graph, sankey, gauge, ...)\n// out of consumer bundles.\n//\n// If you add a new chart type or use a new ECharts feature (e.g. dataZoom,\n// toolbox, markLine), register it here. Consumers passing custom `options`\n// that need extra features can register them in their own app via\n// `import { use } from \"echarts/core\"`.\n//\n// Note: tooltip-driven axisPointer is bundled with `TooltipComponent`, so no\n// explicit AxisPointerComponent registration is needed.\n//\n// This `use()` call must stay co-located in the same module as `BaseChart`:\n// `package.json#sideEffects` declares JS modules side-effect free, so moving\n// registration to a separate import-for-side-effect module would let bundlers\n// drop it during tree-shaking.\necharts.use([\n // Series types used by the option builders\n LineChart, // line + area charts (area = line with areaStyle)\n BarChart, // bar + horizontal bar charts\n PieChart, // pie + donut charts\n ScatterChart,\n HeatmapChart,\n RadarChart,\n // Components referenced by built options\n TitleComponent, // `title`\n TooltipComponent, // `tooltip`\n LegendComponent, // `legend`\n GridComponent, // `grid` / `xAxis` / `yAxis`\n VisualMapComponent, // `visualMap` (heatmap color scale)\n // Features\n LegacyGridContainLabel, // `grid.containLabel` (cartesian option builder)\n // Renderer (BaseChart always renders with `renderer: \"canvas\"`)\n CanvasRenderer,\n]);\n\n// ============================================================================\n// Palette Selection\n// ============================================================================\n\n/**\n * Determines the appropriate color palette for a chart type.\n * - Heatmaps use sequential (low → high intensity)\n * - All other charts use categorical (distinct categories)\n */\nfunction getDefaultPalette(chartType: ChartType): ChartColorPalette {\n switch (chartType) {\n case \"heatmap\":\n return \"sequential\";\n default:\n return \"categorical\";\n }\n}\n\n// ============================================================================\n// Component Props\n// ============================================================================\n\nexport interface BaseChartProps {\n /** Chart data (Arrow Table or JSON array) - format is auto-detected */\n data: ChartData;\n /** Chart type */\n chartType: ChartType;\n /** X-axis field key (auto-detected from schema if not provided) */\n xKey?: string;\n /** Y-axis field key(s) (auto-detected from schema if not provided) */\n yKey?: string | string[];\n /** Chart orientation @default \"vertical\" */\n orientation?: Orientation;\n /** Chart height in pixels @default 300 */\n height?: number;\n /** Chart title */\n title?: string;\n /** Show legend @default true */\n showLegend?: boolean;\n /**\n * Color palette to use. Auto-selected based on chart type if not specified.\n * - \"categorical\": Distinct colors for different categories (bar, pie, line)\n * - \"sequential\": Gradient for magnitude (heatmap)\n * - \"diverging\": Two-tone for positive/negative (correlation)\n */\n colorPalette?: ChartColorPalette;\n /** Custom colors (overrides colorPalette) */\n colors?: string[];\n /** Show data point symbols (line/area charts) @default false */\n showSymbol?: boolean;\n /** Smooth line curves (line/area charts) @default true */\n smooth?: boolean;\n /** Stack series @default false */\n stacked?: boolean;\n /** Symbol size for scatter charts @default 8 */\n symbolSize?: number;\n /** Show area fill for radar charts @default true */\n showArea?: boolean;\n /** Inner radius for pie/donut (0-100) @default 0 */\n innerRadius?: number;\n /** Show labels on pie/donut slices @default true */\n showLabels?: boolean;\n /** Label position for pie/donut @default \"outside\" */\n labelPosition?: \"outside\" | \"inside\" | \"center\";\n /** Y-axis field key for heatmap (the row dimension) */\n yAxisKey?: string;\n /** Min value for heatmap color scale */\n min?: number;\n /** Max value for heatmap color scale */\n max?: number;\n /**\n * Additional ECharts options to merge.\n *\n * Only the built-in feature set is registered by this package, so options\n * referencing extra ECharts features (`dataZoom`, `toolbox`, `markLine`,\n * `markArea`, `graphic`, `dataset`, top-level `axisPointer`, ...) require\n * registering them in your app via `import { use } from \"echarts/core\"`.\n * This only works when your `echarts` resolves to the same module\n * instance/version as this package's (the registry is a singleton;\n * duplicate echarts copies won't share registrations).\n */\n options?: Record<string, unknown>;\n /** Formats measure values. See {@link ChartBaseProps.valueFormatter}. */\n valueFormatter?: ChartValueFormatter;\n /** Additional CSS classes */\n className?: string;\n /**\n * Fired when a data element (bar, slice, point) is clicked. Fire-and-forget:\n * the return value is ignored (async handlers are fine — the chart never awaits).\n * The handler receives a normalized {@link ChartClickDatum}.\n *\n * Pointer-only: charts render to <canvas>, so this does not fire for keyboard\n * users. Provide a keyboard-accessible equivalent (e.g. a table row action) for\n * the same action.\n */\n onDataClick?: (datum: ChartClickDatum) => void;\n /** Controlled selection by category name. See {@link ChartBaseProps.selected}. */\n selected?: string | string[];\n}\n\n// ============================================================================\n// Base Chart Component\n// ============================================================================\n\n/**\n * Base chart component that handles both Arrow and JSON data.\n * Renders using ECharts for consistent output across both formats.\n */\nexport function BaseChart({\n data,\n chartType,\n xKey,\n yKey,\n orientation,\n height = 300,\n title,\n showLegend = true,\n colorPalette,\n colors: customColors,\n showSymbol = false,\n smooth = true,\n stacked = false,\n symbolSize = 8,\n showArea = true,\n innerRadius = 0,\n showLabels = true,\n labelPosition = \"outside\",\n yAxisKey,\n min,\n max,\n options: customOptions,\n valueFormatter,\n className,\n onDataClick,\n selected,\n}: BaseChartProps) {\n // Determine the appropriate color palette based on chart type\n const resolvedPalette = colorPalette ?? getDefaultPalette(chartType);\n const themeColors = useThemeColors(resolvedPalette);\n const colors = customColors ?? themeColors;\n\n const ui = useChartUITokens();\n\n // Handler presence enables line interaction and gates events. Tracking the\n // boolean keeps inline handler identities from rebuilding chart options.\n const interactive = !!onDataClick;\n\n // Keep the latest handler in a ref so `onEvents` can call the current\n // `onDataClick` without listing it as a dependency (see `onEvents` below).\n const onDataClickRef = useRef(onDataClick);\n onDataClickRef.current = onDataClick;\n\n // Store ECharts instance directly to avoid stale ref issues on unmount\n const echartsInstanceRef = useRef<ECharts | null>(null);\n\n // Callback ref pattern: captures the ECharts instance when ReactECharts mounts\n // This ensures we always have a stable reference to the actual instance\n const chartRefCallback = useCallback((node: ReactEChartsCore | null) => {\n // Dispose previous instance if component is being replaced\n if (\n echartsInstanceRef.current &&\n !echartsInstanceRef.current.isDisposed()\n ) {\n echartsInstanceRef.current.dispose();\n }\n\n // Store the new instance\n if (node) {\n echartsInstanceRef.current = node.getEchartsInstance();\n } else {\n // Component unmounting - dispose the stored instance\n if (\n echartsInstanceRef.current &&\n !echartsInstanceRef.current.isDisposed()\n ) {\n echartsInstanceRef.current.dispose();\n }\n echartsInstanceRef.current = null;\n }\n }, []);\n\n // Memoize data normalization\n const normalized = useMemo(\n () =>\n chartType === \"heatmap\"\n ? normalizeHeatmapData(data, xKey, yAxisKey, yKey)\n : normalizeChartData(data, xKey, yKey, orientation),\n [data, xKey, yKey, yAxisKey, orientation, chartType],\n );\n\n // Memoize option building\n const option = useMemo(() => {\n const { xData, yFields, xField, chartType: detectedChartType } = normalized;\n\n if (xData.length === 0) return null;\n\n // Determine chart mode first (needed to handle yDataMap)\n const isHeatmap = chartType === \"heatmap\";\n\n // Heatmaps use heatmapData instead of yDataMap\n // For other charts, yDataMap is required\n const yDataMap = \"yDataMap\" in normalized ? normalized.yDataMap : {};\n\n const baseCtx: OptionBuilderContext = {\n xData,\n yDataMap,\n yFields,\n colors,\n title,\n showLegend,\n xField,\n ui,\n valueFormatter,\n };\n const isPie = chartType === \"pie\" || chartType === \"donut\";\n const isRadar = chartType === \"radar\";\n const isHorizontal =\n !isPie &&\n !isRadar &&\n !isHeatmap &&\n (orientation === \"horizontal\" ||\n (detectedChartType === \"categorical\" &&\n !orientation &&\n chartType === \"bar\"));\n const isTimeSeries =\n detectedChartType === \"timeseries\" &&\n !isHorizontal &&\n !isRadar &&\n !isHeatmap;\n\n // Build option based on chart type\n let opt: Record<string, unknown>;\n\n if (isHeatmap && \"yAxisData\" in normalized && \"heatmapData\" in normalized) {\n const heatmapNorm = normalized as {\n yAxisData: (string | number)[];\n heatmapData: [number, number, number][];\n min: number;\n max: number;\n } & typeof normalized;\n opt = buildHeatmapOption({\n ...baseCtx,\n yAxisData: heatmapNorm.yAxisData,\n heatmapData: heatmapNorm.heatmapData,\n min: min ?? heatmapNorm.min,\n max: max ?? heatmapNorm.max,\n showLabels,\n });\n } else if (isRadar) {\n opt = buildRadarOption(baseCtx, showArea);\n } else if (isPie) {\n opt = buildPieOption(\n baseCtx,\n chartType as \"pie\" | \"donut\",\n innerRadius,\n showLabels,\n labelPosition,\n );\n } else if (isHorizontal) {\n opt = buildHorizontalBarOption(baseCtx, stacked);\n } else {\n opt = buildCartesianOption({\n ...baseCtx,\n chartType,\n isTimeSeries,\n stacked,\n smooth,\n showSymbol,\n symbolSize,\n interactive,\n });\n }\n\n // Apply selection after custom options; empty selection is a no-op.\n const merged = customOptions ? { ...opt, ...customOptions } : opt;\n return applySelectionEmphasis(merged, selected);\n }, [\n normalized,\n colors,\n ui,\n title,\n showLegend,\n chartType,\n orientation,\n innerRadius,\n showLabels,\n labelPosition,\n stacked,\n smooth,\n showSymbol,\n symbolSize,\n showArea,\n min,\n max,\n customOptions,\n valueFormatter,\n selected,\n interactive,\n ]);\n\n // Heatmap data uses axis indexes; preserve labels for click results instead\n // of exposing those raw positions.\n const axisLabels = useMemo(\n () => ({\n xLabels: normalized.xData,\n yLabels:\n \"yAxisData\" in normalized\n ? (normalized.yAxisData as (string | number)[])\n : undefined,\n }),\n [normalized],\n );\n\n // `onEvents` must not re-subscribe when the data changes (e.g. each SSE tick).\n const axisLabelsRef = useRef(axisLabels);\n axisLabelsRef.current = axisLabels;\n\n // Memoize by handler presence because echarts-for-react re-subscribes whenever\n // `onEvents` changes, while callers commonly pass a new inline callback on\n // every render. This also avoids churn during frequently changing data such\n // as SSE ticks.\n const onEvents = useMemo(\n () =>\n interactive\n ? {\n click: (params: unknown, instance: ECharts) => {\n const result = onDataClickRef.current?.(\n mapToDatum(params, axisLabelsRef.current, instance),\n ) as void | Promise<void>;\n if (\n result &&\n typeof (result as Promise<void>).then === \"function\"\n ) {\n (result as Promise<void>).catch(() => {});\n }\n },\n }\n : undefined,\n [interactive],\n );\n\n if (!option) {\n return (\n <div className=\"flex items-center justify-center h-full text-muted-foreground\">\n No data\n </div>\n );\n }\n\n return (\n <ReactEChartsCore\n ref={chartRefCallback}\n echarts={echarts}\n option={option}\n style={{ height }}\n className={className}\n opts={{ renderer: \"canvas\" }}\n notMerge={false}\n lazyUpdate={true}\n onEvents={onEvents}\n />\n );\n}\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","names":[],"sources":["../../../../src/react/charts/heatmap/index.tsx"],"mappings":";;;;;;;AAkBA;;;;;;;;;;;cAAa,YAAA;EAAA,QAGZ,iBAAA,GAAA,kBAAA,CAAA,GAAA,CAAA,OAAA"}
1
+ {"version":3,"file":"index.d.ts","names":[],"sources":["../../../../src/react/charts/heatmap/index.tsx"],"mappings":";;;;;;;AAmBA;;;;;;;;;;;cAAa,YAAA;EAAA,QAGZ,iBAAA,GAAA,kBAAA,CAAA,GAAA,CAAA,OAAA"}
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":[],"sources":["../../../../src/react/charts/heatmap/index.tsx"],"sourcesContent":["import type { JSX } from \"react\";\nimport { createChart } from \"../create-chart\";\nimport type { HeatmapChartProps } from \"../types\";\n\n/**\n * Heatmap Chart component for matrix-style data visualization.\n *\n * **Important:** This component uses Apache ECharts architecture. Configure it via props, not by passing child components.\n *\n * **Best Practice:** Use the built-in data fetching by passing `queryKey` and `parameters` props instead of pre-fetching data with `useAnalyticsQuery`.\n *\n * Data should be in \"long format\" with three fields:\n * - xKey: X-axis category (columns)\n * - yAxisKey: Y-axis category (rows)\n * - yKey: The numeric value for each cell\n *\n * Supports both query mode (queryKey + parameters) and data mode (static data).\n */\nexport const HeatmapChart = createChart<HeatmapChartProps>(\n \"heatmap\",\n \"HeatmapChart\",\n);\n\n// Type-only definition for documentation generation (not used at runtime)\n/**\n * Heatmap Chart component for matrix-style data visualization.\n *\n * **Important:** This component uses Apache ECharts architecture. Configure it via props, not by passing child components.\n *\n * **Best Practice:** Use the built-in data fetching by passing `queryKey` and `parameters` props instead of pre-fetching data with `useAnalyticsQuery`.\n *\n * Data should be in \"long format\" with three fields:\n * - xKey: X-axis category (columns)\n * - yAxisKey: Y-axis category (rows)\n * - yKey: The numeric value for each cell\n *\n * Supports both query mode (queryKey + parameters) and data mode (static data).\n */\nfunction _HeatmapChartDoc(props: HeatmapChartProps): JSX.Element {\n return HeatmapChart(props);\n}\n"],"mappings":";;;;;;;;;;;;;;;;;AAkBA,MAAa,eAAe,YAC1B,WACA,eACD"}
1
+ {"version":3,"file":"index.js","names":[],"sources":["../../../../src/react/charts/heatmap/index.tsx"],"sourcesContent":["import type { JSX } from \"react\";\n\nimport { createChart } from \"../create-chart\";\nimport type { HeatmapChartProps } from \"../types\";\n\n/**\n * Heatmap Chart component for matrix-style data visualization.\n *\n * **Important:** This component uses Apache ECharts architecture. Configure it via props, not by passing child components.\n *\n * **Best Practice:** Use the built-in data fetching by passing `queryKey` and `parameters` props instead of pre-fetching data with `useAnalyticsQuery`.\n *\n * Data should be in \"long format\" with three fields:\n * - xKey: X-axis category (columns)\n * - yAxisKey: Y-axis category (rows)\n * - yKey: The numeric value for each cell\n *\n * Supports both query mode (queryKey + parameters) and data mode (static data).\n */\nexport const HeatmapChart = createChart<HeatmapChartProps>(\n \"heatmap\",\n \"HeatmapChart\",\n);\n\n// Type-only definition for documentation generation (not used at runtime)\n/**\n * Heatmap Chart component for matrix-style data visualization.\n *\n * **Important:** This component uses Apache ECharts architecture. Configure it via props, not by passing child components.\n *\n * **Best Practice:** Use the built-in data fetching by passing `queryKey` and `parameters` props instead of pre-fetching data with `useAnalyticsQuery`.\n *\n * Data should be in \"long format\" with three fields:\n * - xKey: X-axis category (columns)\n * - yAxisKey: Y-axis category (rows)\n * - yKey: The numeric value for each cell\n *\n * Supports both query mode (queryKey + parameters) and data mode (static data).\n */\nfunction _HeatmapChartDoc(props: HeatmapChartProps): JSX.Element {\n return HeatmapChart(props);\n}\n"],"mappings":";;;;;;;;;;;;;;;;;AAmBA,MAAa,eAAe,YAC1B,WACA,eACD"}
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","names":[],"sources":["../../../../src/react/charts/line/index.tsx"],"mappings":";;;;;;;AAaA;;;;;;cAAa,SAAA;EAAA,QAA4D,cAAA,GAAA,kBAAA,CAAA,GAAA,CAAA,OAAA"}
1
+ {"version":3,"file":"index.d.ts","names":[],"sources":["../../../../src/react/charts/line/index.tsx"],"mappings":";;;;;;;AAcA;;;;;;cAAa,SAAA;EAAA,QAA4D,cAAA,GAAA,kBAAA,CAAA,GAAA,CAAA,OAAA"}
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":[],"sources":["../../../../src/react/charts/line/index.tsx"],"sourcesContent":["import type { JSX } from \"react\";\nimport { createChart } from \"../create-chart\";\nimport type { LineChartProps } from \"../types\";\n\n/**\n * Line Chart component for time-series and trend visualization.\n *\n * **Important:** This component uses Apache ECharts architecture. Configure it via props, not by passing child components.\n *\n * **Best Practice:** Use the built-in data fetching by passing `queryKey` and `parameters` props instead of pre-fetching data with `useAnalyticsQuery`.\n *\n * Supports both query mode (queryKey + parameters) and data mode (static data).\n */\nexport const LineChart = createChart<LineChartProps>(\"line\", \"LineChart\");\n\n// Type-only definition for documentation generation (not used at runtime)\n/**\n * Line Chart component for time-series and trend visualization.\n *\n * **Important:** This component uses Apache ECharts architecture. Configure it via props, not by passing child components.\n *\n * **Best Practice:** Use the built-in data fetching by passing `queryKey` and `parameters` props instead of pre-fetching data with `useAnalyticsQuery`.\n *\n * Supports both query mode (queryKey + parameters) and data mode (static data).\n */\nfunction _LineChartDoc(props: LineChartProps): JSX.Element {\n return LineChart(props);\n}\n"],"mappings":";;;;;;;;;;;;AAaA,MAAa,YAAY,YAA4B,QAAQ,YAAY"}
1
+ {"version":3,"file":"index.js","names":[],"sources":["../../../../src/react/charts/line/index.tsx"],"sourcesContent":["import type { JSX } from \"react\";\n\nimport { createChart } from \"../create-chart\";\nimport type { LineChartProps } from \"../types\";\n\n/**\n * Line Chart component for time-series and trend visualization.\n *\n * **Important:** This component uses Apache ECharts architecture. Configure it via props, not by passing child components.\n *\n * **Best Practice:** Use the built-in data fetching by passing `queryKey` and `parameters` props instead of pre-fetching data with `useAnalyticsQuery`.\n *\n * Supports both query mode (queryKey + parameters) and data mode (static data).\n */\nexport const LineChart = createChart<LineChartProps>(\"line\", \"LineChart\");\n\n// Type-only definition for documentation generation (not used at runtime)\n/**\n * Line Chart component for time-series and trend visualization.\n *\n * **Important:** This component uses Apache ECharts architecture. Configure it via props, not by passing child components.\n *\n * **Best Practice:** Use the built-in data fetching by passing `queryKey` and `parameters` props instead of pre-fetching data with `useAnalyticsQuery`.\n *\n * Supports both query mode (queryKey + parameters) and data mode (static data).\n */\nfunction _LineChartDoc(props: LineChartProps): JSX.Element {\n return LineChart(props);\n}\n"],"mappings":";;;;;;;;;;;;AAcA,MAAa,YAAY,YAA4B,QAAQ,YAAY"}
@@ -1 +1 @@
1
- {"version":3,"file":"normalize.d.ts","names":[],"sources":["../../../src/react/charts/normalize.ts"],"mappings":";;;;;AA4NA;;iBAAgB,kBAAA,CACd,IAAA,EAAM,SAAA,EACN,IAAA,WACA,IAAA,sBACA,WAAA,GAAc,WAAA,GACb,mBAAA;;;;;;UAiGc,qBAAA,SAA8B,uBAAA;EArG7C;EAuGA,SAAA;EArGA;EAuGA,WAAA;EAtGA;EAwGA,GAAA;EAvGoB;EAyGpB,GAAA;AAAA;;;;;;;;;;iBAYc,oBAAA,CACd,IAAA,EAAM,SAAA,EACN,IAAA,WACA,QAAA,WACA,QAAA,uBACC,qBAAA"}
1
+ {"version":3,"file":"normalize.d.ts","names":[],"sources":["../../../src/react/charts/normalize.ts"],"mappings":";;;;;AA8NA;;iBAAgB,kBAAA,CACd,IAAA,EAAM,SAAA,EACN,IAAA,WACA,IAAA,sBACA,WAAA,GAAc,WAAA,GACb,mBAAA;;;;;;UAiGc,qBAAA,SAA8B,uBAAA;EArG7C;EAuGA,SAAA;EArGA;EAuGA,WAAA;EAtGA;EAwGA,GAAA;EAvGoB;EAyGpB,GAAA;AAAA;;;;;;;;;;iBAYc,oBAAA,CACd,IAAA,EAAM,SAAA,EACN,IAAA,WACA,QAAA,WACA,QAAA,uBACC,qBAAA"}
@@ -1 +1 @@
1
- {"version":3,"file":"normalize.js","names":[],"sources":["../../../src/react/charts/normalize.ts"],"sourcesContent":["import type { Table } from \"apache-arrow\";\nimport { ArrowClient } from \"@/js\";\nimport { DATE_FIELD_PATTERNS, NAME_FIELD_PATTERNS } from \"./constants\";\nimport type {\n ChartData,\n NormalizedChartData,\n NormalizedChartDataBase,\n Orientation,\n} from \"./types\";\nimport { isArrowTable } from \"./types\";\nimport {\n sortNumericAscending,\n sortTimeSeriesAscending,\n toChartArray,\n toChronologicalValue,\n} from \"./utils\";\n\n// ============================================================================\n// Type Detection Helpers\n// ============================================================================\n\n/**\n * Checks if a value is a date string a time axis can plot.\n */\nfunction isDateString(value: unknown): boolean {\n if (typeof value !== \"string\") return false;\n return toChronologicalValue(value) !== null;\n}\n\n/**\n * Checks if a value is numeric (number or numeric string)\n */\nfunction isNumericValue(value: unknown): boolean {\n if (typeof value === \"number\") return true;\n if (typeof value === \"bigint\") return true;\n if (typeof value === \"string\") {\n const trimmed = value.trim();\n if (trimmed === \"\" || isDateString(trimmed)) return false;\n const parsed = Number(trimmed);\n return !Number.isNaN(parsed) && Number.isFinite(parsed);\n }\n return false;\n}\n\n/**\n * Checks if a value looks like a category/label (non-numeric string)\n */\nfunction isCategoryValue(value: unknown): boolean {\n if (typeof value !== \"string\") return false;\n const trimmed = value.trim();\n if (trimmed === \"\") return false;\n if (/^\\d{4}-\\d{2}-\\d{2}/.test(trimmed)) return false;\n const parsed = Number(trimmed);\n return Number.isNaN(parsed) || !Number.isFinite(parsed);\n}\n\n// ============================================================================\n// Field Detection\n// ============================================================================\n\n/**\n * Detects fields from JSON data for charting\n */\nfunction detectFieldsFromJson(\n data: Record<string, unknown>[],\n orientation?: Orientation,\n): {\n xField: string;\n yFields: string[];\n chartType: \"timeseries\" | \"categorical\";\n} {\n if (!data || data.length === 0) {\n return { xField: \"x\", yFields: [\"y\"], chartType: \"categorical\" };\n }\n\n const firstRow = data[0];\n const keys = Object.keys(firstRow);\n\n // Detect date fields by key name OR by value being a date string\n const dateFields = keys.filter((key) => {\n const value = firstRow[key];\n const keyMatchesDatePattern = DATE_FIELD_PATTERNS.some((p) =>\n key.toLowerCase().includes(p),\n );\n const valueIsDateString = isDateString(value);\n return keyMatchesDatePattern || valueIsDateString;\n });\n\n // Detect name/category fields by pattern AND value type\n let nameFields = keys.filter((key) => {\n const value = firstRow[key];\n return (\n isCategoryValue(value) &&\n !isDateString(value) &&\n NAME_FIELD_PATTERNS.some((p) => key.toLowerCase().includes(p))\n );\n });\n\n // Fallback: any string field that isn't a date or ID\n if (nameFields.length === 0) {\n nameFields = keys.filter((key) => {\n const value = firstRow[key];\n return (\n isCategoryValue(value) &&\n !isDateString(value) &&\n !dateFields.includes(key) &&\n !key.toLowerCase().endsWith(\"_id\")\n );\n });\n }\n\n // Detect numeric fields\n const numericFields = keys.filter((key) => {\n const value = firstRow[key];\n return isNumericValue(value) && !dateFields.includes(key);\n });\n\n const isHorizontal = orientation === \"horizontal\";\n\n if (isHorizontal || (nameFields.length > 0 && dateFields.length === 0)) {\n const xField = nameFields[0] || dateFields[0] || keys[0];\n const yFields =\n numericFields.length > 0\n ? numericFields\n : keys.filter((k) => k !== xField);\n return { xField, yFields, chartType: \"categorical\" };\n }\n\n const xField = dateFields[0] || nameFields[0] || keys[0];\n const yFields =\n numericFields.length > 0 ? numericFields : keys.filter((k) => k !== xField);\n return {\n xField,\n yFields,\n chartType: dateFields.length > 0 ? \"timeseries\" : \"categorical\",\n };\n}\n\n// ============================================================================\n// Value Conversion\n// ============================================================================\n\n/**\n * Converts a JSON value to a chart-compatible value.\n */\nfunction jsonValueToChartValue(\n value: unknown,\n isYValue: boolean,\n isDateField: boolean,\n): string | number {\n if (value === null || value === undefined) {\n return isYValue ? 0 : \"\";\n }\n if (typeof value === \"number\") {\n return value;\n }\n if (typeof value === \"bigint\") {\n return Number(value);\n }\n if (typeof value === \"string\") {\n if (isDateField) {\n const timestamp = toChronologicalValue(value);\n if (timestamp !== null) {\n return timestamp;\n }\n }\n if (isYValue) {\n const trimmed = value.trim();\n const parsed = Number(trimmed);\n if (!Number.isNaN(parsed) && Number.isFinite(parsed)) {\n return parsed;\n }\n }\n return value;\n }\n return String(value);\n}\n\n// ============================================================================\n// Data Extraction\n// ============================================================================\n\n/**\n * Extracts chart data from JSON array\n */\nfunction extractFromJson(\n data: Record<string, unknown>[],\n xField: string,\n yFields: string[],\n): {\n xData: (string | number)[];\n yDataMap: Record<string, (string | number)[]>;\n} {\n const xData: (string | number)[] = [];\n const yDataMap: Record<string, (string | number)[]> = {};\n\n for (const field of yFields) {\n yDataMap[field] = [];\n }\n\n const xIsDateField = data.length > 0 && isDateString(data[0][xField]);\n\n for (const row of data) {\n xData.push(jsonValueToChartValue(row[xField], false, xIsDateField));\n for (const field of yFields) {\n yDataMap[field].push(jsonValueToChartValue(row[field], true, false));\n }\n }\n\n return { xData, yDataMap };\n}\n\n// ============================================================================\n// Main Normalization Function\n// ============================================================================\n\n/**\n * Normalizes chart data from either Arrow or JSON format.\n * Converts BigInt and Date values to chart-compatible types.\n */\nexport function normalizeChartData(\n data: ChartData,\n xKey?: string,\n yKey?: string | string[],\n orientation?: Orientation,\n): NormalizedChartData {\n if (isArrowTable(data)) {\n const table = data as Table;\n const detected = ArrowClient.detectFieldsFromArrow(table, orientation);\n const resolvedXKey = xKey ?? detected.xField;\n const resolvedYKeys = yKey\n ? Array.isArray(yKey)\n ? yKey\n : [yKey]\n : detected.yFields;\n\n const { xData: rawXData, yDataMap: rawYDataMap } =\n ArrowClient.extractChartData(table, resolvedXKey, resolvedYKeys);\n\n let xData = toChartArray(rawXData);\n let yDataMap: Record<string, (string | number)[]> = {};\n for (const key of resolvedYKeys) {\n yDataMap[key] = toChartArray(rawYDataMap[key] ?? []);\n }\n\n if (detected.chartType === \"timeseries\") {\n ({ xData, yDataMap } = sortTimeSeriesAscending(\n xData,\n yDataMap,\n resolvedYKeys,\n ));\n } else if (xData.length > 0 && xData.every(isNumericValue)) {\n ({ xData, yDataMap } = sortNumericAscending(\n xData,\n yDataMap,\n resolvedYKeys,\n ));\n }\n\n return {\n xData,\n yDataMap,\n xField: resolvedXKey,\n yFields: resolvedYKeys,\n chartType: detected.chartType,\n };\n }\n\n // JSON Array\n const jsonData = data as Record<string, unknown>[];\n const detected = detectFieldsFromJson(jsonData, orientation);\n const resolvedXKey = xKey ?? detected.xField;\n const resolvedYKeys = yKey\n ? Array.isArray(yKey)\n ? yKey\n : [yKey]\n : detected.yFields;\n\n const { xData: rawXData, yDataMap: rawYDataMap } = extractFromJson(\n jsonData,\n resolvedXKey,\n resolvedYKeys,\n );\n\n let xData = toChartArray(rawXData);\n let yDataMap: Record<string, (string | number)[]> = {};\n for (const key of resolvedYKeys) {\n yDataMap[key] = toChartArray(rawYDataMap[key] ?? []);\n }\n\n if (detected.chartType === \"timeseries\") {\n ({ xData, yDataMap } = sortTimeSeriesAscending(\n xData,\n yDataMap,\n resolvedYKeys,\n ));\n } else if (xData.length > 0 && xData.every(isNumericValue)) {\n ({ xData, yDataMap } = sortNumericAscending(\n xData,\n yDataMap,\n resolvedYKeys,\n ));\n }\n\n return {\n xData,\n yDataMap,\n xField: resolvedXKey,\n yFields: resolvedYKeys,\n chartType: detected.chartType,\n };\n}\n\n// ============================================================================\n// Heatmap Data Normalization\n// ============================================================================\n\n/**\n * Normalized data for heatmap charts.\n * Extends base (not NormalizedChartData) because heatmaps don't use yDataMap.\n * Instead, they use heatmapData which contains [xIndex, yIndex, value] tuples.\n */\nexport interface NormalizedHeatmapData extends NormalizedChartDataBase {\n /** Y-axis categories (rows) */\n yAxisData: (string | number)[];\n /** Heatmap data as [xIndex, yIndex, value] tuples */\n heatmapData: [number, number, number][];\n /** Min value in the data */\n min: number;\n /** Max value in the data */\n max: number;\n}\n\n/**\n * Normalizes data specifically for heatmap charts.\n * Expects data in format: `{ xKey: string, yAxisKey: string, valueKey: number }`\n *\n * @param data - Raw data (Arrow Table or JSON array)\n * @param xKey - Field key for X-axis (columns)\n * @param yAxisKey - Field key for Y-axis (rows)\n * @param valueKey - Field key for the cell values\n */\nexport function normalizeHeatmapData(\n data: ChartData,\n xKey?: string,\n yAxisKey?: string,\n valueKey?: string | string[],\n): NormalizedHeatmapData {\n // First, get the standard normalization\n const jsonData = isArrowTable(data)\n ? extractJsonFromArrow(data)\n : (data as Record<string, unknown>[]);\n\n if (jsonData.length === 0) {\n return {\n xData: [],\n xField: xKey ?? \"x\",\n yFields: [],\n chartType: \"categorical\",\n yAxisData: [],\n heatmapData: [],\n min: 0,\n max: 0,\n };\n }\n\n // Detect fields if not provided\n const keys = Object.keys(jsonData[0]);\n const resolvedXKey = xKey ?? keys[0];\n const resolvedYAxisKey = yAxisKey ?? keys[1];\n const resolvedValueKey = valueKey\n ? Array.isArray(valueKey)\n ? valueKey[0]\n : valueKey\n : keys[2];\n\n // Extract unique X and Y categories\n const xSet = new Set<string | number>();\n const ySet = new Set<string | number>();\n\n for (const row of jsonData) {\n const xVal = jsonValueToChartValue(row[resolvedXKey], false, false);\n const yVal = jsonValueToChartValue(row[resolvedYAxisKey], false, false);\n xSet.add(xVal);\n ySet.add(yVal);\n }\n\n const xData = Array.from(xSet);\n const yAxisData = Array.from(ySet);\n\n // Create index maps for fast lookup\n const xIndexMap = new Map<string | number, number>();\n const yIndexMap = new Map<string | number, number>();\n xData.forEach((v, i) => {\n xIndexMap.set(v, i);\n });\n yAxisData.forEach((v, i) => {\n yIndexMap.set(v, i);\n });\n\n // Build heatmap data and track min/max\n const heatmapData: [number, number, number][] = [];\n let min = Number.POSITIVE_INFINITY;\n let max = Number.NEGATIVE_INFINITY;\n\n for (const row of jsonData) {\n const xVal = jsonValueToChartValue(row[resolvedXKey], false, false);\n const yVal = jsonValueToChartValue(row[resolvedYAxisKey], false, false);\n const value = jsonValueToChartValue(row[resolvedValueKey], true, false);\n\n const xIdx = xIndexMap.get(xVal);\n const yIdx = yIndexMap.get(yVal);\n const numValue = typeof value === \"number\" ? value : 0;\n\n if (xIdx !== undefined && yIdx !== undefined) {\n heatmapData.push([xIdx, yIdx, numValue]);\n min = Math.min(min, numValue);\n max = Math.max(max, numValue);\n }\n }\n\n // Handle edge case where no valid data was found\n if (heatmapData.length === 0) {\n min = 0;\n max = 0;\n }\n\n return {\n xData,\n xField: resolvedXKey,\n yFields: [resolvedValueKey],\n chartType: \"categorical\",\n yAxisData,\n heatmapData,\n min,\n max,\n };\n}\n\n/**\n * Helper to extract JSON array from Arrow table for heatmap processing.\n */\nfunction extractJsonFromArrow(table: Table): Record<string, unknown>[] {\n const result: Record<string, unknown>[] = [];\n const fields = table.schema.fields.map((f) => f.name);\n\n for (let i = 0; i < table.numRows; i++) {\n const row: Record<string, unknown> = {};\n for (const field of fields) {\n const col = table.getChild(field);\n row[field] = col?.get(i);\n }\n result.push(row);\n }\n\n return result;\n}\n"],"mappings":";;;;;;;;;AAwBA,SAAS,aAAa,OAAyB;AAC7C,KAAI,OAAO,UAAU,SAAU,QAAO;AACtC,QAAO,qBAAqB,MAAM,KAAK;;;;;AAMzC,SAAS,eAAe,OAAyB;AAC/C,KAAI,OAAO,UAAU,SAAU,QAAO;AACtC,KAAI,OAAO,UAAU,SAAU,QAAO;AACtC,KAAI,OAAO,UAAU,UAAU;EAC7B,MAAM,UAAU,MAAM,MAAM;AAC5B,MAAI,YAAY,MAAM,aAAa,QAAQ,CAAE,QAAO;EACpD,MAAM,SAAS,OAAO,QAAQ;AAC9B,SAAO,CAAC,OAAO,MAAM,OAAO,IAAI,OAAO,SAAS,OAAO;;AAEzD,QAAO;;;;;AAMT,SAAS,gBAAgB,OAAyB;AAChD,KAAI,OAAO,UAAU,SAAU,QAAO;CACtC,MAAM,UAAU,MAAM,MAAM;AAC5B,KAAI,YAAY,GAAI,QAAO;AAC3B,KAAI,qBAAqB,KAAK,QAAQ,CAAE,QAAO;CAC/C,MAAM,SAAS,OAAO,QAAQ;AAC9B,QAAO,OAAO,MAAM,OAAO,IAAI,CAAC,OAAO,SAAS,OAAO;;;;;AAUzD,SAAS,qBACP,MACA,aAKA;AACA,KAAI,CAAC,QAAQ,KAAK,WAAW,EAC3B,QAAO;EAAE,QAAQ;EAAK,SAAS,CAAC,IAAI;EAAE,WAAW;EAAe;CAGlE,MAAM,WAAW,KAAK;CACtB,MAAM,OAAO,OAAO,KAAK,SAAS;CAGlC,MAAM,aAAa,KAAK,QAAQ,QAAQ;EACtC,MAAM,QAAQ,SAAS;EACvB,MAAM,wBAAwB,oBAAoB,MAAM,MACtD,IAAI,aAAa,CAAC,SAAS,EAAE,CAC9B;EACD,MAAM,oBAAoB,aAAa,MAAM;AAC7C,SAAO,yBAAyB;GAChC;CAGF,IAAI,aAAa,KAAK,QAAQ,QAAQ;EACpC,MAAM,QAAQ,SAAS;AACvB,SACE,gBAAgB,MAAM,IACtB,CAAC,aAAa,MAAM,IACpB,oBAAoB,MAAM,MAAM,IAAI,aAAa,CAAC,SAAS,EAAE,CAAC;GAEhE;AAGF,KAAI,WAAW,WAAW,EACxB,cAAa,KAAK,QAAQ,QAAQ;EAChC,MAAM,QAAQ,SAAS;AACvB,SACE,gBAAgB,MAAM,IACtB,CAAC,aAAa,MAAM,IACpB,CAAC,WAAW,SAAS,IAAI,IACzB,CAAC,IAAI,aAAa,CAAC,SAAS,MAAM;GAEpC;CAIJ,MAAM,gBAAgB,KAAK,QAAQ,QAAQ;EACzC,MAAM,QAAQ,SAAS;AACvB,SAAO,eAAe,MAAM,IAAI,CAAC,WAAW,SAAS,IAAI;GACzD;AAIF,KAFqB,gBAAgB,gBAEhB,WAAW,SAAS,KAAK,WAAW,WAAW,GAAI;EACtE,MAAM,SAAS,WAAW,MAAM,WAAW,MAAM,KAAK;AAKtD,SAAO;GAAE;GAAQ,SAHf,cAAc,SAAS,IACnB,gBACA,KAAK,QAAQ,MAAM,MAAM,OAAO;GACZ,WAAW;GAAe;;CAGtD,MAAM,SAAS,WAAW,MAAM,WAAW,MAAM,KAAK;AAGtD,QAAO;EACL;EACA,SAHA,cAAc,SAAS,IAAI,gBAAgB,KAAK,QAAQ,MAAM,MAAM,OAAO;EAI3E,WAAW,WAAW,SAAS,IAAI,eAAe;EACnD;;;;;AAUH,SAAS,sBACP,OACA,UACA,aACiB;AACjB,KAAI,UAAU,QAAQ,UAAU,OAC9B,QAAO,WAAW,IAAI;AAExB,KAAI,OAAO,UAAU,SACnB,QAAO;AAET,KAAI,OAAO,UAAU,SACnB,QAAO,OAAO,MAAM;AAEtB,KAAI,OAAO,UAAU,UAAU;AAC7B,MAAI,aAAa;GACf,MAAM,YAAY,qBAAqB,MAAM;AAC7C,OAAI,cAAc,KAChB,QAAO;;AAGX,MAAI,UAAU;GACZ,MAAM,UAAU,MAAM,MAAM;GAC5B,MAAM,SAAS,OAAO,QAAQ;AAC9B,OAAI,CAAC,OAAO,MAAM,OAAO,IAAI,OAAO,SAAS,OAAO,CAClD,QAAO;;AAGX,SAAO;;AAET,QAAO,OAAO,MAAM;;;;;AAUtB,SAAS,gBACP,MACA,QACA,SAIA;CACA,MAAM,QAA6B,EAAE;CACrC,MAAM,WAAgD,EAAE;AAExD,MAAK,MAAM,SAAS,QAClB,UAAS,SAAS,EAAE;CAGtB,MAAM,eAAe,KAAK,SAAS,KAAK,aAAa,KAAK,GAAG,QAAQ;AAErE,MAAK,MAAM,OAAO,MAAM;AACtB,QAAM,KAAK,sBAAsB,IAAI,SAAS,OAAO,aAAa,CAAC;AACnE,OAAK,MAAM,SAAS,QAClB,UAAS,OAAO,KAAK,sBAAsB,IAAI,QAAQ,MAAM,MAAM,CAAC;;AAIxE,QAAO;EAAE;EAAO;EAAU;;;;;;AAW5B,SAAgB,mBACd,MACA,MACA,MACA,aACqB;AACrB,KAAI,aAAa,KAAK,EAAE;EACtB,MAAM,QAAQ;EACd,MAAM,WAAW,YAAY,sBAAsB,OAAO,YAAY;EACtE,MAAM,eAAe,QAAQ,SAAS;EACtC,MAAM,gBAAgB,OAClB,MAAM,QAAQ,KAAK,GACjB,OACA,CAAC,KAAK,GACR,SAAS;EAEb,MAAM,EAAE,OAAO,UAAU,UAAU,gBACjC,YAAY,iBAAiB,OAAO,cAAc,cAAc;EAElE,IAAI,QAAQ,aAAa,SAAS;EAClC,IAAI,WAAgD,EAAE;AACtD,OAAK,MAAM,OAAO,cAChB,UAAS,OAAO,aAAa,YAAY,QAAQ,EAAE,CAAC;AAGtD,MAAI,SAAS,cAAc,aACzB,EAAC,CAAE,OAAO,YAAa,wBACrB,OACA,UACA,cACD;WACQ,MAAM,SAAS,KAAK,MAAM,MAAM,eAAe,CACxD,EAAC,CAAE,OAAO,YAAa,qBACrB,OACA,UACA,cACD;AAGH,SAAO;GACL;GACA;GACA,QAAQ;GACR,SAAS;GACT,WAAW,SAAS;GACrB;;CAIH,MAAM,WAAW;CACjB,MAAM,WAAW,qBAAqB,UAAU,YAAY;CAC5D,MAAM,eAAe,QAAQ,SAAS;CACtC,MAAM,gBAAgB,OAClB,MAAM,QAAQ,KAAK,GACjB,OACA,CAAC,KAAK,GACR,SAAS;CAEb,MAAM,EAAE,OAAO,UAAU,UAAU,gBAAgB,gBACjD,UACA,cACA,cACD;CAED,IAAI,QAAQ,aAAa,SAAS;CAClC,IAAI,WAAgD,EAAE;AACtD,MAAK,MAAM,OAAO,cAChB,UAAS,OAAO,aAAa,YAAY,QAAQ,EAAE,CAAC;AAGtD,KAAI,SAAS,cAAc,aACzB,EAAC,CAAE,OAAO,YAAa,wBACrB,OACA,UACA,cACD;UACQ,MAAM,SAAS,KAAK,MAAM,MAAM,eAAe,CACxD,EAAC,CAAE,OAAO,YAAa,qBACrB,OACA,UACA,cACD;AAGH,QAAO;EACL;EACA;EACA,QAAQ;EACR,SAAS;EACT,WAAW,SAAS;EACrB;;;;;;;;;;;AAgCH,SAAgB,qBACd,MACA,MACA,UACA,UACuB;CAEvB,MAAM,WAAW,aAAa,KAAK,GAC/B,qBAAqB,KAAK,GACzB;AAEL,KAAI,SAAS,WAAW,EACtB,QAAO;EACL,OAAO,EAAE;EACT,QAAQ,QAAQ;EAChB,SAAS,EAAE;EACX,WAAW;EACX,WAAW,EAAE;EACb,aAAa,EAAE;EACf,KAAK;EACL,KAAK;EACN;CAIH,MAAM,OAAO,OAAO,KAAK,SAAS,GAAG;CACrC,MAAM,eAAe,QAAQ,KAAK;CAClC,MAAM,mBAAmB,YAAY,KAAK;CAC1C,MAAM,mBAAmB,WACrB,MAAM,QAAQ,SAAS,GACrB,SAAS,KACT,WACF,KAAK;CAGT,MAAM,uBAAO,IAAI,KAAsB;CACvC,MAAM,uBAAO,IAAI,KAAsB;AAEvC,MAAK,MAAM,OAAO,UAAU;EAC1B,MAAM,OAAO,sBAAsB,IAAI,eAAe,OAAO,MAAM;EACnE,MAAM,OAAO,sBAAsB,IAAI,mBAAmB,OAAO,MAAM;AACvE,OAAK,IAAI,KAAK;AACd,OAAK,IAAI,KAAK;;CAGhB,MAAM,QAAQ,MAAM,KAAK,KAAK;CAC9B,MAAM,YAAY,MAAM,KAAK,KAAK;CAGlC,MAAM,4BAAY,IAAI,KAA8B;CACpD,MAAM,4BAAY,IAAI,KAA8B;AACpD,OAAM,SAAS,GAAG,MAAM;AACtB,YAAU,IAAI,GAAG,EAAE;GACnB;AACF,WAAU,SAAS,GAAG,MAAM;AAC1B,YAAU,IAAI,GAAG,EAAE;GACnB;CAGF,MAAM,cAA0C,EAAE;CAClD,IAAI,MAAM,OAAO;CACjB,IAAI,MAAM,OAAO;AAEjB,MAAK,MAAM,OAAO,UAAU;EAC1B,MAAM,OAAO,sBAAsB,IAAI,eAAe,OAAO,MAAM;EACnE,MAAM,OAAO,sBAAsB,IAAI,mBAAmB,OAAO,MAAM;EACvE,MAAM,QAAQ,sBAAsB,IAAI,mBAAmB,MAAM,MAAM;EAEvE,MAAM,OAAO,UAAU,IAAI,KAAK;EAChC,MAAM,OAAO,UAAU,IAAI,KAAK;EAChC,MAAM,WAAW,OAAO,UAAU,WAAW,QAAQ;AAErD,MAAI,SAAS,UAAa,SAAS,QAAW;AAC5C,eAAY,KAAK;IAAC;IAAM;IAAM;IAAS,CAAC;AACxC,SAAM,KAAK,IAAI,KAAK,SAAS;AAC7B,SAAM,KAAK,IAAI,KAAK,SAAS;;;AAKjC,KAAI,YAAY,WAAW,GAAG;AAC5B,QAAM;AACN,QAAM;;AAGR,QAAO;EACL;EACA,QAAQ;EACR,SAAS,CAAC,iBAAiB;EAC3B,WAAW;EACX;EACA;EACA;EACA;EACD;;;;;AAMH,SAAS,qBAAqB,OAAyC;CACrE,MAAM,SAAoC,EAAE;CAC5C,MAAM,SAAS,MAAM,OAAO,OAAO,KAAK,MAAM,EAAE,KAAK;AAErD,MAAK,IAAI,IAAI,GAAG,IAAI,MAAM,SAAS,KAAK;EACtC,MAAM,MAA+B,EAAE;AACvC,OAAK,MAAM,SAAS,OAElB,KAAI,SADQ,MAAM,SAAS,MAAM,EACf,IAAI,EAAE;AAE1B,SAAO,KAAK,IAAI;;AAGlB,QAAO"}
1
+ {"version":3,"file":"normalize.js","names":[],"sources":["../../../src/react/charts/normalize.ts"],"sourcesContent":["import type { Table } from \"apache-arrow\";\n\nimport { ArrowClient } from \"@/js\";\n\nimport { DATE_FIELD_PATTERNS, NAME_FIELD_PATTERNS } from \"./constants\";\nimport type {\n ChartData,\n NormalizedChartData,\n NormalizedChartDataBase,\n Orientation,\n} from \"./types\";\nimport { isArrowTable } from \"./types\";\nimport {\n sortNumericAscending,\n sortTimeSeriesAscending,\n toChartArray,\n toChronologicalValue,\n} from \"./utils\";\n\n// ============================================================================\n// Type Detection Helpers\n// ============================================================================\n\n/**\n * Checks if a value is a date string a time axis can plot.\n */\nfunction isDateString(value: unknown): boolean {\n if (typeof value !== \"string\") return false;\n return toChronologicalValue(value) !== null;\n}\n\n/**\n * Checks if a value is numeric (number or numeric string)\n */\nfunction isNumericValue(value: unknown): boolean {\n if (typeof value === \"number\") return true;\n if (typeof value === \"bigint\") return true;\n if (typeof value === \"string\") {\n const trimmed = value.trim();\n if (trimmed === \"\" || isDateString(trimmed)) return false;\n const parsed = Number(trimmed);\n return !Number.isNaN(parsed) && Number.isFinite(parsed);\n }\n return false;\n}\n\n/**\n * Checks if a value looks like a category/label (non-numeric string)\n */\nfunction isCategoryValue(value: unknown): boolean {\n if (typeof value !== \"string\") return false;\n const trimmed = value.trim();\n if (trimmed === \"\") return false;\n if (/^\\d{4}-\\d{2}-\\d{2}/.test(trimmed)) return false;\n const parsed = Number(trimmed);\n return Number.isNaN(parsed) || !Number.isFinite(parsed);\n}\n\n// ============================================================================\n// Field Detection\n// ============================================================================\n\n/**\n * Detects fields from JSON data for charting\n */\nfunction detectFieldsFromJson(\n data: Record<string, unknown>[],\n orientation?: Orientation,\n): {\n xField: string;\n yFields: string[];\n chartType: \"timeseries\" | \"categorical\";\n} {\n if (!data || data.length === 0) {\n return { xField: \"x\", yFields: [\"y\"], chartType: \"categorical\" };\n }\n\n const firstRow = data[0];\n const keys = Object.keys(firstRow);\n\n // Detect date fields by key name OR by value being a date string\n const dateFields = keys.filter((key) => {\n const value = firstRow[key];\n const keyMatchesDatePattern = DATE_FIELD_PATTERNS.some((p) =>\n key.toLowerCase().includes(p),\n );\n const valueIsDateString = isDateString(value);\n return keyMatchesDatePattern || valueIsDateString;\n });\n\n // Detect name/category fields by pattern AND value type\n let nameFields = keys.filter((key) => {\n const value = firstRow[key];\n return (\n isCategoryValue(value) &&\n !isDateString(value) &&\n NAME_FIELD_PATTERNS.some((p) => key.toLowerCase().includes(p))\n );\n });\n\n // Fallback: any string field that isn't a date or ID\n if (nameFields.length === 0) {\n nameFields = keys.filter((key) => {\n const value = firstRow[key];\n return (\n isCategoryValue(value) &&\n !isDateString(value) &&\n !dateFields.includes(key) &&\n !key.toLowerCase().endsWith(\"_id\")\n );\n });\n }\n\n // Detect numeric fields\n const numericFields = keys.filter((key) => {\n const value = firstRow[key];\n return isNumericValue(value) && !dateFields.includes(key);\n });\n\n const isHorizontal = orientation === \"horizontal\";\n\n if (isHorizontal || (nameFields.length > 0 && dateFields.length === 0)) {\n const xField = nameFields[0] || dateFields[0] || keys[0];\n const yFields =\n numericFields.length > 0\n ? numericFields\n : keys.filter((k) => k !== xField);\n return { xField, yFields, chartType: \"categorical\" };\n }\n\n const xField = dateFields[0] || nameFields[0] || keys[0];\n const yFields =\n numericFields.length > 0 ? numericFields : keys.filter((k) => k !== xField);\n return {\n xField,\n yFields,\n chartType: dateFields.length > 0 ? \"timeseries\" : \"categorical\",\n };\n}\n\n// ============================================================================\n// Value Conversion\n// ============================================================================\n\n/**\n * Converts a JSON value to a chart-compatible value.\n */\nfunction jsonValueToChartValue(\n value: unknown,\n isYValue: boolean,\n isDateField: boolean,\n): string | number {\n if (value === null || value === undefined) {\n return isYValue ? 0 : \"\";\n }\n if (typeof value === \"number\") {\n return value;\n }\n if (typeof value === \"bigint\") {\n return Number(value);\n }\n if (typeof value === \"string\") {\n if (isDateField) {\n const timestamp = toChronologicalValue(value);\n if (timestamp !== null) {\n return timestamp;\n }\n }\n if (isYValue) {\n const trimmed = value.trim();\n const parsed = Number(trimmed);\n if (!Number.isNaN(parsed) && Number.isFinite(parsed)) {\n return parsed;\n }\n }\n return value;\n }\n return String(value);\n}\n\n// ============================================================================\n// Data Extraction\n// ============================================================================\n\n/**\n * Extracts chart data from JSON array\n */\nfunction extractFromJson(\n data: Record<string, unknown>[],\n xField: string,\n yFields: string[],\n): {\n xData: (string | number)[];\n yDataMap: Record<string, (string | number)[]>;\n} {\n const xData: (string | number)[] = [];\n const yDataMap: Record<string, (string | number)[]> = {};\n\n for (const field of yFields) {\n yDataMap[field] = [];\n }\n\n const xIsDateField = data.length > 0 && isDateString(data[0][xField]);\n\n for (const row of data) {\n xData.push(jsonValueToChartValue(row[xField], false, xIsDateField));\n for (const field of yFields) {\n yDataMap[field].push(jsonValueToChartValue(row[field], true, false));\n }\n }\n\n return { xData, yDataMap };\n}\n\n// ============================================================================\n// Main Normalization Function\n// ============================================================================\n\n/**\n * Normalizes chart data from either Arrow or JSON format.\n * Converts BigInt and Date values to chart-compatible types.\n */\nexport function normalizeChartData(\n data: ChartData,\n xKey?: string,\n yKey?: string | string[],\n orientation?: Orientation,\n): NormalizedChartData {\n if (isArrowTable(data)) {\n const table = data as Table;\n const detected = ArrowClient.detectFieldsFromArrow(table, orientation);\n const resolvedXKey = xKey ?? detected.xField;\n const resolvedYKeys = yKey\n ? Array.isArray(yKey)\n ? yKey\n : [yKey]\n : detected.yFields;\n\n const { xData: rawXData, yDataMap: rawYDataMap } =\n ArrowClient.extractChartData(table, resolvedXKey, resolvedYKeys);\n\n let xData = toChartArray(rawXData);\n let yDataMap: Record<string, (string | number)[]> = {};\n for (const key of resolvedYKeys) {\n yDataMap[key] = toChartArray(rawYDataMap[key] ?? []);\n }\n\n if (detected.chartType === \"timeseries\") {\n ({ xData, yDataMap } = sortTimeSeriesAscending(\n xData,\n yDataMap,\n resolvedYKeys,\n ));\n } else if (xData.length > 0 && xData.every(isNumericValue)) {\n ({ xData, yDataMap } = sortNumericAscending(\n xData,\n yDataMap,\n resolvedYKeys,\n ));\n }\n\n return {\n xData,\n yDataMap,\n xField: resolvedXKey,\n yFields: resolvedYKeys,\n chartType: detected.chartType,\n };\n }\n\n // JSON Array\n const jsonData = data as Record<string, unknown>[];\n const detected = detectFieldsFromJson(jsonData, orientation);\n const resolvedXKey = xKey ?? detected.xField;\n const resolvedYKeys = yKey\n ? Array.isArray(yKey)\n ? yKey\n : [yKey]\n : detected.yFields;\n\n const { xData: rawXData, yDataMap: rawYDataMap } = extractFromJson(\n jsonData,\n resolvedXKey,\n resolvedYKeys,\n );\n\n let xData = toChartArray(rawXData);\n let yDataMap: Record<string, (string | number)[]> = {};\n for (const key of resolvedYKeys) {\n yDataMap[key] = toChartArray(rawYDataMap[key] ?? []);\n }\n\n if (detected.chartType === \"timeseries\") {\n ({ xData, yDataMap } = sortTimeSeriesAscending(\n xData,\n yDataMap,\n resolvedYKeys,\n ));\n } else if (xData.length > 0 && xData.every(isNumericValue)) {\n ({ xData, yDataMap } = sortNumericAscending(\n xData,\n yDataMap,\n resolvedYKeys,\n ));\n }\n\n return {\n xData,\n yDataMap,\n xField: resolvedXKey,\n yFields: resolvedYKeys,\n chartType: detected.chartType,\n };\n}\n\n// ============================================================================\n// Heatmap Data Normalization\n// ============================================================================\n\n/**\n * Normalized data for heatmap charts.\n * Extends base (not NormalizedChartData) because heatmaps don't use yDataMap.\n * Instead, they use heatmapData which contains [xIndex, yIndex, value] tuples.\n */\nexport interface NormalizedHeatmapData extends NormalizedChartDataBase {\n /** Y-axis categories (rows) */\n yAxisData: (string | number)[];\n /** Heatmap data as [xIndex, yIndex, value] tuples */\n heatmapData: [number, number, number][];\n /** Min value in the data */\n min: number;\n /** Max value in the data */\n max: number;\n}\n\n/**\n * Normalizes data specifically for heatmap charts.\n * Expects data in format: `{ xKey: string, yAxisKey: string, valueKey: number }`\n *\n * @param data - Raw data (Arrow Table or JSON array)\n * @param xKey - Field key for X-axis (columns)\n * @param yAxisKey - Field key for Y-axis (rows)\n * @param valueKey - Field key for the cell values\n */\nexport function normalizeHeatmapData(\n data: ChartData,\n xKey?: string,\n yAxisKey?: string,\n valueKey?: string | string[],\n): NormalizedHeatmapData {\n // First, get the standard normalization\n const jsonData = isArrowTable(data)\n ? extractJsonFromArrow(data)\n : (data as Record<string, unknown>[]);\n\n if (jsonData.length === 0) {\n return {\n xData: [],\n xField: xKey ?? \"x\",\n yFields: [],\n chartType: \"categorical\",\n yAxisData: [],\n heatmapData: [],\n min: 0,\n max: 0,\n };\n }\n\n // Detect fields if not provided\n const keys = Object.keys(jsonData[0]);\n const resolvedXKey = xKey ?? keys[0];\n const resolvedYAxisKey = yAxisKey ?? keys[1];\n const resolvedValueKey = valueKey\n ? Array.isArray(valueKey)\n ? valueKey[0]\n : valueKey\n : keys[2];\n\n // Extract unique X and Y categories\n const xSet = new Set<string | number>();\n const ySet = new Set<string | number>();\n\n for (const row of jsonData) {\n const xVal = jsonValueToChartValue(row[resolvedXKey], false, false);\n const yVal = jsonValueToChartValue(row[resolvedYAxisKey], false, false);\n xSet.add(xVal);\n ySet.add(yVal);\n }\n\n const xData = Array.from(xSet);\n const yAxisData = Array.from(ySet);\n\n // Create index maps for fast lookup\n const xIndexMap = new Map<string | number, number>();\n const yIndexMap = new Map<string | number, number>();\n xData.forEach((v, i) => {\n xIndexMap.set(v, i);\n });\n yAxisData.forEach((v, i) => {\n yIndexMap.set(v, i);\n });\n\n // Build heatmap data and track min/max\n const heatmapData: [number, number, number][] = [];\n let min = Number.POSITIVE_INFINITY;\n let max = Number.NEGATIVE_INFINITY;\n\n for (const row of jsonData) {\n const xVal = jsonValueToChartValue(row[resolvedXKey], false, false);\n const yVal = jsonValueToChartValue(row[resolvedYAxisKey], false, false);\n const value = jsonValueToChartValue(row[resolvedValueKey], true, false);\n\n const xIdx = xIndexMap.get(xVal);\n const yIdx = yIndexMap.get(yVal);\n const numValue = typeof value === \"number\" ? value : 0;\n\n if (xIdx !== undefined && yIdx !== undefined) {\n heatmapData.push([xIdx, yIdx, numValue]);\n min = Math.min(min, numValue);\n max = Math.max(max, numValue);\n }\n }\n\n // Handle edge case where no valid data was found\n if (heatmapData.length === 0) {\n min = 0;\n max = 0;\n }\n\n return {\n xData,\n xField: resolvedXKey,\n yFields: [resolvedValueKey],\n chartType: \"categorical\",\n yAxisData,\n heatmapData,\n min,\n max,\n };\n}\n\n/**\n * Helper to extract JSON array from Arrow table for heatmap processing.\n */\nfunction extractJsonFromArrow(table: Table): Record<string, unknown>[] {\n const result: Record<string, unknown>[] = [];\n const fields = table.schema.fields.map((f) => f.name);\n\n for (let i = 0; i < table.numRows; i++) {\n const row: Record<string, unknown> = {};\n for (const field of fields) {\n const col = table.getChild(field);\n row[field] = col?.get(i);\n }\n result.push(row);\n }\n\n return result;\n}\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","names":[],"sources":["../../../../src/react/charts/pie/index.tsx"],"mappings":";;;;;;;AAaA;;;;;;cAAa,QAAA;EAAA,QAAwD,aAAA,GAAA,kBAAA,CAAA,GAAA,CAAA,OAAA;;;;AAWrE;;;;;;;;cAAa,UAAA;EAAA,QAAgE,eAAA,GAAA,kBAAA,CAAA,GAAA,CAAA,OAAA"}
1
+ {"version":3,"file":"index.d.ts","names":[],"sources":["../../../../src/react/charts/pie/index.tsx"],"mappings":";;;;;;;AAcA;;;;;;cAAa,QAAA;EAAA,QAAwD,aAAA,GAAA,kBAAA,CAAA,GAAA,CAAA,OAAA;;;;AAWrE;;;;;;;;cAAa,UAAA;EAAA,QAAgE,eAAA,GAAA,kBAAA,CAAA,GAAA,CAAA,OAAA"}
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":[],"sources":["../../../../src/react/charts/pie/index.tsx"],"sourcesContent":["import type { JSX } from \"react\";\nimport { createChart } from \"../create-chart\";\nimport type { DonutChartProps, PieChartProps } from \"../types\";\n\n/**\n * Pie Chart component for proportional data visualization.\n *\n * **Important:** This component uses Apache ECharts architecture. Configure it via props, not by passing child components.\n *\n * **Best Practice:** Use the built-in data fetching by passing `queryKey` and `parameters` props instead of pre-fetching data with `useAnalyticsQuery`.\n *\n * Supports both query mode (queryKey + parameters) and data mode (static data).\n */\nexport const PieChart = createChart<PieChartProps>(\"pie\", \"PieChart\");\n\n/**\n * Donut Chart component (Pie chart with inner radius).\n *\n * **Important:** This component uses Apache ECharts architecture. Configure it via props, not by passing child components.\n *\n * **Best Practice:** Use the built-in data fetching by passing `queryKey` and `parameters` props instead of pre-fetching data with `useAnalyticsQuery`.\n *\n * Supports both query mode (queryKey + parameters) and data mode (static data).\n */\nexport const DonutChart = createChart<DonutChartProps>(\"donut\", \"DonutChart\");\n\n// Type-only definitions for documentation generation (not used at runtime)\n/**\n * Pie Chart component for proportional data visualization.\n *\n * **Important:** This component uses Apache ECharts architecture. Configure it via props, not by passing child components.\n *\n * **Best Practice:** Use the built-in data fetching by passing `queryKey` and `parameters` props instead of pre-fetching data with `useAnalyticsQuery`.\n *\n * Supports both query mode (queryKey + parameters) and data mode (static data).\n */\nfunction _PieChartDoc(props: PieChartProps): JSX.Element {\n return PieChart(props);\n}\n\n/**\n * Donut Chart component (Pie chart with inner radius).\n *\n * **Important:** This component uses Apache ECharts architecture. Configure it via props, not by passing child components.\n *\n * **Best Practice:** Use the built-in data fetching by passing `queryKey` and `parameters` props instead of pre-fetching data with `useAnalyticsQuery`.\n *\n * Supports both query mode (queryKey + parameters) and data mode (static data).\n */\nfunction _DonutChartDoc(props: DonutChartProps): JSX.Element {\n return DonutChart(props);\n}\n"],"mappings":";;;;;;;;;;;;AAaA,MAAa,WAAW,YAA2B,OAAO,WAAW;;;;;;;;;;AAWrE,MAAa,aAAa,YAA6B,SAAS,aAAa"}
1
+ {"version":3,"file":"index.js","names":[],"sources":["../../../../src/react/charts/pie/index.tsx"],"sourcesContent":["import type { JSX } from \"react\";\n\nimport { createChart } from \"../create-chart\";\nimport type { DonutChartProps, PieChartProps } from \"../types\";\n\n/**\n * Pie Chart component for proportional data visualization.\n *\n * **Important:** This component uses Apache ECharts architecture. Configure it via props, not by passing child components.\n *\n * **Best Practice:** Use the built-in data fetching by passing `queryKey` and `parameters` props instead of pre-fetching data with `useAnalyticsQuery`.\n *\n * Supports both query mode (queryKey + parameters) and data mode (static data).\n */\nexport const PieChart = createChart<PieChartProps>(\"pie\", \"PieChart\");\n\n/**\n * Donut Chart component (Pie chart with inner radius).\n *\n * **Important:** This component uses Apache ECharts architecture. Configure it via props, not by passing child components.\n *\n * **Best Practice:** Use the built-in data fetching by passing `queryKey` and `parameters` props instead of pre-fetching data with `useAnalyticsQuery`.\n *\n * Supports both query mode (queryKey + parameters) and data mode (static data).\n */\nexport const DonutChart = createChart<DonutChartProps>(\"donut\", \"DonutChart\");\n\n// Type-only definitions for documentation generation (not used at runtime)\n/**\n * Pie Chart component for proportional data visualization.\n *\n * **Important:** This component uses Apache ECharts architecture. Configure it via props, not by passing child components.\n *\n * **Best Practice:** Use the built-in data fetching by passing `queryKey` and `parameters` props instead of pre-fetching data with `useAnalyticsQuery`.\n *\n * Supports both query mode (queryKey + parameters) and data mode (static data).\n */\nfunction _PieChartDoc(props: PieChartProps): JSX.Element {\n return PieChart(props);\n}\n\n/**\n * Donut Chart component (Pie chart with inner radius).\n *\n * **Important:** This component uses Apache ECharts architecture. Configure it via props, not by passing child components.\n *\n * **Best Practice:** Use the built-in data fetching by passing `queryKey` and `parameters` props instead of pre-fetching data with `useAnalyticsQuery`.\n *\n * Supports both query mode (queryKey + parameters) and data mode (static data).\n */\nfunction _DonutChartDoc(props: DonutChartProps): JSX.Element {\n return DonutChart(props);\n}\n"],"mappings":";;;;;;;;;;;;AAcA,MAAa,WAAW,YAA2B,OAAO,WAAW;;;;;;;;;;AAWrE,MAAa,aAAa,YAA6B,SAAS,aAAa"}
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","names":[],"sources":["../../../../src/react/charts/radar/index.tsx"],"mappings":";;;;;;;AAaA;;;;;;cAAa,UAAA;EAAA,QAAgE,eAAA,GAAA,kBAAA,CAAA,GAAA,CAAA,OAAA"}
1
+ {"version":3,"file":"index.d.ts","names":[],"sources":["../../../../src/react/charts/radar/index.tsx"],"mappings":";;;;;;;AAcA;;;;;;cAAa,UAAA;EAAA,QAAgE,eAAA,GAAA,kBAAA,CAAA,GAAA,CAAA,OAAA"}
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":[],"sources":["../../../../src/react/charts/radar/index.tsx"],"sourcesContent":["import type { JSX } from \"react\";\nimport { createChart } from \"../create-chart\";\nimport type { RadarChartProps } from \"../types\";\n\n/**\n * Radar Chart component for multi-dimensional data comparison.\n *\n * **Important:** This component uses Apache ECharts architecture. Configure it via props, not by passing child components.\n *\n * **Best Practice:** Use the built-in data fetching by passing `queryKey` and `parameters` props instead of pre-fetching data with `useAnalyticsQuery`.\n *\n * Supports both query mode (queryKey + parameters) and data mode (static data).\n */\nexport const RadarChart = createChart<RadarChartProps>(\"radar\", \"RadarChart\");\n\n// Type-only definition for documentation generation (not used at runtime)\n/**\n * Radar Chart component for multi-dimensional data comparison.\n *\n * **Important:** This component uses Apache ECharts architecture. Configure it via props, not by passing child components.\n *\n * **Best Practice:** Use the built-in data fetching by passing `queryKey` and `parameters` props instead of pre-fetching data with `useAnalyticsQuery`.\n *\n * Supports both query mode (queryKey + parameters) and data mode (static data).\n */\nfunction _RadarChartDoc(props: RadarChartProps): JSX.Element {\n return RadarChart(props);\n}\n"],"mappings":";;;;;;;;;;;;AAaA,MAAa,aAAa,YAA6B,SAAS,aAAa"}
1
+ {"version":3,"file":"index.js","names":[],"sources":["../../../../src/react/charts/radar/index.tsx"],"sourcesContent":["import type { JSX } from \"react\";\n\nimport { createChart } from \"../create-chart\";\nimport type { RadarChartProps } from \"../types\";\n\n/**\n * Radar Chart component for multi-dimensional data comparison.\n *\n * **Important:** This component uses Apache ECharts architecture. Configure it via props, not by passing child components.\n *\n * **Best Practice:** Use the built-in data fetching by passing `queryKey` and `parameters` props instead of pre-fetching data with `useAnalyticsQuery`.\n *\n * Supports both query mode (queryKey + parameters) and data mode (static data).\n */\nexport const RadarChart = createChart<RadarChartProps>(\"radar\", \"RadarChart\");\n\n// Type-only definition for documentation generation (not used at runtime)\n/**\n * Radar Chart component for multi-dimensional data comparison.\n *\n * **Important:** This component uses Apache ECharts architecture. Configure it via props, not by passing child components.\n *\n * **Best Practice:** Use the built-in data fetching by passing `queryKey` and `parameters` props instead of pre-fetching data with `useAnalyticsQuery`.\n *\n * Supports both query mode (queryKey + parameters) and data mode (static data).\n */\nfunction _RadarChartDoc(props: RadarChartProps): JSX.Element {\n return RadarChart(props);\n}\n"],"mappings":";;;;;;;;;;;;AAcA,MAAa,aAAa,YAA6B,SAAS,aAAa"}
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","names":[],"sources":["../../../../src/react/charts/scatter/index.tsx"],"mappings":";;;;;;;AAaA;;;;;;cAAa,YAAA;EAAA,QAGZ,iBAAA,GAAA,kBAAA,CAAA,GAAA,CAAA,OAAA"}
1
+ {"version":3,"file":"index.d.ts","names":[],"sources":["../../../../src/react/charts/scatter/index.tsx"],"mappings":";;;;;;;AAcA;;;;;;cAAa,YAAA;EAAA,QAGZ,iBAAA,GAAA,kBAAA,CAAA,GAAA,CAAA,OAAA"}
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":[],"sources":["../../../../src/react/charts/scatter/index.tsx"],"sourcesContent":["import type { JSX } from \"react\";\nimport { createChart } from \"../create-chart\";\nimport type { ScatterChartProps } from \"../types\";\n\n/**\n * Scatter Chart component for correlation and distribution visualization.\n *\n * **Important:** This component uses Apache ECharts architecture. Configure it via props, not by passing child components.\n *\n * **Best Practice:** Use the built-in data fetching by passing `queryKey` and `parameters` props instead of pre-fetching data with `useAnalyticsQuery`.\n *\n * Supports both query mode (queryKey + parameters) and data mode (static data).\n */\nexport const ScatterChart = createChart<ScatterChartProps>(\n \"scatter\",\n \"ScatterChart\",\n);\n\n// Type-only definition for documentation generation (not used at runtime)\n/**\n * Scatter Chart component for correlation and distribution visualization.\n *\n * **Important:** This component uses Apache ECharts architecture. Configure it via props, not by passing child components.\n *\n * **Best Practice:** Use the built-in data fetching by passing `queryKey` and `parameters` props instead of pre-fetching data with `useAnalyticsQuery`.\n *\n * Supports both query mode (queryKey + parameters) and data mode (static data).\n */\nfunction _ScatterChartDoc(props: ScatterChartProps): JSX.Element {\n return ScatterChart(props);\n}\n"],"mappings":";;;;;;;;;;;;AAaA,MAAa,eAAe,YAC1B,WACA,eACD"}
1
+ {"version":3,"file":"index.js","names":[],"sources":["../../../../src/react/charts/scatter/index.tsx"],"sourcesContent":["import type { JSX } from \"react\";\n\nimport { createChart } from \"../create-chart\";\nimport type { ScatterChartProps } from \"../types\";\n\n/**\n * Scatter Chart component for correlation and distribution visualization.\n *\n * **Important:** This component uses Apache ECharts architecture. Configure it via props, not by passing child components.\n *\n * **Best Practice:** Use the built-in data fetching by passing `queryKey` and `parameters` props instead of pre-fetching data with `useAnalyticsQuery`.\n *\n * Supports both query mode (queryKey + parameters) and data mode (static data).\n */\nexport const ScatterChart = createChart<ScatterChartProps>(\n \"scatter\",\n \"ScatterChart\",\n);\n\n// Type-only definition for documentation generation (not used at runtime)\n/**\n * Scatter Chart component for correlation and distribution visualization.\n *\n * **Important:** This component uses Apache ECharts architecture. Configure it via props, not by passing child components.\n *\n * **Best Practice:** Use the built-in data fetching by passing `queryKey` and `parameters` props instead of pre-fetching data with `useAnalyticsQuery`.\n *\n * Supports both query mode (queryKey + parameters) and data mode (static data).\n */\nfunction _ScatterChartDoc(props: ScatterChartProps): JSX.Element {\n return ScatterChart(props);\n}\n"],"mappings":";;;;;;;;;;;;AAcA,MAAa,eAAe,YAC1B,WACA,eACD"}
@@ -1 +1 @@
1
- {"version":3,"file":"theme.d.ts","names":[],"sources":["../../../src/react/charts/theme.ts"],"mappings":";;;AAyNA;;;;;AAmBA;AAnBA,iBAxBgB,cAAA,CACd,OAAA,GAAS,iBAAA;;;;;;iBAuBK,gBAAA,CAAA,GAAoB,aAAA;;;;;iBAmBpB,iBAAA,CAAA;EACd,WAAA;EACA,UAAA;EACA,SAAA;AAAA"}
1
+ {"version":3,"file":"theme.d.ts","names":[],"sources":["../../../src/react/charts/theme.ts"],"mappings":";;;AA0NA;;;;;AAmBA;AAnBA,iBAxBgB,cAAA,CACd,OAAA,GAAS,iBAAA;;;;;;iBAuBK,gBAAA,CAAA,GAAoB,aAAA;;;;;iBAmBpB,iBAAA,CAAA;EACd,WAAA;EACA,UAAA;EACA,SAAA;AAAA"}
@@ -1 +1 @@
1
- {"version":3,"file":"theme.js","names":[],"sources":["../../../src/react/charts/theme.ts"],"sourcesContent":["import { useCallback, useEffect, useRef, useState } from \"react\";\nimport {\n CHART_COLOR_VARS_CATEGORICAL,\n CHART_COLOR_VARS_DIVERGING,\n CHART_COLOR_VARS_SEQUENTIAL,\n CHART_UI_VARS,\n FALLBACK_COLORS_CATEGORICAL,\n FALLBACK_COLORS_DIVERGING,\n FALLBACK_COLORS_SEQUENTIAL,\n FALLBACK_UI_TOKENS,\n} from \"./constants\";\nimport type { ChartColorPalette, ChartUITokens } from \"./types\";\n\n// ============================================================================\n// Theme Colors (resolved from CSS variables)\n// ============================================================================\n\nconst PALETTE_CONFIG: Record<\n ChartColorPalette,\n { vars: readonly string[]; fallback: string[] }\n> = {\n categorical: {\n vars: CHART_COLOR_VARS_CATEGORICAL,\n fallback: FALLBACK_COLORS_CATEGORICAL,\n },\n sequential: {\n vars: CHART_COLOR_VARS_SEQUENTIAL,\n fallback: FALLBACK_COLORS_SEQUENTIAL,\n },\n diverging: {\n vars: CHART_COLOR_VARS_DIVERGING,\n fallback: FALLBACK_COLORS_DIVERGING,\n },\n};\n\n// ============================================================================\n// Module-Level Caching\n// ============================================================================\n\n/**\n * Cache for computed theme colors to avoid repeated CSS variable lookups.\n * Cache is cleared when theme change events fire (MutationObserver/matchMedia).\n */\nconst colorCache = new Map<string, string[]>();\n\n/** Cache for the computed chart UI tokens (axis text, grid lines). */\nlet uiTokenCache: ChartUITokens | null = null;\n\n/** Clears both theme caches (palette colors + UI tokens). */\nfunction clearThemeCaches(): void {\n colorCache.clear();\n uiTokenCache = null;\n}\n\n/**\n * Gets theme colors with module-level caching.\n * Avoids repeated CSS variable lookups for the same palette within a theme.\n */\nfunction getThemeColors(palette: ChartColorPalette = \"categorical\"): string[] {\n const config = PALETTE_CONFIG[palette];\n\n if (typeof window === \"undefined\") return config.fallback;\n\n // Return cached colors if available\n const cached = colorCache.get(palette);\n if (cached) {\n return cached;\n }\n\n // Compute colors from CSS variables\n const styles = getComputedStyle(document.documentElement);\n const colors: string[] = [];\n\n for (const varName of config.vars) {\n const value = styles.getPropertyValue(varName).trim();\n if (value) colors.push(value);\n }\n\n const result = colors.length > 0 ? colors : config.fallback;\n\n // Cache the result\n colorCache.set(palette, result);\n\n return result;\n}\n\n/**\n * Gets the chart UI tokens (axis text, titles, grid lines) with caching.\n * Authored in `hsla` because ECharts/zrender cannot parse the `oklch` semantic\n * tokens.\n */\nfunction getThemeUITokens(): ChartUITokens {\n if (typeof window === \"undefined\") return FALLBACK_UI_TOKENS;\n\n if (uiTokenCache) return uiTokenCache;\n\n const styles = getComputedStyle(document.documentElement);\n const read = (varName: string, fallback: string): string => {\n const value = styles.getPropertyValue(varName).trim();\n return value || fallback;\n };\n\n uiTokenCache = {\n axisLabel: read(CHART_UI_VARS.axisLabel, FALLBACK_UI_TOKENS.axisLabel),\n axisTitle: read(CHART_UI_VARS.axisTitle, FALLBACK_UI_TOKENS.axisTitle),\n grid: read(CHART_UI_VARS.grid, FALLBACK_UI_TOKENS.grid),\n tooltipBg: read(CHART_UI_VARS.tooltipBg, FALLBACK_UI_TOKENS.tooltipBg),\n };\n\n return uiTokenCache;\n}\n\n// ============================================================================\n// Theme Change Subscription (shared)\n// ============================================================================\n\n// One shared, ref-counted matchMedia + MutationObserver for the whole module: a\n// theme change clears the caches once, then notifies every subscribed hook.\nconst subscribers = new Set<() => void>();\nlet teardownListeners: (() => void) | null = null;\n\nfunction handleThemeChange(): void {\n clearThemeCaches();\n // Snapshot: a subscriber may add/remove itself during iteration.\n for (const notify of [...subscribers]) notify();\n}\n\nfunction ensureListening(): void {\n if (teardownListeners) return;\n\n const mediaQuery = window.matchMedia(\"(prefers-color-scheme: dark)\");\n mediaQuery.addEventListener(\"change\", handleThemeChange);\n\n const observer = new MutationObserver(handleThemeChange);\n observer.observe(document.documentElement, {\n attributes: true,\n attributeFilter: [\"class\", \"data-theme\", \"data-mode\"],\n });\n\n teardownListeners = () => {\n mediaQuery.removeEventListener(\"change\", handleThemeChange);\n observer.disconnect();\n };\n}\n\n/**\n * Resets all module-level theme state: clears both caches and drops the shared\n * subscription (removing the matchMedia/MutationObserver listeners). Used by\n * tests to isolate runs; the runtime only ever clears caches.\n * @internal\n */\nexport function resetThemeCache(): void {\n clearThemeCaches();\n subscribers.clear();\n teardownListeners?.();\n teardownListeners = null;\n}\n\n/**\n * Subscribes `onChange` to theme changes (system color scheme via matchMedia, or\n * a theme attribute on the root element). Listeners are shared and ref-counted,\n * so each hook subscribes once per mount regardless of how `onChange`'s identity\n * changes between renders.\n */\nfunction useThemeChangeEffect(onChange: () => void): void {\n const onChangeRef = useRef(onChange);\n onChangeRef.current = onChange;\n\n useEffect(() => {\n const subscriber = () => onChangeRef.current();\n subscribers.add(subscriber);\n ensureListening();\n\n return () => {\n subscribers.delete(subscriber);\n if (subscribers.size === 0 && teardownListeners) {\n teardownListeners();\n teardownListeners = null;\n }\n };\n }, []);\n}\n\n// ============================================================================\n// Hooks\n// ============================================================================\n\n/**\n * Hook to get theme colors with automatic updates on theme change.\n * Re-resolves CSS variables when color scheme or theme attributes change.\n *\n * @param palette - Color palette type: \"categorical\" (default), \"sequential\", or \"diverging\"\n */\nexport function useThemeColors(\n palette: ChartColorPalette = \"categorical\",\n): string[] {\n const [colors, setColors] = useState<string[]>(() =>\n typeof window === \"undefined\"\n ? PALETTE_CONFIG[palette].fallback\n : getThemeColors(palette),\n );\n\n // Re-resolve colors when the theme changes.\n const updateColors = useCallback(() => {\n setColors(getThemeColors(palette));\n }, [palette]);\n\n useThemeChangeEffect(updateColors);\n\n return colors;\n}\n\n/**\n * Hook to get the chart UI tokens (axis text, titles, grid lines) with automatic\n * updates on theme change. Pass the result into the ECharts option builders so\n * axis labels, lines, legends, and titles follow the active theme.\n */\nexport function useChartUITokens(): ChartUITokens {\n const [tokens, setTokens] = useState<ChartUITokens>(() =>\n typeof window === \"undefined\" ? FALLBACK_UI_TOKENS : getThemeUITokens(),\n );\n\n // Re-resolve tokens when the theme changes.\n const updateTokens = useCallback(() => {\n setTokens(getThemeUITokens());\n }, []);\n\n useThemeChangeEffect(updateTokens);\n\n return tokens;\n}\n\n/**\n * Hook to get all three color palettes at once.\n * Useful when a component needs access to multiple palette types.\n */\nexport function useAllThemeColors(): {\n categorical: string[];\n sequential: string[];\n diverging: string[];\n} {\n const categorical = useThemeColors(\"categorical\");\n const sequential = useThemeColors(\"sequential\");\n const diverging = useThemeColors(\"diverging\");\n\n return { categorical, sequential, diverging };\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"theme.js","names":[],"sources":["../../../src/react/charts/theme.ts"],"sourcesContent":["import { useCallback, useEffect, useRef, useState } from \"react\";\n\nimport {\n CHART_COLOR_VARS_CATEGORICAL,\n CHART_COLOR_VARS_DIVERGING,\n CHART_COLOR_VARS_SEQUENTIAL,\n CHART_UI_VARS,\n FALLBACK_COLORS_CATEGORICAL,\n FALLBACK_COLORS_DIVERGING,\n FALLBACK_COLORS_SEQUENTIAL,\n FALLBACK_UI_TOKENS,\n} from \"./constants\";\nimport type { ChartColorPalette, ChartUITokens } from \"./types\";\n\n// ============================================================================\n// Theme Colors (resolved from CSS variables)\n// ============================================================================\n\nconst PALETTE_CONFIG: Record<\n ChartColorPalette,\n { vars: readonly string[]; fallback: string[] }\n> = {\n categorical: {\n vars: CHART_COLOR_VARS_CATEGORICAL,\n fallback: FALLBACK_COLORS_CATEGORICAL,\n },\n sequential: {\n vars: CHART_COLOR_VARS_SEQUENTIAL,\n fallback: FALLBACK_COLORS_SEQUENTIAL,\n },\n diverging: {\n vars: CHART_COLOR_VARS_DIVERGING,\n fallback: FALLBACK_COLORS_DIVERGING,\n },\n};\n\n// ============================================================================\n// Module-Level Caching\n// ============================================================================\n\n/**\n * Cache for computed theme colors to avoid repeated CSS variable lookups.\n * Cache is cleared when theme change events fire (MutationObserver/matchMedia).\n */\nconst colorCache = new Map<string, string[]>();\n\n/** Cache for the computed chart UI tokens (axis text, grid lines). */\nlet uiTokenCache: ChartUITokens | null = null;\n\n/** Clears both theme caches (palette colors + UI tokens). */\nfunction clearThemeCaches(): void {\n colorCache.clear();\n uiTokenCache = null;\n}\n\n/**\n * Gets theme colors with module-level caching.\n * Avoids repeated CSS variable lookups for the same palette within a theme.\n */\nfunction getThemeColors(palette: ChartColorPalette = \"categorical\"): string[] {\n const config = PALETTE_CONFIG[palette];\n\n if (typeof window === \"undefined\") return config.fallback;\n\n // Return cached colors if available\n const cached = colorCache.get(palette);\n if (cached) {\n return cached;\n }\n\n // Compute colors from CSS variables\n const styles = getComputedStyle(document.documentElement);\n const colors: string[] = [];\n\n for (const varName of config.vars) {\n const value = styles.getPropertyValue(varName).trim();\n if (value) colors.push(value);\n }\n\n const result = colors.length > 0 ? colors : config.fallback;\n\n // Cache the result\n colorCache.set(palette, result);\n\n return result;\n}\n\n/**\n * Gets the chart UI tokens (axis text, titles, grid lines) with caching.\n * Authored in `hsla` because ECharts/zrender cannot parse the `oklch` semantic\n * tokens.\n */\nfunction getThemeUITokens(): ChartUITokens {\n if (typeof window === \"undefined\") return FALLBACK_UI_TOKENS;\n\n if (uiTokenCache) return uiTokenCache;\n\n const styles = getComputedStyle(document.documentElement);\n const read = (varName: string, fallback: string): string => {\n const value = styles.getPropertyValue(varName).trim();\n return value || fallback;\n };\n\n uiTokenCache = {\n axisLabel: read(CHART_UI_VARS.axisLabel, FALLBACK_UI_TOKENS.axisLabel),\n axisTitle: read(CHART_UI_VARS.axisTitle, FALLBACK_UI_TOKENS.axisTitle),\n grid: read(CHART_UI_VARS.grid, FALLBACK_UI_TOKENS.grid),\n tooltipBg: read(CHART_UI_VARS.tooltipBg, FALLBACK_UI_TOKENS.tooltipBg),\n };\n\n return uiTokenCache;\n}\n\n// ============================================================================\n// Theme Change Subscription (shared)\n// ============================================================================\n\n// One shared, ref-counted matchMedia + MutationObserver for the whole module: a\n// theme change clears the caches once, then notifies every subscribed hook.\nconst subscribers = new Set<() => void>();\nlet teardownListeners: (() => void) | null = null;\n\nfunction handleThemeChange(): void {\n clearThemeCaches();\n // Snapshot: a subscriber may add/remove itself during iteration.\n for (const notify of [...subscribers]) notify();\n}\n\nfunction ensureListening(): void {\n if (teardownListeners) return;\n\n const mediaQuery = window.matchMedia(\"(prefers-color-scheme: dark)\");\n mediaQuery.addEventListener(\"change\", handleThemeChange);\n\n const observer = new MutationObserver(handleThemeChange);\n observer.observe(document.documentElement, {\n attributes: true,\n attributeFilter: [\"class\", \"data-theme\", \"data-mode\"],\n });\n\n teardownListeners = () => {\n mediaQuery.removeEventListener(\"change\", handleThemeChange);\n observer.disconnect();\n };\n}\n\n/**\n * Resets all module-level theme state: clears both caches and drops the shared\n * subscription (removing the matchMedia/MutationObserver listeners). Used by\n * tests to isolate runs; the runtime only ever clears caches.\n * @internal\n */\nexport function resetThemeCache(): void {\n clearThemeCaches();\n subscribers.clear();\n teardownListeners?.();\n teardownListeners = null;\n}\n\n/**\n * Subscribes `onChange` to theme changes (system color scheme via matchMedia, or\n * a theme attribute on the root element). Listeners are shared and ref-counted,\n * so each hook subscribes once per mount regardless of how `onChange`'s identity\n * changes between renders.\n */\nfunction useThemeChangeEffect(onChange: () => void): void {\n const onChangeRef = useRef(onChange);\n onChangeRef.current = onChange;\n\n useEffect(() => {\n const subscriber = () => onChangeRef.current();\n subscribers.add(subscriber);\n ensureListening();\n\n return () => {\n subscribers.delete(subscriber);\n if (subscribers.size === 0 && teardownListeners) {\n teardownListeners();\n teardownListeners = null;\n }\n };\n }, []);\n}\n\n// ============================================================================\n// Hooks\n// ============================================================================\n\n/**\n * Hook to get theme colors with automatic updates on theme change.\n * Re-resolves CSS variables when color scheme or theme attributes change.\n *\n * @param palette - Color palette type: \"categorical\" (default), \"sequential\", or \"diverging\"\n */\nexport function useThemeColors(\n palette: ChartColorPalette = \"categorical\",\n): string[] {\n const [colors, setColors] = useState<string[]>(() =>\n typeof window === \"undefined\"\n ? PALETTE_CONFIG[palette].fallback\n : getThemeColors(palette),\n );\n\n // Re-resolve colors when the theme changes.\n const updateColors = useCallback(() => {\n setColors(getThemeColors(palette));\n }, [palette]);\n\n useThemeChangeEffect(updateColors);\n\n return colors;\n}\n\n/**\n * Hook to get the chart UI tokens (axis text, titles, grid lines) with automatic\n * updates on theme change. Pass the result into the ECharts option builders so\n * axis labels, lines, legends, and titles follow the active theme.\n */\nexport function useChartUITokens(): ChartUITokens {\n const [tokens, setTokens] = useState<ChartUITokens>(() =>\n typeof window === \"undefined\" ? FALLBACK_UI_TOKENS : getThemeUITokens(),\n );\n\n // Re-resolve tokens when the theme changes.\n const updateTokens = useCallback(() => {\n setTokens(getThemeUITokens());\n }, []);\n\n useThemeChangeEffect(updateTokens);\n\n return tokens;\n}\n\n/**\n * Hook to get all three color palettes at once.\n * Useful when a component needs access to multiple palette types.\n */\nexport function useAllThemeColors(): {\n categorical: string[];\n sequential: string[];\n diverging: string[];\n} {\n const categorical = useThemeColors(\"categorical\");\n const sequential = useThemeColors(\"sequential\");\n const diverging = useThemeColors(\"diverging\");\n\n return { categorical, sequential, diverging };\n}\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"wrapper.d.ts","names":[],"sources":["../../../src/react/charts/wrapper.tsx"],"mappings":";;;;;UA+BU,sBAAA;;EAER,QAAA;EAFQ;EAIR,UAAA,GAAa,MAAA;EAJiB;EAM9B,MAAA,GAAS,UAAA;EAAA;EAET,WAAA,OAAkB,IAAA,EAAM,CAAA,KAAM,CAAA;EAAA;EAE9B,IAAA;AAAA;AAAA,UAGQ,qBAAA;EATR;EAWA,IAAA,EAAM,SAAA;EATN;EAWA,QAAA;EACA,UAAA;EACA,MAAA;EACA,WAAA;AAAA;AAAA,UAGQ,WAAA;EAbR;EAeA,MAAA;EAfI;EAiBJ,SAAA;EAd6B;EAgB7B,SAAA;EAde;EAgBf,MAAA;EAhBM;EAkBN,QAAA,GAAW,IAAA,EAAM,SAAA,KAAc,SAAA;AAAA;AAAA,KAGrB,iBAAA,GAAoB,WAAA,IAC7B,sBAAA,GAAyB,qBAAA;;;;AAjBf;;;;;;;;;;;;;;AAgBb;;;;;iBA8GgB,YAAA,CAAa,KAAA,EAAO,iBAAA,GAAiB,kBAAA,CAAA,GAAA,CAAA,OAAA"}
1
+ {"version":3,"file":"wrapper.d.ts","names":[],"sources":["../../../src/react/charts/wrapper.tsx"],"mappings":";;;;;UAgCU,sBAAA;;EAER,QAAA;EAFQ;EAIR,UAAA,GAAa,MAAA;EAJiB;EAM9B,MAAA,GAAS,UAAA;EAAA;EAET,WAAA,OAAkB,IAAA,EAAM,CAAA,KAAM,CAAA;EAAA;EAE9B,IAAA;AAAA;AAAA,UAGQ,qBAAA;EATR;EAWA,IAAA,EAAM,SAAA;EATN;EAWA,QAAA;EACA,UAAA;EACA,MAAA;EACA,WAAA;AAAA;AAAA,UAGQ,WAAA;EAbR;EAeA,MAAA;EAfI;EAiBJ,SAAA;EAd6B;EAgB7B,SAAA;EAde;EAgBf,MAAA;EAhBM;EAkBN,QAAA,GAAW,IAAA,EAAM,SAAA,KAAc,SAAA;AAAA;AAAA,KAGrB,iBAAA,GAAoB,WAAA,IAC7B,sBAAA,GAAyB,qBAAA;;;;AAjBf;;;;;;;;;;;;;;AAgBb;;;;;iBA8GgB,YAAA,CAAa,KAAA,EAAO,iBAAA,GAAiB,kBAAA,CAAA,GAAA,CAAA,OAAA"}
@@ -1 +1 @@
1
- {"version":3,"file":"wrapper.js","names":[],"sources":["../../../src/react/charts/wrapper.tsx"],"sourcesContent":["import type { ReactNode } from \"react\";\nimport type { WarehouseStatus } from \"../hooks/types\";\nimport { useChartData } from \"../hooks/use-chart-data\";\nimport { ChartErrorBoundary } from \"./chart-error-boundary\";\nimport { EmptyState } from \"./empty\";\nimport { ErrorState } from \"./error\";\nimport { LoadingSkeleton, ResourceWaitingPlaceholder } from \"./loading\";\nimport type { ChartData, DataFormat } from \"./types\";\nimport { isArrowTable } from \"./types\";\n\nconst WAREHOUSE_ERROR_STATES = new Set([\"DELETED\", \"DELETING\"]);\n\nfunction isWarehouseWaiting(\n loading: boolean,\n data: ChartData | null,\n warehouseStatus: WarehouseStatus | null,\n): boolean {\n if (!loading || data || !warehouseStatus) return false;\n if (\n warehouseStatus.state === \"RUNNING\" ||\n WAREHOUSE_ERROR_STATES.has(warehouseStatus.state)\n ) {\n return false;\n }\n return true;\n}\n\n// ============================================================================\n// Props Types\n// ============================================================================\n\ninterface ChartWrapperQueryProps {\n /** Analytics query key */\n queryKey: string;\n /** Query parameters */\n parameters?: Record<string, unknown>;\n /** Data format preference */\n format?: DataFormat;\n /** Transform data after fetching */\n transformer?: <T>(data: T) => T;\n /** Direct data - not used in query mode */\n data?: never;\n}\n\ninterface ChartWrapperDataProps {\n /** Direct data (Arrow Table or JSON array) */\n data: ChartData;\n /** Not used in data mode */\n queryKey?: never;\n parameters?: never;\n format?: never;\n transformer?: never;\n}\n\ninterface CommonProps {\n /** Chart height in pixels */\n height?: number;\n /** Additional CSS classes */\n className?: string;\n /** Accessibility label */\n ariaLabel?: string;\n /** Test ID for automated testing */\n testId?: string;\n /** Render function receiving the chart data */\n children: (data: ChartData) => ReactNode;\n}\n\nexport type ChartWrapperProps = CommonProps &\n (ChartWrapperQueryProps | ChartWrapperDataProps);\n\n// ============================================================================\n// Query Mode Content\n// ============================================================================\n\nfunction QueryModeContent({\n queryKey,\n parameters,\n format,\n transformer,\n height,\n className,\n ariaLabel,\n testId,\n children,\n}: CommonProps & ChartWrapperQueryProps) {\n const { data, loading, error, isEmpty, warehouseStatus } = useChartData({\n queryKey,\n parameters,\n format,\n transformer,\n });\n\n if (isWarehouseWaiting(loading, data, warehouseStatus)) {\n return <ResourceWaitingPlaceholder height={height ?? 300} />;\n }\n if (loading) return <LoadingSkeleton height={height ?? 300} />;\n if (error) return <ErrorState error={error} />;\n if (isEmpty || !data) return <EmptyState />;\n\n return (\n <ChartErrorBoundary\n fallback={<ErrorState error=\"Failed to render chart\" />}\n >\n <div\n className={className}\n style={{ height }}\n aria-label={ariaLabel}\n data-testid={testId}\n role=\"img\"\n >\n {children(data)}\n </div>\n </ChartErrorBoundary>\n );\n}\n\n// ============================================================================\n// Data Mode Content\n// ============================================================================\n\nfunction DataModeContent({\n data,\n height,\n className,\n ariaLabel,\n testId,\n children,\n}: CommonProps & ChartWrapperDataProps) {\n const isEmpty = isArrowTable(data)\n ? data.numRows === 0\n : !Array.isArray(data) || data.length === 0;\n\n if (isEmpty) return <EmptyState />;\n\n return (\n <ChartErrorBoundary\n fallback={<ErrorState error=\"Failed to render chart\" />}\n >\n <div\n className={className}\n style={{ height }}\n aria-label={ariaLabel}\n data-testid={testId}\n role=\"img\"\n >\n {children(data)}\n </div>\n </ChartErrorBoundary>\n );\n}\n\n// ============================================================================\n// Main Wrapper Component\n// ============================================================================\n\n/**\n * Wrapper component for charts.\n * Handles data fetching (query mode) or direct data injection (data mode).\n *\n * @example Query mode - fetches data from analytics endpoint\n * ```tsx\n * <ChartWrapper\n * queryKey=\"spend_data\"\n * parameters={{ limit: 100 }}\n * format=\"auto\"\n * >\n * {(data) => <MyChart data={data} />}\n * </ChartWrapper>\n * ```\n *\n * @example Data mode - uses provided data directly\n * ```tsx\n * <ChartWrapper data={myArrowTable}>\n * {(data) => <MyChart data={data} />}\n * </ChartWrapper>\n * ```\n */\nexport function ChartWrapper(props: ChartWrapperProps) {\n const { height = 300, className, ariaLabel, testId, children } = props;\n\n // Data mode: use provided data directly\n if (\"data\" in props && props.data !== undefined) {\n return (\n <DataModeContent\n data={props.data}\n height={height}\n className={className}\n ariaLabel={ariaLabel}\n testId={testId}\n >\n {children}\n </DataModeContent>\n );\n }\n\n // Query mode: fetch data from analytics endpoint\n if (\"queryKey\" in props && props.queryKey !== undefined) {\n return (\n <QueryModeContent\n queryKey={props.queryKey}\n parameters={props.parameters}\n format={props.format}\n transformer={props.transformer}\n height={height}\n className={className}\n ariaLabel={ariaLabel}\n testId={testId}\n >\n {children}\n </QueryModeContent>\n );\n }\n\n // Should never reach here due to TypeScript, but safety fallback\n return <ErrorState error=\"Chart requires either 'queryKey' or 'data' prop\" />;\n}\n"],"mappings":";;;;;;;;;AAUA,MAAM,yBAAyB,IAAI,IAAI,CAAC,WAAW,WAAW,CAAC;AAE/D,SAAS,mBACP,SACA,MACA,iBACS;AACT,KAAI,CAAC,WAAW,QAAQ,CAAC,gBAAiB,QAAO;AACjD,KACE,gBAAgB,UAAU,aAC1B,uBAAuB,IAAI,gBAAgB,MAAM,CAEjD,QAAO;AAET,QAAO;;AAkDT,SAAS,iBAAiB,EACxB,UACA,YACA,QACA,aACA,QACA,WACA,WACA,QACA,YACuC;CACvC,MAAM,EAAE,MAAM,SAAS,OAAO,SAAS,oBAAoB,aAAa;EACtE;EACA;EACA;EACA;EACD,CAAC;AAEF,KAAI,mBAAmB,SAAS,MAAM,gBAAgB,CACpD,QAAO,oBAAC,8BAA2B,QAAQ,UAAU,MAAO;AAE9D,KAAI,QAAS,QAAO,oBAAC,mBAAgB,QAAQ,UAAU,MAAO;AAC9D,KAAI,MAAO,QAAO,oBAAC,cAAkB,QAAS;AAC9C,KAAI,WAAW,CAAC,KAAM,QAAO,oBAAC,eAAa;AAE3C,QACE,oBAAC;EACC,UAAU,oBAAC,cAAW,OAAM,2BAA2B;YAEvD,oBAAC;GACY;GACX,OAAO,EAAE,QAAQ;GACjB,cAAY;GACZ,eAAa;GACb,MAAK;aAEJ,SAAS,KAAK;IACX;GACa;;AAQzB,SAAS,gBAAgB,EACvB,MACA,QACA,WACA,WACA,QACA,YACsC;AAKtC,KAJgB,aAAa,KAAK,GAC9B,KAAK,YAAY,IACjB,CAAC,MAAM,QAAQ,KAAK,IAAI,KAAK,WAAW,EAE/B,QAAO,oBAAC,eAAa;AAElC,QACE,oBAAC;EACC,UAAU,oBAAC,cAAW,OAAM,2BAA2B;YAEvD,oBAAC;GACY;GACX,OAAO,EAAE,QAAQ;GACjB,cAAY;GACZ,eAAa;GACb,MAAK;aAEJ,SAAS,KAAK;IACX;GACa;;;;;;;;;;;;;;;;;;;;;;;;AA8BzB,SAAgB,aAAa,OAA0B;CACrD,MAAM,EAAE,SAAS,KAAK,WAAW,WAAW,QAAQ,aAAa;AAGjE,KAAI,UAAU,SAAS,MAAM,SAAS,OACpC,QACE,oBAAC;EACC,MAAM,MAAM;EACJ;EACG;EACA;EACH;EAEP;GACe;AAKtB,KAAI,cAAc,SAAS,MAAM,aAAa,OAC5C,QACE,oBAAC;EACC,UAAU,MAAM;EAChB,YAAY,MAAM;EAClB,QAAQ,MAAM;EACd,aAAa,MAAM;EACX;EACG;EACA;EACH;EAEP;GACgB;AAKvB,QAAO,oBAAC,cAAW,OAAM,oDAAoD"}
1
+ {"version":3,"file":"wrapper.js","names":[],"sources":["../../../src/react/charts/wrapper.tsx"],"sourcesContent":["import type { ReactNode } from \"react\";\n\nimport type { WarehouseStatus } from \"../hooks/types\";\nimport { useChartData } from \"../hooks/use-chart-data\";\nimport { ChartErrorBoundary } from \"./chart-error-boundary\";\nimport { EmptyState } from \"./empty\";\nimport { ErrorState } from \"./error\";\nimport { LoadingSkeleton, ResourceWaitingPlaceholder } from \"./loading\";\nimport type { ChartData, DataFormat } from \"./types\";\nimport { isArrowTable } from \"./types\";\n\nconst WAREHOUSE_ERROR_STATES = new Set([\"DELETED\", \"DELETING\"]);\n\nfunction isWarehouseWaiting(\n loading: boolean,\n data: ChartData | null,\n warehouseStatus: WarehouseStatus | null,\n): boolean {\n if (!loading || data || !warehouseStatus) return false;\n if (\n warehouseStatus.state === \"RUNNING\" ||\n WAREHOUSE_ERROR_STATES.has(warehouseStatus.state)\n ) {\n return false;\n }\n return true;\n}\n\n// ============================================================================\n// Props Types\n// ============================================================================\n\ninterface ChartWrapperQueryProps {\n /** Analytics query key */\n queryKey: string;\n /** Query parameters */\n parameters?: Record<string, unknown>;\n /** Data format preference */\n format?: DataFormat;\n /** Transform data after fetching */\n transformer?: <T>(data: T) => T;\n /** Direct data - not used in query mode */\n data?: never;\n}\n\ninterface ChartWrapperDataProps {\n /** Direct data (Arrow Table or JSON array) */\n data: ChartData;\n /** Not used in data mode */\n queryKey?: never;\n parameters?: never;\n format?: never;\n transformer?: never;\n}\n\ninterface CommonProps {\n /** Chart height in pixels */\n height?: number;\n /** Additional CSS classes */\n className?: string;\n /** Accessibility label */\n ariaLabel?: string;\n /** Test ID for automated testing */\n testId?: string;\n /** Render function receiving the chart data */\n children: (data: ChartData) => ReactNode;\n}\n\nexport type ChartWrapperProps = CommonProps &\n (ChartWrapperQueryProps | ChartWrapperDataProps);\n\n// ============================================================================\n// Query Mode Content\n// ============================================================================\n\nfunction QueryModeContent({\n queryKey,\n parameters,\n format,\n transformer,\n height,\n className,\n ariaLabel,\n testId,\n children,\n}: CommonProps & ChartWrapperQueryProps) {\n const { data, loading, error, isEmpty, warehouseStatus } = useChartData({\n queryKey,\n parameters,\n format,\n transformer,\n });\n\n if (isWarehouseWaiting(loading, data, warehouseStatus)) {\n return <ResourceWaitingPlaceholder height={height ?? 300} />;\n }\n if (loading) return <LoadingSkeleton height={height ?? 300} />;\n if (error) return <ErrorState error={error} />;\n if (isEmpty || !data) return <EmptyState />;\n\n return (\n <ChartErrorBoundary\n fallback={<ErrorState error=\"Failed to render chart\" />}\n >\n <div\n className={className}\n style={{ height }}\n aria-label={ariaLabel}\n data-testid={testId}\n role=\"img\"\n >\n {children(data)}\n </div>\n </ChartErrorBoundary>\n );\n}\n\n// ============================================================================\n// Data Mode Content\n// ============================================================================\n\nfunction DataModeContent({\n data,\n height,\n className,\n ariaLabel,\n testId,\n children,\n}: CommonProps & ChartWrapperDataProps) {\n const isEmpty = isArrowTable(data)\n ? data.numRows === 0\n : !Array.isArray(data) || data.length === 0;\n\n if (isEmpty) return <EmptyState />;\n\n return (\n <ChartErrorBoundary\n fallback={<ErrorState error=\"Failed to render chart\" />}\n >\n <div\n className={className}\n style={{ height }}\n aria-label={ariaLabel}\n data-testid={testId}\n role=\"img\"\n >\n {children(data)}\n </div>\n </ChartErrorBoundary>\n );\n}\n\n// ============================================================================\n// Main Wrapper Component\n// ============================================================================\n\n/**\n * Wrapper component for charts.\n * Handles data fetching (query mode) or direct data injection (data mode).\n *\n * @example Query mode - fetches data from analytics endpoint\n * ```tsx\n * <ChartWrapper\n * queryKey=\"spend_data\"\n * parameters={{ limit: 100 }}\n * format=\"auto\"\n * >\n * {(data) => <MyChart data={data} />}\n * </ChartWrapper>\n * ```\n *\n * @example Data mode - uses provided data directly\n * ```tsx\n * <ChartWrapper data={myArrowTable}>\n * {(data) => <MyChart data={data} />}\n * </ChartWrapper>\n * ```\n */\nexport function ChartWrapper(props: ChartWrapperProps) {\n const { height = 300, className, ariaLabel, testId, children } = props;\n\n // Data mode: use provided data directly\n if (\"data\" in props && props.data !== undefined) {\n return (\n <DataModeContent\n data={props.data}\n height={height}\n className={className}\n ariaLabel={ariaLabel}\n testId={testId}\n >\n {children}\n </DataModeContent>\n );\n }\n\n // Query mode: fetch data from analytics endpoint\n if (\"queryKey\" in props && props.queryKey !== undefined) {\n return (\n <QueryModeContent\n queryKey={props.queryKey}\n parameters={props.parameters}\n format={props.format}\n transformer={props.transformer}\n height={height}\n className={className}\n ariaLabel={ariaLabel}\n testId={testId}\n >\n {children}\n </QueryModeContent>\n );\n }\n\n // Should never reach here due to TypeScript, but safety fallback\n return <ErrorState error=\"Chart requires either 'queryKey' or 'data' prop\" />;\n}\n"],"mappings":";;;;;;;;;AAWA,MAAM,yBAAyB,IAAI,IAAI,CAAC,WAAW,WAAW,CAAC;AAE/D,SAAS,mBACP,SACA,MACA,iBACS;AACT,KAAI,CAAC,WAAW,QAAQ,CAAC,gBAAiB,QAAO;AACjD,KACE,gBAAgB,UAAU,aAC1B,uBAAuB,IAAI,gBAAgB,MAAM,CAEjD,QAAO;AAET,QAAO;;AAkDT,SAAS,iBAAiB,EACxB,UACA,YACA,QACA,aACA,QACA,WACA,WACA,QACA,YACuC;CACvC,MAAM,EAAE,MAAM,SAAS,OAAO,SAAS,oBAAoB,aAAa;EACtE;EACA;EACA;EACA;EACD,CAAC;AAEF,KAAI,mBAAmB,SAAS,MAAM,gBAAgB,CACpD,QAAO,oBAAC,8BAA2B,QAAQ,UAAU,MAAO;AAE9D,KAAI,QAAS,QAAO,oBAAC,mBAAgB,QAAQ,UAAU,MAAO;AAC9D,KAAI,MAAO,QAAO,oBAAC,cAAkB,QAAS;AAC9C,KAAI,WAAW,CAAC,KAAM,QAAO,oBAAC,eAAa;AAE3C,QACE,oBAAC;EACC,UAAU,oBAAC,cAAW,OAAM,2BAA2B;YAEvD,oBAAC;GACY;GACX,OAAO,EAAE,QAAQ;GACjB,cAAY;GACZ,eAAa;GACb,MAAK;aAEJ,SAAS,KAAK;IACX;GACa;;AAQzB,SAAS,gBAAgB,EACvB,MACA,QACA,WACA,WACA,QACA,YACsC;AAKtC,KAJgB,aAAa,KAAK,GAC9B,KAAK,YAAY,IACjB,CAAC,MAAM,QAAQ,KAAK,IAAI,KAAK,WAAW,EAE/B,QAAO,oBAAC,eAAa;AAElC,QACE,oBAAC;EACC,UAAU,oBAAC,cAAW,OAAM,2BAA2B;YAEvD,oBAAC;GACY;GACX,OAAO,EAAE,QAAQ;GACjB,cAAY;GACZ,eAAa;GACb,MAAK;aAEJ,SAAS,KAAK;IACX;GACa;;;;;;;;;;;;;;;;;;;;;;;;AA8BzB,SAAgB,aAAa,OAA0B;CACrD,MAAM,EAAE,SAAS,KAAK,WAAW,WAAW,QAAQ,aAAa;AAGjE,KAAI,UAAU,SAAS,MAAM,SAAS,OACpC,QACE,oBAAC;EACC,MAAM,MAAM;EACJ;EACG;EACA;EACH;EAEP;GACe;AAKtB,KAAI,cAAc,SAAS,MAAM,aAAa,OAC5C,QACE,oBAAC;EACC,UAAU,MAAM;EAChB,YAAY,MAAM;EAClB,QAAQ,MAAM;EACd,aAAa,MAAM;EACX;EACG;EACA;EACH;EAEP;GACgB;AAKvB,QAAO,oBAAC,cAAW,OAAM,oDAAoD"}
@@ -1 +1 @@
1
- {"version":3,"file":"directory-list.d.ts","names":[],"sources":["../../../src/react/file-browser/directory-list.tsx"],"mappings":";;;;;UAQiB,kBAAA,SACP,IAAA,CAAK,KAAA,CAAM,cAAA;;EAEnB,OAAA,EAAS,cAAA;EAFT;EAIA,OAAA;EAJa;EAMb,KAAA;EAEsB;EAAtB,YAAA,GAAe,KAAA,EAAO,cAAA;EAYN;EAVhB,kBAAA;EAgBS;EAdT,OAAA;EAZY;EAcZ,QAAA;EAdQ;EAgBR,YAAA;EAhBmB;EAkBnB,gBAAA,GAAmB,KAAA,EAAO,cAAA;EAhBjB;EAkBT,aAAA,GAAgB,KAAA,CAAM,SAAA;EAdtB;EAgBA,cAAA;EAdsB;EAgBtB,UAAA,IAAc,KAAA;EAdd;EAgBA,MAAA,GAAS,IAAA,CACP,iBAAA;AAAA;;iBAMY,aAAA,CAAA;EACd,OAAA;EACA,OAAA;EACA,KAAA;EACA,YAAA;EACA,kBAAA;EACA,OAAA;EACA,QAAA;EACA,YAAA;EACA,gBAAA;EACA,aAAA;EACA,cAAA;EACA,UAAA;EACA,MAAA;EACA,SAAA;EAAA,GACG;AAAA,GACF,kBAAA,GAAkB,kBAAA,CAAA,GAAA,CAAA,OAAA"}
1
+ {"version":3,"file":"directory-list.d.ts","names":[],"sources":["../../../src/react/file-browser/directory-list.tsx"],"mappings":";;;;;UASiB,kBAAA,SAA2B,IAAA,CAC1C,KAAA,CAAM,cAAA;;EAIN,OAAA,EAAS,cAAA;EALyB;EAOlC,OAAA;EANA;EAQA,KAAA;EAEsB;EAAtB,YAAA,GAAe,KAAA,EAAO,cAAA;EAYN;EAVhB,kBAAA;EAgBS;EAdT,OAAA;EAf8C;EAiB9C,QAAA;EAjB0C;EAmB1C,YAAA;EAlBM;EAoBN,gBAAA,GAAmB,KAAA,EAAO,cAAA;EAhBjB;EAkBT,aAAA,GAAgB,KAAA,CAAM,SAAA;EAdtB;EAgBA,cAAA;EAdsB;EAgBtB,UAAA,IAAc,KAAA;EAdd;EAgBA,MAAA,GAAS,IAAA,CACP,iBAAA;AAAA;;iBAMY,aAAA,CAAA;EACd,OAAA;EACA,OAAA;EACA,KAAA;EACA,YAAA;EACA,kBAAA;EACA,OAAA;EACA,QAAA;EACA,YAAA;EACA,gBAAA;EACA,aAAA;EACA,cAAA;EACA,UAAA;EACA,MAAA;EACA,SAAA;EAAA,GACG;AAAA,GACF,kBAAA,GAAkB,kBAAA,CAAA,GAAA,CAAA,OAAA"}
@@ -1 +1 @@
1
- {"version":3,"file":"directory-list.js","names":[],"sources":["../../../src/react/file-browser/directory-list.tsx"],"sourcesContent":["import { AlertCircle, ArrowLeft, FileIcon } from \"lucide-react\";\nimport { Button } from \"../ui/button\";\nimport { Card } from \"../ui/card\";\nimport { Skeleton } from \"../ui/skeleton\";\nimport { FileEntry } from \"./file-entry\";\nimport type { DirectoryEntry, FileBrowserLabels } from \"./types\";\n\n/** Props for the DirectoryList component */\nexport interface DirectoryListProps\n extends Omit<React.ComponentProps<\"div\">, \"children\"> {\n /** Directory entries to display */\n entries: DirectoryEntry[];\n /** Whether the directory is currently loading */\n loading?: boolean;\n /** Error message to display */\n error?: string | null;\n /** Called when an entry is clicked */\n onEntryClick: (entry: DirectoryEntry) => void;\n /** Called when the back/parent button is clicked */\n onNavigateToParent?: () => void;\n /** Called when the retry button is clicked */\n onRetry?: () => void;\n /** Whether the user is at the root directory (hides back button) */\n isAtRoot?: boolean;\n /** Currently selected file path for highlighting */\n selectedPath?: string | null;\n /** Resolves a DirectoryEntry to its full path */\n resolveEntryPath: (entry: DirectoryEntry) => string;\n /** Content rendered between the back button and the entry list (e.g., NewFolderInput) */\n headerContent?: React.ReactNode;\n /** Whether a current path is set (affects empty state message) */\n hasCurrentPath?: boolean;\n /** Custom file size formatter */\n formatSize?: (bytes: number | undefined) => string;\n /** Customizable labels */\n labels?: Pick<\n FileBrowserLabels,\n \"backToParent\" | \"emptyDirectory\" | \"noVolumeConfigured\" | \"retry\"\n >;\n}\n\n/** Card-wrapped directory listing with loading, error, and empty states */\nexport function DirectoryList({\n entries,\n loading,\n error,\n onEntryClick,\n onNavigateToParent,\n onRetry,\n isAtRoot,\n selectedPath,\n resolveEntryPath,\n headerContent,\n hasCurrentPath,\n formatSize,\n labels,\n className,\n ...props\n}: DirectoryListProps) {\n return (\n <div data-slot=\"directory-list\" className={className} {...props}>\n <Card className=\"p-0 overflow-hidden\">\n {!isAtRoot && onNavigateToParent && (\n <button\n type=\"button\"\n onClick={onNavigateToParent}\n className=\"flex items-center gap-2 px-4 py-3 w-full text-left hover:bg-muted/50 border-b text-sm text-muted-foreground transition-colors\"\n >\n <ArrowLeft className=\"h-4 w-4\" />\n {labels?.backToParent ?? \"Back to parent\"}\n </button>\n )}\n\n {headerContent}\n\n {loading && (\n <div className=\"p-4 space-y-3\">\n <Skeleton className=\"h-10 w-full\" />\n <Skeleton className=\"h-10 w-full\" />\n <Skeleton className=\"h-10 w-full\" />\n </div>\n )}\n\n {error && (\n <div className=\"p-6 text-center\">\n <AlertCircle className=\"h-8 w-8 text-destructive mx-auto mb-2\" />\n <p className=\"text-sm text-destructive\">{error}</p>\n {onRetry && (\n <Button\n variant=\"outline\"\n size=\"sm\"\n className=\"mt-3\"\n onClick={onRetry}\n >\n {labels?.retry ?? \"Retry\"}\n </Button>\n )}\n </div>\n )}\n\n {!loading && !error && entries.length === 0 && (\n <div className=\"p-6 text-center text-muted-foreground\">\n <FileIcon className=\"h-8 w-8 mx-auto mb-2 opacity-50\" />\n <p className=\"text-sm\">\n {hasCurrentPath\n ? (labels?.emptyDirectory ?? \"This directory is empty.\")\n : (labels?.noVolumeConfigured ??\n \"No volume configured. Configure volumes in the files plugin to get started.\")}\n </p>\n </div>\n )}\n\n {!loading &&\n !error &&\n entries.map((entry) => {\n const entryPath = resolveEntryPath(entry);\n return (\n <FileEntry\n key={entryPath}\n entry={entry}\n entryPath={entryPath}\n isSelected={selectedPath === entryPath}\n formatSize={formatSize}\n onClick={() => onEntryClick(entry)}\n />\n );\n })}\n </Card>\n </div>\n );\n}\n"],"mappings":";;;;;;;;;AA0CA,SAAgB,cAAc,EAC5B,SACA,SACA,OACA,cACA,oBACA,SACA,UACA,cACA,kBACA,eACA,gBACA,YACA,QACA,WACA,GAAG,SACkB;AACrB,QACE,oBAAC;EAAI,aAAU;EAA4B;EAAW,GAAI;YACxD,qBAAC;GAAK,WAAU;;IACb,CAAC,YAAY,sBACZ,qBAAC;KACC,MAAK;KACL,SAAS;KACT,WAAU;gBAEV,oBAAC,aAAU,WAAU,YAAY,EAChC,QAAQ,gBAAgB;MAClB;IAGV;IAEA,WACC,qBAAC;KAAI,WAAU;;MACb,oBAAC,YAAS,WAAU,gBAAgB;MACpC,oBAAC,YAAS,WAAU,gBAAgB;MACpC,oBAAC,YAAS,WAAU,gBAAgB;;MAChC;IAGP,SACC,qBAAC;KAAI,WAAU;;MACb,oBAAC,eAAY,WAAU,0CAA0C;MACjE,oBAAC;OAAE,WAAU;iBAA4B;QAAU;MAClD,WACC,oBAAC;OACC,SAAQ;OACR,MAAK;OACL,WAAU;OACV,SAAS;iBAER,QAAQ,SAAS;QACX;;MAEP;IAGP,CAAC,WAAW,CAAC,SAAS,QAAQ,WAAW,KACxC,qBAAC;KAAI,WAAU;gBACb,oBAAC,YAAS,WAAU,oCAAoC,EACxD,oBAAC;MAAE,WAAU;gBACV,iBACI,QAAQ,kBAAkB,6BAC1B,QAAQ,sBACT;OACF;MACA;IAGP,CAAC,WACA,CAAC,SACD,QAAQ,KAAK,UAAU;KACrB,MAAM,YAAY,iBAAiB,MAAM;AACzC,YACE,oBAAC;MAEQ;MACI;MACX,YAAY,iBAAiB;MACjB;MACZ,eAAe,aAAa,MAAM;QAL7B,UAML;MAEJ;;IACC;GACH"}
1
+ {"version":3,"file":"directory-list.js","names":[],"sources":["../../../src/react/file-browser/directory-list.tsx"],"sourcesContent":["import { AlertCircle, ArrowLeft, FileIcon } from \"lucide-react\";\n\nimport { Button } from \"../ui/button\";\nimport { Card } from \"../ui/card\";\nimport { Skeleton } from \"../ui/skeleton\";\nimport { FileEntry } from \"./file-entry\";\nimport type { DirectoryEntry, FileBrowserLabels } from \"./types\";\n\n/** Props for the DirectoryList component */\nexport interface DirectoryListProps extends Omit<\n React.ComponentProps<\"div\">,\n \"children\"\n> {\n /** Directory entries to display */\n entries: DirectoryEntry[];\n /** Whether the directory is currently loading */\n loading?: boolean;\n /** Error message to display */\n error?: string | null;\n /** Called when an entry is clicked */\n onEntryClick: (entry: DirectoryEntry) => void;\n /** Called when the back/parent button is clicked */\n onNavigateToParent?: () => void;\n /** Called when the retry button is clicked */\n onRetry?: () => void;\n /** Whether the user is at the root directory (hides back button) */\n isAtRoot?: boolean;\n /** Currently selected file path for highlighting */\n selectedPath?: string | null;\n /** Resolves a DirectoryEntry to its full path */\n resolveEntryPath: (entry: DirectoryEntry) => string;\n /** Content rendered between the back button and the entry list (e.g., NewFolderInput) */\n headerContent?: React.ReactNode;\n /** Whether a current path is set (affects empty state message) */\n hasCurrentPath?: boolean;\n /** Custom file size formatter */\n formatSize?: (bytes: number | undefined) => string;\n /** Customizable labels */\n labels?: Pick<\n FileBrowserLabels,\n \"backToParent\" | \"emptyDirectory\" | \"noVolumeConfigured\" | \"retry\"\n >;\n}\n\n/** Card-wrapped directory listing with loading, error, and empty states */\nexport function DirectoryList({\n entries,\n loading,\n error,\n onEntryClick,\n onNavigateToParent,\n onRetry,\n isAtRoot,\n selectedPath,\n resolveEntryPath,\n headerContent,\n hasCurrentPath,\n formatSize,\n labels,\n className,\n ...props\n}: DirectoryListProps) {\n return (\n <div data-slot=\"directory-list\" className={className} {...props}>\n <Card className=\"p-0 overflow-hidden\">\n {!isAtRoot && onNavigateToParent && (\n <button\n type=\"button\"\n onClick={onNavigateToParent}\n className=\"flex items-center gap-2 px-4 py-3 w-full text-left hover:bg-muted/50 border-b text-sm text-muted-foreground transition-colors\"\n >\n <ArrowLeft className=\"h-4 w-4\" />\n {labels?.backToParent ?? \"Back to parent\"}\n </button>\n )}\n\n {headerContent}\n\n {loading && (\n <div className=\"p-4 space-y-3\">\n <Skeleton className=\"h-10 w-full\" />\n <Skeleton className=\"h-10 w-full\" />\n <Skeleton className=\"h-10 w-full\" />\n </div>\n )}\n\n {error && (\n <div className=\"p-6 text-center\">\n <AlertCircle className=\"h-8 w-8 text-destructive mx-auto mb-2\" />\n <p className=\"text-sm text-destructive\">{error}</p>\n {onRetry && (\n <Button\n variant=\"outline\"\n size=\"sm\"\n className=\"mt-3\"\n onClick={onRetry}\n >\n {labels?.retry ?? \"Retry\"}\n </Button>\n )}\n </div>\n )}\n\n {!loading && !error && entries.length === 0 && (\n <div className=\"p-6 text-center text-muted-foreground\">\n <FileIcon className=\"h-8 w-8 mx-auto mb-2 opacity-50\" />\n <p className=\"text-sm\">\n {hasCurrentPath\n ? (labels?.emptyDirectory ?? \"This directory is empty.\")\n : (labels?.noVolumeConfigured ??\n \"No volume configured. Configure volumes in the files plugin to get started.\")}\n </p>\n </div>\n )}\n\n {!loading &&\n !error &&\n entries.map((entry) => {\n const entryPath = resolveEntryPath(entry);\n return (\n <FileEntry\n key={entryPath}\n entry={entry}\n entryPath={entryPath}\n isSelected={selectedPath === entryPath}\n formatSize={formatSize}\n onClick={() => onEntryClick(entry)}\n />\n );\n })}\n </Card>\n </div>\n );\n}\n"],"mappings":";;;;;;;;;AA6CA,SAAgB,cAAc,EAC5B,SACA,SACA,OACA,cACA,oBACA,SACA,UACA,cACA,kBACA,eACA,gBACA,YACA,QACA,WACA,GAAG,SACkB;AACrB,QACE,oBAAC;EAAI,aAAU;EAA4B;EAAW,GAAI;YACxD,qBAAC;GAAK,WAAU;;IACb,CAAC,YAAY,sBACZ,qBAAC;KACC,MAAK;KACL,SAAS;KACT,WAAU;gBAEV,oBAAC,aAAU,WAAU,YAAY,EAChC,QAAQ,gBAAgB;MAClB;IAGV;IAEA,WACC,qBAAC;KAAI,WAAU;;MACb,oBAAC,YAAS,WAAU,gBAAgB;MACpC,oBAAC,YAAS,WAAU,gBAAgB;MACpC,oBAAC,YAAS,WAAU,gBAAgB;;MAChC;IAGP,SACC,qBAAC;KAAI,WAAU;;MACb,oBAAC,eAAY,WAAU,0CAA0C;MACjE,oBAAC;OAAE,WAAU;iBAA4B;QAAU;MAClD,WACC,oBAAC;OACC,SAAQ;OACR,MAAK;OACL,WAAU;OACV,SAAS;iBAER,QAAQ,SAAS;QACX;;MAEP;IAGP,CAAC,WAAW,CAAC,SAAS,QAAQ,WAAW,KACxC,qBAAC;KAAI,WAAU;gBACb,oBAAC,YAAS,WAAU,oCAAoC,EACxD,oBAAC;MAAE,WAAU;gBACV,iBACI,QAAQ,kBAAkB,6BAC1B,QAAQ,sBACT;OACF;MACA;IAGP,CAAC,WACA,CAAC,SACD,QAAQ,KAAK,UAAU;KACrB,MAAM,YAAY,iBAAiB,MAAM;AACzC,YACE,oBAAC;MAEQ;MACI;MACX,YAAY,iBAAiB;MACjB;MACZ,eAAe,aAAa,MAAM;QAL7B,UAML;MAEJ;;IACC;GACH"}
@@ -1 +1 @@
1
- {"version":3,"file":"file-breadcrumb.d.ts","names":[],"sources":["../../../src/react/file-browser/file-breadcrumb.tsx"],"mappings":";;;;UAUiB,mBAAA,SACP,IAAA,CAAK,KAAA,CAAM,cAAA;;EAEnB,SAAA;EAFA;EAIA,QAAA;EAJY;EAMZ,gBAAA;EANa;EAQb,mBAAA,GAAsB,KAAA;AAAA;;iBAIR,cAAA,CAAA;EACd,SAAA;EACA,QAAA;EACA,gBAAA;EACA,mBAAA;EAAA,GACG;AAAA,GACF,mBAAA,GAAmB,kBAAA,CAAA,GAAA,CAAA,OAAA"}
1
+ {"version":3,"file":"file-breadcrumb.d.ts","names":[],"sources":["../../../src/react/file-browser/file-breadcrumb.tsx"],"mappings":";;;;UAUiB,mBAAA,SAA4B,IAAA,CAC3C,KAAA,CAAM,cAAA;;EAIN,SAAA;EALmC;EAOnC,QAAA;EAP+C;EAS/C,gBAAA;EARA;EAUA,mBAAA,GAAsB,KAAA;AAAA;;iBAIR,cAAA,CAAA;EACd,SAAA;EACA,QAAA;EACA,gBAAA;EACA,mBAAA;EAAA,GACG;AAAA,GACF,mBAAA,GAAmB,kBAAA,CAAA,GAAA,CAAA,OAAA"}
@@ -1 +1 @@
1
- {"version":3,"file":"file-breadcrumb.js","names":[],"sources":["../../../src/react/file-browser/file-breadcrumb.tsx"],"sourcesContent":["import {\n Breadcrumb,\n BreadcrumbItem,\n BreadcrumbLink,\n BreadcrumbList,\n BreadcrumbPage,\n BreadcrumbSeparator,\n} from \"../ui/breadcrumb\";\n\n/** Props for the FileBreadcrumb component */\nexport interface FileBreadcrumbProps\n extends Omit<React.ComponentProps<\"nav\">, \"children\"> {\n /** Label for the root breadcrumb item */\n rootLabel: string;\n /** Path segments after the root */\n segments: string[];\n /** Called when the root breadcrumb is clicked */\n onNavigateToRoot: () => void;\n /** Called when a segment breadcrumb is clicked (receives segment index) */\n onNavigateToSegment: (index: number) => void;\n}\n\n/** Path-aware breadcrumb navigation built on top of Breadcrumb primitives */\nexport function FileBreadcrumb({\n rootLabel,\n segments,\n onNavigateToRoot,\n onNavigateToSegment,\n ...props\n}: FileBreadcrumbProps) {\n return (\n <Breadcrumb data-slot=\"file-breadcrumb\" {...props}>\n <BreadcrumbList>\n <BreadcrumbItem>\n {segments.length > 0 ? (\n <BreadcrumbLink\n className=\"cursor-pointer\"\n onClick={onNavigateToRoot}\n >\n {rootLabel}\n </BreadcrumbLink>\n ) : (\n <BreadcrumbPage>{rootLabel}</BreadcrumbPage>\n )}\n </BreadcrumbItem>\n {segments.map((segment, index) => (\n <span key={segment} className=\"contents\">\n <BreadcrumbSeparator />\n <BreadcrumbItem>\n {index === segments.length - 1 ? (\n <BreadcrumbPage>{segment}</BreadcrumbPage>\n ) : (\n <BreadcrumbLink\n className=\"cursor-pointer\"\n onClick={() => onNavigateToSegment(index)}\n >\n {segment}\n </BreadcrumbLink>\n )}\n </BreadcrumbItem>\n </span>\n ))}\n </BreadcrumbList>\n </Breadcrumb>\n );\n}\n"],"mappings":";;;;;AAuBA,SAAgB,eAAe,EAC7B,WACA,UACA,kBACA,qBACA,GAAG,SACmB;AACtB,QACE,oBAAC;EAAW,aAAU;EAAkB,GAAI;YAC1C,qBAAC,6BACC,oBAAC,4BACE,SAAS,SAAS,IACjB,oBAAC;GACC,WAAU;GACV,SAAS;aAER;IACc,GAEjB,oBAAC,4BAAgB,YAA2B,GAE/B,EAChB,SAAS,KAAK,SAAS,UACtB,qBAAC;GAAmB,WAAU;cAC5B,oBAAC,wBAAsB,EACvB,oBAAC,4BACE,UAAU,SAAS,SAAS,IAC3B,oBAAC,4BAAgB,UAAyB,GAE1C,oBAAC;IACC,WAAU;IACV,eAAe,oBAAoB,MAAM;cAExC;KACc,GAEJ;KAbR,QAcJ,CACP,IACa;GACN"}
1
+ {"version":3,"file":"file-breadcrumb.js","names":[],"sources":["../../../src/react/file-browser/file-breadcrumb.tsx"],"sourcesContent":["import {\n Breadcrumb,\n BreadcrumbItem,\n BreadcrumbLink,\n BreadcrumbList,\n BreadcrumbPage,\n BreadcrumbSeparator,\n} from \"../ui/breadcrumb\";\n\n/** Props for the FileBreadcrumb component */\nexport interface FileBreadcrumbProps extends Omit<\n React.ComponentProps<\"nav\">,\n \"children\"\n> {\n /** Label for the root breadcrumb item */\n rootLabel: string;\n /** Path segments after the root */\n segments: string[];\n /** Called when the root breadcrumb is clicked */\n onNavigateToRoot: () => void;\n /** Called when a segment breadcrumb is clicked (receives segment index) */\n onNavigateToSegment: (index: number) => void;\n}\n\n/** Path-aware breadcrumb navigation built on top of Breadcrumb primitives */\nexport function FileBreadcrumb({\n rootLabel,\n segments,\n onNavigateToRoot,\n onNavigateToSegment,\n ...props\n}: FileBreadcrumbProps) {\n return (\n <Breadcrumb data-slot=\"file-breadcrumb\" {...props}>\n <BreadcrumbList>\n <BreadcrumbItem>\n {segments.length > 0 ? (\n <BreadcrumbLink\n className=\"cursor-pointer\"\n onClick={onNavigateToRoot}\n >\n {rootLabel}\n </BreadcrumbLink>\n ) : (\n <BreadcrumbPage>{rootLabel}</BreadcrumbPage>\n )}\n </BreadcrumbItem>\n {segments.map((segment, index) => (\n <span key={segment} className=\"contents\">\n <BreadcrumbSeparator />\n <BreadcrumbItem>\n {index === segments.length - 1 ? (\n <BreadcrumbPage>{segment}</BreadcrumbPage>\n ) : (\n <BreadcrumbLink\n className=\"cursor-pointer\"\n onClick={() => onNavigateToSegment(index)}\n >\n {segment}\n </BreadcrumbLink>\n )}\n </BreadcrumbItem>\n </span>\n ))}\n </BreadcrumbList>\n </Breadcrumb>\n );\n}\n"],"mappings":";;;;;AAyBA,SAAgB,eAAe,EAC7B,WACA,UACA,kBACA,qBACA,GAAG,SACmB;AACtB,QACE,oBAAC;EAAW,aAAU;EAAkB,GAAI;YAC1C,qBAAC,6BACC,oBAAC,4BACE,SAAS,SAAS,IACjB,oBAAC;GACC,WAAU;GACV,SAAS;aAER;IACc,GAEjB,oBAAC,4BAAgB,YAA2B,GAE/B,EAChB,SAAS,KAAK,SAAS,UACtB,qBAAC;GAAmB,WAAU;cAC5B,oBAAC,wBAAsB,EACvB,oBAAC,4BACE,UAAU,SAAS,SAAS,IAC3B,oBAAC,4BAAgB,UAAyB,GAE1C,oBAAC;IACC,WAAU;IACV,eAAe,oBAAoB,MAAM;cAExC;KACc,GAEJ;KAbR,QAcJ,CACP,IACa;GACN"}
@@ -1 +1 @@
1
- {"version":3,"file":"file-entry.d.ts","names":[],"sources":["../../../src/react/file-browser/file-entry.tsx"],"mappings":";;;;;UAMiB,cAAA,SACP,IAAA,CAAK,KAAA,CAAM,cAAA;;EAEnB,KAAA,EAAO,cAAA;EAFP;EAIA,SAAA;EAJa;EAMb,UAAA;EANQ;EAQR,UAAA,IAAc,KAAA;AAAA;;iBAIA,SAAA,CAAA;EACd,KAAA;EACA,SAAA;EACA,UAAA;EACA,UAAA;EACA,SAAA;EAAA,GACG;AAAA,GACF,cAAA,GAAc,kBAAA,CAAA,GAAA,CAAA,OAAA"}
1
+ {"version":3,"file":"file-entry.d.ts","names":[],"sources":["../../../src/react/file-browser/file-entry.tsx"],"mappings":";;;;;UAOiB,cAAA,SAAuB,IAAA,CACtC,KAAA,CAAM,cAAA;;EAIN,KAAA,EAAO,cAAA;EALuB;EAO9B,SAAA;EANA;EAQA,UAAA;EATsC;EAWtC,UAAA,IAAc,KAAA;AAAA;;iBAIA,SAAA,CAAA;EACd,KAAA;EACA,SAAA;EACA,UAAA;EACA,UAAA;EACA,SAAA;EAAA,GACG;AAAA,GACF,cAAA,GAAc,kBAAA,CAAA,GAAA,CAAA,OAAA"}
@@ -1 +1 @@
1
- {"version":3,"file":"file-entry.js","names":[],"sources":["../../../src/react/file-browser/file-entry.tsx"],"sourcesContent":["import { ChevronRight, FileIcon, FolderIcon } from \"lucide-react\";\nimport { formatFileSize } from \"../lib/format\";\nimport { cn } from \"../lib/utils\";\nimport type { DirectoryEntry } from \"./types\";\n\n/** Props for the FileEntry component */\nexport interface FileEntryProps\n extends Omit<React.ComponentProps<\"button\">, \"children\"> {\n /** The directory entry to render */\n entry: DirectoryEntry;\n /** Resolved full path for this entry */\n entryPath: string;\n /** Whether this entry is currently selected */\n isSelected?: boolean;\n /** Custom file size formatter (defaults to formatFileSize) */\n formatSize?: (bytes: number | undefined) => string;\n}\n\n/** Single file or directory row with icon, name, size, and selection state */\nexport function FileEntry({\n entry,\n entryPath,\n isSelected,\n formatSize = formatFileSize,\n className,\n ...props\n}: FileEntryProps) {\n return (\n <button\n type=\"button\"\n data-slot=\"file-entry\"\n className={cn(\n \"flex items-center gap-3 px-4 py-3 w-full text-left hover:bg-muted/50 border-b last:border-b-0 transition-colors\",\n isSelected && \"bg-muted\",\n className,\n )}\n {...props}\n >\n {entry.is_directory ? (\n <FolderIcon className=\"h-5 w-5 text-blue-500 shrink-0\" />\n ) : (\n <FileIcon className=\"h-5 w-5 text-muted-foreground shrink-0\" />\n )}\n <span className=\"flex-1 truncate text-sm text-foreground\">\n {entry.name ?? entryPath.split(\"/\").pop()}\n </span>\n {entry.is_directory && (\n <ChevronRight className=\"h-4 w-4 text-muted-foreground shrink-0\" />\n )}\n {!entry.is_directory && entry.file_size !== undefined && (\n <span className=\"text-xs text-muted-foreground shrink-0\">\n {formatSize(entry.file_size)}\n </span>\n )}\n </button>\n );\n}\n"],"mappings":";;;;;;;AAmBA,SAAgB,UAAU,EACxB,OACA,WACA,YACA,aAAa,gBACb,WACA,GAAG,SACc;AACjB,QACE,qBAAC;EACC,MAAK;EACL,aAAU;EACV,WAAW,GACT,mHACA,cAAc,YACd,UACD;EACD,GAAI;;GAEH,MAAM,eACL,oBAAC,cAAW,WAAU,mCAAmC,GAEzD,oBAAC,YAAS,WAAU,2CAA2C;GAEjE,oBAAC;IAAK,WAAU;cACb,MAAM,QAAQ,UAAU,MAAM,IAAI,CAAC,KAAK;KACpC;GACN,MAAM,gBACL,oBAAC,gBAAa,WAAU,2CAA2C;GAEpE,CAAC,MAAM,gBAAgB,MAAM,cAAc,UAC1C,oBAAC;IAAK,WAAU;cACb,WAAW,MAAM,UAAU;KACvB;;GAEF"}
1
+ {"version":3,"file":"file-entry.js","names":[],"sources":["../../../src/react/file-browser/file-entry.tsx"],"sourcesContent":["import { ChevronRight, FileIcon, FolderIcon } from \"lucide-react\";\n\nimport { formatFileSize } from \"../lib/format\";\nimport { cn } from \"../lib/utils\";\nimport type { DirectoryEntry } from \"./types\";\n\n/** Props for the FileEntry component */\nexport interface FileEntryProps extends Omit<\n React.ComponentProps<\"button\">,\n \"children\"\n> {\n /** The directory entry to render */\n entry: DirectoryEntry;\n /** Resolved full path for this entry */\n entryPath: string;\n /** Whether this entry is currently selected */\n isSelected?: boolean;\n /** Custom file size formatter (defaults to formatFileSize) */\n formatSize?: (bytes: number | undefined) => string;\n}\n\n/** Single file or directory row with icon, name, size, and selection state */\nexport function FileEntry({\n entry,\n entryPath,\n isSelected,\n formatSize = formatFileSize,\n className,\n ...props\n}: FileEntryProps) {\n return (\n <button\n type=\"button\"\n data-slot=\"file-entry\"\n className={cn(\n \"flex items-center gap-3 px-4 py-3 w-full text-left hover:bg-muted/50 border-b last:border-b-0 transition-colors\",\n isSelected && \"bg-muted\",\n className,\n )}\n {...props}\n >\n {entry.is_directory ? (\n <FolderIcon className=\"h-5 w-5 text-blue-500 shrink-0\" />\n ) : (\n <FileIcon className=\"h-5 w-5 text-muted-foreground shrink-0\" />\n )}\n <span className=\"flex-1 truncate text-sm text-foreground\">\n {entry.name ?? entryPath.split(\"/\").pop()}\n </span>\n {entry.is_directory && (\n <ChevronRight className=\"h-4 w-4 text-muted-foreground shrink-0\" />\n )}\n {!entry.is_directory && entry.file_size !== undefined && (\n <span className=\"text-xs text-muted-foreground shrink-0\">\n {formatSize(entry.file_size)}\n </span>\n )}\n </button>\n );\n}\n"],"mappings":";;;;;;;AAsBA,SAAgB,UAAU,EACxB,OACA,WACA,YACA,aAAa,gBACb,WACA,GAAG,SACc;AACjB,QACE,qBAAC;EACC,MAAK;EACL,aAAU;EACV,WAAW,GACT,mHACA,cAAc,YACd,UACD;EACD,GAAI;;GAEH,MAAM,eACL,oBAAC,cAAW,WAAU,mCAAmC,GAEzD,oBAAC,YAAS,WAAU,2CAA2C;GAEjE,oBAAC;IAAK,WAAU;cACb,MAAM,QAAQ,UAAU,MAAM,IAAI,CAAC,KAAK;KACpC;GACN,MAAM,gBACL,oBAAC,gBAAa,WAAU,2CAA2C;GAEpE,CAAC,MAAM,gBAAgB,MAAM,cAAc,UAC1C,oBAAC;IAAK,WAAU;cACb,WAAW,MAAM,UAAU;KACvB;;GAEF"}
@@ -1 +1 @@
1
- {"version":3,"file":"file-preview-panel.d.ts","names":[],"sources":["../../../src/react/file-browser/file-preview-panel.tsx"],"mappings":";;;;;UAQiB,qBAAA,SACP,IAAA,CAAK,KAAA,CAAM,cAAA;;EAEnB,YAAA;EAFA;EAIA,OAAA,EAAS,WAAA;EAJI;EAMb,cAAA;EAaE;EAXF,UAAA,IAAc,QAAA;EARN;EAUR,QAAA,IAAY,QAAA;EAVA;EAYZ,QAAA;EAZa;EAcb,eAAA,cAA6B,QAAA;EAZ7B;EAcA,UAAA,IAAc,KAAA;EAZL;EAcT,MAAA,GAAS,IAAA,CACP,iBAAA;AAAA;;iBAaY,gBAAA,CAAA;EACd,YAAA;EACA,OAAA;EACA,cAAA;EACA,UAAA;EACA,QAAA;EACA,QAAA;EACA,eAAA;EACA,UAAA;EACA,MAAA;EACA,SAAA;EAAA,GACG;AAAA,GACF,qBAAA,GAAqB,kBAAA,CAAA,GAAA,CAAA,OAAA"}
1
+ {"version":3,"file":"file-preview-panel.d.ts","names":[],"sources":["../../../src/react/file-browser/file-preview-panel.tsx"],"mappings":";;;;;UASiB,qBAAA,SAA8B,IAAA,CAC7C,KAAA,CAAM,cAAA;;EAIN,YAAA;EALqC;EAOrC,OAAA,EAAS,WAAA;EANT;EAQA,cAAA;EAaE;EAXF,UAAA,IAAc,QAAA;EAX+B;EAa7C,QAAA,IAAY,QAAA;EAbqC;EAejD,QAAA;EAdA;EAgBA,eAAA,cAA6B,QAAA;EAZ7B;EAcA,UAAA,IAAc,KAAA;EAZL;EAcT,MAAA,GAAS,IAAA,CACP,iBAAA;AAAA;;iBAaY,gBAAA,CAAA;EACd,YAAA;EACA,OAAA;EACA,cAAA;EACA,UAAA;EACA,QAAA;EACA,QAAA;EACA,eAAA;EACA,UAAA;EACA,MAAA;EACA,SAAA;EAAA,GACG;AAAA,GACF,qBAAA,GAAqB,kBAAA,CAAA,GAAA,CAAA,OAAA"}
@@ -1 +1 @@
1
- {"version":3,"file":"file-preview-panel.js","names":[],"sources":["../../../src/react/file-browser/file-preview-panel.tsx"],"sourcesContent":["import { AlertCircle, Download, FileIcon, Loader2, Trash2 } from \"lucide-react\";\nimport { formatFileSize } from \"../lib/format\";\nimport { Button } from \"../ui/button\";\nimport { Card } from \"../ui/card\";\nimport { Skeleton } from \"../ui/skeleton\";\nimport type { FileBrowserLabels, FilePreview } from \"./types\";\n\n/** Props for the FilePreviewPanel component */\nexport interface FilePreviewPanelProps\n extends Omit<React.ComponentProps<\"div\">, \"children\"> {\n /** Full path of the selected file (null when nothing is selected) */\n selectedFile: string | null;\n /** Preview data for the selected file */\n preview: FilePreview | null;\n /** Whether the preview is loading */\n previewLoading?: boolean;\n /** Called when the download button is clicked */\n onDownload?: (filePath: string) => void;\n /** Called when the delete button is clicked */\n onDelete?: (filePath: string) => void;\n /** Whether a delete operation is in progress */\n deleting?: boolean;\n /** Image preview source — string URL or function that receives the file path */\n imagePreviewSrc?: string | ((filePath: string) => string);\n /** Custom file size formatter (defaults to formatFileSize) */\n formatSize?: (bytes: number | undefined) => string;\n /** Customizable labels */\n labels?: Pick<\n FileBrowserLabels,\n | \"selectFilePrompt\"\n | \"previewNotAvailable\"\n | \"previewFailed\"\n | \"download\"\n | \"size\"\n | \"type\"\n | \"modified\"\n | \"unknown\"\n >;\n}\n\n/** Preview panel displaying file metadata, image/text preview, and download/delete actions */\nexport function FilePreviewPanel({\n selectedFile,\n preview,\n previewLoading,\n onDownload,\n onDelete,\n deleting,\n imagePreviewSrc,\n formatSize = formatFileSize,\n labels,\n className,\n ...props\n}: FilePreviewPanelProps) {\n const resolveImageSrc = (filePath: string) => {\n if (!imagePreviewSrc) return \"\";\n if (typeof imagePreviewSrc === \"string\") return imagePreviewSrc;\n return imagePreviewSrc(filePath);\n };\n\n return (\n <div data-slot=\"file-preview-panel\" className={className} {...props}>\n <Card className=\"p-6\">\n {/* No file selected */}\n {!selectedFile && (\n <div className=\"text-center text-muted-foreground py-8\">\n <FileIcon className=\"h-10 w-10 mx-auto mb-3 opacity-40\" />\n <p className=\"text-sm\">\n {labels?.selectFilePrompt ?? \"Select a file to preview\"}\n </p>\n </div>\n )}\n\n {/* Loading state */}\n {selectedFile && previewLoading && (\n <div className=\"space-y-3\">\n <Skeleton className=\"h-5 w-3/4\" />\n <Skeleton className=\"h-4 w-1/2\" />\n <Skeleton className=\"h-4 w-2/3\" />\n <Skeleton className=\"h-32 w-full mt-4\" />\n </div>\n )}\n\n {/* Preview content */}\n {selectedFile && !previewLoading && preview && (\n <div className=\"space-y-4\">\n <div>\n <h3 className=\"font-semibold text-foreground truncate mb-1\">\n {selectedFile.split(\"/\").pop()}\n </h3>\n <p className=\"text-xs text-muted-foreground truncate\">\n {selectedFile}\n </p>\n </div>\n\n <div className=\"space-y-2 text-sm\">\n <div className=\"flex justify-between\">\n <span className=\"text-muted-foreground\">\n {labels?.size ?? \"Size\"}\n </span>\n <span className=\"text-foreground\">\n {formatSize(preview.contentLength)}\n </span>\n </div>\n <div className=\"flex justify-between\">\n <span className=\"text-muted-foreground\">\n {labels?.type ?? \"Type\"}\n </span>\n <span className=\"text-foreground truncate ml-2\">\n {preview.contentType ?? labels?.unknown ?? \"Unknown\"}\n </span>\n </div>\n {preview.lastModified && (\n <div className=\"flex justify-between\">\n <span className=\"text-muted-foreground\">\n {labels?.modified ?? \"Modified\"}\n </span>\n <span className=\"text-foreground\">\n {preview.lastModified}\n </span>\n </div>\n )}\n </div>\n\n <div className=\"flex gap-2\">\n {onDownload && (\n <Button\n variant=\"outline\"\n size=\"sm\"\n className=\"flex-1\"\n onClick={() => onDownload(selectedFile)}\n >\n <Download className=\"h-4 w-4 mr-2\" />\n {labels?.download ?? \"Download\"}\n </Button>\n )}\n {onDelete && (\n <Button\n variant=\"destructive\"\n size=\"sm\"\n disabled={deleting}\n onClick={() => onDelete(selectedFile)}\n >\n {deleting ? (\n <Loader2 className=\"h-4 w-4 animate-spin\" />\n ) : (\n <Trash2 className=\"h-4 w-4\" />\n )}\n </Button>\n )}\n </div>\n\n {preview.isImage && imagePreviewSrc && (\n <div className=\"border rounded overflow-hidden\">\n <img\n src={resolveImageSrc(selectedFile)}\n alt={selectedFile.split(\"/\").pop() ?? \"Preview\"}\n className=\"w-full h-auto\"\n />\n </div>\n )}\n\n {preview.isText && preview.textPreview !== null && (\n <div className=\"border rounded\">\n <pre className=\"p-3 text-xs font-mono overflow-auto max-h-80 whitespace-pre-wrap text-foreground bg-muted/30\">\n {preview.textPreview}\n </pre>\n </div>\n )}\n\n {!preview.isText && !preview.isImage && (\n <div className=\"text-center py-4 text-sm text-muted-foreground\">\n {labels?.previewNotAvailable ??\n \"Preview not available for this file type.\"}\n </div>\n )}\n </div>\n )}\n\n {/* Preview load failed */}\n {selectedFile && !previewLoading && !preview && (\n <div className=\"text-center py-8\">\n <AlertCircle className=\"h-8 w-8 text-destructive mx-auto mb-2\" />\n <p className=\"text-sm text-destructive\">\n {labels?.previewFailed ?? \"Failed to load preview\"}\n </p>\n </div>\n )}\n </Card>\n </div>\n );\n}\n"],"mappings":";;;;;;;;;AAyCA,SAAgB,iBAAiB,EAC/B,cACA,SACA,gBACA,YACA,UACA,UACA,iBACA,aAAa,gBACb,QACA,WACA,GAAG,SACqB;CACxB,MAAM,mBAAmB,aAAqB;AAC5C,MAAI,CAAC,gBAAiB,QAAO;AAC7B,MAAI,OAAO,oBAAoB,SAAU,QAAO;AAChD,SAAO,gBAAgB,SAAS;;AAGlC,QACE,oBAAC;EAAI,aAAU;EAAgC;EAAW,GAAI;YAC5D,qBAAC;GAAK,WAAU;;IAEb,CAAC,gBACA,qBAAC;KAAI,WAAU;gBACb,oBAAC,YAAS,WAAU,sCAAsC,EAC1D,oBAAC;MAAE,WAAU;gBACV,QAAQ,oBAAoB;OAC3B;MACA;IAIP,gBAAgB,kBACf,qBAAC;KAAI,WAAU;;MACb,oBAAC,YAAS,WAAU,cAAc;MAClC,oBAAC,YAAS,WAAU,cAAc;MAClC,oBAAC,YAAS,WAAU,cAAc;MAClC,oBAAC,YAAS,WAAU,qBAAqB;;MACrC;IAIP,gBAAgB,CAAC,kBAAkB,WAClC,qBAAC;KAAI,WAAU;;MACb,qBAAC,oBACC,oBAAC;OAAG,WAAU;iBACX,aAAa,MAAM,IAAI,CAAC,KAAK;QAC3B,EACL,oBAAC;OAAE,WAAU;iBACV;QACC,IACA;MAEN,qBAAC;OAAI,WAAU;;QACb,qBAAC;SAAI,WAAU;oBACb,oBAAC;UAAK,WAAU;oBACb,QAAQ,QAAQ;WACZ,EACP,oBAAC;UAAK,WAAU;oBACb,WAAW,QAAQ,cAAc;WAC7B;UACH;QACN,qBAAC;SAAI,WAAU;oBACb,oBAAC;UAAK,WAAU;oBACb,QAAQ,QAAQ;WACZ,EACP,oBAAC;UAAK,WAAU;oBACb,QAAQ,eAAe,QAAQ,WAAW;WACtC;UACH;QACL,QAAQ,gBACP,qBAAC;SAAI,WAAU;oBACb,oBAAC;UAAK,WAAU;oBACb,QAAQ,YAAY;WAChB,EACP,oBAAC;UAAK,WAAU;oBACb,QAAQ;WACJ;UACH;;QAEJ;MAEN,qBAAC;OAAI,WAAU;kBACZ,cACC,qBAAC;QACC,SAAQ;QACR,MAAK;QACL,WAAU;QACV,eAAe,WAAW,aAAa;mBAEvC,oBAAC,YAAS,WAAU,iBAAiB,EACpC,QAAQ,YAAY;SACd,EAEV,YACC,oBAAC;QACC,SAAQ;QACR,MAAK;QACL,UAAU;QACV,eAAe,SAAS,aAAa;kBAEpC,WACC,oBAAC,WAAQ,WAAU,yBAAyB,GAE5C,oBAAC,UAAO,WAAU,YAAY;SAEzB;QAEP;MAEL,QAAQ,WAAW,mBAClB,oBAAC;OAAI,WAAU;iBACb,oBAAC;QACC,KAAK,gBAAgB,aAAa;QAClC,KAAK,aAAa,MAAM,IAAI,CAAC,KAAK,IAAI;QACtC,WAAU;SACV;QACE;MAGP,QAAQ,UAAU,QAAQ,gBAAgB,QACzC,oBAAC;OAAI,WAAU;iBACb,oBAAC;QAAI,WAAU;kBACZ,QAAQ;SACL;QACF;MAGP,CAAC,QAAQ,UAAU,CAAC,QAAQ,WAC3B,oBAAC;OAAI,WAAU;iBACZ,QAAQ,uBACP;QACE;;MAEJ;IAIP,gBAAgB,CAAC,kBAAkB,CAAC,WACnC,qBAAC;KAAI,WAAU;gBACb,oBAAC,eAAY,WAAU,0CAA0C,EACjE,oBAAC;MAAE,WAAU;gBACV,QAAQ,iBAAiB;OACxB;MACA;;IAEH;GACH"}
1
+ {"version":3,"file":"file-preview-panel.js","names":[],"sources":["../../../src/react/file-browser/file-preview-panel.tsx"],"sourcesContent":["import { AlertCircle, Download, FileIcon, Loader2, Trash2 } from \"lucide-react\";\n\nimport { formatFileSize } from \"../lib/format\";\nimport { Button } from \"../ui/button\";\nimport { Card } from \"../ui/card\";\nimport { Skeleton } from \"../ui/skeleton\";\nimport type { FileBrowserLabels, FilePreview } from \"./types\";\n\n/** Props for the FilePreviewPanel component */\nexport interface FilePreviewPanelProps extends Omit<\n React.ComponentProps<\"div\">,\n \"children\"\n> {\n /** Full path of the selected file (null when nothing is selected) */\n selectedFile: string | null;\n /** Preview data for the selected file */\n preview: FilePreview | null;\n /** Whether the preview is loading */\n previewLoading?: boolean;\n /** Called when the download button is clicked */\n onDownload?: (filePath: string) => void;\n /** Called when the delete button is clicked */\n onDelete?: (filePath: string) => void;\n /** Whether a delete operation is in progress */\n deleting?: boolean;\n /** Image preview source — string URL or function that receives the file path */\n imagePreviewSrc?: string | ((filePath: string) => string);\n /** Custom file size formatter (defaults to formatFileSize) */\n formatSize?: (bytes: number | undefined) => string;\n /** Customizable labels */\n labels?: Pick<\n FileBrowserLabels,\n | \"selectFilePrompt\"\n | \"previewNotAvailable\"\n | \"previewFailed\"\n | \"download\"\n | \"size\"\n | \"type\"\n | \"modified\"\n | \"unknown\"\n >;\n}\n\n/** Preview panel displaying file metadata, image/text preview, and download/delete actions */\nexport function FilePreviewPanel({\n selectedFile,\n preview,\n previewLoading,\n onDownload,\n onDelete,\n deleting,\n imagePreviewSrc,\n formatSize = formatFileSize,\n labels,\n className,\n ...props\n}: FilePreviewPanelProps) {\n const resolveImageSrc = (filePath: string) => {\n if (!imagePreviewSrc) return \"\";\n if (typeof imagePreviewSrc === \"string\") return imagePreviewSrc;\n return imagePreviewSrc(filePath);\n };\n\n return (\n <div data-slot=\"file-preview-panel\" className={className} {...props}>\n <Card className=\"p-6\">\n {/* No file selected */}\n {!selectedFile && (\n <div className=\"text-center text-muted-foreground py-8\">\n <FileIcon className=\"h-10 w-10 mx-auto mb-3 opacity-40\" />\n <p className=\"text-sm\">\n {labels?.selectFilePrompt ?? \"Select a file to preview\"}\n </p>\n </div>\n )}\n\n {/* Loading state */}\n {selectedFile && previewLoading && (\n <div className=\"space-y-3\">\n <Skeleton className=\"h-5 w-3/4\" />\n <Skeleton className=\"h-4 w-1/2\" />\n <Skeleton className=\"h-4 w-2/3\" />\n <Skeleton className=\"h-32 w-full mt-4\" />\n </div>\n )}\n\n {/* Preview content */}\n {selectedFile && !previewLoading && preview && (\n <div className=\"space-y-4\">\n <div>\n <h3 className=\"font-semibold text-foreground truncate mb-1\">\n {selectedFile.split(\"/\").pop()}\n </h3>\n <p className=\"text-xs text-muted-foreground truncate\">\n {selectedFile}\n </p>\n </div>\n\n <div className=\"space-y-2 text-sm\">\n <div className=\"flex justify-between\">\n <span className=\"text-muted-foreground\">\n {labels?.size ?? \"Size\"}\n </span>\n <span className=\"text-foreground\">\n {formatSize(preview.contentLength)}\n </span>\n </div>\n <div className=\"flex justify-between\">\n <span className=\"text-muted-foreground\">\n {labels?.type ?? \"Type\"}\n </span>\n <span className=\"text-foreground truncate ml-2\">\n {preview.contentType ?? labels?.unknown ?? \"Unknown\"}\n </span>\n </div>\n {preview.lastModified && (\n <div className=\"flex justify-between\">\n <span className=\"text-muted-foreground\">\n {labels?.modified ?? \"Modified\"}\n </span>\n <span className=\"text-foreground\">\n {preview.lastModified}\n </span>\n </div>\n )}\n </div>\n\n <div className=\"flex gap-2\">\n {onDownload && (\n <Button\n variant=\"outline\"\n size=\"sm\"\n className=\"flex-1\"\n onClick={() => onDownload(selectedFile)}\n >\n <Download className=\"h-4 w-4 mr-2\" />\n {labels?.download ?? \"Download\"}\n </Button>\n )}\n {onDelete && (\n <Button\n variant=\"destructive\"\n size=\"sm\"\n disabled={deleting}\n onClick={() => onDelete(selectedFile)}\n >\n {deleting ? (\n <Loader2 className=\"h-4 w-4 animate-spin\" />\n ) : (\n <Trash2 className=\"h-4 w-4\" />\n )}\n </Button>\n )}\n </div>\n\n {preview.isImage && imagePreviewSrc && (\n <div className=\"border rounded overflow-hidden\">\n <img\n src={resolveImageSrc(selectedFile)}\n alt={selectedFile.split(\"/\").pop() ?? \"Preview\"}\n className=\"w-full h-auto\"\n />\n </div>\n )}\n\n {preview.isText && preview.textPreview !== null && (\n <div className=\"border rounded\">\n <pre className=\"p-3 text-xs font-mono overflow-auto max-h-80 whitespace-pre-wrap text-foreground bg-muted/30\">\n {preview.textPreview}\n </pre>\n </div>\n )}\n\n {!preview.isText && !preview.isImage && (\n <div className=\"text-center py-4 text-sm text-muted-foreground\">\n {labels?.previewNotAvailable ??\n \"Preview not available for this file type.\"}\n </div>\n )}\n </div>\n )}\n\n {/* Preview load failed */}\n {selectedFile && !previewLoading && !preview && (\n <div className=\"text-center py-8\">\n <AlertCircle className=\"h-8 w-8 text-destructive mx-auto mb-2\" />\n <p className=\"text-sm text-destructive\">\n {labels?.previewFailed ?? \"Failed to load preview\"}\n </p>\n </div>\n )}\n </Card>\n </div>\n );\n}\n"],"mappings":";;;;;;;;;AA4CA,SAAgB,iBAAiB,EAC/B,cACA,SACA,gBACA,YACA,UACA,UACA,iBACA,aAAa,gBACb,QACA,WACA,GAAG,SACqB;CACxB,MAAM,mBAAmB,aAAqB;AAC5C,MAAI,CAAC,gBAAiB,QAAO;AAC7B,MAAI,OAAO,oBAAoB,SAAU,QAAO;AAChD,SAAO,gBAAgB,SAAS;;AAGlC,QACE,oBAAC;EAAI,aAAU;EAAgC;EAAW,GAAI;YAC5D,qBAAC;GAAK,WAAU;;IAEb,CAAC,gBACA,qBAAC;KAAI,WAAU;gBACb,oBAAC,YAAS,WAAU,sCAAsC,EAC1D,oBAAC;MAAE,WAAU;gBACV,QAAQ,oBAAoB;OAC3B;MACA;IAIP,gBAAgB,kBACf,qBAAC;KAAI,WAAU;;MACb,oBAAC,YAAS,WAAU,cAAc;MAClC,oBAAC,YAAS,WAAU,cAAc;MAClC,oBAAC,YAAS,WAAU,cAAc;MAClC,oBAAC,YAAS,WAAU,qBAAqB;;MACrC;IAIP,gBAAgB,CAAC,kBAAkB,WAClC,qBAAC;KAAI,WAAU;;MACb,qBAAC,oBACC,oBAAC;OAAG,WAAU;iBACX,aAAa,MAAM,IAAI,CAAC,KAAK;QAC3B,EACL,oBAAC;OAAE,WAAU;iBACV;QACC,IACA;MAEN,qBAAC;OAAI,WAAU;;QACb,qBAAC;SAAI,WAAU;oBACb,oBAAC;UAAK,WAAU;oBACb,QAAQ,QAAQ;WACZ,EACP,oBAAC;UAAK,WAAU;oBACb,WAAW,QAAQ,cAAc;WAC7B;UACH;QACN,qBAAC;SAAI,WAAU;oBACb,oBAAC;UAAK,WAAU;oBACb,QAAQ,QAAQ;WACZ,EACP,oBAAC;UAAK,WAAU;oBACb,QAAQ,eAAe,QAAQ,WAAW;WACtC;UACH;QACL,QAAQ,gBACP,qBAAC;SAAI,WAAU;oBACb,oBAAC;UAAK,WAAU;oBACb,QAAQ,YAAY;WAChB,EACP,oBAAC;UAAK,WAAU;oBACb,QAAQ;WACJ;UACH;;QAEJ;MAEN,qBAAC;OAAI,WAAU;kBACZ,cACC,qBAAC;QACC,SAAQ;QACR,MAAK;QACL,WAAU;QACV,eAAe,WAAW,aAAa;mBAEvC,oBAAC,YAAS,WAAU,iBAAiB,EACpC,QAAQ,YAAY;SACd,EAEV,YACC,oBAAC;QACC,SAAQ;QACR,MAAK;QACL,UAAU;QACV,eAAe,SAAS,aAAa;kBAEpC,WACC,oBAAC,WAAQ,WAAU,yBAAyB,GAE5C,oBAAC,UAAO,WAAU,YAAY;SAEzB;QAEP;MAEL,QAAQ,WAAW,mBAClB,oBAAC;OAAI,WAAU;iBACb,oBAAC;QACC,KAAK,gBAAgB,aAAa;QAClC,KAAK,aAAa,MAAM,IAAI,CAAC,KAAK,IAAI;QACtC,WAAU;SACV;QACE;MAGP,QAAQ,UAAU,QAAQ,gBAAgB,QACzC,oBAAC;OAAI,WAAU;iBACb,oBAAC;QAAI,WAAU;kBACZ,QAAQ;SACL;QACF;MAGP,CAAC,QAAQ,UAAU,CAAC,QAAQ,WAC3B,oBAAC;OAAI,WAAU;iBACZ,QAAQ,uBACP;QACE;;MAEJ;IAIP,gBAAgB,CAAC,kBAAkB,CAAC,WACnC,qBAAC;KAAI,WAAU;gBACb,oBAAC,eAAY,WAAU,0CAA0C,EACjE,oBAAC;MAAE,WAAU;gBACV,QAAQ,iBAAiB;OACxB;MACA;;IAEH;GACH"}
@@ -1 +1 @@
1
- {"version":3,"file":"new-folder-input.d.ts","names":[],"sources":["../../../src/react/file-browser/new-folder-input.tsx"],"mappings":";;;;;UAOiB,mBAAA,SACP,IAAA,CAAK,KAAA,CAAM,cAAA;;EAEnB,KAAA;EAFA;EAIA,QAAA,GAAW,KAAA;EAJE;EAMb,QAAA;EAQS;EANT,QAAA;EARY;EAUZ,QAAA;EAVQ;EAYR,SAAA;EAZmB;EAcnB,MAAA,GAAS,IAAA,CAAK,iBAAA;AAAA;;iBAIA,cAAA,CAAA;EACd,KAAA;EACA,QAAA;EACA,QAAA;EACA,QAAA;EACA,QAAA;EACA,SAAA;EACA,MAAA;EACA,SAAA;EAAA,GACG;AAAA,GACF,mBAAA,GAAmB,kBAAA,CAAA,GAAA,CAAA,OAAA"}
1
+ {"version":3,"file":"new-folder-input.d.ts","names":[],"sources":["../../../src/react/file-browser/new-folder-input.tsx"],"mappings":";;;;;UAQiB,mBAAA,SAA4B,IAAA,CAC3C,KAAA,CAAM,cAAA;;EAIN,KAAA;EALmC;EAOnC,QAAA,GAAW,KAAA;EANX;EAQA,QAAA;EAQS;EANT,QAAA;EAX+C;EAa/C,QAAA;EAb2C;EAe3C,SAAA;EAdM;EAgBN,MAAA,GAAS,IAAA,CAAK,iBAAA;AAAA;;iBAIA,cAAA,CAAA;EACd,KAAA;EACA,QAAA;EACA,QAAA;EACA,QAAA;EACA,QAAA;EACA,SAAA;EACA,MAAA;EACA,SAAA;EAAA,GACG;AAAA,GACF,mBAAA,GAAmB,kBAAA,CAAA,GAAA,CAAA,OAAA"}