@funnest/charts-ui 0.6.14 → 0.6.16
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/context.d.ts +2 -0
- package/dist/i18n.d.ts +2 -0
- package/dist/index.js +70 -5
- package/dist/pane.d.ts +1 -0
- package/dist/trading-chart.d.ts +5 -0
- package/package.json +2 -2
package/dist/context.d.ts
CHANGED
|
@@ -80,6 +80,8 @@ export interface WidgetContext {
|
|
|
80
80
|
intervalGroups: readonly IntervalGroup[];
|
|
81
81
|
searchCategories: readonly SearchCategory[];
|
|
82
82
|
searchExchanges: readonly SearchExchange[];
|
|
83
|
+
/** Rows per exchange before a "모두 보기" (0: all). */
|
|
84
|
+
searchPreviewPerExchange: number;
|
|
83
85
|
/** IANA zone used for the status-bar clock (KST for Korean users by default). */
|
|
84
86
|
displayTimezone: string;
|
|
85
87
|
showLogo: boolean;
|
package/dist/i18n.d.ts
CHANGED
|
@@ -124,6 +124,7 @@ export declare const STRINGS: {
|
|
|
124
124
|
allSymbols: string;
|
|
125
125
|
favorites: string;
|
|
126
126
|
exchanges: string;
|
|
127
|
+
showAllIn: string;
|
|
127
128
|
noFavorites: string;
|
|
128
129
|
navigate: string;
|
|
129
130
|
openAction: string;
|
|
@@ -268,6 +269,7 @@ export declare const STRINGS: {
|
|
|
268
269
|
allSymbols: string;
|
|
269
270
|
favorites: string;
|
|
270
271
|
exchanges: string;
|
|
272
|
+
showAllIn: string;
|
|
271
273
|
noFavorites: string;
|
|
272
274
|
navigate: string;
|
|
273
275
|
openAction: string;
|
package/dist/index.js
CHANGED
|
@@ -549,6 +549,7 @@ var STRINGS = {
|
|
|
549
549
|
allSymbols: "\uC804\uCCB4",
|
|
550
550
|
favorites: "\uC990\uACA8\uCC3E\uAE30",
|
|
551
551
|
exchanges: "\uAC70\uB798\uC18C",
|
|
552
|
+
showAllIn: "{exchange} {n}\uAC1C \uBAA8\uB450 \uBCF4\uAE30 \u203A",
|
|
552
553
|
noFavorites: "\uC990\uACA8\uCC3E\uAE30\uD55C \uC885\uBAA9\uC774 \uC5C6\uC5B4\uC694. \u2606\uB97C \uB20C\uB7EC \uCD94\uAC00\uD574 \uBCF4\uC138\uC694",
|
|
553
554
|
navigate: "\uC774\uB3D9",
|
|
554
555
|
openAction: "\uC5F4\uAE30",
|
|
@@ -693,6 +694,7 @@ var STRINGS = {
|
|
|
693
694
|
allSymbols: "All",
|
|
694
695
|
favorites: "Favorites",
|
|
695
696
|
exchanges: "Exchanges",
|
|
697
|
+
showAllIn: "All {n} on {exchange} \u203A",
|
|
696
698
|
noFavorites: "No favorites yet \u2014 tap \u2606 to add one",
|
|
697
699
|
navigate: "navigate",
|
|
698
700
|
openAction: "open",
|
|
@@ -1819,6 +1821,8 @@ var DEBOUNCE_MS = 150;
|
|
|
1819
1821
|
var RECENT_KEY2 = "recent-symbols";
|
|
1820
1822
|
var FAVORITE_KEY = "favorite-symbols";
|
|
1821
1823
|
var MAX_RECENT = 8;
|
|
1824
|
+
var FIRST_ROWS = 40;
|
|
1825
|
+
var MORE_ROWS = 80;
|
|
1822
1826
|
var displayCode = (symbol) => symbol.slice(symbol.lastIndexOf(":") + 1);
|
|
1823
1827
|
var toStored = (info) => JSON.parse(JSON.stringify({ ...info, tickSize: 0, price: void 0, changePercent: void 0, sparkline: void 0 }));
|
|
1824
1828
|
function Highlight({ text, query }) {
|
|
@@ -1894,8 +1898,10 @@ function SymbolSearch({ ctx }) {
|
|
|
1894
1898
|
const [recent, setRecent] = d2(() => ctx.storage.get(RECENT_KEY2, []));
|
|
1895
1899
|
const [favorites, setFavorites] = d2(() => ctx.storage.get(FAVORITE_KEY, []));
|
|
1896
1900
|
const [active, setActive] = d2(0);
|
|
1901
|
+
const [limit, setLimit] = d2(FIRST_ROWS);
|
|
1897
1902
|
const inputRef = T2(null);
|
|
1898
1903
|
const listRef = T2(null);
|
|
1904
|
+
const endRef = T2(null);
|
|
1899
1905
|
A2(() => inputRef.current?.focus(), []);
|
|
1900
1906
|
A2(() => {
|
|
1901
1907
|
let alive = true;
|
|
@@ -1921,7 +1927,8 @@ function SymbolSearch({ ctx }) {
|
|
|
1921
1927
|
}, [query]);
|
|
1922
1928
|
const matchCategory = ctx.searchCategories.find((c3) => c3.id === category)?.match ?? (() => true);
|
|
1923
1929
|
const categoryOf = (info) => ctx.searchCategories.find((c3) => c3.id !== "all" && c3.match(info));
|
|
1924
|
-
const
|
|
1930
|
+
const favoriteSet = w2(() => new Set(favorites.map((f4) => f4.symbol)), [favorites]);
|
|
1931
|
+
const isFavorite = (info) => favoriteSet.has(info.symbol);
|
|
1925
1932
|
const filter = (list) => list.filter((i3) => matchCategory(i3) && (!exchange || i3.exchange === exchange));
|
|
1926
1933
|
const exchanges = w2(() => {
|
|
1927
1934
|
const counts = /* @__PURE__ */ new Map();
|
|
@@ -1934,12 +1941,54 @@ function SymbolSearch({ ctx }) {
|
|
|
1934
1941
|
const favoriteRows = filter(favorites).filter((f4) => !q2 || f4.name.toLowerCase().includes(q2) || f4.symbol.toLowerCase().includes(q2));
|
|
1935
1942
|
const showRecent = view.kind === "all" && !q2 && recent.length > 0;
|
|
1936
1943
|
const recentRows = showRecent ? filter(recent) : [];
|
|
1937
|
-
const
|
|
1944
|
+
const allResults = view.kind === "favorites" ? favoriteRows : filter(results ?? []);
|
|
1945
|
+
const preview = ctx.searchPreviewPerExchange;
|
|
1946
|
+
const more = /* @__PURE__ */ new Map();
|
|
1947
|
+
let resultRows = allResults;
|
|
1948
|
+
if (preview > 0 && view.kind === "all" && !exchange) {
|
|
1949
|
+
const seen = /* @__PURE__ */ new Map();
|
|
1950
|
+
const total = /* @__PURE__ */ new Map();
|
|
1951
|
+
for (const r3 of allResults) total.set(r3.exchange, (total.get(r3.exchange) ?? 0) + 1);
|
|
1952
|
+
resultRows = [];
|
|
1953
|
+
for (const r3 of allResults) {
|
|
1954
|
+
const n2 = (seen.get(r3.exchange) ?? 0) + 1;
|
|
1955
|
+
seen.set(r3.exchange, n2);
|
|
1956
|
+
if (n2 > preview) continue;
|
|
1957
|
+
resultRows.push(r3);
|
|
1958
|
+
if (n2 === preview && (total.get(r3.exchange) ?? 0) > preview) more.set(resultRows.length - 1, { exchange: r3.exchange, count: total.get(r3.exchange) });
|
|
1959
|
+
}
|
|
1960
|
+
}
|
|
1938
1961
|
const rows = [...recentRows, ...resultRows];
|
|
1962
|
+
const shownRows = resultRows.length > limit ? resultRows.slice(0, limit) : resultRows;
|
|
1963
|
+
const exchangeLabel = (name) => ctx.searchExchanges.find((e3) => e3.name === name)?.label?.[locale] ?? name;
|
|
1939
1964
|
A2(() => setActive(0), [query, category, exchange, view, results]);
|
|
1940
1965
|
A2(() => {
|
|
1941
|
-
|
|
1966
|
+
setLimit(FIRST_ROWS);
|
|
1967
|
+
if (listRef.current) listRef.current.scrollTop = 0;
|
|
1968
|
+
}, [query, category, exchange, view]);
|
|
1969
|
+
const hasMore = resultRows.length > limit;
|
|
1970
|
+
A2(() => {
|
|
1971
|
+
const end = endRef.current;
|
|
1972
|
+
if (!hasMore || !end) return;
|
|
1973
|
+
const io = new IntersectionObserver((entries) => entries.some((e3) => e3.isIntersecting) && setLimit((l3) => l3 + MORE_ROWS), {
|
|
1974
|
+
root: listRef.current,
|
|
1975
|
+
rootMargin: "0px 0px 600px 0px"
|
|
1976
|
+
});
|
|
1977
|
+
io.observe(end);
|
|
1978
|
+
return () => io.disconnect();
|
|
1979
|
+
}, [hasMore, limit]);
|
|
1980
|
+
const scrollToActive = T2(false);
|
|
1981
|
+
A2(() => {
|
|
1982
|
+
if (active - recentRows.length >= limit - 1) {
|
|
1983
|
+
scrollToActive.current = true;
|
|
1984
|
+
setLimit(active - recentRows.length + MORE_ROWS);
|
|
1985
|
+
} else listRef.current?.querySelector(`[data-index="${active}"]`)?.scrollIntoView({ block: "nearest" });
|
|
1942
1986
|
}, [active]);
|
|
1987
|
+
A2(() => {
|
|
1988
|
+
if (!scrollToActive.current) return;
|
|
1989
|
+
scrollToActive.current = false;
|
|
1990
|
+
listRef.current?.querySelector(`[data-index="${active}"]`)?.scrollIntoView({ block: "nearest" });
|
|
1991
|
+
}, [limit]);
|
|
1943
1992
|
const close = () => ctx.setSearchOpen(false);
|
|
1944
1993
|
const save = (key, next, set) => {
|
|
1945
1994
|
set(next);
|
|
@@ -2029,7 +2078,8 @@ function SymbolSearch({ ctx }) {
|
|
|
2029
2078
|
}
|
|
2030
2079
|
)
|
|
2031
2080
|
]
|
|
2032
|
-
}
|
|
2081
|
+
},
|
|
2082
|
+
(isRecent ? "recent:" : "") + info.symbol
|
|
2033
2083
|
);
|
|
2034
2084
|
};
|
|
2035
2085
|
const sideItem = (label, selected, onClick, extra, logoUrl) => /* @__PURE__ */ a3("button", { class: "fnc-sr-side-item", "aria-pressed": selected, onClick, children: [
|
|
@@ -2085,7 +2135,14 @@ function SymbolSearch({ ctx }) {
|
|
|
2085
2135
|
] }),
|
|
2086
2136
|
recentRows.map((info, i3) => row2(info, i3, true)),
|
|
2087
2137
|
(recentRows.length > 0 || view.kind === "favorites") && /* @__PURE__ */ a3("div", { class: "fnc-sr-section", children: view.kind === "favorites" ? t3.favorites : t3.symbols }),
|
|
2088
|
-
loading && !results && view.kind === "all" ? Array.from({ length: 6 }, () => /* @__PURE__ */ a3("div", { class: "fnc-sr-skeleton", "aria-hidden": "true" })) :
|
|
2138
|
+
loading && !results && view.kind === "all" ? Array.from({ length: 6 }, () => /* @__PURE__ */ a3("div", { class: "fnc-sr-skeleton", "aria-hidden": "true" })) : shownRows.map((info, i3) => {
|
|
2139
|
+
const m3 = more.get(i3);
|
|
2140
|
+
return m3 ? /* @__PURE__ */ a3($, { children: [
|
|
2141
|
+
row2(info, recentRows.length + i3, false),
|
|
2142
|
+
/* @__PURE__ */ a3("button", { class: "fnc-sr-more", onClick: () => (setView({ kind: "all" }), setExchange(m3.exchange)), children: t3.showAllIn.replace("{exchange}", exchangeLabel(m3.exchange)).replace("{n}", m3.count.toLocaleString(locale === "ko" ? "ko-KR" : "en-US")) })
|
|
2143
|
+
] }, info.symbol) : row2(info, recentRows.length + i3, false);
|
|
2144
|
+
}),
|
|
2145
|
+
hasMore && /* @__PURE__ */ a3("div", { ref: endRef, class: "fnc-sr-end", "aria-hidden": "true" }),
|
|
2089
2146
|
!loading && rows.length === 0 && /* @__PURE__ */ a3("div", { class: "fnc-empty", children: view.kind === "favorites" && favorites.length === 0 ? t3.noFavorites : t3.noResults })
|
|
2090
2147
|
] })
|
|
2091
2148
|
] }),
|
|
@@ -3228,6 +3285,9 @@ var CSS = (
|
|
|
3228
3285
|
.fnc-sr-side-item em { font-style: normal; font-size: 12px; color: var(--fnc-text-2); }
|
|
3229
3286
|
.fnc-sr-side-logo { flex: none; width: 18px; height: 18px; border-radius: 5px; object-fit: cover; background: var(--fnc-surface); }
|
|
3230
3287
|
.fnc-sr-spark-slot { display: inline-flex; flex: none; width: 72px; height: 24px; }
|
|
3288
|
+
.fnc-sr-more { display: block; width: calc(100% - 16px); margin: 2px 8px 8px; padding: 8px 12px; border-radius: var(--fnc-radius); background: var(--fnc-surface); color: var(--fnc-text-2); font-size: 13px; font-weight: 600; text-align: left; }
|
|
3289
|
+
.fnc-sr-more:hover { color: var(--fnc-text); }
|
|
3290
|
+
.fnc-sr-end { height: 1px; }
|
|
3231
3291
|
.fnc-sr-side-item:hover { background: var(--fnc-surface); }
|
|
3232
3292
|
.fnc-sr-side-item[aria-pressed='true'] { background: var(--fnc-surface); font-weight: 700; }
|
|
3233
3293
|
.fnc-chip-token {
|
|
@@ -4255,6 +4315,7 @@ function createPane(shell, config) {
|
|
|
4255
4315
|
intervalGroups: config.intervalGroups,
|
|
4256
4316
|
searchCategories: config.searchCategories,
|
|
4257
4317
|
searchExchanges: config.searchExchanges ?? [],
|
|
4318
|
+
searchPreviewPerExchange: config.searchPreviewPerExchange ?? 0,
|
|
4258
4319
|
displayTimezone: config.displayTimezone,
|
|
4259
4320
|
showLogo: config.symbolLogo,
|
|
4260
4321
|
searchHotkey: config.searchHotkey,
|
|
@@ -4330,6 +4391,7 @@ function createTradingChart(container, options) {
|
|
|
4330
4391
|
onFavoriteIntervalsChange,
|
|
4331
4392
|
searchCategories = DEFAULT_SEARCH_CATEGORIES,
|
|
4332
4393
|
searchExchanges = [],
|
|
4394
|
+
searchPreviewPerExchange = 0,
|
|
4333
4395
|
storageKey = "funnest-charts",
|
|
4334
4396
|
searchHotkey = true,
|
|
4335
4397
|
symbolLogo = true,
|
|
@@ -4360,6 +4422,7 @@ function createTradingChart(container, options) {
|
|
|
4360
4422
|
intervalGroups,
|
|
4361
4423
|
searchCategories,
|
|
4362
4424
|
searchExchanges,
|
|
4425
|
+
searchPreviewPerExchange,
|
|
4363
4426
|
symbolLogo,
|
|
4364
4427
|
searchHotkey,
|
|
4365
4428
|
drawingToolbar,
|
|
@@ -4430,6 +4493,7 @@ function createMultiChart(container, options) {
|
|
|
4430
4493
|
onFavoriteIntervalsChange,
|
|
4431
4494
|
searchCategories = DEFAULT_SEARCH_CATEGORIES,
|
|
4432
4495
|
searchExchanges = [],
|
|
4496
|
+
searchPreviewPerExchange = 0,
|
|
4433
4497
|
storageKey = "funnest-charts",
|
|
4434
4498
|
searchHotkey = true,
|
|
4435
4499
|
symbolLogo = true,
|
|
@@ -4501,6 +4565,7 @@ function createMultiChart(container, options) {
|
|
|
4501
4565
|
intervalGroups,
|
|
4502
4566
|
searchCategories,
|
|
4503
4567
|
searchExchanges,
|
|
4568
|
+
searchPreviewPerExchange,
|
|
4504
4569
|
symbolLogo,
|
|
4505
4570
|
searchHotkey,
|
|
4506
4571
|
drawingToolbar,
|
package/dist/pane.d.ts
CHANGED
|
@@ -12,6 +12,7 @@ export interface PaneConfig {
|
|
|
12
12
|
intervalGroups: readonly IntervalGroup[];
|
|
13
13
|
searchCategories: readonly SearchCategory[];
|
|
14
14
|
searchExchanges?: readonly SearchExchange[];
|
|
15
|
+
searchPreviewPerExchange?: number;
|
|
15
16
|
symbolLogo: boolean;
|
|
16
17
|
drawingToolbar: boolean;
|
|
17
18
|
attribution: boolean;
|
package/dist/trading-chart.d.ts
CHANGED
|
@@ -24,6 +24,11 @@ export interface TradingChartOptions extends Omit<ChartOptions, 'datafeed'> {
|
|
|
24
24
|
searchCategories?: readonly SearchCategory[];
|
|
25
25
|
/** Exchanges listed in the symbol search sidebar from the start, with logos (counts fill in as results come). */
|
|
26
26
|
searchExchanges?: readonly SearchExchange[];
|
|
27
|
+
/**
|
|
28
|
+
* Symbol search: rows per exchange shown at first, each followed by "N개 모두 보기" when there
|
|
29
|
+
* are more (picking the exchange lists them all). Default 0: everything at once.
|
|
30
|
+
*/
|
|
31
|
+
searchPreviewPerExchange?: number;
|
|
27
32
|
/**
|
|
28
33
|
* localStorage key prefix for UI preferences (favorite intervals, recent searches).
|
|
29
34
|
* Default 'funnest-charts'. Pass null to keep them in memory only.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@funnest/charts-ui",
|
|
3
|
-
"version": "0.6.
|
|
3
|
+
"version": "0.6.16",
|
|
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.
|
|
45
|
+
"@funnest/charts": "0.6.16"
|
|
46
46
|
},
|
|
47
47
|
"devDependencies": {
|
|
48
48
|
"preact": "^11.2.0"
|