@funnest/charts-ui 0.4.0 → 0.5.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.
@@ -0,0 +1,34 @@
1
+ /**
2
+ * Split layouts for the multi-chart widget, as trees: a leaf is a pane index, a split lays
3
+ * its children out in a row (side by side) or a column (stacked). Pure data — rendering
4
+ * lives in multi-chart.tsx.
5
+ */
6
+ export type SplitNode = number | {
7
+ dir: 'row' | 'col';
8
+ children: SplitNode[];
9
+ };
10
+ export type LayoutId = '1' | '2-cols' | '2-rows' | '3-cols' | '3-rows' | '3-left' | '3-top' | '4-grid' | '4-cols' | '4-left' | '6-grid' | '8-grid';
11
+ export declare const LAYOUTS: Record<LayoutId, SplitNode>;
12
+ /** Menu order, grouped by pane count. */
13
+ export declare const LAYOUT_GROUPS: readonly (readonly LayoutId[])[];
14
+ export declare const MAX_PANES = 8;
15
+ export declare function isLayoutId(value: unknown): value is LayoutId;
16
+ export declare function paneCount(node: SplitNode): number;
17
+ /**
18
+ * Flex weights per split, keyed by `layoutId:path` (path = child indices from the root, e.g.
19
+ * '4-grid:1' is the bottom row of the 2×2 grid). Missing entries mean equal sizes.
20
+ */
21
+ export type SplitSizes = Record<string, number[]>;
22
+ export declare function sizesFor(sizes: SplitSizes, key: string, count: number): number[];
23
+ /**
24
+ * Moves the boundary between children `i` and `i + 1` by `deltaFraction` of the split's
25
+ * length. Neither side shrinks below `min` of the pair's total.
26
+ */
27
+ export declare function resizePair(weights: readonly number[], i: number, deltaFraction: number, min?: number): number[];
28
+ /** Small SVG preview of a layout for menus (rects in a 20×16 box). */
29
+ export declare function layoutRects(node: SplitNode, x?: number, y?: number, w?: number, h?: number, gap?: number): {
30
+ x: number;
31
+ y: number;
32
+ w: number;
33
+ h: number;
34
+ }[];
@@ -0,0 +1,78 @@
1
+ /** @jsxImportSource preact */
2
+ import { type Chart, type ChartState, type Locale, type Resolution, type ThemeTokens } from '@funnest/charts';
3
+ import type { LayoutSync } from './context';
4
+ import { type LayoutId, type SplitSizes } from './layouts';
5
+ import { type ColorScheme, type TradingChartSlots } from './shell';
6
+ import { type TradingChartOptions } from './trading-chart';
7
+ export interface PaneSpec {
8
+ symbol: string;
9
+ /** Default: the widget's `resolution`, else '1D'. */
10
+ resolution?: Resolution;
11
+ }
12
+ export interface MultiChartOptions extends Omit<TradingChartOptions, 'symbol'> {
13
+ /**
14
+ * Initial panes, in layout order (up to 8). Panes the layout needs beyond this list open
15
+ * the active pane's symbol.
16
+ */
17
+ panes: readonly PaneSpec[];
18
+ /** Initial split. Default '1'. */
19
+ layout?: LayoutId;
20
+ /** Default: crosshair on, everything else off. */
21
+ sync?: Partial<LayoutSync>;
22
+ /** Below this container width only the active pane shows, with tabs to switch. Default 640. */
23
+ narrowWidth?: number;
24
+ }
25
+ /** Everything `load()` needs to rebuild the widget: split, sync, sizes and every pane's chart. */
26
+ export interface MultiChartState {
27
+ version: 1;
28
+ layout: LayoutId;
29
+ sync: LayoutSync;
30
+ active: number;
31
+ sizes: SplitSizes;
32
+ panes: ChartState[];
33
+ }
34
+ export interface MultiChartEvents {
35
+ /** The pane the toolbar acts on changed. */
36
+ activeChange: {
37
+ index: number;
38
+ chart: Chart;
39
+ };
40
+ /** Split layout or pane count changed. */
41
+ layoutChange: {
42
+ layout: LayoutId;
43
+ panes: number;
44
+ };
45
+ /** Something worth persisting changed in any pane or in the layout — a hook for autosave. */
46
+ stateChange: void;
47
+ }
48
+ export interface MultiChart {
49
+ readonly slots: TradingChartSlots;
50
+ /** Engines of the visible panes, in layout order. */
51
+ readonly charts: readonly Chart[];
52
+ /** The pane the toolbar, drawing bar and `setSymbol` act on. */
53
+ readonly activeChart: Chart;
54
+ readonly activeIndex: number;
55
+ readonly layout: LayoutId;
56
+ readonly sync: LayoutSync;
57
+ setLayout(layout: LayoutId): void;
58
+ setSync(patch: Partial<LayoutSync>): void;
59
+ activate(index: number): void;
60
+ /** Fill the grid with one pane (default: the active one); call again to go back. */
61
+ toggleMaximize(index?: number): void;
62
+ /** Opens a symbol in the active pane (and every pane, with symbol sync on). */
63
+ setSymbol(symbol: string, resolution?: Resolution): Promise<void>;
64
+ setResolution(resolution: Resolution): Promise<void>;
65
+ setLocale(locale: Locale): void;
66
+ setTheme(theme: Partial<ThemeTokens>): void;
67
+ setColorScheme(scheme: ColorScheme): void;
68
+ save(): MultiChartState;
69
+ load(state: MultiChartState | unknown): Promise<void>;
70
+ on<K extends keyof MultiChartEvents>(event: K, listener: (payload: MultiChartEvents[K]) => void): () => void;
71
+ destroy(): void;
72
+ }
73
+ /**
74
+ * Several linked charts in one split layout (1–8 panes) sharing one toolbar and drawing bar
75
+ * that act on the active pane. Clicking a pane activates it; Alt+1…8 too, Alt+Enter maximizes.
76
+ * Crosshair, time range, symbol and interval can be synced across panes.
77
+ */
78
+ export declare function createMultiChart(container: HTMLElement, options: MultiChartOptions): MultiChart;
package/dist/pane.d.ts ADDED
@@ -0,0 +1,33 @@
1
+ /** @jsxImportSource preact */
2
+ import { type Chart, type ChartOptions, type ChartType, type Datafeed, type Resolution } from '@funnest/charts';
3
+ import type { IntervalGroup, MultiControls, SearchCategory, UiState, WidgetContext } from './context';
4
+ import { type Shell } from './shell';
5
+ import { Store } from './store';
6
+ export interface PaneConfig {
7
+ datafeed: Datafeed;
8
+ chartOptions: Omit<ChartOptions, 'datafeed' | 'theme'>;
9
+ displayTimezone: string;
10
+ resolution: Resolution;
11
+ chartType: ChartType;
12
+ intervalGroups: readonly IntervalGroup[];
13
+ searchCategories: readonly SearchCategory[];
14
+ symbolLogo: boolean;
15
+ drawingToolbar: boolean;
16
+ attribution: boolean;
17
+ multi?: MultiControls | undefined;
18
+ }
19
+ /**
20
+ * One chart with its legend/navigation overlay and UI state. The toolbar and drawing bar
21
+ * belong to the shell and are pointed at whichever pane is active.
22
+ */
23
+ export interface Pane {
24
+ /** `.fnc-stage`: chart canvas + overlay. The owner places it in the layout. */
25
+ readonly stage: HTMLElement;
26
+ readonly chart: Chart;
27
+ readonly store: Store<UiState>;
28
+ readonly ctx: WidgetContext;
29
+ readonly canSearch: boolean;
30
+ load(symbol: string, resolution: Resolution): Promise<void>;
31
+ destroy(): void;
32
+ }
33
+ export declare function createPane(shell: Shell, config: PaneConfig): Pane;
@@ -0,0 +1,77 @@
1
+ import { type Resolution, type ThemeTokens } from '@funnest/charts';
2
+ import type { UiState } from './context';
3
+ import { type WidgetStorage } from './storage';
4
+ import type { Store } from './store';
5
+ export type ColorScheme = 'light' | 'dark' | 'system';
6
+ /**
7
+ * Empty elements inside the widget layout where the host app mounts its own UI (any framework):
8
+ * market stats, account info, status bars… They inherit the widget's `--fnc-*` theme variables
9
+ * and collapse when empty.
10
+ */
11
+ export interface TradingChartSlots {
12
+ /** In the toolbar row, after the interval buttons. */
13
+ readonly toolbar: HTMLElement;
14
+ /** Right end of the toolbar, next to the settings (gear) button — for extra icon buttons. */
15
+ readonly toolbarEnd: HTMLElement;
16
+ /** A full-width row under the toolbar. */
17
+ readonly belowToolbar: HTMLElement;
18
+ /**
19
+ * Under the chart, right of the drawing bar — for an account/positions panel that should
20
+ * line up with the chart while the drawing bar keeps the full height (TradingView-style).
21
+ * The host sets its height.
22
+ */
23
+ readonly bottom: HTMLElement;
24
+ /** A full-width row under everything (status bar). */
25
+ readonly footer: HTMLElement;
26
+ }
27
+ export declare function div(className: string, parent?: HTMLElement): HTMLDivElement;
28
+ /** What the shell needs from a chart pane (see pane.tsx). */
29
+ export interface ShellPane {
30
+ readonly store: Store<UiState>;
31
+ readonly chart: {
32
+ setTheme(theme: Partial<ThemeTokens>): void;
33
+ };
34
+ }
35
+ export interface ShellOptions {
36
+ colorScheme: ColorScheme;
37
+ theme: Partial<ThemeTokens> | undefined;
38
+ storageKey: string | null;
39
+ drawingToolbar: boolean;
40
+ favoriteIntervals: readonly Resolution[];
41
+ onFavoriteIntervalsChange?: ((intervals: Resolution[]) => void) | undefined;
42
+ }
43
+ /**
44
+ * The frame around one or more chart panes: root element with theme variables, toolbar host,
45
+ * slots, drawing-bar host, fullscreen, and the preferences every pane shares (favorite
46
+ * intervals, folded drawing bar). Panes register through `setPanes`.
47
+ */
48
+ export interface Shell {
49
+ readonly root: HTMLElement;
50
+ readonly toolbarHost: HTMLElement;
51
+ readonly body: HTMLElement;
52
+ readonly drawbarHost: HTMLElement | null;
53
+ /** Column right of the drawing bar: put the chart stage (or pane grid) here, before `slots.bottom`. */
54
+ readonly main: HTMLElement;
55
+ readonly slots: TradingChartSlots;
56
+ readonly storage: WidgetStorage;
57
+ theme(): ThemeTokens;
58
+ /** Initial UI-state fields owned by the shell (same for every pane). */
59
+ sharedState(): Pick<UiState, 'fullscreen' | 'favoriteIntervals' | 'drawbarCollapsed'>;
60
+ setPanes(panes: () => readonly ShellPane[]): void;
61
+ setTheme(patch: Partial<ThemeTokens>): void;
62
+ setColorScheme(scheme: ColorScheme): void;
63
+ isFullscreen(): boolean;
64
+ toggleFullscreen(): void;
65
+ setDrawbarCollapsed(collapsed: boolean): void;
66
+ toggleFavoriteInterval(resolution: Resolution): void;
67
+ destroy(): void;
68
+ }
69
+ export declare function createShell(container: HTMLElement, options: ShellOptions): Shell;
70
+ /**
71
+ * Ctrl/⌘+K and Escape handling for the pane that currently owns the toolbar.
72
+ * Returns a cleanup function.
73
+ */
74
+ export declare function bindWidgetKeys(shell: Shell, active: () => {
75
+ store: Store<UiState>;
76
+ canSearch: boolean;
77
+ } | null, searchHotkey: boolean, extra?: (e: KeyboardEvent) => boolean): () => void;
@@ -1,6 +1,8 @@
1
1
  /** @jsxImportSource preact */
