@constela/core 0.18.3 → 0.18.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.ts CHANGED
@@ -2441,121 +2441,76 @@ declare function isStreamChunk(value: unknown): value is StreamChunk;
2441
2441
  /**
2442
2442
  * Chart Helper Functions
2443
2443
  *
2444
- * Shared chart helper functions used by both @constela/runtime and @constela/server.
2445
- * These are pure functions with no DOM dependencies.
2444
+ * Shared chart helper functions used by both runtime evaluator and SSR renderer.
2445
+ * This module provides coordinate calculation, path generation, and data utilities
2446
+ * for chart rendering.
2446
2447
  */
2447
2448
  /**
2448
2449
  * Normalizes a value to 0-1 range
2450
+ *
2451
+ * @param value - The value to normalize
2452
+ * @param min - The minimum value of the range
2453
+ * @param max - The maximum value of the range
2454
+ * @returns Normalized value (0-1), or undefined for invalid input
2449
2455
  */
2450
2456
  declare function normalizeValue(value: unknown, min: unknown, max: unknown): number | undefined;
2451
2457
  /**
2452
2458
  * Scales a value from one range to another
2459
+ *
2460
+ * @param value - The value to scale
2461
+ * @param domainMin - Minimum of source range
2462
+ * @param domainMax - Maximum of source range
2463
+ * @param rangeMin - Minimum of target range
2464
+ * @param rangeMax - Maximum of target range
2465
+ * @returns Scaled value, or undefined for invalid input
2453
2466
  */
2454
2467
  declare function scaleValue(value: unknown, domainMin: unknown, domainMax: unknown, rangeMin: unknown, rangeMax: unknown): number | undefined;
2455
2468
  /**
2456
2469
  * Finds min and max values in data
2470
+ *
2471
+ * @param data - Array of objects
2472
+ * @param valueKey - Key to use for values
2473
+ * @returns Object with min and max, or undefined for invalid input
2457
2474
  */
2458
2475
  declare function getChartBounds(data: unknown, valueKey: unknown): {
2459
2476
  min: number;
2460
2477
  max: number;
2461
2478
  } | undefined;
2462
2479
  /**
2463
- * Calculates bar dimensions for bar chart
2464
- */
2465
- declare function getBarDimensions(data: unknown, index: unknown, width: unknown, height: unknown, gap: unknown, orientation: unknown): {
2466
- x: number;
2467
- y: number;
2468
- width: number;
2469
- height: number;
2470
- } | undefined;
2471
- /**
2472
- * Generates SVG path string for line chart
2473
- */
2474
- declare function getLinePath(points: unknown, curved?: unknown): string | undefined;
2475
- /**
2476
- * Generates SVG path string for area chart
2477
- */
2478
- declare function getAreaPath(points: unknown, baseline: unknown, curved?: unknown): string | undefined;
2479
- /**
2480
- * Generates scaled line chart points from data
2480
+ * Generates scaled line chart points from data.
2481
+ *
2482
+ * @param data - Array of data objects
2483
+ * @param valueKey - Key to extract values from data
2484
+ * @param width - Chart width
2485
+ * @param height - Chart height
2486
+ * @param padding - Padding around chart area (default: 40)
2487
+ * @returns Array of {x, y} points scaled to fit the chart area
2481
2488
  */
2482
2489
  declare function getLinePoints(data: unknown, valueKey: unknown, width: unknown, height: unknown, padding?: unknown): Array<{
2483
2490
  x: number;
2484
2491
  y: number;
2485
2492
  }> | undefined;
2486
2493
  /**
2487
- * Generates SVG arc path for pie/donut slices
2488
- */
2489
- declare function getArcPath(cx: unknown, cy: unknown, radius: unknown, startAngle: unknown, endAngle: unknown): string | undefined;
2490
- /**
2491
- * Calculates pie slices from data
2492
- */
2493
- declare function getPieSlices(data: unknown, valueKey: unknown): Array<{
2494
- startAngle: number;
2495
- endAngle: number;
2496
- value: number;
2497
- percentage: number;
2498
- }> | undefined;
2499
- /**
2500
- * Calculates donut slices from data
2501
- */
2502
- declare function getDonutSlices(data: unknown, valueKey: unknown, innerRadius: unknown): Array<{
2503
- startAngle: number;
2504
- endAngle: number;
2505
- outerRadius: number;
2506
- innerRadius: number;
2507
- value: number;
2508
- percentage: number;
2509
- }> | undefined;
2510
- /**
2511
- * Converts data to radar polygon points
2512
- */
2513
- declare function getRadarPoints(data: unknown, valueKey: unknown, cx: unknown, cy: unknown, radius: unknown, maxValue: unknown): Array<{
2514
- x: number;
2515
- y: number;
2516
- }> | undefined;
2517
- /**
2518
- * Calculates radar axis line coordinates
2519
- */
2520
- declare function getRadarAxes(labels: unknown, cx: unknown, cy: unknown, radius: unknown): Array<{
2521
- x1: number;
2522
- y1: number;
2523
- x2: number;
2524
- y2: number;
2525
- label: string;
2526
- angle: number;
2527
- }> | undefined;
2528
- /**
2529
- * Generates nice tick values for axis
2530
- */
2531
- declare function generateTicks(min: unknown, max: unknown, count: unknown): number[];
2532
- /**
2533
- * Bins data into histogram buckets
2534
- */
2535
- declare function binData(data: unknown, valueKey: unknown, binCount: unknown): Array<{
2536
- binStart: number;
2537
- binEnd: number;
2538
- count: number;
2539
- values: number[];
2540
- }> | undefined;
2541
- /**
2542
- * Aggregates data by group
2543
- */
2544
- declare function aggregateData(data: unknown, groupKey: unknown, valueKey: unknown, aggregation: unknown): Array<{
2545
- group: string;
2546
- value: number;
2547
- }> | undefined;
2548
- /**
2549
- * Downsamples data for performance
2494
+ * Generates SVG path string for line chart
2495
+ *
2496
+ * @param points - Array of {x, y} points
2497
+ * @param curved - Whether to use curved lines (Catmull-Rom spline)
2498
+ * @returns SVG path string, or undefined for invalid input
2550
2499
  */
