@363045841yyt/klinechart 0.8.2 → 0.8.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.
@@ -12,6 +12,22 @@ declare const KLineChartElement: import('vue').VueElementConstructor<{
12
12
  initialZoomLevel?: number;
13
13
  isFullscreen?: boolean;
14
14
  timezone?: string;
15
+ mcp?: {
16
+ wsUrl?: string;
17
+ onToolCall?: (call: {
18
+ name: string;
19
+ input: Record<string, unknown>;
20
+ }) => {
21
+ success: boolean;
22
+ error?: string;
23
+ data?: unknown;
24
+ } | Promise<{
25
+ success: boolean;
26
+ error?: string;
27
+ data?: unknown;
28
+ }>;
29
+ autoReconnect?: boolean;
30
+ };
15
31
  }>;
16
32
  export { KLineChartElement };
17
33
  export default KLineChartElement;
@@ -1 +1 @@
1
- {"version":3,"file":"web-component.d.ts","sourceRoot":"","sources":["../src/web-component.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,mBAAmB,EAAE,WAAW,EAAE,MAAM,wCAAwC,CAAA;AAE9F,QAAA,MAAM,iBAAiB;;;;;;;;;;;;;EAErB,CAAA;AAIF,OAAO,EAAE,iBAAiB,EAAE,CAAA;AAC5B,eAAe,iBAAiB,CAAA;AAEhC,YAAY,EAAE,mBAAmB,EAAE,WAAW,EAAE,CAAA"}
1
+ {"version":3,"file":"web-component.d.ts","sourceRoot":"","sources":["../src/web-component.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,mBAAmB,EAAE,WAAW,EAAE,MAAM,wCAAwC,CAAA;AAE9F,QAAA,MAAM,iBAAiB;;;;;;;;;;;;;;aAUo0zC,CAAC;kBAAyB,CAAC;;;;;iBAAsH,CAAC;gBAAc,CAAC;;;iBAAuD,CAAC;gBAAc,CAAC;;qBAAgC,CAAC;;EARlm0C,CAAA;AAIF,OAAO,EAAE,iBAAiB,EAAE,CAAA;AAC5B,eAAe,iBAAiB,CAAA;AAEhC,YAAY,EAAE,mBAAmB,EAAE,WAAW,EAAE,CAAA"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@363045841yyt/klinechart",
3
- "version": "0.8.2",
3
+ "version": "0.8.4",
4
4
  "description": "Vue 3 bindings for @363045841yyt/klinechart-core. Idiomatic composables, SFC components.",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -71,6 +71,7 @@
71
71
  "vue": "^3.4.0"
72
72
  },
73
73
  "devDependencies": {
74
+ "@363045841yyt/klinechart-ai-runtime": "workspace:*",
74
75
  "@arethetypeswrong/cli": "^0.18.3",
75
76
  "@size-limit/preset-small-lib": "^12.1.0",
76
77
  "@vitejs/plugin-vue": "^6.0.7",
@@ -219,6 +219,8 @@ import {
219
219
  allIndicators,
220
220
  findIndicator,
221
221
  type Indicator,
222
+ loadBuiltinIndicators,
223
+ isBuiltinIndicatorsLoaded,
222
224
  } from '@363045841yyt/klinechart-core/controllers'
223
225
 
224
226
  const props = defineProps<{
@@ -233,7 +235,7 @@ const emit = defineEmits<{
233
235
  }>()
234
236
 
235
237
  // ── 将 Indicator[] 转换为 IndicatorDefinition[] ──
236
- function toIndicatorDefinitions(source: typeof allIndicators): IndicatorDefinition[] {
238
+ function toIndicatorDefinitions(source: Indicator[]): IndicatorDefinition[] {
237
239
  return source.map((i) => ({
238
240
  id: i.id,
239
241
  label: i.label,
@@ -253,9 +255,7 @@ function toIndicatorDefinitions(source: typeof allIndicators): IndicatorDefiniti
253
255
  }
254
256
 
255
257
  // ── Controller ──
256
- const controller = createIndicatorSelectorController({
257
- catalog: toIndicatorDefinitions(allIndicators),
258
- })
258
+ const controller = createIndicatorSelectorController()
259
259
 
260
260
  // ── 从 Controller Signal 桥接的 Vue 响应式状态 ──
261
261
  const menuOpen = coreSignalToVueRef(controller.menuOpen)
@@ -267,7 +267,15 @@ const hasSearchResults = computed(
267
267
  () => filteredMain.value.length > 0 || filteredSub.value.length > 0,
268
268
  )
269
269
 
270
- const catalogLen = controller.catalog.peek().length
270
+ const catalog = coreSignalToVueRef(controller.catalog)
271
+ const catalogLen = computed(() => catalog.value.length)
272
+
273
+ onMounted(async () => {
274
+ if (!isBuiltinIndicatorsLoaded()) {
275
+ await loadBuiltinIndicators()
276
+ }
277
+ controller.catalog.set(toIndicatorDefinitions(allIndicators()))
278
+ })
271
279
 
272
280
  // ── 本地 UI 状态(非 Controller 管理的纯 UI 状态) ──
273
281
  const paramsVisible = ref(false)
@@ -196,6 +196,18 @@ const props = withDefaults(
196
196
  isFullscreen?: boolean
197
197
  /** 时区,默认 Asia/Shanghai */
198
198
  timezone?: string
199
+
200
+ /** MCP / AI runtime bridge 配置。传入后自动连接 MCP WebSocket server */
201
+ mcp?: {
202
+ wsUrl?: string
203
+ onToolCall?: (call: {
204
+ name: string
205
+ input: Record<string, unknown>
206
+ }) =>
207
+ | { success: boolean; error?: string; data?: unknown }
208
+ | Promise<{ success: boolean; error?: string; data?: unknown }>
209
+ autoReconnect?: boolean
210
+ }
199
211
  }>(),
200
212
  {
201
213
  yPaddingPx: 20,
@@ -864,6 +876,7 @@ defineExpose({
864
876
  zoomOut: (anchorX?: number) => applyZoomToLevel(zoomLevel.value - 1, anchorX),
865
877
  getZoomLevel: () => zoomLevel.value,
866
878
  getZoomLevelCount: () => controller.value?.getZoomLevelCount() ?? 10,
879
+ getController: () => controller.value,
867
880
  })
868
881
 
869
882
  // ==================== onMounted 拆分函数 ====================
@@ -881,7 +894,7 @@ function initChart(
881
894
  canvasLayer: HTMLDivElement,
882
895
  rightAxisLayer: HTMLDivElement,
883
896
  xAxisCanvas: HTMLCanvasElement,
884
- ): ChartController {
897
+ ): Promise<ChartController> {
885
898
  const ctrl = createChartController({
886
899
  container,
887
900
  data: [],
@@ -896,6 +909,7 @@ function initChart(
896
909
  priceLabelWidth: props.priceLabelWidth,
897
910
  minKWidth: props.minKWidth,
898
911
  maxKWidth: props.maxKWidth,
912
+ mcp: props.mcp,
899
913
  })
900
914
  return ctrl
901
915
  }
@@ -1082,7 +1096,7 @@ function setupSemanticController(ctrl: ChartController): void {
1082
1096
  // })
1083
1097
  }
1084
1098
 
1085
- onMounted(() => {
1099
+ onMounted(async () => {
1086
1100
  useAnchorPositioning.value = false
1087
1101
 
1088
1102
  const container = containerRef.value
@@ -1097,7 +1111,8 @@ onMounted(() => {
1097
1111
  const canvasLayer = container.querySelector<HTMLDivElement>('.canvas-layer')
1098
1112
  const xAxisCanvas = container.querySelector<HTMLCanvasElement>('.x-axis-canvas')
1099
1113
  const rightAxisLayer = chartMain.querySelector<HTMLDivElement>('.right-axis-host')
1100
- const ctrl = initChart(container, canvasLayer!, rightAxisLayer!, xAxisCanvas!)
1114
+ const ctrl = await initChart(container, canvasLayer!, rightAxisLayer!, xAxisCanvas!)
1115
+ if (!containerRef.value || !chartMainRef.value) return // 组件已卸载
1101
1116
  controller.value = ctrl
1102
1117
 
1103
1118
  // 3) 信号回调
package/src/index.ts CHANGED
@@ -88,7 +88,7 @@ export function __setControllerFactory(
88
88
  *
89
89
  * Throws if container is null/undefined (SSR-safe guard).
90
90
  */
91
- export function createChart(opts: ChartMountOptions): ChartController {
91
+ export function createChart(opts: ChartMountOptions): ChartController | Promise<ChartController> {
92
92
  if (opts.container == null) {
93
93
  throw new Error(
94
94
  '[@363045841yyt/klinechart] createChart: `container` is required and must be a non-null HTMLElement',
@@ -147,10 +147,24 @@ export function useChart(
147
147
  opts: Omit<ChartMountOptions, 'container'>,
148
148
  ): { chart: Ref<ChartController | null> } {
149
149
  const chart = shallowRef<ChartController | null>(null)
150
+ let disposed = false
150
151
 
151
152
  const mountIfReady = (el: HTMLElement | null): void => {
152
153
  if (el == null || chart.value != null) return
153
- chart.value = createChart({ ...opts, container: el })
154
+ const created = createChart({ ...opts, container: el })
155
+ const applyController = (ctrl: ChartController): void => {
156
+ if (disposed) {
157
+ ctrl.dispose()
158
+ return
159
+ }
160
+ chart.value = ctrl
161
+ }
162
+
163
+ if (typeof (created as Promise<ChartController>).then === 'function') {
164
+ ;(created as Promise<ChartController>).then(applyController)
165
+ } else {
166
+ applyController(created as ChartController)
167
+ }
154
168
  }
155
169
 
156
170
  // Mount synchronously if the ref is already populated (e.g. SFC where the
@@ -167,6 +181,7 @@ export function useChart(
167
181
  )
168
182
 
169
183
  const dispose = (): void => {
184
+ disposed = true
170
185
  stopWatch()
171
186
  const ctrl = chart.value
172
187
  if (ctrl != null) {
@@ -359,29 +374,40 @@ export const KLineChart = defineComponent({
359
374
  const scope = effectScope()
360
375
 
361
376
  const chart = shallowRef<ChartController | null>(null)
377
+ let mounted = true
378
+
379
+ const applyController = (ctrl: ChartController): void => {
380
+ if (!mounted) {
381
+ ctrl.dispose()
382
+ return
383
+ }
384
+ chart.value = ctrl
385
+ emit('ready', ctrl)
386
+ // Bridge viewport changes back out as zoomLevelChange.
387
+ const emitViewport = (): void => {
388
+ const vp = ctrl.viewport.peek()
389
+ emit('zoomLevelChange', vp.zoomLevel, vp.kWidth)
390
+ }
391
+ emitViewport()
392
+ const unsub = ctrl.viewport.subscribe(emitViewport)
393
+ onScopeDispose(unsub)
394
+ }
362
395
 
363
396
  onMounted(() => {
364
397
  const el = containerRef.value
365
398
  if (el == null) return
366
399
  scope.run(() => {
367
- chart.value = createChart({
400
+ const created = createChart({
368
401
  container: el,
369
402
  data: props.data,
370
403
  initialZoomLevel: props.initialZoomLevel,
371
404
  zoomLevels: props.zoomLevels,
372
405
  theme: props.theme,
373
406
  })
374
- if (chart.value != null) {
375
- emit('ready', chart.value)
376
- // Bridge viewport changes back out as zoomLevelChange.
377
- const ctrl = chart.value
378
- const emitViewport = (): void => {
379
- const vp = ctrl.viewport.peek()
380
- emit('zoomLevelChange', vp.zoomLevel, vp.kWidth)
381
- }
382
- emitViewport()
383
- const unsub = ctrl.viewport.subscribe(emitViewport)
384
- onScopeDispose(unsub)
407
+ if (typeof (created as Promise<ChartController>).then === 'function') {
408
+ ;(created as Promise<ChartController>).then(applyController)
409
+ } else {
410
+ applyController(created as ChartController)
385
411
  }
386
412
  })
387
413
 
@@ -401,6 +427,7 @@ export const KLineChart = defineComponent({
401
427
  })
402
428
 
403
429
  onUnmounted(() => {
430
+ mounted = false
404
431
  chart.value?.dispose()
405
432
  chart.value = null
406
433
  scope.stop()