2
2
  import { type Chart, type ChartOptions, type ChartType, type Datafeed, type Locale, type ChartState, type Resolution, type ThemeTokens } from '@funnest/charts';
3
3
  import type { IntervalGroup, SearchCategory } from './context';
4
+ import { type ColorScheme, type TradingChartSlots } from './shell';
5
+ export type { ColorScheme, TradingChartSlots } from './shell';
4
6
  /** Interval menu: 분 | 시간 | 일. '12M' is shown as 1년. */
5
7
  export declare const DEFAULT_INTERVAL_GROUPS: readonly IntervalGroup[];
6
8
  /** Toolbar chips until the user stars their own. */
@@ -44,22 +46,6 @@ export interface TradingChartOptions extends Omit<ChartOptions, 'datafeed'> {
44
46
  */
45
47
  colorScheme?: ColorScheme;
46
48
  }
47
- export type ColorScheme = 'light' | 'dark' | 'system';
48
- /**
49
- * Empty elements inside the widget layout where the host app mounts its own UI (any framework):
50
- * market stats, account info, status bars… They inherit the widget's `--fnc-*` theme variables
51
- * and collapse when empty.
52
- */
53
- export interface TradingChartSlots {
54
- /** In the toolbar row, after the interval buttons. */
55
- readonly toolbar: HTMLElement;
56
- /** Right end of the toolbar, next to the settings (gear) button — for extra icon buttons. */
57
- readonly toolbarEnd: HTMLElement;
58
- /** A full-width row under the toolbar. */
59
- readonly belowToolbar: HTMLElement;
60
- /** A full-width row under the chart. */
61
- readonly footer: HTMLElement;
62
- }
63
49
  export interface TradingChart {
64
50
  /** The underlying engine, for anything the widget doesn't wrap. */
65
51
  readonly chart: Chart;
@@ -76,6 +62,8 @@ export interface TradingChart {
76
62
  load(state: ChartState | unknown): Promise<void>;
77
63
  destroy(): void;
78
64
  }
65
+ /** Korean users read every time in KST unless told otherwise. */
66
+ export declare function defaultDisplayTimezone(locale: Locale, explicit?: string): string;
79
67
  /**
80
68
  * Full trading chart widget: toolbar (symbol search, intervals, screenshot, fullscreen),
81
69
  * legend, navigation controls and the canvas engine. Framework-agnostic: mount into any element.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@funnest/charts-ui",
3
- "version": "0.4.0",
3
+ "version": "0.5.0",
4
4
  "description": "Pro trading UI (toolbar, drawing tools, sheets) for Funnest Charts. Framework-agnostic.",
5
5
  "keywords": [
6
6
  "chart",
@@ -42,7 +42,7 @@
42
42
  "NOTICE"
43
43
  ],
44
44
  "dependencies": {
45
- "@funnest/charts": "0.4.0"
45
+ "@funnest/charts": "0.5.0"
46
46
  },
47
47
  "devDependencies": {
48
48
  "preact": "^11.2.0"