2551
- declare function downsample(data: unknown, targetCount: unknown, method: unknown): unknown[] | undefined;
2500
+ declare function getLinePath(points: unknown, curved?: unknown): string | undefined;
2552
2501
  /**
2553
- * All chart helper functions registered as global functions
2502
+ * Registry of chart helper functions that can be called from expressions.
2503
+ * This is used by both runtime evaluator and SSR renderer.
2554
2504
  */
2555
2505
  declare const CHART_HELPERS: Record<string, (...args: unknown[]) => unknown>;
2556
2506
  /**
2557
- * Calls a chart helper function by name
2507
+ * Calls a chart helper function by name.
2508
+ * Returns undefined if the function is not found.
2509
+ *
2510
+ * @param method - The function name to call
2511
+ * @param args - Arguments to pass to the function
2512
+ * @returns The function result, or undefined if not found
2558
2513
  */
2559
2514
  declare function callChartHelper(method: string, args: unknown[]): unknown;
2560
2515
 
2561
- export { AI_OUTPUT_TYPES, AI_PROVIDER_TYPES, type ActionDefinition, type ActionStep, type AiDataSource, type AiOutputType, type AiProviderType, type ArrayExpr, BINARY_OPERATORS, type BinExpr, type BinaryOperator, type BindStep, type BooleanField, CHART_HELPERS, CLIPBOARD_OPERATIONS, COLOR_SCHEMES, type CallExpr, type CallStep, type ClearTimerStep, type ClipboardOperation, type ClipboardStep, type CloseStep, type CodeNode, type ColorScheme, type ComponentDef, type ComponentNode, type ComponentsRef, type CompoundVariant, type ConcatExpr, type CondExpr, type ConfirmStep, type ConstelaAst, ConstelaError, type ConstelaProgram, type CookieInitialExpr, DATA_SOURCE_TYPES, DATA_TRANSFORMS, type DataExpr, type DataSource, type DataSourceType, type DataTransform, type DelayStep, type DisposeStep, type DomStep, type EachNode, type ElementNode, type ErrorBoundaryNode, type ErrorCode, type ErrorOptions, type EventHandler, type EventHandlerOptions, type Expression, FOCUS_OPERATIONS, type FetchStep, type FlushStrategy, type FocusOperation, type FocusStep, type GenerateStep, type GetExpr, HTTP_METHODS, type HttpMethod, ISLAND_STRATEGIES, type IfNode, type IfStep, type ImportExpr, type ImportStep, type IndexExpr, type IntervalStep, type IslandNode, type IslandStrategy, type IslandStrategyOptions, type LambdaExpr, type LayoutProgram, type LifecycleHooks, type ListField, type LitExpr, type LocalActionDefinition, type LocalActionStep, type LocalExpr, type MarkdownNode, NAVIGATE_TARGETS, type NavigateStep, type NavigateTarget, type NotExpr, type NumberField, type ObjExpr, type ObjectField, type OptimisticStep, PARAM_TYPES, type ParamDef, type ParamExpr, type ParamType, type PortalNode, type Program, type ReconnectConfig, type RefExpr, type RejectStep, type RouteDefinition, type RouteExpr, type SSECloseStep, type SSEConnectStep, STORAGE_OPERATIONS, STORAGE_TYPES, type SendStep, type SetPathStep, type SetStep, type SlotNode, type StateExpr, type StateField, type StaticPathsDefinition, type StorageOperation, type StorageStep, type StorageType, type StreamChunk, type StreamChunkType, type StreamingRenderOptions, type StringField, type StyleExpr, type StylePreset, type SubscribeStep, type SuspenseBoundary, type SuspenseNode, type TextNode, type ThemeColors, type ThemeConfig, type ThemeFonts, UPDATE_OPERATIONS, type UnbindStep, type UpdateOperation, type UpdateStep, VALIDITY_PROPERTIES, type ValidationFailure, type ValidationResult, type ValidationSuccess, type ValidityExpr, type ValidityProperty, type VarExpr, type ViewNode, aggregateData, astSchema, binData, callChartHelper, createClipboardWriteMissingValueError, createComponentCycleError, createComponentNotFoundError, createComponentPropMissingError, createComponentPropTypeError, createCondElseRequiredError, createDataNotDefinedError, createDuplicateActionError, createDuplicateDefaultSlotError, createDuplicateIslandIdError, createDuplicateSlotNameError, createImportsNotDefinedError, createInvalidClipboardOperationError, createInvalidDataSourceError, createInvalidNavigateTargetError, createInvalidSlotNameError, createInvalidStorageOperationError, createInvalidStorageTypeError, createLayoutMissingSlotError, createLayoutNotFoundError, createLocalActionInvalidStepError, createOperationInvalidForTypeError, createOperationMissingFieldError, createOperationUnknownError, createRouteNotDefinedError, createSchemaError, createSlotInLoopError, createStorageSetMissingValueError, createUndefinedActionError, createUndefinedDataError, createUndefinedDataSourceError, createUndefinedImportError, createUndefinedLocalStateError, createUndefinedParamError, createUndefinedRefError, createUndefinedRouteParamError, createUndefinedStateError, createUndefinedStyleError, createUndefinedVarError, createUndefinedVariantError, createUnsupportedVersionError, downsample, findSimilarNames, generateTicks, getArcPath, getAreaPath, getBarDimensions, getChartBounds, getDonutSlices, getLinePath, getLinePoints, getPieSlices, getRadarAxes, getRadarPoints, isActionStep, isAiDataSource, isArrayExpr, isBinExpr, isBooleanField, isCallStep, isClipboardStep, isCodeNode, isColorScheme, isComponentNode, isConcatExpr, isCondExpr, isConstelaError, isCookieInitialExpr, isDataExpr, isDataSource, isDisposeStep, isEachNode, isElementNode, isErrorBoundaryNode, isEventHandler, isExpression, isFetchStep, isFocusStep, isGenerateStep, isGetExpr, isIfNode, isImportExpr, isImportStep, isIslandNode, isIslandStrategy, isIslandStrategyOptions, isLayoutProgram, isLifecycleHooks, isListField, isLitExpr, isLocalActionDefinition, isLocalActionStep, isMarkdownNode, isNamedSlotNode, isNavigateStep, isNotExpr, isNumberField, isObjectField, isParamExpr, isPortalNode, isRefExpr, isRouteDefinition, isRouteExpr, isSetPathStep, isSetStep, isSlotNode, isStateExpr, isStateField, isStaticPathsDefinition, isStorageStep, isStreamChunk, isStreamingRenderOptions, isStringField, isStyleExpr, isSubscribeStep, isSuspenseBoundary, isSuspenseNode, isTextNode, isThemeColors, isThemeConfig, isThemeFonts, isUpdateStep, isValidityExpr, isVarExpr, isViewNode, normalizeValue, scaleValue, validateAst };
2516
+ export { AI_OUTPUT_TYPES, AI_PROVIDER_TYPES, type ActionDefinition, type ActionStep, type AiDataSource, type AiOutputType, type AiProviderType, type ArrayExpr, BINARY_OPERATORS, type BinExpr, type BinaryOperator, type BindStep, type BooleanField, CHART_HELPERS, CLIPBOARD_OPERATIONS, COLOR_SCHEMES, type CallExpr, type CallStep, type ClearTimerStep, type ClipboardOperation, type ClipboardStep, type CloseStep, type CodeNode, type ColorScheme, type ComponentDef, type ComponentNode, type ComponentsRef, type CompoundVariant, type ConcatExpr, type CondExpr, type ConfirmStep, type ConstelaAst, ConstelaError, type ConstelaProgram, type CookieInitialExpr, DATA_SOURCE_TYPES, DATA_TRANSFORMS, type DataExpr, type DataSource, type DataSourceType, type DataTransform, type DelayStep, type DisposeStep, type DomStep, type EachNode, type ElementNode, type ErrorBoundaryNode, type ErrorCode, type ErrorOptions, type EventHandler, type EventHandlerOptions, type Expression, FOCUS_OPERATIONS, type FetchStep, type FlushStrategy, type FocusOperation, type FocusStep, type GenerateStep, type GetExpr, HTTP_METHODS, type HttpMethod, ISLAND_STRATEGIES, type IfNode, type IfStep, type ImportExpr, type ImportStep, type IndexExpr, type IntervalStep, type IslandNode, type IslandStrategy, type IslandStrategyOptions, type LambdaExpr, type LayoutProgram, type LifecycleHooks, type ListField, type LitExpr, type LocalActionDefinition, type LocalActionStep, type LocalExpr, type MarkdownNode, NAVIGATE_TARGETS, type NavigateStep, type NavigateTarget, type NotExpr, type NumberField, type ObjExpr, type ObjectField, type OptimisticStep, PARAM_TYPES, type ParamDef, type ParamExpr, type ParamType, type PortalNode, type Program, type ReconnectConfig, type RefExpr, type RejectStep, type RouteDefinition, type RouteExpr, type SSECloseStep, type SSEConnectStep, STORAGE_OPERATIONS, STORAGE_TYPES, type SendStep, type SetPathStep, type SetStep, type SlotNode, type StateExpr, type StateField, type StaticPathsDefinition, type StorageOperation, type StorageStep, type StorageType, type StreamChunk, type StreamChunkType, type StreamingRenderOptions, type StringField, type StyleExpr, type StylePreset, type SubscribeStep, type SuspenseBoundary, type SuspenseNode, type TextNode, type ThemeColors, type ThemeConfig, type ThemeFonts, UPDATE_OPERATIONS, type UnbindStep, type UpdateOperation, type UpdateStep, VALIDITY_PROPERTIES, type ValidationFailure, type ValidationResult, type ValidationSuccess, type ValidityExpr, type ValidityProperty, type VarExpr, type ViewNode, astSchema, callChartHelper, createClipboardWriteMissingValueError, createComponentCycleError, createComponentNotFoundError, createComponentPropMissingError, createComponentPropTypeError, createCondElseRequiredError, createDataNotDefinedError, createDuplicateActionError, createDuplicateDefaultSlotError, createDuplicateIslandIdError, createDuplicateSlotNameError, createImportsNotDefinedError, createInvalidClipboardOperationError, createInvalidDataSourceError, createInvalidNavigateTargetError, createInvalidSlotNameError, createInvalidStorageOperationError, createInvalidStorageTypeError, createLayoutMissingSlotError, createLayoutNotFoundError, createLocalActionInvalidStepError, createOperationInvalidForTypeError, createOperationMissingFieldError, createOperationUnknownError, createRouteNotDefinedError, createSchemaError, createSlotInLoopError, createStorageSetMissingValueError, createUndefinedActionError, createUndefinedDataError, createUndefinedDataSourceError, createUndefinedImportError, createUndefinedLocalStateError, createUndefinedParamError, createUndefinedRefError, createUndefinedRouteParamError, createUndefinedStateError, createUndefinedStyleError, createUndefinedVarError, createUndefinedVariantError, createUnsupportedVersionError, findSimilarNames, getChartBounds, getLinePath, getLinePoints, isActionStep, isAiDataSource, isArrayExpr, isBinExpr, isBooleanField, isCallStep, isClipboardStep, isCodeNode, isColorScheme, isComponentNode, isConcatExpr, isCondExpr, isConstelaError, isCookieInitialExpr, isDataExpr, isDataSource, isDisposeStep, isEachNode, isElementNode, isErrorBoundaryNode, isEventHandler, isExpression, isFetchStep, isFocusStep, isGenerateStep, isGetExpr, isIfNode, isImportExpr, isImportStep, isIslandNode, isIslandStrategy, isIslandStrategyOptions, isLayoutProgram, isLifecycleHooks, isListField, isLitExpr, isLocalActionDefinition, isLocalActionStep, isMarkdownNode, isNamedSlotNode, isNavigateStep, isNotExpr, isNumberField, isObjectField, isParamExpr, isPortalNode, isRefExpr, isRouteDefinition, isRouteExpr, isSetPathStep, isSetStep, isSlotNode, isStateExpr, isStateField, isStaticPathsDefinition, isStorageStep, isStreamChunk, isStreamingRenderOptions, isStringField, isStyleExpr, isSubscribeStep, isSuspenseBoundary, isSuspenseNode, isTextNode, isThemeColors, isThemeConfig, isThemeFonts, isUpdateStep, isValidityExpr, isVarExpr, isViewNode, normalizeValue, scaleValue, validateAst };
package/dist/index.js CHANGED
@@ -2660,55 +2660,65 @@ function normalizeValue(value, min, max) {
2660
2660
  if (typeof value !== "number" || typeof min !== "number" || typeof max !== "number") {
2661
2661
  return void 0;
2662
2662
  }
2663
- if (max === min) return 0;
2663
+ if (max === min) {
2664
+ return 0;
2665
+ }
2664
2666
  return (value - min) / (max - min);
2665
2667
  }
