@funnest/charts-ui 0.6.22 → 0.6.24

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/i18n.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import type { Locale, Resolution } from '@funnest/charts';
1
+ import type { Locale } from '@funnest/charts';
2
2
  export declare const STRINGS: {
3
3
  ko: {
4
4
  searchSymbol: string;
@@ -93,6 +93,8 @@ export declare const STRINGS: {
93
93
  addIndicator: string;
94
94
  indicatorSettings: string;
95
95
  removeIndicator: string;
96
+ hideVolume: string;
97
+ volumeDesc: string;
96
98
  apply: string;
97
99
  cancel: string;
98
100
  numbersHint: string;
@@ -238,6 +240,8 @@ export declare const STRINGS: {
238
240
  addIndicator: string;
239
241
  indicatorSettings: string;
240
242
  removeIndicator: string;
243
+ hideVolume: string;
244
+ volumeDesc: string;
241
245
  apply: string;
242
246
  cancel: string;
243
247
  numbersHint: string;
@@ -300,8 +304,4 @@ export declare function stringsOf(s: {
300
304
  locale: Locale;
301
305
  strings?: Partial<Strings> | undefined;
302
306
  }): Strings;
303
- /**
304
- * '1' → 1분, '60' → 1시간, '1D' → 일 (short) / 1일 (long), '12M' → 1년.
305
- * Short labels are for the toolbar chips, long ones for the interval menu.
306
- */
307
- export declare function resolutionLabel(resolution: Resolution, locale: Locale, form?: 'short' | 'long'): string;
307
+ export { resolutionLabel } from '@funnest/charts';
package/dist/index.js CHANGED
@@ -424,6 +424,7 @@ function G2(n2, t3) {
424
424
  }
425
425
 
426
426
  // src/i18n.ts
427
+ import { resolutionLabel } from "@funnest/charts";
427
428
  var STRINGS = {
428
429
  ko: {
429
430
  searchSymbol: "\uC885\uBAA9 \uAC80\uC0C9",
@@ -518,6 +519,8 @@ var STRINGS = {
518
519
  addIndicator: "\uC9C0\uD45C \uCD94\uAC00",
519
520
  indicatorSettings: "\uC9C0\uD45C \uC124\uC815",
520
521
  removeIndicator: "\uC9C0\uD45C \uC0AD\uC81C",
522
+ hideVolume: "\uAC70\uB798\uB7C9 \uC228\uAE30\uAE30",
523
+ volumeDesc: "\uBD09\uB9C8\uB2E4 \uAC70\uB798\uB41C \uC591 (\uAC00\uACA9 \uC544\uB798 \uC601\uC5ED)",
521
524
  apply: "\uC801\uC6A9",
522
525
  cancel: "\uCDE8\uC18C",
523
526
  numbersHint: "\uC27C\uD45C\uB85C \uAD6C\uBD84 (\uC608: 5, 20, 60)",
@@ -665,6 +668,8 @@ var STRINGS = {
665
668
  addIndicator: "Add indicator",
666
669
  indicatorSettings: "Indicator settings",
667
670
  removeIndicator: "Remove indicator",
671
+ hideVolume: "Hide volume",
672
+ volumeDesc: "How much traded in each bar (pane under the price)",
668
673
  apply: "Apply",
669
674
  cancel: "Cancel",
670
675
  numbersHint: "Comma separated (e.g. 5, 20, 60)",
@@ -725,28 +730,6 @@ function stringsOf(s3) {
725
730
  if (!byLocale) merged.set(s3.strings, byLocale = {});
726
731
  return byLocale[s3.locale] ??= { ...STRINGS[s3.locale], ...s3.strings };
727
732
  }
728
- function resolutionLabel(resolution, locale, form = "short") {
729
- const match = /^(\d*)([SDWM]?)$/i.exec(resolution.trim());
730
- if (!match) return resolution;
731
- const n2 = match[1] ? Number(match[1]) : 1;
732
- const unit = (match[2] ?? "").toUpperCase();
733
- const ko = locale === "ko";
734
- const long = form === "long";
735
- switch (unit) {
736
- case "S":
737
- return ko ? `${n2}\uCD08` : `${n2}s`;
738
- case "D":
739
- return ko ? n2 === 1 && !long ? "\uC77C" : `${n2}\uC77C` : `${n2}D`;
740
- case "W":
741
- return ko ? n2 === 1 && !long ? "\uC8FC" : `${n2}\uC8FC` : `${n2}W`;
742
- case "M":
743
- if (n2 % 12 === 0) return ko ? `${n2 / 12}\uB144` : `${n2 / 12}Y`;
744
- return ko ? n2 === 1 && !long ? "\uC6D4" : `${n2}\uAC1C\uC6D4` : `${n2}M`;
745
- default:
746
- if (n2 >= 60 && n2 % 60 === 0) return ko ? `${n2 / 60}\uC2DC\uAC04` : `${n2 / 60}h`;
747
- return ko ? `${n2}\uBD84` : `${n2}m`;
748
- }
749
- }
750
733
 
751
734
  // ../../node_modules/.pnpm/preact@11.2.0/node_modules/preact/jsx-runtime/dist/jsxRuntime.mjs
752
735
  var f3 = /* @__PURE__ */ Symbol.for("pv");
@@ -1451,11 +1434,16 @@ function IndicatorPicker({ ctx }) {
1451
1434
  const all = ctx.chart.indicatorDefinitions().filter((d3) => !d3.hidden);
1452
1435
  const q2 = query.trim().toLowerCase();
1453
1436
  const matches = (d3) => !q2 || [d3.type, d3.name.ko, d3.name.en, d3.description[locale]].some((s3) => s3.toLowerCase().includes(q2));
1437
+ const volumeHidden = !ctx.chart.settings.volume && (!q2 || [t3.settingVolume, t3.volume, "volume"].some((s3) => s3.toLowerCase().includes(q2)));
1438
+ const showVolume = () => {
1439
+ ctx.chart.setVolumeVisible(true);
1440
+ close();
1441
+ };
1454
1442
  const groups = [
1455
- [locale === "ko" ? "\uAC00\uACA9 \uCC28\uD2B8\uC5D0 \uD45C\uC2DC" : "On price", all.filter((d3) => d3.overlay && matches(d3))],
1456
- [locale === "ko" ? "\uC544\uB798 \uC601\uC5ED\uC5D0 \uD45C\uC2DC" : "Separate pane", all.filter((d3) => !d3.overlay && matches(d3))]
1457
- ].filter(([, defs]) => defs.length > 0);
1458
- const first = groups[0]?.[1][0];
1443
+ { label: locale === "ko" ? "\uAC00\uACA9 \uCC28\uD2B8\uC5D0 \uD45C\uC2DC" : "On price", defs: all.filter((d3) => d3.overlay && matches(d3)), volume: false },
1444
+ { label: locale === "ko" ? "\uC544\uB798 \uC601\uC5ED\uC5D0 \uD45C\uC2DC" : "Separate pane", defs: all.filter((d3) => !d3.overlay && matches(d3)), volume: volumeHidden }
1445
+ ].filter((g3) => g3.defs.length > 0 || g3.volume);
1446
+ const first = groups.find((g3) => g3.defs.length)?.defs[0];
1459
1447
  return /* @__PURE__ */ a3(Dialog, { title: t3.addIndicator, onClose: close, children: [
1460
1448
  all.length > SEARCH_THRESHOLD && /* @__PURE__ */ a3("div", { class: "fnc-search fnc-ind-search", children: /* @__PURE__ */ a3(
1461
1449
  "input",
@@ -1470,8 +1458,12 @@ function IndicatorPicker({ ctx }) {
1470
1458
  ) }),
1471
1459
  /* @__PURE__ */ a3("div", { class: "fnc-sr-list fnc-scroll", children: [
1472
1460
  groups.length === 0 && /* @__PURE__ */ a3("div", { class: "fnc-empty", children: t3.noResults }),
1473
- groups.map(([label, defs]) => /* @__PURE__ */ a3($, { children: [
1461
+ groups.map(({ label, defs, volume }) => /* @__PURE__ */ a3($, { children: [
1474
1462
  /* @__PURE__ */ a3("div", { class: "fnc-sr-section", children: label }),
1463
+ volume && /* @__PURE__ */ a3("button", { class: "fnc-sr-row", onClick: showVolume, children: /* @__PURE__ */ a3("span", { class: "fnc-sr-main", children: [
1464
+ /* @__PURE__ */ a3("span", { class: "fnc-sr-name", children: t3.settingVolume }),
1465
+ /* @__PURE__ */ a3("span", { class: "fnc-sr-meta", children: t3.volumeDesc })
1466
+ ] }) }),
1475
1467
  defs.map((def) => {
1476
1468
  const type = def.type;
1477
1469
  return /* @__PURE__ */ a3("button", { class: "fnc-sr-row", onClick: () => add(type), children: /* @__PURE__ */ a3("span", { class: "fnc-sr-main", children: [
@@ -2645,6 +2637,26 @@ function AppItem({ ctx, item }) {
2645
2637
  ] })
2646
2638
  ] });
2647
2639
  }
2640
+ function VolumeItem({ ctx, value }) {
2641
+ const t3 = stringsOf(ctx.store.get());
2642
+ return /* @__PURE__ */ a3("div", { class: "fnc-ind fnc-volume-item", children: [
2643
+ /* @__PURE__ */ a3("span", { class: "fnc-ind-title", children: t3.settingVolume }),
2644
+ value !== null && /* @__PURE__ */ a3("b", { class: "fnc-flat", children: value }),
2645
+ /* @__PURE__ */ a3("span", { class: "fnc-ind-actions", children: [
2646
+ /* @__PURE__ */ a3(
2647
+ "button",
2648
+ {
2649
+ class: "fnc-ind-btn",
2650
+ "data-tip": t3.chartSettings,
2651
+ "aria-label": `${t3.settingVolume} ${t3.chartSettings}`,
2652
+ onClick: () => ctx.store.set({ dialog: { kind: "chartSettings" } }),
2653
+ children: /* @__PURE__ */ a3(GearIcon, {})
2654
+ }
2655
+ ),
2656
+ /* @__PURE__ */ a3("button", { class: "fnc-ind-btn", "data-tip": t3.hideVolume, "aria-label": t3.hideVolume, onClick: () => ctx.chart.setVolumeVisible(false), children: /* @__PURE__ */ a3(SmallCloseIcon, {}) })
2657
+ ] })
2658
+ ] });
2659
+ }
2648
2660
  function Legend({ ctx }) {
2649
2661
  const s3 = useStore(ctx.store);
2650
2662
  const t3 = stringsOf(s3);
@@ -2722,6 +2734,7 @@ function Legend({ ctx }) {
2722
2734
  const items = s3.indicators.length ? ctx.chart.indicatorLegend(hover?.index) : [];
2723
2735
  const overlayItems = items.filter((i3) => i3.overlay);
2724
2736
  const paneLegends = s3.layout.panes.filter((p3) => p3.kind === "indicator").map((pane) => ({ pane, item: items.find((i3) => i3.id === pane.id) }));
2737
+ const volumePane = s3.layout.panes.find((p3) => p3.kind === "volume");
2725
2738
  return /* @__PURE__ */ a3($, { children: [
2726
2739
  /* @__PURE__ */ a3("div", { class: "fnc-legend", ref, children: [
2727
2740
  /* @__PURE__ */ a3("div", { class: "fnc-legend-title", children: [
@@ -2753,6 +2766,7 @@ function Legend({ ctx }) {
2753
2766
  !collapsed && s3.legendItems.map((item) => /* @__PURE__ */ a3(AppItem, { ctx, item })),
2754
2767
  overlayItems.length + s3.legendItems.length > 0 && (collapsed ? /* @__PURE__ */ a3("button", { class: "fnc-ind-handle", "aria-expanded": "false", "aria-label": t3.expand, "data-tip": t3.expand, onClick: () => setCollapsed(false), children: /* @__PURE__ */ a3("span", {}) }) : /* @__PURE__ */ a3("button", { class: "fnc-ind-collapse", "aria-expanded": "true", "aria-label": t3.collapse, "data-tip": t3.collapse, onClick: () => setCollapsed(true), children: /* @__PURE__ */ a3(ChevronUpIcon, {}) }))
2755
2768
  ] }),
2769
+ volumePane && /* @__PURE__ */ a3("div", { class: "fnc-legend fnc-pane-legend", style: { top: `${volumePane.top + 4}px` }, children: /* @__PURE__ */ a3(VolumeItem, { ctx, value: bar?.volume !== void 0 ? formatCompact(bar.volume, s3.locale) : null }) }),
2756
2770
  paneLegends.map(
2757
2771
  ({ pane, item }) => item && /* @__PURE__ */ a3("div", { class: "fnc-legend fnc-pane-legend", style: { top: `${pane.top + 4}px` }, children: /* @__PURE__ */ a3(IndicatorItem, { ctx, item }) })
2758
2772
  )
@@ -4369,7 +4383,7 @@ function createPane(shell, config) {
4369
4383
  setSearchOpen: (open, target = "symbol") => store.set(open ? { searchOpen: true, searchTarget: target } : { searchOpen: false }),
4370
4384
  screenshot: () => {
4371
4385
  const s3 = store.get();
4372
- chart.takeScreenshot().toBlob((blob) => {
4386
+ chart.takeScreenshot({ legend: true }).toBlob((blob) => {
4373
4387
  if (!blob) return;
4374
4388
  const a4 = document.createElement("a");
4375
4389
  a4.href = URL.createObjectURL(blob);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@funnest/charts-ui",
3
- "version": "0.6.22",
3
+ "version": "0.6.24",
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.6.22"
45
+ "@funnest/charts": "0.6.24"
46
46
  },
47
47
  "devDependencies": {
48
48
  "preact": "^11.2.0"