@uniai-fe/util-react 0.1.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.
package/dist/index.mjs ADDED
@@ -0,0 +1,262 @@
1
+ import React, { Fragment } from 'react';
2
+ import parse from 'html-react-parser';
3
+ import Decimal from 'decimal.js';
4
+ import { extent, quantile } from 'd3-array';
5
+
6
+ // src/convert/index.tsx
7
+ var convertTextToHTML = (text, tagName, key) => {
8
+ if (!text.includes(`<${tagName}>`)) return text;
9
+ const HTML_KEY = key ? key : `util/convert/text-to-html/${tagName}`;
10
+ const parts = text.split(new RegExp(`(<${tagName}>|</${tagName}>)`, "g"));
11
+ let isTagContents = false;
12
+ return /* @__PURE__ */ React.createElement(React.Fragment, null, parts.map((part, index) => {
13
+ if (part === `<${tagName}>`) {
14
+ isTagContents = true;
15
+ return null;
16
+ }
17
+ if (part === `</${tagName}>`) {
18
+ isTagContents = false;
19
+ return null;
20
+ }
21
+ if (isTagContents)
22
+ return /* @__PURE__ */ React.createElement("span", { key: `${HTML_KEY}/${index}`, className: tagName }, part);
23
+ return /* @__PURE__ */ React.createElement(Fragment, { key: `${HTML_KEY}/${index}` }, part);
24
+ }));
25
+ };
26
+ var convertTextToLineArray = (text) => {
27
+ if (text.includes("<br")) return text.split(/<br\s*\/?>|<br>/);
28
+ if (text.includes("\n")) return text.split("\n");
29
+ return [text];
30
+ };
31
+ var convertTextToJsx = ({
32
+ text,
33
+ key,
34
+ callback
35
+ }) => {
36
+ if (typeof text !== "string") return text;
37
+ if (/<[a-z][\s\S]*>/i.test(text)) {
38
+ return /* @__PURE__ */ React.createElement(React.Fragment, null, parse(text));
39
+ }
40
+ const lines = convertTextToLineArray(text);
41
+ if (lines.length > 1) {
42
+ const LINE_KEY = "util/convert/text-to-jsx";
43
+ return lines.map((line, index) => /* @__PURE__ */ React.createElement(Fragment, { key: key ? `${key}/${index}` : `${LINE_KEY}/${line}/${index}` }, index !== 0 && /* @__PURE__ */ React.createElement("br", null), typeof callback === "function" ? callback(line) : line));
44
+ }
45
+ return text;
46
+ };
47
+ var convertArrayToJsx = (textArray, options) => {
48
+ if (typeof textArray === "string" || !Array.isArray(textArray))
49
+ return convertTextToJsx({ text: textArray });
50
+ const LINE_KEY = "util/convert/array-to-jsx";
51
+ const commonKey = (content, index, additionalKey) => options?.key ? `${options.key}${additionalKey ? `/${additionalKey}` : ""}/${index}` : `${LINE_KEY}/${String(content)}${additionalKey ? `/${additionalKey}` : ""}/${index}`;
52
+ return textArray.map((content, index) => /* @__PURE__ */ React.createElement(Fragment, { key: commonKey(content, index) }, index !== 0 && /* @__PURE__ */ React.createElement(React.Fragment, null, new Array(options?.phraseGap || 1).fill({}).map((_, i) => /* @__PURE__ */ React.createElement("br", { key: commonKey(content, i, "br") }))), content));
53
+ };
54
+ function matchKeyword(origin, exp, renderKey) {
55
+ const matches = Array.from(origin.matchAll(exp));
56
+ if (!matches.length) return origin;
57
+ const jsxArray = [];
58
+ for (let i = 0; i < matches.length; i++) {
59
+ const match = matches[i];
60
+ const prevMatch = i ? matches[i - 1] : void 0;
61
+ const offset = prevMatch ? prevMatch.index + prevMatch[0].length : 0;
62
+ jsxArray.push(origin.slice(offset, match.index));
63
+ jsxArray.push(
64
+ /* @__PURE__ */ React.createElement("i", { className: "matched", key: `${renderKey}/${match}/${i}` }, match[0])
65
+ );
66
+ const isLastMatch = i === matches.length - 1;
67
+ const hasTextAfterLastMatch = match.index + match[0].length < origin.length;
68
+ if (isLastMatch && hasTextAfterLastMatch) {
69
+ jsxArray.push(origin.slice(match.index + match[0].length));
70
+ }
71
+ }
72
+ return jsxArray.length ? jsxArray : origin;
73
+ }
74
+ var fileDownload = ({ url, name }) => fetch(url).then((res) => {
75
+ const contentType = res.headers.get("content-type") || "";
76
+ if (!res.ok || contentType.includes("text/html")) {
77
+ throw new Error("\uD30C\uC77C\uC744 \uCC3E\uC744 \uC218 \uC5C6\uAC70\uB098 \uB2E4\uC6B4\uB85C\uB4DC\uD560 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4.");
78
+ }
79
+ return res.blob();
80
+ }).then((blob) => {
81
+ const objectUrl = URL.createObjectURL(blob);
82
+ const anchor = document.createElement("a");
83
+ anchor.href = objectUrl;
84
+ anchor.download = String(name);
85
+ document.body.appendChild(anchor);
86
+ anchor.click();
87
+ document.body.removeChild(anchor);
88
+ URL.revokeObjectURL(objectUrl);
89
+ }).catch((err) => {
90
+ console.error("Download error:", err);
91
+ alert("\uB2E4\uC6B4\uB85C\uB4DC \uC911 \uC624\uB958\uAC00 \uBC1C\uC0DD\uD588\uC2B5\uB2C8\uB2E4.");
92
+ });
93
+ var fileSize = (size, unit = true) => {
94
+ if (typeof size !== "number" || size && isNaN(Number(size))) return "";
95
+ const AMOUNT = 1024;
96
+ const K_AMOUNT = AMOUNT * AMOUNT;
97
+ const M_AMOUNT = AMOUNT * AMOUNT * AMOUNT;
98
+ const byte = new Decimal(size);
99
+ const kb = byte.div(AMOUNT);
100
+ const mb = kb.div(AMOUNT);
101
+ const gb = mb.div(AMOUNT);
102
+ if (byte.toNumber() < AMOUNT) return `${byte.toFixed(0)}B`;
103
+ if (byte.toNumber() < K_AMOUNT) return `${kb.toFixed(0)}KB`;
104
+ if (byte.toNumber() < M_AMOUNT) return `${mb.toFixed(0)}MB`;
105
+ return unit ? `${gb.toFixed(0)}GB` : `${gb.toFixed(2)} GB`;
106
+ };
107
+ var getChartYTicks = ({
108
+ data,
109
+ length,
110
+ pad = 0.5,
111
+ limitMin,
112
+ limitMax,
113
+ digit = 2,
114
+ outliers = false,
115
+ log
116
+ }) => {
117
+ if (data.length === 0 || length <= 1) return void 0;
118
+ if (typeof limitMin === "number" && typeof limitMax === "number")
119
+ return Array.from({ length: length + 1 }).map(
120
+ (_, index) => Math.round((limitMax - limitMin) / length * index + limitMin)
121
+ );
122
+ const dataSet = [];
123
+ data.forEach((d) => {
124
+ if (typeof d !== "number" && typeof d !== "string" && !(typeof d === "object" && d !== null && "value" in d))
125
+ return;
126
+ if (typeof d === "number") dataSet.push(d);
127
+ else if (typeof d === "string" && !isNaN(Number(d)))
128
+ dataSet.push(Number(d));
129
+ else if (typeof d === "object" && d !== null && "value" in d && typeof d.value === "number")
130
+ dataSet.push(d.value);
131
+ });
132
+ if (dataSet.length === 0) return void 0;
133
+ let domain = extent(dataSet);
134
+ if (typeof limitMin === "number") domain = [limitMin, domain[1]];
135
+ if (typeof limitMax === "number") domain = [domain[0], limitMax];
136
+ if (typeof domain[0] === "undefined" || typeof domain[1] === "undefined")
137
+ return void 0;
138
+ const isAllDecimal = dataSet.every(
139
+ (v) => typeof digit === "number" && digit > 0 || String(v).split(".").filter((_, index) => index === 1).filter(Boolean).filter((f) => f.split("").some((s) => s !== "0")).length > 0
140
+ );
141
+ const DECIMAL_LIMIT = typeof digit === "number" ? digit : 2;
142
+ const floor = (domain[0] + 1e-3 * domain[0]) * Math.pow(10, DECIMAL_LIMIT);
143
+ const ceil = (domain[1] + 1e-3 * domain[1]) * Math.pow(10, DECIMAL_LIMIT);
144
+ const interval = (ceil - floor) / length;
145
+ const ticks = [];
146
+ for (let i = 0; i < length + 1; i++)
147
+ ticks.push((floor + i * interval) / Math.pow(10, DECIMAL_LIMIT));
148
+ const [firstTick] = ticks;
149
+ const lastTick = ticks[ticks.length - 1];
150
+ if (typeof firstTick === "undefined" || typeof lastTick === "undefined")
151
+ return void 0;
152
+ const gap = Math.abs(lastTick - firstTick);
153
+ const precision = typeof digit === "number" ? digit : gap < 1 ? 3 : gap < 10 && isAllDecimal ? 2 : gap < 25 ? 1 : 0;
154
+ const ticksArr = ticks.map(
155
+ (tick) => Number((tick + Number.EPSILON).toFixed(precision))
156
+ );
157
+ if (log) {
158
+ const MAX_LENGTH = 8;
159
+ const top = ticksArr[ticksArr.length - 1];
160
+ const bottom = ticksArr[0];
161
+ const domainRange = typeof top === "number" && typeof bottom === "number" ? top - bottom : 0;
162
+ const logScale = domainRange > 0 ? Math.round(Math.log2(domainRange)) : 0;
163
+ if (ticksArr.length > MAX_LENGTH) {
164
+ const step = Math.ceil(ticksArr.length / MAX_LENGTH);
165
+ return ticksArr.filter((_, index) => index % step === 0);
166
+ }
167
+ if (logScale > 0) {
168
+ const step = Math.max(1, Math.floor(MAX_LENGTH / logScale));
169
+ return ticksArr.filter((_, index) => index % step === 0);
170
+ }
171
+ }
172
+ if (pad === 0) return ticksArr;
173
+ const isPowTen = ticksArr.every((t) => {
174
+ const v = Math.abs(t);
175
+ return v === 0 || Number.isInteger(Math.log10(v));
176
+ });
177
+ const [tickMin] = ticksArr;
178
+ const tickMax = ticksArr[ticksArr.length - 1];
179
+ const quantiles = extent(dataSet);
180
+ let [min, max] = quantiles;
181
+ if (typeof min === "undefined" || typeof max === "undefined")
182
+ return ticksArr;
183
+ if (outliers)
184
+ [min, max] = [
185
+ quantile(dataSet, 0.4) ?? min,
186
+ quantile(dataSet, 0.6) ?? max
187
+ ];
188
+ if (pad > 0) {
189
+ const SCALE = typeof max === "number" && typeof min === "number" ? Math.max(Math.abs(max), Math.abs(min)) : 0;
190
+ const OFFSET = SCALE < 10 && isPowTen ? 0.5 : SCALE < 100 && isPowTen ? 5 : SCALE < 1e3 && isPowTen ? 50 : Math.round((max - min) / ticksArr.length);
191
+ if (typeof tickMax === "number")
192
+ ticksArr[ticksArr.length - 1] = Math.round(
193
+ tickMax + OFFSET * pad + Number.EPSILON
194
+ );
195
+ if (typeof tickMin === "number")
196
+ ticksArr[0] = Math.round(tickMin - OFFSET * pad - Number.EPSILON);
197
+ }
198
+ const bad = ticksArr.some((tick, index) => {
199
+ if (index === 0) return false;
200
+ const prev = ticksArr[index - 1];
201
+ const d = Math.abs(tick - prev);
202
+ if (typeof digit === "number" && digit < 1 && String(d).includes("."))
203
+ return false;
204
+ return d !== 1 && d !== 5 && d !== 0;
205
+ });
206
+ if (bad && pad !== 0) {
207
+ return getChartYTicks({
208
+ data,
209
+ length,
210
+ pad: 0,
211
+ limitMin,
212
+ limitMax,
213
+ digit,
214
+ outliers,
215
+ log
216
+ });
217
+ }
218
+ return ticksArr;
219
+ };
220
+ var getDecimalIndex = (v) => !isNaN(Number(v)) && String(v).includes(".") ? String(v).split(".")[1].split("").findIndex((d) => Number(d) !== 0) + 1 : 0;
221
+ var getDomainLimit = ({
222
+ value,
223
+ gap,
224
+ min,
225
+ max
226
+ }) => {
227
+ if (typeof value === "number" && !isNaN(value)) {
228
+ const limit = value + gap;
229
+ if (typeof min === "number" && limit < min) return min;
230
+ if (typeof max === "number" && limit > max) return max;
231
+ return limit;
232
+ }
233
+ return value ?? "";
234
+ };
235
+ var getXAxisTextAttr = (props) => {
236
+ const {
237
+ width,
238
+ height,
239
+ x,
240
+ y,
241
+ stroke,
242
+ fill,
243
+ orientation,
244
+ textAnchor,
245
+ transform
246
+ } = props;
247
+ return {
248
+ width,
249
+ height,
250
+ x,
251
+ y,
252
+ stroke,
253
+ fill,
254
+ textAnchor,
255
+ orientation,
256
+ transform
257
+ };
258
+ };
259
+
260
+ export { convertArrayToJsx, convertTextToHTML, convertTextToJsx, convertTextToLineArray, fileDownload, fileSize, getChartYTicks, getDecimalIndex, getDomainLimit, getXAxisTextAttr, matchKeyword };
261
+ //# sourceMappingURL=index.mjs.map
262
+ //# sourceMappingURL=index.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/convert/index.tsx","../src/match/index.tsx","../src/file/index.tsx","../src/chart/index.tsx"],"names":["React"],"mappings":"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","file":"index.mjs","sourcesContent":["import React, { Fragment } from \"react\";\nimport parse from \"html-react-parser\";\nimport type {\n ConvertArrayToJsxOptions,\n ConvertTextToJsxParams,\n} from \"./types\";\n\nexport const convertTextToHTML = (\n text: string,\n tagName: string,\n key?: string,\n): React.ReactNode => {\n if (!text.includes(`<${tagName}>`)) return text;\n const HTML_KEY = key ? key : `util/convert/text-to-html/${tagName}`;\n const parts = text.split(new RegExp(`(<${tagName}>|</${tagName}>)`, \"g\"));\n\n let isTagContents = false;\n return (\n <>\n {parts.map((part, index) => {\n if (part === `<${tagName}>`) {\n isTagContents = true;\n return null;\n }\n if (part === `</${tagName}>`) {\n isTagContents = false;\n return null;\n }\n\n if (isTagContents)\n return (\n <span key={`${HTML_KEY}/${index}`} className={tagName}>\n {part}\n </span>\n );\n return <Fragment key={`${HTML_KEY}/${index}`}>{part}</Fragment>;\n })}\n </>\n );\n};\n\nexport const convertTextToLineArray = (text: string): string[] => {\n if (text.includes(\"<br\")) return text.split(/<br\\s*\\/?>|<br>/);\n if (text.includes(\"\\n\")) return text.split(\"\\n\");\n return [text];\n};\n\nexport const convertTextToJsx = ({\n text,\n key,\n callback,\n}: ConvertTextToJsxParams): string | React.ReactNode => {\n if (typeof text !== \"string\") return text;\n\n if (/<[a-z][\\s\\S]*>/i.test(text)) {\n return <>{parse(text)}</>;\n }\n\n const lines = convertTextToLineArray(text);\n\n if (lines.length > 1) {\n const LINE_KEY = \"util/convert/text-to-jsx\";\n return lines.map((line, index) => (\n <Fragment key={key ? `${key}/${index}` : `${LINE_KEY}/${line}/${index}`}>\n {index !== 0 && <br />}\n {typeof callback === \"function\" ? callback(line) : line}\n </Fragment>\n ));\n }\n\n return text;\n};\n\nexport const convertArrayToJsx = (\n textArray: React.ReactNode[] | string,\n options?: ConvertArrayToJsxOptions,\n): React.ReactNode => {\n if (typeof textArray === \"string\" || !Array.isArray(textArray))\n return convertTextToJsx({ text: textArray });\n\n const LINE_KEY = \"util/convert/array-to-jsx\";\n const commonKey = (\n content: React.ReactNode,\n index: number,\n additionalKey?: string,\n ) =>\n options?.key\n ? `${options.key}${additionalKey ? `/${additionalKey}` : \"\"}/${index}`\n : `${LINE_KEY}/${String(content)}${additionalKey ? `/${additionalKey}` : \"\"}/${index}`;\n\n return textArray.map((content, index) => (\n <Fragment key={commonKey(content, index)}>\n {index !== 0 && (\n <>\n {new Array(options?.phraseGap || 1).fill({}).map((_, i) => (\n <br key={commonKey(content, i, \"br\")} />\n ))}\n </>\n )}\n {content}\n </Fragment>\n ));\n};\n","import React from \"react\";\nimport type { MatchKeywordResult } from \"./types\";\n\n/**\n * 일치 텍스트를 컴포넌트로 교체\n */\nexport function matchKeyword(\n origin: string,\n exp: RegExp,\n renderKey: string,\n): MatchKeywordResult {\n const matches = Array.from(origin.matchAll(exp));\n if (!matches.length) return origin;\n\n const jsxArray: React.ReactNode[] = [];\n for (let i = 0; i < matches.length; i++) {\n const match = matches[i];\n const prevMatch = i ? matches[i - 1] : undefined;\n const offset = prevMatch ? prevMatch.index! + prevMatch[0].length : 0;\n\n jsxArray.push(origin.slice(offset, match.index));\n jsxArray.push(\n <i className=\"matched\" key={`${renderKey}/${match}/${i}`}>\n {match[0]}\n </i>,\n );\n\n const isLastMatch = i === matches.length - 1;\n const hasTextAfterLastMatch =\n match.index! + match[0].length < origin.length;\n\n if (isLastMatch && hasTextAfterLastMatch) {\n jsxArray.push(origin.slice(match.index! + match[0].length));\n }\n }\n\n return jsxArray.length ? jsxArray : origin;\n}\n","import Decimal from \"decimal.js\";\nimport type { FileDownloadParams } from \"./types\";\n\nexport const fileDownload = ({ url, name }: FileDownloadParams) =>\n fetch(url)\n .then(res => {\n const contentType = res.headers.get(\"content-type\") || \"\";\n if (!res.ok || contentType.includes(\"text/html\")) {\n throw new Error(\"파일을 찾을 수 없거나 다운로드할 수 없습니다.\");\n }\n return res.blob();\n })\n .then(blob => {\n const objectUrl = URL.createObjectURL(blob);\n const anchor = document.createElement(\"a\");\n anchor.href = objectUrl;\n anchor.download = String(name);\n document.body.appendChild(anchor);\n anchor.click();\n document.body.removeChild(anchor);\n URL.revokeObjectURL(objectUrl);\n })\n .catch(err => {\n console.error(\"Download error:\", err);\n alert(\"다운로드 중 오류가 발생했습니다.\");\n });\n\nexport const fileSize = (size: unknown, unit: boolean = true): string => {\n if (typeof size !== \"number\" || (size && isNaN(Number(size)))) return \"\";\n\n const AMOUNT = 1024;\n const K_AMOUNT = AMOUNT * AMOUNT;\n const M_AMOUNT = AMOUNT * AMOUNT * AMOUNT;\n\n const byte = new Decimal(size);\n const kb = byte.div(AMOUNT);\n const mb = kb.div(AMOUNT);\n const gb = mb.div(AMOUNT);\n\n if (byte.toNumber() < AMOUNT) return `${byte.toFixed(0)}B`;\n if (byte.toNumber() < K_AMOUNT) return `${kb.toFixed(0)}KB`;\n if (byte.toNumber() < M_AMOUNT) return `${mb.toFixed(0)}MB`;\n return unit ? `${gb.toFixed(0)}GB` : `${gb.toFixed(2)} GB`;\n};\n","import type { SVGAttributes } from \"react\";\nimport { extent, quantile } from \"d3-array\";\nimport type {\n GetChartYTicksProps,\n RechartsXAxisTickPayload,\n RechartsXAxisTickProps,\n} from \"./types\";\n\nexport const getChartYTicks = ({\n data,\n length,\n pad = 0.5,\n limitMin,\n limitMax,\n digit = 2,\n outliers = false,\n log,\n}: GetChartYTicksProps): number[] | undefined => {\n if (data.length === 0 || length <= 1) return undefined;\n if (typeof limitMin === \"number\" && typeof limitMax === \"number\")\n return Array.from({ length: length + 1 }).map((_, index) =>\n Math.round(((limitMax - limitMin) / length) * index + limitMin),\n );\n\n const dataSet: number[] = [];\n\n data.forEach(d => {\n if (\n typeof d !== \"number\" &&\n typeof d !== \"string\" &&\n !(typeof d === \"object\" && d !== null && \"value\" in d)\n )\n return;\n\n if (typeof d === \"number\") dataSet.push(d);\n else if (typeof d === \"string\" && !isNaN(Number(d)))\n dataSet.push(Number(d));\n else if (\n typeof d === \"object\" &&\n d !== null &&\n \"value\" in d &&\n typeof (d as { value: unknown }).value === \"number\"\n )\n dataSet.push((d as { value: number }).value);\n });\n\n if (dataSet.length === 0) return undefined;\n\n let domain = extent(dataSet) as [number | undefined, number | undefined];\n if (typeof limitMin === \"number\") domain = [limitMin, domain[1]];\n if (typeof limitMax === \"number\") domain = [domain[0], limitMax];\n\n if (typeof domain[0] === \"undefined\" || typeof domain[1] === \"undefined\")\n return undefined;\n\n const isAllDecimal = dataSet.every(\n v =>\n (typeof digit === \"number\" && digit > 0) ||\n String(v)\n .split(\".\")\n .filter((_, index) => index === 1)\n .filter(Boolean)\n .filter(f => f.split(\"\").some(s => s !== \"0\")).length > 0,\n );\n\n const DECIMAL_LIMIT = typeof digit === \"number\" ? digit : 2;\n\n const floor = (domain[0] + 0.001 * domain[0]) * Math.pow(10, DECIMAL_LIMIT);\n const ceil = (domain[1] + 0.001 * domain[1]) * Math.pow(10, DECIMAL_LIMIT);\n const interval = (ceil - floor) / length;\n\n const ticks: number[] = [];\n for (let i = 0; i < length + 1; i++)\n ticks.push((floor + i * interval) / Math.pow(10, DECIMAL_LIMIT));\n\n const [firstTick] = ticks;\n const lastTick = ticks[ticks.length - 1];\n if (typeof firstTick === \"undefined\" || typeof lastTick === \"undefined\")\n return undefined;\n\n const gap = Math.abs(lastTick - firstTick);\n const precision =\n typeof digit === \"number\"\n ? digit\n : gap < 1\n ? 3\n : gap < 10 && isAllDecimal\n ? 2\n : gap < 25\n ? 1\n : 0;\n\n const ticksArr = ticks.map(tick =>\n Number((tick + Number.EPSILON).toFixed(precision)),\n );\n\n if (log) {\n const MAX_LENGTH = 8;\n const top = ticksArr[ticksArr.length - 1];\n const bottom = ticksArr[0];\n const domainRange =\n typeof top === \"number\" && typeof bottom === \"number\"\n ? top - bottom\n : 0;\n const logScale =\n domainRange > 0 ? Math.round(Math.log2(domainRange)) : 0;\n\n if (ticksArr.length > MAX_LENGTH) {\n const step = Math.ceil(ticksArr.length / MAX_LENGTH);\n return ticksArr.filter((_, index) => index % step === 0);\n }\n\n if (logScale > 0) {\n const step = Math.max(1, Math.floor(MAX_LENGTH / logScale));\n return ticksArr.filter((_, index) => index % step === 0);\n }\n }\n\n if (pad === 0) return ticksArr;\n\n const isPowTen = ticksArr.every(t => {\n const v = Math.abs(t);\n return v === 0 || Number.isInteger(Math.log10(v));\n });\n\n const [tickMin] = ticksArr;\n const tickMax = ticksArr[ticksArr.length - 1];\n\n const quantiles = extent(dataSet);\n let [min, max] = quantiles;\n if (typeof min === \"undefined\" || typeof max === \"undefined\")\n return ticksArr;\n\n if (outliers)\n [min, max] = [\n quantile(dataSet, 0.4) ?? min,\n quantile(dataSet, 0.6) ?? max,\n ];\n\n if (pad > 0) {\n const SCALE =\n typeof max === \"number\" && typeof min === \"number\"\n ? Math.max(Math.abs(max), Math.abs(min))\n : 0;\n const OFFSET =\n SCALE < 10 && isPowTen\n ? 0.5\n : SCALE < 100 && isPowTen\n ? 5\n : SCALE < 1000 && isPowTen\n ? 50\n : Math.round((max - min) / ticksArr.length);\n\n if (typeof tickMax === \"number\")\n ticksArr[ticksArr.length - 1] = Math.round(\n tickMax + OFFSET * pad + Number.EPSILON,\n );\n if (typeof tickMin === \"number\")\n ticksArr[0] = Math.round(tickMin - OFFSET * pad - Number.EPSILON);\n }\n\n const bad = ticksArr.some((tick, index) => {\n if (index === 0) return false;\n const prev = ticksArr[index - 1];\n const d = Math.abs(tick - prev);\n if (\n typeof digit === \"number\" &&\n digit < 1 &&\n String(d).includes(\".\")\n )\n return false;\n\n return d !== 1 && d !== 5 && d !== 0;\n });\n\n if (bad && pad !== 0) {\n return getChartYTicks({\n data,\n length,\n pad: 0,\n limitMin,\n limitMax,\n digit,\n outliers,\n log,\n });\n }\n\n return ticksArr;\n};\n\nexport const getDecimalIndex = (v: unknown): number =>\n !isNaN(Number(v)) && String(v).includes(\".\")\n ? String(v)\n .split(\".\")[1]\n .split(\"\")\n .findIndex(d => Number(d) !== 0) + 1\n : 0;\n\nexport const getDomainLimit = ({\n value,\n gap,\n min,\n max,\n}: {\n value: number | null;\n gap: number;\n min?: number;\n max?: number;\n}): number | string => {\n if (typeof value === \"number\" && !isNaN(value)) {\n const limit = value + gap;\n if (typeof min === \"number\" && limit < min) return min;\n if (typeof max === \"number\" && limit > max) return max;\n return limit;\n }\n return value ?? \"\";\n};\n\nexport const getXAxisTextAttr = (\n props: RechartsXAxisTickProps,\n): SVGAttributes<SVGTextElement> => {\n const {\n width,\n height,\n x,\n y,\n stroke,\n fill,\n orientation,\n textAnchor,\n transform,\n } = props;\n\n return {\n width,\n height,\n x,\n y,\n stroke,\n fill,\n textAnchor,\n orientation,\n transform,\n };\n};\n"]}
@@ -0,0 +1,33 @@
1
+ 'use strict';
2
+
3
+ var React = require('react');
4
+
5
+ function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
6
+
7
+ var React__default = /*#__PURE__*/_interopDefault(React);
8
+
9
+ // src/match/index.tsx
10
+ function matchKeyword(origin, exp, renderKey) {
11
+ const matches = Array.from(origin.matchAll(exp));
12
+ if (!matches.length) return origin;
13
+ const jsxArray = [];
14
+ for (let i = 0; i < matches.length; i++) {
15
+ const match = matches[i];
16
+ const prevMatch = i ? matches[i - 1] : void 0;
17
+ const offset = prevMatch ? prevMatch.index + prevMatch[0].length : 0;
18
+ jsxArray.push(origin.slice(offset, match.index));
19
+ jsxArray.push(
20
+ /* @__PURE__ */ React__default.default.createElement("i", { className: "matched", key: `${renderKey}/${match}/${i}` }, match[0])
21
+ );
22
+ const isLastMatch = i === matches.length - 1;
23
+ const hasTextAfterLastMatch = match.index + match[0].length < origin.length;
24
+ if (isLastMatch && hasTextAfterLastMatch) {
25
+ jsxArray.push(origin.slice(match.index + match[0].length));
26
+ }
27
+ }
28
+ return jsxArray.length ? jsxArray : origin;
29
+ }
30
+
31
+ exports.matchKeyword = matchKeyword;
32
+ //# sourceMappingURL=index.cjs.map
33
+ //# sourceMappingURL=index.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/match/index.tsx"],"names":["React"],"mappings":";;;;;;;;;AAMO,SAAS,YAAA,CACd,MAAA,EACA,GAAA,EACA,SAAA,EACoB;AACpB,EAAA,MAAM,UAAU,KAAA,CAAM,IAAA,CAAK,MAAA,CAAO,QAAA,CAAS,GAAG,CAAC,CAAA;AAC/C,EAAA,IAAI,CAAC,OAAA,CAAQ,MAAA,EAAQ,OAAO,MAAA;AAE5B,EAAA,MAAM,WAA8B,EAAC;AACrC,EAAA,KAAA,IAAS,CAAA,GAAI,CAAA,EAAG,CAAA,GAAI,OAAA,CAAQ,QAAQ,CAAA,EAAA,EAAK;AACvC,IAAA,MAAM,KAAA,GAAQ,QAAQ,CAAC,CAAA;AACvB,IAAA,MAAM,SAAA,GAAY,CAAA,GAAI,OAAA,CAAQ,CAAA,GAAI,CAAC,CAAA,GAAI,MAAA;AACvC,IAAA,MAAM,SAAS,SAAA,GAAY,SAAA,CAAU,QAAS,SAAA,CAAU,CAAC,EAAE,MAAA,GAAS,CAAA;AAEpE,IAAA,QAAA,CAAS,KAAK,MAAA,CAAO,KAAA,CAAM,MAAA,EAAQ,KAAA,CAAM,KAAK,CAAC,CAAA;AAC/C,IAAA,QAAA,CAAS,IAAA;AAAA,sBACPA,sBAAA,CAAA,aAAA,CAAC,GAAA,EAAA,EAAE,SAAA,EAAU,SAAA,EAAU,KAAK,CAAA,EAAG,SAAS,CAAA,CAAA,EAAI,KAAK,CAAA,CAAA,EAAI,CAAC,CAAA,CAAA,EAAA,EACnD,KAAA,CAAM,CAAC,CACV;AAAA,KACF;AAEA,IAAA,MAAM,WAAA,GAAc,CAAA,KAAM,OAAA,CAAQ,MAAA,GAAS,CAAA;AAC3C,IAAA,MAAM,wBACJ,KAAA,CAAM,KAAA,GAAS,MAAM,CAAC,CAAA,CAAE,SAAS,MAAA,CAAO,MAAA;AAE1C,IAAA,IAAI,eAAe,qBAAA,EAAuB;AACxC,MAAA,QAAA,CAAS,IAAA,CAAK,OAAO,KAAA,CAAM,KAAA,CAAM,QAAS,KAAA,CAAM,CAAC,CAAA,CAAE,MAAM,CAAC,CAAA;AAAA,IAC5D;AAAA,EACF;AAEA,EAAA,OAAO,QAAA,CAAS,SAAS,QAAA,GAAW,MAAA;AACtC","file":"index.cjs","sourcesContent":["import React from \"react\";\nimport type { MatchKeywordResult } from \"./types\";\n\n/**\n * 일치 텍스트를 컴포넌트로 교체\n */\nexport function matchKeyword(\n origin: string,\n exp: RegExp,\n renderKey: string,\n): MatchKeywordResult {\n const matches = Array.from(origin.matchAll(exp));\n if (!matches.length) return origin;\n\n const jsxArray: React.ReactNode[] = [];\n for (let i = 0; i < matches.length; i++) {\n const match = matches[i];\n const prevMatch = i ? matches[i - 1] : undefined;\n const offset = prevMatch ? prevMatch.index! + prevMatch[0].length : 0;\n\n jsxArray.push(origin.slice(offset, match.index));\n jsxArray.push(\n <i className=\"matched\" key={`${renderKey}/${match}/${i}`}>\n {match[0]}\n </i>,\n );\n\n const isLastMatch = i === matches.length - 1;\n const hasTextAfterLastMatch =\n match.index! + match[0].length < origin.length;\n\n if (isLastMatch && hasTextAfterLastMatch) {\n jsxArray.push(origin.slice(match.index! + match[0].length));\n }\n }\n\n return jsxArray.length ? jsxArray : origin;\n}\n"]}
@@ -0,0 +1,10 @@
1
+ import React from 'react';
2
+
3
+ type MatchKeywordResult = React.ReactNode[] | string;
4
+
5
+ /**
6
+ * 일치 텍스트를 컴포넌트로 교체
7
+ */
8
+ declare function matchKeyword(origin: string, exp: RegExp, renderKey: string): MatchKeywordResult;
9
+
10
+ export { matchKeyword };
@@ -0,0 +1,10 @@
1
+ import React from 'react';
2
+
3
+ type MatchKeywordResult = React.ReactNode[] | string;
4
+
5
+ /**
6
+ * 일치 텍스트를 컴포넌트로 교체
7
+ */
8
+ declare function matchKeyword(origin: string, exp: RegExp, renderKey: string): MatchKeywordResult;
9
+
10
+ export { matchKeyword };
@@ -0,0 +1,27 @@
1
+ import React from 'react';
2
+
3
+ // src/match/index.tsx
4
+ function matchKeyword(origin, exp, renderKey) {
5
+ const matches = Array.from(origin.matchAll(exp));
6
+ if (!matches.length) return origin;
7
+ const jsxArray = [];
8
+ for (let i = 0; i < matches.length; i++) {
9
+ const match = matches[i];
10
+ const prevMatch = i ? matches[i - 1] : void 0;
11
+ const offset = prevMatch ? prevMatch.index + prevMatch[0].length : 0;
12
+ jsxArray.push(origin.slice(offset, match.index));
13
+ jsxArray.push(
14
+ /* @__PURE__ */ React.createElement("i", { className: "matched", key: `${renderKey}/${match}/${i}` }, match[0])
15
+ );
16
+ const isLastMatch = i === matches.length - 1;
17
+ const hasTextAfterLastMatch = match.index + match[0].length < origin.length;
18
+ if (isLastMatch && hasTextAfterLastMatch) {
19
+ jsxArray.push(origin.slice(match.index + match[0].length));
20
+ }
21
+ }
22
+ return jsxArray.length ? jsxArray : origin;
23
+ }
24
+
25
+ export { matchKeyword };
26
+ //# sourceMappingURL=index.mjs.map
27
+ //# sourceMappingURL=index.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/match/index.tsx"],"names":[],"mappings":";;;AAMO,SAAS,YAAA,CACd,MAAA,EACA,GAAA,EACA,SAAA,EACoB;AACpB,EAAA,MAAM,UAAU,KAAA,CAAM,IAAA,CAAK,MAAA,CAAO,QAAA,CAAS,GAAG,CAAC,CAAA;AAC/C,EAAA,IAAI,CAAC,OAAA,CAAQ,MAAA,EAAQ,OAAO,MAAA;AAE5B,EAAA,MAAM,WAA8B,EAAC;AACrC,EAAA,KAAA,IAAS,CAAA,GAAI,CAAA,EAAG,CAAA,GAAI,OAAA,CAAQ,QAAQ,CAAA,EAAA,EAAK;AACvC,IAAA,MAAM,KAAA,GAAQ,QAAQ,CAAC,CAAA;AACvB,IAAA,MAAM,SAAA,GAAY,CAAA,GAAI,OAAA,CAAQ,CAAA,GAAI,CAAC,CAAA,GAAI,MAAA;AACvC,IAAA,MAAM,SAAS,SAAA,GAAY,SAAA,CAAU,QAAS,SAAA,CAAU,CAAC,EAAE,MAAA,GAAS,CAAA;AAEpE,IAAA,QAAA,CAAS,KAAK,MAAA,CAAO,KAAA,CAAM,MAAA,EAAQ,KAAA,CAAM,KAAK,CAAC,CAAA;AAC/C,IAAA,QAAA,CAAS,IAAA;AAAA,sBACP,KAAA,CAAA,aAAA,CAAC,GAAA,EAAA,EAAE,SAAA,EAAU,SAAA,EAAU,KAAK,CAAA,EAAG,SAAS,CAAA,CAAA,EAAI,KAAK,CAAA,CAAA,EAAI,CAAC,CAAA,CAAA,EAAA,EACnD,KAAA,CAAM,CAAC,CACV;AAAA,KACF;AAEA,IAAA,MAAM,WAAA,GAAc,CAAA,KAAM,OAAA,CAAQ,MAAA,GAAS,CAAA;AAC3C,IAAA,MAAM,wBACJ,KAAA,CAAM,KAAA,GAAS,MAAM,CAAC,CAAA,CAAE,SAAS,MAAA,CAAO,MAAA;AAE1C,IAAA,IAAI,eAAe,qBAAA,EAAuB;AACxC,MAAA,QAAA,CAAS,IAAA,CAAK,OAAO,KAAA,CAAM,KAAA,CAAM,QAAS,KAAA,CAAM,CAAC,CAAA,CAAE,MAAM,CAAC,CAAA;AAAA,IAC5D;AAAA,EACF;AAEA,EAAA,OAAO,QAAA,CAAS,SAAS,QAAA,GAAW,MAAA;AACtC","file":"index.mjs","sourcesContent":["import React from \"react\";\nimport type { MatchKeywordResult } from \"./types\";\n\n/**\n * 일치 텍스트를 컴포넌트로 교체\n */\nexport function matchKeyword(\n origin: string,\n exp: RegExp,\n renderKey: string,\n): MatchKeywordResult {\n const matches = Array.from(origin.matchAll(exp));\n if (!matches.length) return origin;\n\n const jsxArray: React.ReactNode[] = [];\n for (let i = 0; i < matches.length; i++) {\n const match = matches[i];\n const prevMatch = i ? matches[i - 1] : undefined;\n const offset = prevMatch ? prevMatch.index! + prevMatch[0].length : 0;\n\n jsxArray.push(origin.slice(offset, match.index));\n jsxArray.push(\n <i className=\"matched\" key={`${renderKey}/${match}/${i}`}>\n {match[0]}\n </i>,\n );\n\n const isLastMatch = i === matches.length - 1;\n const hasTextAfterLastMatch =\n match.index! + match[0].length < origin.length;\n\n if (isLastMatch && hasTextAfterLastMatch) {\n jsxArray.push(origin.slice(match.index! + match[0].length));\n }\n }\n\n return jsxArray.length ? jsxArray : origin;\n}\n"]}
package/package.json ADDED
@@ -0,0 +1,95 @@
1
+ {
2
+ "name": "@uniai-fe/util-react",
3
+ "version": "0.1.0",
4
+ "description": "React Utilities for UNIAI FE Projects",
5
+ "type": "module",
6
+ "private": false,
7
+ "sideEffects": false,
8
+ "license": "MIT",
9
+ "homepage": "https://www.uniai.co.kr/",
10
+ "publishConfig": {
11
+ "access": "public"
12
+ },
13
+ "packageManager": "pnpm@10.20.0",
14
+ "engines": {
15
+ "node": ">=22",
16
+ "pnpm": ">=10"
17
+ },
18
+ "author": {
19
+ "name": "GraffitoRyu",
20
+ "email": "yth4135@naver.com",
21
+ "url": "https://github.com/GraffitoRyu"
22
+ },
23
+ "files": [
24
+ "dist"
25
+ ],
26
+ "scripts": {
27
+ "build": "tsup",
28
+ "dev": "tsup --watch",
29
+ "util-react:build": "pnpm run build",
30
+ "util-react:dev": "pnpm run dev"
31
+ },
32
+ "main": "./dist/index.cjs",
33
+ "module": "./dist/index.mjs",
34
+ "types": "./dist/index.d.ts",
35
+ "exports": {
36
+ ".": {
37
+ "types": "./dist/index.d.ts",
38
+ "import": "./dist/index.mjs",
39
+ "require": "./dist/index.cjs",
40
+ "default": "./dist/index.mjs"
41
+ },
42
+ "./convert": {
43
+ "types": "./dist/convert.d.ts",
44
+ "import": "./dist/convert.mjs",
45
+ "require": "./dist/convert.cjs",
46
+ "default": "./dist/convert.mjs"
47
+ },
48
+ "./match": {
49
+ "types": "./dist/match.d.ts",
50
+ "import": "./dist/match.mjs",
51
+ "require": "./dist/match.cjs",
52
+ "default": "./dist/match.mjs"
53
+ },
54
+ "./file": {
55
+ "types": "./dist/file.d.ts",
56
+ "import": "./dist/file.mjs",
57
+ "require": "./dist/file.cjs",
58
+ "default": "./dist/file.mjs"
59
+ },
60
+ "./chart": {
61
+ "types": "./dist/chart.d.ts",
62
+ "import": "./dist/chart.mjs",
63
+ "require": "./dist/chart.cjs",
64
+ "default": "./dist/chart.mjs"
65
+ }
66
+ },
67
+ "peerDependencies": {
68
+ "react": ">= 19",
69
+ "react-dom": ">= 19",
70
+ "recharts": "^3.3.0"
71
+ },
72
+ "peerDependenciesMeta": {
73
+ "recharts": {
74
+ "optional": true
75
+ }
76
+ },
77
+ "dependencies": {
78
+ "d3-array": "^3.2.4",
79
+ "decimal.js": "^10.6.0",
80
+ "html-react-parser": "^5.2.7"
81
+ },
82
+ "devDependencies": {
83
+ "@types/d3-array": "^3.2.2",
84
+ "@types/node": "^22.15.30",
85
+ "@types/react": "^19.2.2",
86
+ "@types/react-dom": "^19.2.2",
87
+ "@types/recharts": "^1.8.26",
88
+ "@uniai-fe/eslint-config": "workspace:*",
89
+ "@uniai-fe/tsconfig": "workspace:*",
90
+ "eslint": "^9.38.0",
91
+ "prettier": "^3.6.2",
92
+ "tsup": "^8.5.0",
93
+ "typescript": "~5.9.3"
94
+ }
95
+ }