2666
2668
  function scaleValue(value, domainMin, domainMax, rangeMin, rangeMax) {
2667
2669
  if (typeof value !== "number" || typeof domainMin !== "number" || typeof domainMax !== "number" || typeof rangeMin !== "number" || typeof rangeMax !== "number") {
2668
2670
  return void 0;
2669
2671
  }
2670
- if (domainMax === domainMin) return rangeMin;
2672
+ if (domainMax === domainMin) {
2673
+ return rangeMin;
2674
+ }
2671
2675
  const normalized = (value - domainMin) / (domainMax - domainMin);
2672
2676
  return rangeMin + normalized * (rangeMax - rangeMin);
2673
2677
  }
2674
2678
  function getChartBounds(data, valueKey) {
2675
- if (!Array.isArray(data) || data.length === 0) return void 0;
2676
- if (typeof valueKey !== "string") return void 0;
2679
+ if (!Array.isArray(data) || data.length === 0) {
2680
+ return void 0;
2681
+ }
2682
+ if (typeof valueKey !== "string") {
2683
+ return void 0;
2684
+ }
2677
2685
  const values = [];
2678
2686
  for (const item of data) {
2679
- if (typeof item !== "object" || item === null) continue;
2687
+ if (typeof item !== "object" || item === null) {
2688
+ continue;
2689
+ }
2680
2690
  const val = item[valueKey];
2681
- if (typeof val === "number") values.push(val);
2691
+ if (typeof val === "number") {
2692
+ values.push(val);
2693
+ }
2682
2694
  }
2683
- if (values.length === 0) return void 0;
2684
- return { min: Math.min(...values), max: Math.max(...values) };
2685
- }
2686
- function getBarDimensions(data, index, width, height, gap, orientation) {
2687
- if (!Array.isArray(data) || data.length === 0) return void 0;
2688
- if (typeof index !== "number" || index < 0 || index >= data.length) return void 0;
2689
- if (typeof width !== "number" || typeof height !== "number" || typeof gap !== "number") {
2695
+ if (values.length === 0) {
2690
2696
  return void 0;
2691
2697
  }
2692
- const isVertical = orientation === "vertical";
2693
- const barCount = data.length;
2694
- const values = data.map((d) => typeof d === "number" ? d : 0);
2695
- const maxValue = Math.max(...values);
2696
- if (isVertical) {
2697
- const totalGap = gap * (barCount + 1);
2698
- const barWidth = (width - totalGap) / barCount;
2699
- const barX = gap + index * (barWidth + gap);
2700
- const value = values[index] ?? 0;
2701
- const barHeight = maxValue > 0 ? value / maxValue * height : 0;
2702
- const barY = height - barHeight;
2703
- return { x: barX, y: barY, width: barWidth, height: barHeight };
2704
- } else {
2705
- const totalGap = gap * barCount;
2706
- const barHeight = (height - totalGap) / barCount;
2707
- const barY = gap + index * (barHeight + gap);
2708
- const value = values[index] ?? 0;
2709
- const barWidth = maxValue > 0 ? value / maxValue * width : 0;
2710
- return { x: 0, y: barY, width: barWidth, height: barHeight };
2711
- }
2698
+ return {
2699
+ min: Math.min(...values),
2700
+ max: Math.max(...values)
2701
+ };
2702
+ }
2703
+ function getLinePoints(data, valueKey, width, height, padding) {
2704
+ if (!Array.isArray(data) || data.length === 0) return void 0;
2705
+ if (typeof valueKey !== "string") return void 0;
2706
+ if (typeof width !== "number" || typeof height !== "number") return void 0;
2707
+ if (width <= 0 || height <= 0) return void 0;
2708
+ const pad = typeof padding === "number" ? padding : 40;
2709
+ if (typeof padding !== "undefined" && typeof padding !== "number") return void 0;
2710
+ const bounds = getChartBounds(data, valueKey);
2711
+ if (!bounds) return void 0;
2712
+ const { min, max } = bounds;
2713
+ const chartWidth = width - pad * 2;
2714
+ const chartHeight = height - pad * 2;
2715
+ return data.map((item, idx) => {
2716
+ const value = item[valueKey];
2717
+ if (typeof value !== "number") return { x: 0, y: 0 };
2718
+ const x = data.length === 1 ? pad : pad + idx / (data.length - 1) * chartWidth;
2719
+ const y = min === max ? pad + chartHeight / 2 : pad + chartHeight - scaleValue(value, min, max, 0, chartHeight);
2720
+ return { x, y };
2721
+ });
2712
2722
  }
2713
2723
  function getCurvedPath(points) {
2714
2724
  if (points.length < 2) {
@@ -2732,355 +2742,42 @@ function getCurvedPath(points) {
2732
2742
  return pathParts.join(" ");
2733
2743
  }
2734
2744
  function getLinePath(points, curved) {
2735
- if (!Array.isArray(points)) return void 0;
2736
- if (points.length === 0) return "";
2737
- for (const point of points) {
2738
- if (typeof point !== "object" || point === null || typeof point.x !== "number" || typeof point.y !== "number") {
2739
- return void 0;
2740
- }
2745
+ if (!Array.isArray(points)) {
2746
+ return void 0;
2741
2747
  }
2742
- const validPoints = points;
2743
- if (validPoints.length === 1) return `M${validPoints[0].x},${validPoints[0].y}`;
2744
- if (curved !== true) {
2745
- return validPoints.map((p, i) => `${i === 0 ? "M" : "L"}${p.x},${p.y}`).join(" ");
2748
+ if (points.length === 0) {
2749
+ return "";
2746
2750
  }
2747
- return getCurvedPath(validPoints);
2748
- }
2749
- function getAreaPath(points, baseline, curved) {
2750
- if (!Array.isArray(points)) return void 0;
2751
- if (typeof baseline !== "number") return void 0;
2752
- if (points.length === 0) return "";
2753
2751
  for (const point of points) {
2754
2752
  if (typeof point !== "object" || point === null || typeof point.x !== "number" || typeof point.y !== "number") {
2755
2753
  return void 0;
2756
2754
  }
2757
2755
  }
2758
2756
  const validPoints = points;
2759
- let upperPath;
2760
- if (curved === true && validPoints.length > 2) {
2761
- upperPath = getCurvedPath(validPoints);
2762
- } else {
2763
- upperPath = validPoints.map((p, i) => `${i === 0 ? "M" : "L"}${p.x},${p.y}`).join(" ");
2764
- }
2765
- const lastPoint = validPoints[validPoints.length - 1];
2766
- const firstPoint = validPoints[0];
2767
- return `${upperPath} L${lastPoint.x},${baseline} L${firstPoint.x},${baseline} Z`;
2768
- }
2769
- function getLinePoints(data, valueKey, width, height, padding) {
2770
- if (!Array.isArray(data) || data.length === 0) return void 0;
2771
- if (typeof valueKey !== "string") return void 0;
2772
- if (typeof width !== "number" || typeof height !== "number") return void 0;
2773
- const pad = typeof padding === "number" ? padding : 40;
2774
- const bounds = getChartBounds(data, valueKey);
2775
- if (!bounds) return void 0;
2776
- const { min, max } = bounds;
2777
- const chartWidth = width - pad * 2;
2778
- const chartHeight = height - pad * 2;
2779
- return data.map((item, idx) => {
2780
- const value = item[valueKey];
2781
- if (typeof value !== "number") return { x: 0, y: 0 };
2782
- const x = pad + (data.length > 1 ? idx / (data.length - 1) * chartWidth : chartWidth / 2);
2783
- const y = min === max ? pad + chartHeight / 2 : pad + chartHeight - scaleValue(value, min, max, 0, chartHeight);
2784
- return { x, y };
2785
- });
2786
- }
2787
- function getArcPath(cx, cy, radius, startAngle, endAngle) {
2788
- if (typeof cx !== "number" || typeof cy !== "number" || typeof radius !== "number" || typeof startAngle !== "number" || typeof endAngle !== "number") {
2789
- return void 0;
2790
- }
2791
- if (radius <= 0) return void 0;
2792
- const x1 = cx + radius * Math.cos(startAngle);
2793
- const y1 = cy + radius * Math.sin(startAngle);
2794
- const x2 = cx + radius * Math.cos(endAngle);
2795
- const y2 = cy + radius * Math.sin(endAngle);
2796
- const largeArcFlag = Math.abs(endAngle - startAngle) > Math.PI ? 1 : 0;
2797
- return `M${x1},${y1} A${radius},${radius} 0 ${largeArcFlag},1 ${x2},${y2}`;
2798
- }
2799
- function getPieSlices(data, valueKey) {
2800
- if (!Array.isArray(data)) return void 0;
2801
- if (typeof valueKey !== "string") return void 0;
2802
- if (data.length === 0) return [];
2803
- const values = data.map((item) => {
2804
- if (typeof item !== "object" || item === null) return 0;
2805
- const val = item[valueKey];
2806
- return typeof val === "number" ? val : 0;
2807
- });
2808
- const total = values.reduce((sum, val) => sum + val, 0);
2809
- const slices = [];
2810
- let currentAngle = 0;
2811
- for (const value of values) {
2812
- const percentage = total > 0 ? value / total * 100 : 0;
2813
- const angleSpan = total > 0 ? value / total * Math.PI * 2 : 0;
2814
- slices.push({
2815
- startAngle: currentAngle,
2816
- endAngle: currentAngle + angleSpan,
2817
- value,
2818
- percentage
2819
- });
2820
- currentAngle += angleSpan;
2821
- }
2822
- return slices;
2823
- }
2824
- function getDonutSlices(data, valueKey, innerRadius) {
2825
- if (typeof innerRadius !== "number" || innerRadius < 0) return void 0;
2826
- const pieSlices = getPieSlices(data, valueKey);
2827
- if (pieSlices === void 0) return void 0;
2828
- const outerRadius = 100;
2829
- return pieSlices.map((slice) => ({
2830
- ...slice,
2831
- outerRadius,
2832
- innerRadius
2833
- }));
2834
- }
2835
- function getRadarPoints(data, valueKey, cx, cy, radius, maxValue) {
2836
- if (!Array.isArray(data)) return void 0;
2837
- if (typeof valueKey !== "string") return void 0;
2838
- if (typeof cx !== "number" || typeof cy !== "number" || typeof radius !== "number" || typeof maxValue !== "number") {
2839
- return void 0;
2840
- }
2841
- if (maxValue <= 0) return void 0;
2842
- if (data.length === 0) return [];
2843
- const points = [];
2844
- const angleStep = Math.PI * 2 / data.length;
2845
- for (let i = 0; i < data.length; i++) {
2846
- const item = data[i];
2847
- const value = typeof item === "object" && item !== null ? item[valueKey] : 0;
2848
- const numValue = typeof value === "number" ? value : 0;
2849
- const scaledRadius = numValue / maxValue * radius;
2850
- const angle = -Math.PI / 2 + i * angleStep;
2851
- points.push({
2852
- x: cx + scaledRadius * Math.cos(angle),
2853
- y: cy + scaledRadius * Math.sin(angle)
2854
- });
2855
- }
2856
- return points;
2857
- }
2858
- function getRadarAxes(labels, cx, cy, radius) {
2859
- if (!Array.isArray(labels)) return void 0;
2860
- if (typeof cx !== "number" || typeof cy !== "number" || typeof radius !== "number") return void 0;
2861
- if (radius < 0) return void 0;
2862
- if (labels.length === 0) return [];
2863
- const axes = [];
2864
- const angleStep = Math.PI * 2 / labels.length;
2865
- for (let i = 0; i < labels.length; i++) {
2866
- const label = String(labels[i]);
2867
- const angle = -Math.PI / 2 + i * angleStep;
2868
- axes.push({
2869
- x1: cx,
2870
- y1: cy,
2871
- x2: cx + radius * Math.cos(angle),
2872
- y2: cy + radius * Math.sin(angle),
2873
- label,
2874
- angle
2875
- });
2757
+ if (validPoints.length === 1) {
2758
+ return `M${validPoints[0].x},${validPoints[0].y}`;
2876
2759
  }
2877
- return axes;
2878
- }
2879
- function getNiceStep(rawStep) {
2880
- const magnitude = Math.pow(10, Math.floor(Math.log10(rawStep)));
2881
- const normalized = rawStep / magnitude;
2882
- let niceNormalized;
2883
- if (normalized <= 1) niceNormalized = 1;
2884
- else if (normalized <= 2) niceNormalized = 2;
2885
- else if (normalized <= 2.5) niceNormalized = 2.5;
2886
- else if (normalized <= 5) niceNormalized = 5;
2887
- else niceNormalized = 10;
2888
- return niceNormalized * magnitude;
2889
- }
2890
- function generateTicks(min, max, count) {
2891
- if (typeof min !== "number" || typeof max !== "number" || typeof count !== "number") return [];
2892
- if (count <= 0) return [];
2893
- if (min === max) return [min];
2894
- if (count === 1) return [min];
2895
- if (count === 2) return [min, max];
2896
- const range = max - min;
2897
- const rawStep = range / (count - 1);
2898
- const niceStep = getNiceStep(rawStep);
2899
- const niceMin = Math.floor(min / niceStep) * niceStep;
2900
- const ticks = [];
2901
- for (let i = 0; i < count; i++) {
2902
- const tick = niceMin + i * niceStep;
2903
- ticks.push(Math.round(tick * 1e10) / 1e10);
2904
- }
2905
- return ticks;
2906
- }
2907
- function binData(data, valueKey, binCount) {
2908
- if (!Array.isArray(data)) return void 0;
2909
- if (typeof valueKey !== "string") return void 0;
2910
- if (typeof binCount !== "number" || binCount <= 0) return [];
2911
- if (data.length === 0) return [];
2912
- const values = [];
2913
- for (const item of data) {
2914
- if (typeof item !== "object" || item === null) continue;
2915
- const val = item[valueKey];
2916
- if (typeof val === "number") values.push(val);
2917
- }
2918
- if (values.length === 0) return [];
2919
- const minVal = Math.min(...values);
2920
- const maxVal = Math.max(...values);
2921
- const binWidth = maxVal === minVal ? 1 : (maxVal - minVal) / binCount;
2922
- const bins = [];
2923
- for (let i = 0; i < binCount; i++) {
2924
- bins.push({
2925
- binStart: minVal + i * binWidth,
2926
- binEnd: minVal + (i + 1) * binWidth,
2927
- count: 0,
2928
- values: []
2760
+ if (curved !== true) {
2761
+ const pathParts = validPoints.map((point, i) => {
2762
+ const command = i === 0 ? "M" : "L";
2763
+ return `${command}${point.x},${point.y}`;
2929
2764
  });
2765
+ return pathParts.join(" ");
2930
2766
  }
2931
- for (const val of values) {
2932
- let binIndex = Math.floor((val - minVal) / binWidth);
2933
- if (binIndex >= binCount) binIndex = binCount - 1;
2934
- bins[binIndex].count++;
2935
- bins[binIndex].values.push(val);
2936
- }
2937
- return bins;
2938
- }
2939
- function aggregateData(data, groupKey, valueKey, aggregation) {
2940
- if (!Array.isArray(data)) return void 0;
2941
- if (typeof groupKey !== "string" || typeof valueKey !== "string") return void 0;
2942
- const validAggregations = /* @__PURE__ */ new Set(["sum", "avg", "min", "max", "count"]);
2943
- if (typeof aggregation !== "string" || !validAggregations.has(aggregation)) return void 0;
2944
- if (data.length === 0) return [];
2945
- const groups = /* @__PURE__ */ new Map();
2946
- for (const item of data) {
2947
- if (typeof item !== "object" || item === null) continue;
2948
- const group = String(item[groupKey] ?? "");
2949
- const val = item[valueKey];
2950
- const numVal = typeof val === "number" ? val : 0;
2951
- if (!groups.has(group)) groups.set(group, []);
2952
- groups.get(group).push(numVal);
2953
- }
2954
- const result = [];
2955
- for (const [group, values] of groups) {
2956
- let value;
2957
- switch (aggregation) {
2958
- case "sum":
2959
- value = values.reduce((a, b) => a + b, 0);
2960
- break;
2961
- case "avg":
2962
- value = values.reduce((a, b) => a + b, 0) / values.length;
2963
- break;
2964
- case "min":
2965
- value = Math.min(...values);
2966
- break;
2967
- case "max":
2968
- value = Math.max(...values);
2969
- break;
2970
- case "count":
2971
- value = values.length;
2972
- break;
2973
- default:
2974
- value = 0;
2975
- }
2976
- result.push({ group, value });
2977
- }
2978
- return result;
2979
- }
2980
- function downsample(data, targetCount, method) {
2981
- if (!Array.isArray(data)) return void 0;
2982
- if (typeof targetCount !== "number" || targetCount <= 0) return void 0;
2983
- const validMethods = /* @__PURE__ */ new Set(["uniform", "lttb"]);
2984
- if (typeof method !== "string" || !validMethods.has(method)) return void 0;
2985
- if (data.length === 0) return [];
2986
- if (targetCount >= data.length) return data;
2987
- if (method === "uniform") {
2988
- return downsampleUniform(data, targetCount);
2989
- } else {
2990
- return downsampleLTTB(data, targetCount);
2991
- }
2992
- }
2993
- function downsampleUniform(data, targetCount) {
2994
- if (targetCount === 1) return [data[0]];
2995
- if (targetCount === 2) return [data[0], data[data.length - 1]];
2996
- const result = [];
2997
- const step = (data.length - 1) / (targetCount - 1);
2998
- for (let i = 0; i < targetCount; i++) {
2999
- const index = Math.round(i * step);
3000
- result.push(data[index]);
3001
- }
3002
- return result;
3003
- }
3004
- function downsampleLTTB(data, targetCount) {
3005
- if (targetCount === 1) return [data[0]];
3006
- if (targetCount === 2) return [data[0], data[data.length - 1]];
3007
- const getXY = (point) => {
3008
- if (typeof point !== "object" || point === null) return { x: 0, y: 0 };
3009
- const obj = point;
3010
- const x = typeof obj["x"] === "number" ? obj["x"] : typeof obj["timestamp"] === "number" ? obj["timestamp"] : 0;
3011
- const y = typeof obj["y"] === "number" ? obj["y"] : typeof obj["value"] === "number" ? obj["value"] : 0;
3012
- return { x, y };
3013
- };
3014
- const result = [];
3015
- result.push(data[0]);
3016
- const numBuckets = targetCount - 2;
3017
- const middleData = data.length - 2;
3018
- const bucketSize = middleData / numBuckets;
3019
- let prevSelectedIndex = 0;
3020
- for (let bucketIndex = 0; bucketIndex < numBuckets; bucketIndex++) {
3021
- const bucketStart = Math.floor(bucketIndex * bucketSize) + 1;
3022
- const bucketEnd = Math.floor((bucketIndex + 1) * bucketSize) + 1;
3023
- const nextBucketStart = bucketEnd;
3024
- const nextBucketEnd = bucketIndex < numBuckets - 1 ? Math.floor((bucketIndex + 2) * bucketSize) + 1 : data.length;
3025
- let avgX = 0, avgY = 0, avgCount = 0;
3026
- for (let j = nextBucketStart; j < nextBucketEnd && j < data.length; j++) {
3027
- const { x, y } = getXY(data[j]);
3028
- avgX += x;
3029
- avgY += y;
3030
- avgCount++;
3031
- }
3032
- if (avgCount > 0) {
3033
- avgX /= avgCount;
3034
- avgY /= avgCount;
3035
- }
3036
- const prevPoint = getXY(data[prevSelectedIndex]);
3037
- let maxArea = -1;
3038
- let maxAreaIndex = bucketStart;
3039
- for (let j = bucketStart; j < bucketEnd && j < data.length; j++) {
3040
- const currPoint = getXY(data[j]);
3041
- const area = Math.abs(
3042
- (prevPoint.x - avgX) * (currPoint.y - prevPoint.y) - (prevPoint.x - currPoint.x) * (avgY - prevPoint.y)
3043
- );
3044
- if (area > maxArea) {
3045
- maxArea = area;
3046
- maxAreaIndex = j;
3047
- }
3048
- }
3049
- result.push(data[maxAreaIndex]);
3050
- prevSelectedIndex = maxAreaIndex;
3051
- }
3052
- result.push(data[data.length - 1]);
3053
- return result;
2767
+ return getCurvedPath(validPoints);
3054
2768
  }
3055
2769
  var CHART_HELPERS = {
3056
- // Value scaling
3057
2770
  normalizeValue: (value, min, max) => normalizeValue(value, min, max),
3058
2771
  scaleValue: (value, domainMin, domainMax, rangeMin, rangeMax) => scaleValue(value, domainMin, domainMax, rangeMin, rangeMax),
3059
- // Chart bounds
3060
2772
  getChartBounds: (data, valueKey) => getChartBounds(data, valueKey),
3061
- // Bar chart
3062
- getBarDimensions: (data, index, width, height, gap, orientation) => getBarDimensions(data, index, width, height, gap, orientation),
3063
- // Line/Area chart
3064
- getLinePath: (points, curved) => getLinePath(points, curved),
3065
- getAreaPath: (points, baseline, curved) => getAreaPath(points, baseline, curved),
3066
2773
  getLinePoints: (data, valueKey, width, height, padding) => getLinePoints(data, valueKey, width, height, padding),
3067
- // Pie/Donut chart
3068
- getArcPath: (cx, cy, radius, startAngle, endAngle) => getArcPath(cx, cy, radius, startAngle, endAngle),
3069
- getPieSlices: (data, valueKey) => getPieSlices(data, valueKey),
3070
- getDonutSlices: (data, valueKey, innerRadius) => getDonutSlices(data, valueKey, innerRadius),
3071
- // Radar chart
3072
- getRadarPoints: (data, valueKey, cx, cy, radius, maxValue) => getRadarPoints(data, valueKey, cx, cy, radius, maxValue),
3073
- getRadarAxes: (labels, cx, cy, radius) => getRadarAxes(labels, cx, cy, radius),
3074
- // Axis ticks
3075
- generateTicks: (min, max, count) => generateTicks(min, max, count),
3076
- // Data aggregation
3077
- binData: (data, valueKey, binCount) => binData(data, valueKey, binCount),
3078
- aggregateData: (data, groupKey, valueKey, aggregation) => aggregateData(data, groupKey, valueKey, aggregation),
3079
- downsample: (data, targetCount, method) => downsample(data, targetCount, method)
2774
+ getLinePath: (points, curved) => getLinePath(points, curved)
3080
2775
  };
3081
2776
  function callChartHelper(method, args) {
3082
2777
  const fn = CHART_HELPERS[method];
3083
- if (!fn) return void 0;
2778
+ if (!fn) {
2779
+ return void 0;
2780
+ }
3084
2781
  return fn(...args);
3085
2782
  }
3086
2783
  export {
@@ -3102,9 +2799,7 @@ export {
3102
2799
  STORAGE_TYPES,
3103
2800
  UPDATE_OPERATIONS,
3104
2801
  VALIDITY_PROPERTIES,
3105
- aggregateData,
3106
2802
  astSchema,
3107
- binData,
3108
2803
  callChartHelper,
3109
2804
  createClipboardWriteMissingValueError,
3110
2805
  createComponentCycleError,
@@ -3147,19 +2842,10 @@ export {
3147
2842
  createUndefinedVarError,
3148
2843
  createUndefinedVariantError,
3149
2844
  createUnsupportedVersionError,
3150
- downsample,
3151
2845
  findSimilarNames,
3152
- generateTicks,
3153
- getArcPath,
3154
- getAreaPath,
3155
- getBarDimensions,
3156
2846
  getChartBounds,
3157
- getDonutSlices,
3158
2847
  getLinePath,
3159
2848
  getLinePoints,
3160
- getPieSlices,
3161
- getRadarAxes,
3162
- getRadarPoints,
3163
2849
  isActionStep,
3164
2850
  isAiDataSource,
3165
2851
  isArrayExpr,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@constela/core",
3
- "version": "0.18.3",
3
+ "version": "0.18.4",
4
4
  "description": "Core types, schema, and validator for Constela UI framework",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",