@363045841yyt/klinechart 0.7.6 → 0.7.7

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.
@@ -560,7 +560,7 @@ onUnmounted(() => {
560
560
  width: 1px;
561
561
  height: 20px;
562
562
  align-self: center;
563
- background: #d9d9d9;
563
+ background: var(--klc-color-axis-line);
564
564
  }
565
565
 
566
566
  .indicator-item {
@@ -581,8 +581,7 @@ onUnmounted(() => {
581
581
  }
582
582
 
583
583
  .indicator-item.drag-over .indicator-btn {
584
- border-color: #1a1a1a;
585
- box-shadow: 0 0 0 2px rgba(26, 26, 26, 0.12);
584
+ box-shadow: 0 0 0 2px color-mix(in srgb, var(--klc-color-foreground) 12%, transparent);
586
585
  }
587
586
 
588
587
  .indicator-btn-wrapper {
@@ -593,10 +592,10 @@ onUnmounted(() => {
593
592
  position: relative;
594
593
  flex-shrink: 0;
595
594
  padding: 6px 16px;
596
- border: 1px solid #e0e0e0;
595
+ border: none;
597
596
  border-radius: 16px;
598
- background: #ffffff;
599
- color: #666;
597
+ background: var(--klc-color-tag-bg-white);
598
+ color: var(--klc-color-axis-text);
600
599
  font-size: 13px;
601
600
  font-weight: 500;
602
601
  cursor: pointer;
@@ -610,20 +609,17 @@ onUnmounted(() => {
610
609
  }
611
610
 
612
611
  .indicator-btn:hover:not(.hovering) {
613
- background: #f8f8f8;
614
- border-color: #ccc;
615
- color: #333;
612
+ background: var(--klc-color-tag-bg-hover);
613
+ color: var(--klc-color-foreground);
616
614
  }
617
615
 
618
616
  .indicator-btn.active {
619
- background: #f8f8f8;
620
- border-color: #1a1a1a;
621
- color: #1a1a1a;
617
+ background: var(--klc-color-tag-bg-hover);
618
+ color: var(--klc-color-foreground);
622
619
  }
623
620
 
624
621
  .indicator-btn.active:hover:not(.hovering) {
625
- background: #f0f0f0;
626
- border-color: #333;
622
+ background: var(--klc-color-tag-bg-hover);
627
623
  }
628
624
 
629
625
  .btn-content {
@@ -647,7 +643,7 @@ onUnmounted(() => {
647
643
  align-items: center;
648
644
  justify-content: center;
649
645
  gap: 4px;
650
- background: rgba(255, 255, 255, 0.85);
646
+ background: color-mix(in srgb, var(--klc-color-background) 85%, transparent);
651
647
  backdrop-filter: blur(4px);
652
648
  border-radius: 16px;
653
649
  z-index: 2;
@@ -660,7 +656,7 @@ onUnmounted(() => {
660
656
  border: none;
661
657
  border-radius: 50%;
662
658
  background: transparent;
663
- color: #666;
659
+ color: var(--klc-color-axis-text);
664
660
  cursor: pointer;
665
661
  display: flex;
666
662
  align-items: center;
@@ -669,12 +665,12 @@ onUnmounted(() => {
669
665
  }
670
666
 
671
667
  .action-btn:hover {
672
- background: rgba(0, 0, 0, 0.06);
673
- color: #333;
668
+ background: var(--klc-color-tag-bg-hover);
669
+ color: var(--klc-color-foreground);
674
670
  }
675
671
 
676
672
  .settings-btn:hover {
677
- color: #1a1a1a;
673
+ color: var(--klc-color-foreground);
678
674
  }
679
675
 
680
676
  .remove-btn:hover {
@@ -684,7 +680,7 @@ onUnmounted(() => {
684
680
  .divider {
685
681
  width: 1px;
686
682
  height: 14px;
687
- background: #e0e0e0;
683
+ background: var(--klc-color-border-button);
688
684
  }
689
685
 
690
686
  /* 添加按钮 */
@@ -693,10 +689,10 @@ onUnmounted(() => {
693
689
  width: 32px;
694
690
  height: 32px;
695
691
  padding: 0;
696
- border: 1px dashed #d9d9d9;
692
+ border: none;
697
693
  border-radius: 50%;
698
694
  background: transparent;
699
- color: #999;
695
+ color: var(--klc-color-axis-text);
700
696
  cursor: pointer;
701
697
  display: flex;
702
698
  align-items: center;
@@ -705,9 +701,8 @@ onUnmounted(() => {
705
701
  }
706
702
 
707
703
  .add-btn:hover {
708
- border-color: #1a1a1a;
709
- color: #1a1a1a;
710
- background: rgba(26, 26, 26, 0.04);
704
+ color: var(--klc-color-foreground);
705
+ background: var(--klc-color-tag-bg-hover);
711
706
  }
712
707
 
713
708
  /* ─────────────────────────────────────────────────────────────────
@@ -728,8 +723,8 @@ onUnmounted(() => {
728
723
 
729
724
  /* 弹窗容器 */
730
725
  .selector-modal {
731
- background: #ffffff;
732
- border: 1px solid #e0e0e0;
726
+ background: var(--klc-color-tag-bg-white);
727
+ border: 1px solid var(--klc-color-axis-line);
733
728
  border-radius: 12px;
734
729
  box-shadow: 0 8px 40px rgba(0, 0, 0, 0.15);
735
730
  width: 90vw;
@@ -746,8 +741,8 @@ onUnmounted(() => {
746
741
  justify-content: space-between;
747
742
  align-items: center;
748
743
  padding: 16px 20px;
749
- background: #f8f8f8;
750
- border-bottom: 1px solid #e8e8e8;
744
+ background: var(--klc-color-background);
745
+ border-bottom: 1px solid var(--klc-color-border-chart);
751
746
  flex-shrink: 0;
752
747
  }
753
748
 
@@ -760,18 +755,18 @@ onUnmounted(() => {
760
755
  .title-text {
761
756
  font-size: 14px;
762
757
  font-weight: 600;
763
- color: #1a1a1a;
758
+ color: var(--klc-color-foreground);
764
759
  letter-spacing: 0.2px;
765
760
  }
766
761
 
767
762
  .title-sub {
768
763
  font-size: 11px;
769
- color: #999;
764
+ color: var(--klc-color-axis-text);
770
765
  }
771
766
 
772
767
  .modal-close {
773
- background: #fff;
774
- border: 1px solid #e0e0e0;
768
+ background: var(--klc-color-tag-bg-white);
769
+ border: 1px solid var(--klc-color-border-button);
775
770
  border-radius: 6px;
776
771
  width: 28px;
777
772
  height: 28px;
@@ -779,15 +774,15 @@ onUnmounted(() => {
779
774
  align-items: center;
780
775
  justify-content: center;
781
776
  cursor: pointer;
782
- color: #888;
777
+ color: var(--klc-color-axis-text);
783
778
  transition: all 0.15s;
784
779
  padding: 0;
785
780
  }
786
781
 
787
782
  .modal-close:hover {
788
- background: #f0f0f0;
789
- color: #333;
790
- border-color: #ccc;
783
+ background: var(--klc-color-tag-bg-hover);
784
+ color: var(--klc-color-foreground);
785
+ border-color: var(--klc-color-axis-line);
791
786
  }
792
787
 
793
788
  .modal-close svg {
@@ -802,8 +797,8 @@ onUnmounted(() => {
802
797
  }
803
798
 
804
799
  .view-toggle-btn {
805
- background: #fff;
806
- border: 1px solid #e0e0e0;
800
+ background: var(--klc-color-tag-bg-white);
801
+ border: 1px solid var(--klc-color-border-button);
807
802
  border-radius: 6px;
808
803
  width: 28px;
809
804
  height: 28px;
@@ -811,21 +806,21 @@ onUnmounted(() => {
811
806
  align-items: center;
812
807
  justify-content: center;
813
808
  cursor: pointer;
814
- color: #888;
809
+ color: var(--klc-color-axis-text);
815
810
  transition: all 0.15s;
816
811
  padding: 0;
817
812
  }
818
813
 
819
814
  .view-toggle-btn:hover {
820
- background: #f0f0f0;
821
- color: #333;
822
- border-color: #ccc;
815
+ background: var(--klc-color-tag-bg-hover);
816
+ color: var(--klc-color-foreground);
817
+ border-color: var(--klc-color-axis-line);
823
818
  }
824
819
 
825
820
  .view-toggle-btn.active {
826
- background: #1a1a1a;
827
- border-color: #1a1a1a;
828
- color: #fff;
821
+ background: var(--klc-color-tag-bg-white);
822
+ border-color: var(--klc-color-border-button);
823
+ color: var(--klc-color-foreground);
829
824
  }
830
825
 
831
826
  /* 弹窗主体 */
@@ -838,26 +833,36 @@ onUnmounted(() => {
838
833
  gap: 20px;
839
834
  }
840
835
 
836
+ .modal-body::-webkit-scrollbar {
837
+ width: 8px;
838
+ }
839
+
840
+ .modal-body::-webkit-scrollbar-thumb {
841
+ background: var(--klc-color-axis-line);
842
+ border: 2px solid var(--klc-color-tag-bg-white);
843
+ border-radius: 999px;
844
+ }
845
+
841
846
  /* 搜索框 */
842
847
  .search-box {
843
848
  display: flex;
844
849
  align-items: center;
845
850
  gap: 10px;
846
851
  padding: 10px 14px;
847
- border: 1px solid #e0e0e0;
852
+ border: 1px solid var(--klc-color-border-button);
848
853
  border-radius: 8px;
849
854
  transition: all 0.2s ease;
850
855
  }
851
856
 
852
857
  .search-box:focus-within {
853
- background: #ffffff;
854
- border-color: #1a1a1a;
855
- box-shadow: 0 0 0 2px rgba(26, 26, 26, 0.08);
858
+ background: var(--klc-color-tag-bg-white);
859
+ border-color: var(--klc-color-foreground);
860
+ box-shadow: 0 0 0 2px color-mix(in srgb, var(--klc-color-foreground) 8%, transparent);
856
861
  }
857
862
 
858
863
  .search-icon {
859
864
  flex-shrink: 0;
860
- color: #999;
865
+ color: var(--klc-color-axis-text);
861
866
  }
862
867
 
863
868
  .search-input {
@@ -865,12 +870,12 @@ onUnmounted(() => {
865
870
  border: none;
866
871
  background: transparent;
867
872
  font-size: 13px;
868
- color: #333;
873
+ color: var(--klc-color-foreground);
869
874
  outline: none;
870
875
  }
871
876
 
872
877
  .search-input::placeholder {
873
- color: #aaa;
878
+ color: var(--klc-color-axis-text);
874
879
  }
875
880
 
876
881
  /* 无结果提示 */
@@ -880,7 +885,7 @@ onUnmounted(() => {
880
885
  align-items: center;
881
886
  justify-content: center;
882
887
  padding: 48px 20px;
883
- color: #ccc;
888
+ color: var(--klc-color-axis-text);
884
889
  gap: 12px;
885
890
  }
886
891
 
@@ -891,13 +896,13 @@ onUnmounted(() => {
891
896
  .no-results p {
892
897
  margin: 0;
893
898
  font-size: 14px;
894
- color: #999;
899
+ color: var(--klc-color-axis-text);
895
900
  font-weight: 500;
896
901
  }
897
902
 
898
903
  .no-results-hint {
899
904
  font-size: 12px;
900
- color: #bbb;
905
+ color: var(--klc-color-axis-text);
901
906
  }
902
907
 
903
908
  /* 指标区域 */
@@ -916,13 +921,13 @@ onUnmounted(() => {
916
921
  .section-title {
917
922
  font-size: 13px;
918
923
  font-weight: 600;
919
- color: #1a1a1a;
924
+ color: var(--klc-color-foreground);
920
925
  }
921
926
 
922
927
  .section-count {
923
928
  font-size: 11px;
924
- color: #999;
925
- background: #f0f0f0;
929
+ color: var(--klc-color-axis-text);
930
+ background: var(--klc-color-grid-minor);
926
931
  padding: 2px 8px;
927
932
  border-radius: 10px;
928
933
  }
@@ -959,8 +964,8 @@ onUnmounted(() => {
959
964
  transform: translateX(-50%);
960
965
  padding: 4px 10px;
961
966
  border-radius: 6px;
962
- background: #333;
963
- color: #fff;
967
+ background: var(--klc-color-foreground);
968
+ color: var(--klc-color-background);
964
969
  font-size: 12px;
965
970
  white-space: nowrap;
966
971
  pointer-events: none;
@@ -984,24 +989,24 @@ onUnmounted(() => {
984
989
  flex-direction: column;
985
990
  gap: 4px;
986
991
  padding: 12px 14px;
987
- border: 1px solid #e8e8e8;
992
+ border: 1px solid var(--klc-color-border-chart);
988
993
  border-radius: 8px;
989
- background: #ffffff;
994
+ background: var(--klc-color-tag-bg-white);
990
995
  cursor: pointer;
991
996
  transition: all 0.15s;
992
997
  text-align: left;
993
998
  }
994
999
 
995
1000
  .indicator-card:hover:not(.disabled) {
996
- border-color: #1a1a1a;
997
- background: #fafafa;
1001
+ border-color: var(--klc-color-foreground);
1002
+ background: var(--klc-color-background);
998
1003
  transform: translateY(-1px);
999
1004
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.06);
1000
1005
  }
1001
1006
 
1002
1007
  .indicator-card.active {
1003
- border-color: #1a1a1a;
1004
- background: #f8f8f8;
1008
+ border-color: var(--klc-color-foreground);
1009
+ background: var(--klc-color-tag-bg-hover);
1005
1010
  }
1006
1011
 
1007
1012
  .card-header {
@@ -1014,7 +1019,7 @@ onUnmounted(() => {
1014
1019
  .card-label {
1015
1020
  font-size: 13px;
1016
1021
  font-weight: 600;
1017
- color: #1a1a1a;
1022
+ color: var(--klc-color-foreground);
1018
1023
  }
1019
1024
 
1020
1025
  .card-header-actions {
@@ -1033,32 +1038,32 @@ onUnmounted(() => {
1033
1038
  border: none;
1034
1039
  border-radius: 4px;
1035
1040
  background: transparent;
1036
- color: #bbb;
1041
+ color: var(--klc-color-axis-text);
1037
1042
  cursor: pointer;
1038
1043
  transition: all 0.15s;
1039
1044
  }
1040
1045
 
1041
1046
  .card-settings-btn:hover {
1042
- background: #f0f0f0;
1043
- color: #555;
1047
+ background: var(--klc-color-tag-bg-hover);
1048
+ color: var(--klc-color-foreground);
1044
1049
  }
1045
1050
 
1046
1051
  .card-name {
1047
1052
  font-size: 11px;
1048
- color: #666;
1053
+ color: var(--klc-color-axis-text);
1049
1054
  line-height: 1.4;
1050
1055
  }
1051
1056
 
1052
1057
  .card-params {
1053
1058
  font-size: 10px;
1054
- color: #999;
1059
+ color: var(--klc-color-axis-text);
1055
1060
  margin-top: 2px;
1056
1061
  }
1057
1062
 
1058
1063
  /* 区域分隔线 */
1059
1064
  .section-divider {
1060
1065
  height: 1px;
1061
- background: linear-gradient(90deg, transparent, #e0e0e0, transparent);
1066
+ background: linear-gradient(90deg, transparent, var(--klc-color-border-button), transparent);
1062
1067
  margin: 4px 0;
1063
1068
  }
1064
1069
 
@@ -1068,18 +1073,18 @@ onUnmounted(() => {
1068
1073
  align-items: center;
1069
1074
  justify-content: space-between;
1070
1075
  padding: 12px 20px;
1071
- background: #f8f8f8;
1072
- border-top: 1px solid #e8e8e8;
1076
+ background: var(--klc-color-background);
1077
+ border-top: 1px solid var(--klc-color-border-chart);
1073
1078
  flex-shrink: 0;
1074
1079
  }
1075
1080
 
1076
1081
  .footer-info {
1077
1082
  font-size: 12px;
1078
- color: #666;
1083
+ color: var(--klc-color-axis-text);
1079
1084
  }
1080
1085
 
1081
1086
  .info-text {
1082
- color: #999;
1087
+ color: var(--klc-color-axis-text);
1083
1088
  }
1084
1089
 
1085
1090
  /* 按钮样式 */
@@ -1098,14 +1103,14 @@ onUnmounted(() => {
1098
1103
  }
1099
1104
 
1100
1105
  .btn-confirm {
1101
- background: #1a1a1a;
1102
- border-color: #1a1a1a;
1103
- color: #fff;
1106
+ background: var(--klc-color-foreground);
1107
+ border-color: var(--klc-color-foreground);
1108
+ color: var(--klc-color-background);
1104
1109
  }
1105
1110
 
1106
1111
  .btn-confirm:hover {
1107
- background: #333;
1108
- border-color: #333;
1112
+ background: var(--klc-color-foreground);
1113
+ border-color: var(--klc-color-foreground);
1109
1114
  box-shadow: 0 2px 10px rgba(0, 0, 0, 0.15);
1110
1115
  transform: translateY(-1px);
1111
1116
  }
@@ -1,5 +1,5 @@
1
1
  <template>
2
- <div ref="chartWrapperRef" class="chart-wrapper" :data-theme="chartTheme">
2
+ <div ref="chartWrapperRef" class="chart-wrapper" :data-theme="chartTheme" :style="themeCssVars">
3
3
  <div
4
4
  class="chart-stage"
5
5
  :class="{
@@ -75,6 +75,8 @@
75
75
  :set-el="setTooltipEl"
76
76
  :use-anchor="useAnchorPositioning"
77
77
  :anchor-placement="tooltipAnchorPlacement"
78
+ :up-color="tooltipColors.upColor"
79
+ :down-color="tooltipColors.downColor"
78
80
  />
79
81
  <MarkerTooltip
80
82
  v-if="hoveredMarker || hoveredCustomMarker"
@@ -136,6 +138,8 @@ import {
136
138
  DrawingInteractionController,
137
139
  } from '@363045841yyt/klinechart-core/controllers'
138
140
  import type { DrawingObject, DrawingStyle } from '@363045841yyt/klinechart-core/plugin'
141
+ import type { ChartSettings } from '@363045841yyt/klinechart-core/config'
142
+ import { resolveThemeColors, themeToCssVars, lightTheme, darkTheme, type ColorPresetSettings } from '@363045841yyt/klinechart-core'
139
143
  import LeftToolbar from './LeftToolbar.vue'
140
144
 
141
145
  const props = withDefaults(
@@ -179,6 +183,7 @@ const props = withDefaults(
179
183
  const emit = defineEmits<{
180
184
  (e: 'zoomLevelChange', level: number, kWidth: number): void
181
185
  (e: 'toggleFullscreen'): void
186
+ (e: 'themeChange', theme: 'light' | 'dark'): void
182
187
  }>()
183
188
 
184
189
  const containerRef = ref<HTMLDivElement | null>(null)
@@ -219,11 +224,58 @@ kGap.value = kGapFromKWidth(kWidth.value, viewportDpr.value)
219
224
  /* ========== 主题状态 ========== */
220
225
  const chartTheme = ref<'light' | 'dark'>('light')
221
226
 
227
+ const chartSettings = ref<ChartSettings>({})
228
+
229
+ const tooltipColors = computed(() => {
230
+ const isAsiaMarket = chartSettings.value.isAsiaMarket ?? false
231
+ const colors = resolveThemeColors(chartTheme.value, isAsiaMarket as boolean | undefined)
232
+ return {
233
+ upColor: colors.candleUpBody,
234
+ downColor: colors.candleDownBody,
235
+ }
236
+ })
237
+
238
+ const themeCssVars = computed(() => {
239
+ const theme = chartTheme.value === 'dark' ? darkTheme : lightTheme
240
+ const overrides = (chartSettings.value.colorPresetSettings as ColorPresetSettings | undefined)?.[chartTheme.value]
241
+ if (overrides && Object.keys(overrides).length > 0) {
242
+ return themeToCssVars({ ...theme, colors: { ...theme.colors, ...overrides } })
243
+ }
244
+ return themeToCssVars(theme)
245
+ })
246
+
247
+ /* ========== 主题切换(支持 light / dark / auto 跟随系统) ========== */
248
+ let autoThemeMediaQuery: MediaQueryList | null = null
249
+
250
+ function onSystemThemeChange(e: MediaQueryListEvent) {
251
+ controller.value?.setTheme(e.matches ? 'dark' : 'light')
252
+ }
253
+
254
+ function applyThemeFromSettings(ctrl: ChartController | null, themeSetting: string | undefined) {
255
+ if (!ctrl || !themeSetting) return
256
+
257
+ if (themeSetting === 'auto') {
258
+ const mq = window.matchMedia('(prefers-color-scheme: dark)')
259
+ ctrl.setTheme(mq.matches ? 'dark' : 'light')
260
+ if (autoThemeMediaQuery !== mq) {
261
+ autoThemeMediaQuery?.removeEventListener('change', onSystemThemeChange)
262
+ autoThemeMediaQuery = mq
263
+ mq.addEventListener('change', onSystemThemeChange)
264
+ }
265
+ } else {
266
+ autoThemeMediaQuery?.removeEventListener('change', onSystemThemeChange)
267
+ autoThemeMediaQuery = null
268
+ ctrl.setTheme(themeSetting as 'light' | 'dark')
269
+ }
270
+ }
271
+
222
272
  function scheduleRender() {
223
273
  /* Controller auto-renders on state changes */
224
274
  }
225
275
 
226
- function handleSettingsChange(settings: Record<string, boolean | string>) {
276
+ function handleSettingsChange(settings: ChartSettings) {
277
+ chartSettings.value = settings
278
+ applyThemeFromSettings(controller.value, settings.theme as string)
227
279
  controller.value?.updateSettingsFacade(settings)
228
280
 
229
281
  if (settings.performanceTest10kKlines) {
@@ -735,7 +787,14 @@ function handleReorderSubIndicators(orderedIndicatorIds: string[]) {
735
787
  /* 计算总宽度:从 Vue 响应式状态读取,zoom 变化时自动重算 */
736
788
  const axisHostWidth = computed(() => props.rightAxisWidth + props.priceLabelWidth)
737
789
 
738
- const totalWidth = computed(() => controller.value?.getContentWidth() ?? 0)
790
+ const totalWidth = computed(() => {
791
+ void dataVersion.value
792
+ void viewWidth.value
793
+ void kWidth.value
794
+ void kGap.value
795
+ void viewportDpr.value
796
+ return controller.value?.getContentWidth() ?? 0
797
+ })
739
798
 
740
799
  function scrollToRight() {
741
800
  const container = containerRef.value
@@ -872,7 +931,9 @@ function setupChartCallbacks(ctrl: ChartController): void {
872
931
  })
873
932
 
874
933
  const unsubscribeTheme = ctrl.theme.subscribe(() => {
875
- chartTheme.value = ctrl.theme.peek()
934
+ const newTheme = ctrl.theme.peek()
935
+ chartTheme.value = newTheme
936
+ emit('themeChange', newTheme)
876
937
  })
877
938
 
878
939
  const unsubscribeIndicators = ctrl.indicators.subscribe(() => {
@@ -936,11 +997,14 @@ function setupChartCallbacks(ctrl: ChartController): void {
936
997
  unsubscribeTheme()
937
998
  unsubscribeIndicators()
938
999
  unsubscribeSubPanes()
1000
+ autoThemeMediaQuery?.removeEventListener('change', onSystemThemeChange)
939
1001
  })
940
1002
  }
941
1003
 
942
1004
  function applyInitialSettings(ctrl: ChartController): void {
943
1005
  const initialSettings = toolbarRef.value?.getSettings() ?? { showVolumePriceMarkers: true }
1006
+ chartSettings.value = initialSettings
1007
+ applyThemeFromSettings(ctrl, initialSettings.theme as string)
944
1008
  ctrl.updateSettingsFacade(initialSettings)
945
1009
 
946
1010
  if (initialSettings.performanceTest10kKlines) {
@@ -1070,12 +1134,12 @@ watch(
1070
1134
  --kmap-height: var(--kmap-chart-height, 100%);
1071
1135
  --kmap-width: var(--kmap-chart-width, 100%);
1072
1136
 
1073
- --chart-bg: #ffffff;
1074
- --chart-bg-secondary: #f8f9fa;
1075
- --chart-border: #e5e7eb;
1076
- --chart-border-active: #3b82f6;
1077
- --chart-text: #374151;
1078
- --chart-text-secondary: #6b7280;
1137
+ --chart-bg: var(--klc-color-chart-background);
1138
+ --chart-bg-secondary: var(--klc-color-chart-background);
1139
+ --chart-border: var(--klc-color-border-chart);
1140
+ --chart-border-active: #1890ff;
1141
+ --chart-text: var(--klc-color-foreground);
1142
+ --chart-text-secondary: var(--klc-color-axis-text);
1079
1143
 
1080
1144
  display: flex;
1081
1145
  align-items: center;
@@ -1086,15 +1150,6 @@ watch(
1086
1150
  flex-direction: column;
1087
1151
  }
1088
1152
 
1089
- .chart-wrapper[data-theme='dark'] {
1090
- --chart-bg: #1a1a2e;
1091
- --chart-bg-secondary: #16162a;
1092
- --chart-border: #2d2d44;
1093
- --chart-border-active: #60a5fa;
1094
- --chart-text: #e5e7eb;
1095
- --chart-text-secondary: #9ca3af;
1096
- }
1097
-
1098
1153
  .chart-stage {
1099
1154
  width: 95%;
1100
1155
  height: 85%;
@@ -67,7 +67,7 @@ export interface KLineData {
67
67
  stockCode?: string
68
68
  }
69
69
 
70
- const props = defineProps<{
70
+ const props = withDefaults(defineProps<{
71
71
  k: KLineData | null
72
72
  index: number | null
73
73
  data: ReadonlyArray<KLineData>
@@ -75,7 +75,14 @@ const props = defineProps<{
75
75
  useAnchor?: boolean
76
76
  anchorPlacement?: 'right-bottom' | 'left-bottom'
77
77
  setEl?: (el: HTMLDivElement | null) => void
78
- }>()
78
+ /** 涨的颜色(默认红涨) */
79
+ upColor?: string
80
+ /** 跌的颜色(默认绿跌) */
81
+ downColor?: string
82
+ }>(), {
83
+ upColor: '#ef4444',
84
+ downColor: '#22c55e',
85
+ })
79
86
 
80
87
  const useAnchor = computed(() => props.useAnchor === true)
81
88
  const anchorPlacementClass = computed(() =>
@@ -105,8 +112,6 @@ function formatSigned(val: number, unit: string): string {
105
112
  return `${sign}${val.toFixed(2)}${unit}`
106
113
  }
107
114
 
108
- const UP_COLOR = '#ef4444'
109
- const DOWN_COLOR = '#22c55e'
110
115
  const NEUTRAL_COLOR = '#6b7280'
111
116
 
112
117
  function calcDirection(k: KLineData, data: ReadonlyArray<KLineData>, idx: number | null): number {
@@ -121,21 +126,21 @@ const openColor = computed(() => {
121
126
  const k = props.k
122
127
  if (!k) return NEUTRAL_COLOR
123
128
  const dir = calcDirection(k, props.data, props.index)
124
- return dir > 0 ? UP_COLOR : dir < 0 ? DOWN_COLOR : NEUTRAL_COLOR
129
+ return dir > 0 ? props.upColor : dir < 0 ? props.downColor : NEUTRAL_COLOR
125
130
  })
126
131
 
127
132
  const closeColor = computed(() => {
128
133
  const k = props.k
129
134
  if (!k) return NEUTRAL_COLOR
130
135
  const diff = k.close - k.open
131
- return diff > 0 ? UP_COLOR : diff < 0 ? DOWN_COLOR : NEUTRAL_COLOR
136
+ return diff > 0 ? props.upColor : diff < 0 ? props.downColor : NEUTRAL_COLOR
132
137
  })
133
138
 
134
139
  const changeColor = computed(() => {
135
140
  const k = props.k
136
141
  if (!k) return NEUTRAL_COLOR
137
142
  const pct = k.changePercent ?? (k.close - k.open) / k.open * 100
138
- return pct > 0 ? UP_COLOR : pct < 0 ? DOWN_COLOR : NEUTRAL_COLOR
143
+ return pct > 0 ? props.upColor : pct < 0 ? props.downColor : NEUTRAL_COLOR
139
144
  })
140
145
  </script>
141
146
 
@@ -147,10 +152,10 @@ const changeColor = computed(() => {
147
152
  max-width: 260px;
148
153
  padding: 10px 12px;
149
154
  border-radius: 8px;
150
- background: rgba(255, 255, 255, 0.92);
151
- border: 1px solid rgba(0, 0, 0, 0.12);
155
+ background: var(--klc-color-tooltip-bg);
156
+ border: 1px solid var(--klc-color-tooltip-border);
152
157
  box-shadow: 0 6px 18px rgba(0, 0, 0, 0.12);
153
- color: rgba(0, 0, 0, 0.78);
158
+ color: var(--klc-color-tooltip-text);
154
159
  font-size: 12px;
155
160
  line-height: 1.4;
156
161
  pointer-events: none;
@@ -178,7 +183,8 @@ const changeColor = computed(() => {
178
183
  }
179
184
 
180
185
  .kline-tooltip__grid .row span:first-child {
181
- color: rgba(0, 0, 0, 0.56);
186
+ color: var(--klc-color-tooltip-text);
187
+ opacity: 0.56;
182
188
  }
183
189
 
184
190
  @supports (anchor-name: --kmap-anchor) and (position-anchor: --kmap-anchor) {