bazi-chart 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.js ADDED
@@ -0,0 +1,604 @@
1
+ // src/adapters/baziObject.ts
2
+ import { BRANCH_BY_CHAR, interactionFromZh } from "bazi-terms";
3
+ var POSITION_ZH = {
4
+ \u5E74\u67F1: "year",
5
+ \u6708\u67F1: "month",
6
+ \u65E5\u67F1: "day",
7
+ \u65F6\u67F1: "hour"
8
+ };
9
+ function splitVoid(v) {
10
+ if (typeof v !== "string" || v.length === 0) return void 0;
11
+ return Array.from(v);
12
+ }
13
+ function branchesInText(desc) {
14
+ return Array.from(desc).filter((ch) => ch in BRANCH_BY_CHAR);
15
+ }
16
+ function adaptPillar(position, raw) {
17
+ const hiddenRaw = Array.isArray(raw["\u85CF\u5E72\u8BE6\u60C5"]) ? raw["\u85CF\u5E72\u8BE6\u60C5"] : [];
18
+ const secondary = Array.isArray(raw["\u526F\u661F"]) ? raw["\u526F\u661F"] : [];
19
+ const hiddenStems = hiddenRaw.map((h, i) => ({
20
+ char: String(h["\u5E72"] ?? ""),
21
+ tenGod: secondary[i],
22
+ isMain: i === 0
23
+ }));
24
+ return {
25
+ position,
26
+ ganZhi: String(raw["\u5E72\u652F"] ?? ""),
27
+ stem: String(raw["\u5929\u5E72"] ?? ""),
28
+ branch: String(raw["\u5730\u652F"] ?? ""),
29
+ mainTenGod: raw["\u4E3B\u661F"] != null ? String(raw["\u4E3B\u661F"]) : void 0,
30
+ secondaryTenGods: secondary.length ? secondary : void 0,
31
+ hiddenStems,
32
+ naYin: raw["\u7EB3\u97F3"] != null ? String(raw["\u7EB3\u97F3"]) : void 0,
33
+ growthStage: raw["\u661F\u8FD0"] != null ? String(raw["\u661F\u8FD0"]) : void 0,
34
+ voidBranches: splitVoid(raw["\u7A7A\u4EA1"]),
35
+ shenSha: Array.isArray(raw["\u795E\u715E"]) ? raw["\u795E\u715E"] : void 0
36
+ };
37
+ }
38
+ function adaptInteractions(raw) {
39
+ const out = [];
40
+ const stems = Array.isArray(raw["\u5929\u5E72"]) ? raw["\u5929\u5E72"] : [];
41
+ const branches = Array.isArray(raw["\u5730\u652F"]) ? raw["\u5730\u652F"] : [];
42
+ for (const s of stems) {
43
+ const desc = String(s);
44
+ out.push({
45
+ typeKey: desc.includes("\u5408") ? "stemCombination" : void 0,
46
+ branches: branchesInText(desc),
47
+ description: desc
48
+ });
49
+ }
50
+ for (const b of branches) {
51
+ const desc = String(b);
52
+ out.push({
53
+ typeKey: interactionFromZh(desc)?.key,
54
+ branches: branchesInText(desc),
55
+ description: desc
56
+ });
57
+ }
58
+ return out;
59
+ }
60
+ function adaptFiveElements(raw) {
61
+ if (!raw || typeof raw !== "object") return void 0;
62
+ const scores = [];
63
+ for (const el of ["\u91D1", "\u6728", "\u6C34", "\u706B", "\u571F"]) {
64
+ const entry = raw[el];
65
+ if (entry && typeof entry === "object") {
66
+ scores.push({
67
+ element: el,
68
+ score: typeof entry["\u5206\u503C"] === "number" ? entry["\u5206\u503C"] : void 0,
69
+ percent: entry["\u5360\u6BD4"] != null ? String(entry["\u5360\u6BD4"]) : void 0
70
+ });
71
+ }
72
+ }
73
+ return scores.length ? scores : void 0;
74
+ }
75
+ function adaptDaYun(list) {
76
+ if (!Array.isArray(list)) return [];
77
+ return list.map((raw) => ({
78
+ ganZhi: String(raw["\u5E72\u652F"] ?? ""),
79
+ stem: raw["\u5929\u5E72"] != null ? String(raw["\u5929\u5E72"]) : void 0,
80
+ branch: raw["\u5730\u652F"] != null ? String(raw["\u5730\u652F"]) : void 0,
81
+ stemTenGod: raw["\u4E3B\u661F"] != null ? String(raw["\u4E3B\u661F"]) : void 0,
82
+ startAge: typeof raw["\u8D77\u59CB\u5E74\u9F84"] === "number" ? raw["\u8D77\u59CB\u5E74\u9F84"] : void 0,
83
+ endAge: typeof raw["\u7ED3\u675F\u5E74\u9F84"] === "number" ? raw["\u7ED3\u675F\u5E74\u9F84"] : void 0,
84
+ startYear: typeof raw["\u8D77\u59CB\u5E74\u4EFD"] === "number" ? raw["\u8D77\u59CB\u5E74\u4EFD"] : void 0,
85
+ endYear: typeof raw["\u7ED3\u675F\u5E74\u4EFD"] === "number" ? raw["\u7ED3\u675F\u5E74\u4EFD"] : void 0,
86
+ naYin: raw["\u7EB3\u97F3"] != null ? String(raw["\u7EB3\u97F3"]) : void 0,
87
+ isCurrent: raw["\u5F53\u524D"] === true
88
+ }));
89
+ }
90
+ function fromBaziObject(data) {
91
+ const input = data["\u8F93\u5165"] ?? {};
92
+ const solarTimeRaw = data["\u771F\u592A\u9633\u65F6"] ?? {};
93
+ const bazi = data["\u516B\u5B57"] ?? {};
94
+ const detail = bazi["\u67F1\u4F4D\u8BE6\u7EC6"] ?? {};
95
+ const pillars = [];
96
+ for (const [zh, position] of Object.entries(POSITION_ZH)) {
97
+ const raw = detail[zh];
98
+ if (raw && typeof raw === "object") pillars.push(adaptPillar(position, raw));
99
+ }
100
+ const wuxing = bazi["\u4E94\u884C\u5206\u503C"] ?? {};
101
+ return {
102
+ meta: {
103
+ engine: "baziObject",
104
+ gender: input["\u6027\u522B"] != null ? String(input["\u6027\u522B"]) : void 0,
105
+ zodiac: bazi["\u751F\u8096"] != null ? String(bazi["\u751F\u8096"]) : void 0,
106
+ lunar: bazi["\u519C\u5386"] != null ? String(bazi["\u519C\u5386"]) : void 0,
107
+ solar: bazi["\u516C\u5386"] != null ? String(bazi["\u516C\u5386"]) : void 0
108
+ },
109
+ solarTime: {
110
+ clock: solarTimeRaw["\u949F\u8868\u65F6\u95F4"] != null ? String(solarTimeRaw["\u949F\u8868\u65F6\u95F4"]) : void 0,
111
+ trueSolar: solarTimeRaw["\u771F\u592A\u9633\u65F6"] != null ? String(solarTimeRaw["\u771F\u592A\u9633\u65F6"]) : void 0,
112
+ correctionMinutes: typeof solarTimeRaw["\u4FEE\u6B63\u5206\u949F"] === "number" ? solarTimeRaw["\u4FEE\u6B63\u5206\u949F"] : void 0,
113
+ shiChen: solarTimeRaw["\u65F6\u8FB0"] != null ? String(solarTimeRaw["\u65F6\u8FB0"]) : void 0
114
+ },
115
+ dayMaster: {
116
+ char: bazi["\u65E5\u4E3B"] != null ? String(bazi["\u65E5\u4E3B"]) : void 0,
117
+ element: wuxing["\u65E5\u4E3B\u4E94\u884C"] != null ? String(wuxing["\u65E5\u4E3B\u4E94\u884C"]) : void 0
118
+ },
119
+ pillars,
120
+ fiveElements: adaptFiveElements(wuxing),
121
+ dayMasterElement: wuxing["\u65E5\u4E3B\u4E94\u884C"] != null ? String(wuxing["\u65E5\u4E3B\u4E94\u884C"]) : void 0,
122
+ daYun: adaptDaYun(bazi["\u5927\u8FD0"]),
123
+ daYunOnset: bazi["\u8D77\u8FD0"] != null ? String(bazi["\u8D77\u8FD0"]) : void 0,
124
+ interactions: adaptInteractions(bazi["\u5211\u51B2\u5408\u4F1A"] ?? {}),
125
+ extras: {
126
+ mingGong: bazi["\u547D\u5BAB"] != null ? String(bazi["\u547D\u5BAB"]) : void 0,
127
+ shenGong: bazi["\u8EAB\u5BAB"] != null ? String(bazi["\u8EAB\u5BAB"]) : void 0,
128
+ taiYuan: bazi["\u80CE\u5143"] != null ? String(bazi["\u80CE\u5143"]) : void 0,
129
+ taiXi: bazi["\u80CE\u606F"] != null ? String(bazi["\u80CE\u606F"]) : void 0
130
+ }
131
+ };
132
+ }
133
+
134
+ // src/adapters/pillarMap.ts
135
+ import { interactionFromEnum } from "bazi-terms";
136
+ var PILLAR_ORDER = [
137
+ { field: "year", position: "year" },
138
+ { field: "month", position: "month" },
139
+ { field: "day", position: "day" },
140
+ { field: "hour", position: "hour" }
141
+ ];
142
+ function str(v) {
143
+ return v == null ? void 0 : String(v);
144
+ }
145
+ function num(v) {
146
+ return typeof v === "number" ? v : void 0;
147
+ }
148
+ function adaptPillar2(position, raw) {
149
+ const hiddenRaw = Array.isArray(raw["hiddenStems"]) ? raw["hiddenStems"] : [];
150
+ const hiddenStems = hiddenRaw.map((h, i) => ({
151
+ char: String(h["stem"] ?? ""),
152
+ tenGod: str(h["tenGod"]),
153
+ isMain: h["isMain"] === true || h["isMain"] === void 0 && i === 0
154
+ }));
155
+ return {
156
+ position,
157
+ ganZhi: String(raw["ganZhi"] ?? ""),
158
+ stem: String(raw["stem"] ?? ""),
159
+ branch: String(raw["branch"] ?? ""),
160
+ mainTenGod: str(raw["stemTenGod"]),
161
+ hiddenStems,
162
+ naYin: str(raw["naYin"]),
163
+ growthStage: str(raw["growthStage"]),
164
+ voidBranches: Array.isArray(raw["voidBranches"]) ? raw["voidBranches"] : void 0,
165
+ xun: str(raw["xun"])
166
+ };
167
+ }
168
+ function adaptInteractions2(list) {
169
+ if (!Array.isArray(list)) return [];
170
+ return list.map((raw) => ({
171
+ typeKey: interactionFromEnum(String(raw["type"] ?? ""))?.key,
172
+ branches: Array.isArray(raw["branches"]) ? raw["branches"] : void 0,
173
+ pillars: Array.isArray(raw["pillars"]) ? raw["pillars"] : void 0,
174
+ description: str(raw["description"])
175
+ }));
176
+ }
177
+ function adaptDaYun2(daYun) {
178
+ const cycles = Array.isArray(daYun?.["cycles"]) ? daYun["cycles"] : [];
179
+ return cycles.map((c) => ({
180
+ ganZhi: String(c["ganZhi"] ?? ""),
181
+ stem: str(c["stem"]),
182
+ branch: str(c["branch"]),
183
+ stemTenGod: str(c["stemTenGod"]),
184
+ branchTenGod: str(c["branchTenGod"]),
185
+ startAge: num(c["startAge"]),
186
+ endAge: num(c["endAge"]),
187
+ startYear: num(c["startYear"]),
188
+ endYear: num(c["endYear"])
189
+ }));
190
+ }
191
+ function formatCalendarPart(part) {
192
+ if (!part || typeof part !== "object") return void 0;
193
+ const y = num(part["year"]);
194
+ const m = num(part["month"]);
195
+ const d = num(part["day"]);
196
+ if (y == null || m == null || d == null) return void 0;
197
+ const hh = num(part["hour"]);
198
+ const mm = num(part["minute"]);
199
+ const time = hh != null && mm != null ? ` ${String(hh).padStart(2, "0")}:${String(mm).padStart(2, "0")}` : "";
200
+ return `${y}-${String(m).padStart(2, "0")}-${String(d).padStart(2, "0")}${time}`;
201
+ }
202
+ function fromPillarMap(data) {
203
+ const rawPillars = data["pillars"] ?? {};
204
+ const pillars = [];
205
+ for (const { field, position } of PILLAR_ORDER) {
206
+ const raw = rawPillars[field];
207
+ if (raw && typeof raw === "object") pillars.push(adaptPillar2(position, raw));
208
+ }
209
+ const dm = data["dayMaster"] ?? {};
210
+ const daYun = data["daYun"] ?? {};
211
+ const solar = data["solarTimeInfo"] ?? {};
212
+ const calendar = data["calendar"] ?? {};
213
+ const lonCorr = num(solar["longitudeCorrectionMinutes"]);
214
+ const eotCorr = num(solar["equationOfTimeMinutes"]);
215
+ const correctionMinutes = lonCorr != null || eotCorr != null ? Math.round(((lonCorr ?? 0) + (eotCorr ?? 0)) * 100) / 100 : void 0;
216
+ return {
217
+ meta: {
218
+ engine: "pillarMap",
219
+ zodiac: str(calendar["zodiac"]),
220
+ lunar: formatCalendarPart(calendar["lunar"]),
221
+ solar: formatCalendarPart(calendar["civilSolar"] ?? calendar["calculationSolar"])
222
+ },
223
+ solarTime: {
224
+ trueSolar: str(solar["trueSolarDateTime"] ?? solar["trueSolarTime"]),
225
+ correctionMinutes
226
+ },
227
+ dayMaster: {
228
+ char: str(dm["char"]),
229
+ element: str(dm["element"]),
230
+ polarity: str(dm["polarity"])
231
+ },
232
+ pillars,
233
+ dayMasterElement: str(dm["element"]),
234
+ daYun: adaptDaYun2(daYun),
235
+ daYunDirection: daYun["isForward"] === true ? "forward" : daYun["isForward"] === false ? "backward" : void 0,
236
+ interactions: adaptInteractions2(data["interactions"])
237
+ };
238
+ }
239
+
240
+ // src/normalize.ts
241
+ function detectEngine(data) {
242
+ if (!data || typeof data !== "object") return "unknown";
243
+ const d = data;
244
+ if (d["\u516B\u5B57"] && typeof d["\u516B\u5B57"] === "object") return "baziObject";
245
+ if (d["meta"] && typeof d["meta"] === "object" && "engine" in d["meta"]) return "normalized";
246
+ if (Array.isArray(d["pillars"]) && d["pillars"][0] && typeof d["pillars"][0] === "object" && "position" in d["pillars"][0]) {
247
+ return "normalized";
248
+ }
249
+ if (d["pillars"] && typeof d["pillars"] === "object" && !Array.isArray(d["pillars"])) {
250
+ const year = d["pillars"]["year"];
251
+ if (year && typeof year === "object" && ("ganZhi" in year || "stem" in year)) return "pillarMap";
252
+ }
253
+ return "unknown";
254
+ }
255
+ function normalize(data) {
256
+ const engine = detectEngine(data);
257
+ switch (engine) {
258
+ case "baziObject":
259
+ return fromBaziObject(data);
260
+ case "pillarMap":
261
+ return fromPillarMap(data);
262
+ case "normalized":
263
+ return data;
264
+ default:
265
+ throw new Error(
266
+ "[bazi-chart] Unrecognized chart data. Expected a bazi-object chart, a pillar-map chart, or a pre-normalized NormalizedChart."
267
+ );
268
+ }
269
+ }
270
+
271
+ // src/theme.ts
272
+ var PALETTES = {
273
+ light: {
274
+ bg: "#ffffff",
275
+ card: "#fafafa",
276
+ cardAlt: "#f1f1f3",
277
+ border: "#e4e4e7",
278
+ text: "#18181b",
279
+ muted: "#71717a",
280
+ accent: "#a16207"
281
+ },
282
+ dark: {
283
+ bg: "#18181b",
284
+ card: "#27272a",
285
+ cardAlt: "#333338",
286
+ border: "#3f3f46",
287
+ text: "#fafafa",
288
+ muted: "#a1a1aa",
289
+ accent: "#fbbf24"
290
+ }
291
+ };
292
+ var ELEMENT_COLORS = {
293
+ wood: { light: "#15803d", dark: "#4ade80" },
294
+ fire: { light: "#dc2626", dark: "#f87171" },
295
+ earth: { light: "#a0522d", dark: "#d2a679" },
296
+ metal: { light: "#b8860b", dark: "#e6c34a" },
297
+ water: { light: "#2563eb", dark: "#60a5fa" }
298
+ };
299
+ var NEUTRAL_COLOR = {
300
+ light: "#52525b",
301
+ dark: "#d4d4d8"
302
+ };
303
+ function elementColor(key, theme) {
304
+ if (!key) return NEUTRAL_COLOR[theme];
305
+ return ELEMENT_COLORS[key]?.[theme] ?? NEUTRAL_COLOR[theme];
306
+ }
307
+
308
+ // src/i18n.ts
309
+ import { t, translate, elementOf, branchByChar, stemByChar } from "bazi-terms";
310
+ function combine(zh, en, lang) {
311
+ if (lang === "zh") return zh;
312
+ if (lang === "en") return en;
313
+ if (!en || en === zh) return zh;
314
+ return `${zh} \xB7 ${en}`;
315
+ }
316
+ function labelText(key, lang) {
317
+ return combine(t(key, "zh"), t(key, "en"), lang);
318
+ }
319
+ function valueText(raw, lang) {
320
+ if (!raw) return "";
321
+ const zh = translate(raw, "zh") || raw;
322
+ const en = translate(raw, "en");
323
+ return combine(zh, en, lang);
324
+ }
325
+ function elementKeyOf(raw) {
326
+ if (!raw) return void 0;
327
+ return elementOf(raw)?.key;
328
+ }
329
+ function stemElement(char) {
330
+ if (!char) return void 0;
331
+ return stemByChar(char)?.element;
332
+ }
333
+ function branchElement(char) {
334
+ if (!char) return void 0;
335
+ return branchByChar(char)?.element;
336
+ }
337
+ function branchZodiac(char, lang) {
338
+ if (!char) return "";
339
+ const b = branchByChar(char);
340
+ if (!b) return "";
341
+ return combine(b.zodiacZh, b.zodiacEn, lang);
342
+ }
343
+
344
+ // src/components/BaziChart.tsx
345
+ import { jsx, jsxs } from "react/jsx-runtime";
346
+ var POS_LABEL = {
347
+ year: "yearPillar",
348
+ month: "monthPillar",
349
+ day: "dayPillar",
350
+ hour: "hourPillar"
351
+ };
352
+ function BaziChart(props) {
353
+ const {
354
+ lang = "both",
355
+ theme = "light",
356
+ showDaYun = true,
357
+ showInteractions = true,
358
+ showFiveElements = true,
359
+ showShenSha = true,
360
+ style
361
+ } = props;
362
+ const chart = props.chart ?? (props.data !== void 0 ? normalize(props.data) : void 0);
363
+ const p = PALETTES[theme];
364
+ const box = {
365
+ background: p.bg,
366
+ color: p.text,
367
+ fontFamily: '-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "PingFang SC", "Microsoft YaHei", sans-serif',
368
+ fontSize: 14,
369
+ lineHeight: 1.5,
370
+ padding: 20,
371
+ borderRadius: 12,
372
+ border: `1px solid ${p.border}`,
373
+ boxSizing: "border-box",
374
+ maxWidth: 860
375
+ };
376
+ const card = {
377
+ background: p.card,
378
+ border: `1px solid ${p.border}`,
379
+ borderRadius: 10,
380
+ padding: 12,
381
+ boxSizing: "border-box"
382
+ };
383
+ const sectionTitle = {
384
+ fontSize: 13,
385
+ fontWeight: 600,
386
+ letterSpacing: 0.4,
387
+ color: p.accent,
388
+ textTransform: "uppercase",
389
+ margin: "20px 0 10px"
390
+ };
391
+ const muted = { color: p.muted, fontSize: 12 };
392
+ const bigChar = (color) => ({
393
+ color,
394
+ fontSize: 34,
395
+ fontWeight: 700,
396
+ lineHeight: 1.1
397
+ });
398
+ const chip = {
399
+ display: "inline-block",
400
+ background: p.cardAlt,
401
+ border: `1px solid ${p.border}`,
402
+ borderRadius: 999,
403
+ padding: "2px 9px",
404
+ fontSize: 12,
405
+ margin: "2px 4px 2px 0",
406
+ whiteSpace: "nowrap"
407
+ };
408
+ if (!chart) {
409
+ return /* @__PURE__ */ jsx("div", { style: { ...box, ...style }, children: /* @__PURE__ */ jsx("span", { style: muted, children: "No chart data. Pass `data` (engine output) or `chart` (NormalizedChart)." }) });
410
+ }
411
+ const dmElementKey = elementKeyOf(chart.dayMaster.element ?? chart.dayMasterElement);
412
+ const header = /* @__PURE__ */ jsxs("div", { style: { display: "flex", flexWrap: "wrap", alignItems: "baseline", gap: 10 }, children: [
413
+ /* @__PURE__ */ jsx("h3", { style: { margin: 0, fontSize: 18, fontWeight: 700 }, children: labelText("bazi", lang) }),
414
+ chart.dayMaster.char ? /* @__PURE__ */ jsxs("span", { style: chip, children: [
415
+ labelText("dayMaster", lang),
416
+ ":",
417
+ " ",
418
+ /* @__PURE__ */ jsx("strong", { style: { color: elementColor(dmElementKey, theme) }, children: chart.dayMaster.char }),
419
+ dmElementKey ? ` (${valueText(dmElementKey, lang)})` : ""
420
+ ] }) : null,
421
+ chart.meta.zodiac ? /* @__PURE__ */ jsxs("span", { style: chip, children: [
422
+ labelText("shengXiao", lang),
423
+ ": ",
424
+ valueText(chart.meta.zodiac, lang)
425
+ ] }) : null,
426
+ chart.meta.gender ? /* @__PURE__ */ jsxs("span", { style: chip, children: [
427
+ labelText("gender", lang),
428
+ ": ",
429
+ valueText(chart.meta.gender, lang)
430
+ ] }) : null
431
+ ] });
432
+ const metaItems = [];
433
+ if (chart.meta.solar) metaItems.push(`${labelText("gongLi", lang)}: ${chart.meta.solar}`);
434
+ if (chart.meta.lunar) metaItems.push(`${labelText("nongLi", lang)}: ${chart.meta.lunar}`);
435
+ if (chart.solarTime?.trueSolar)
436
+ metaItems.push(`${labelText("zhenTaiYangShi", lang)}: ${chart.solarTime.trueSolar}`);
437
+ if (chart.solarTime?.shiChen)
438
+ metaItems.push(`${labelText("shiChen", lang)}: ${valueText(chart.solarTime.shiChen.replace("\u65F6", ""), lang)}`);
439
+ const metaBar = metaItems.length ? /* @__PURE__ */ jsx("div", { style: { ...muted, marginTop: 8 }, children: metaItems.map((m, i) => /* @__PURE__ */ jsx("span", { style: { marginRight: 14, display: "inline-block" }, children: m }, i)) }) : null;
440
+ const renderPillar = (pillar) => {
441
+ const sColor = elementColor(stemElement(pillar.stem), theme);
442
+ const bColor = elementColor(branchElement(pillar.branch), theme);
443
+ const isDay = pillar.position === "day";
444
+ return /* @__PURE__ */ jsxs(
445
+ "div",
446
+ {
447
+ style: {
448
+ ...card,
449
+ flex: "1 1 150px",
450
+ minWidth: 150,
451
+ borderColor: isDay ? p.accent : p.border,
452
+ borderWidth: isDay ? 2 : 1
453
+ },
454
+ children: [
455
+ /* @__PURE__ */ jsx("div", { style: { ...muted, textAlign: "center", fontWeight: 600, marginBottom: 6 }, children: labelText(POS_LABEL[pillar.position], lang) }),
456
+ /* @__PURE__ */ jsx("div", { style: { textAlign: "center", fontSize: 12, minHeight: 18, color: p.muted }, children: pillar.mainTenGod ? valueText(pillar.mainTenGod, lang) : "" }),
457
+ /* @__PURE__ */ jsxs("div", { style: { textAlign: "center", margin: "6px 0" }, children: [
458
+ /* @__PURE__ */ jsx("div", { style: bigChar(sColor), children: pillar.stem }),
459
+ /* @__PURE__ */ jsx("div", { style: { ...muted, fontSize: 11 }, children: stemElement(pillar.stem) ? valueText(stemElement(pillar.stem), lang) : "" })
460
+ ] }),
461
+ /* @__PURE__ */ jsxs("div", { style: { textAlign: "center", margin: "6px 0" }, children: [
462
+ /* @__PURE__ */ jsx("div", { style: bigChar(bColor), children: pillar.branch }),
463
+ /* @__PURE__ */ jsx("div", { style: { ...muted, fontSize: 11 }, children: branchZodiac(pillar.branch, lang) })
464
+ ] }),
465
+ pillar.hiddenStems.length ? /* @__PURE__ */ jsxs("div", { style: { borderTop: `1px solid ${p.border}`, marginTop: 8, paddingTop: 6 }, children: [
466
+ /* @__PURE__ */ jsx("div", { style: { ...muted, fontSize: 11, marginBottom: 4 }, children: labelText("hiddenStems", lang) }),
467
+ /* @__PURE__ */ jsx("div", { style: { textAlign: "center" }, children: pillar.hiddenStems.map((h, i) => /* @__PURE__ */ jsxs("span", { style: { display: "inline-block", margin: "0 4px", fontSize: 12 }, children: [
468
+ /* @__PURE__ */ jsx("strong", { style: { color: elementColor(stemElement(h.char), theme) }, children: h.char }),
469
+ h.tenGod ? /* @__PURE__ */ jsx("span", { style: { ...muted, fontSize: 10, display: "block" }, children: valueText(h.tenGod, lang) }) : null
470
+ ] }, i)) })
471
+ ] }) : null,
472
+ /* @__PURE__ */ jsxs("div", { style: { borderTop: `1px solid ${p.border}`, marginTop: 8, paddingTop: 6, fontSize: 11, color: p.muted }, children: [
473
+ pillar.naYin ? /* @__PURE__ */ jsxs("div", { children: [
474
+ labelText("naYin", lang),
475
+ ": ",
476
+ valueText(pillar.naYin, lang)
477
+ ] }) : null,
478
+ pillar.growthStage ? /* @__PURE__ */ jsxs("div", { children: [
479
+ labelText("xingYun", lang),
480
+ ": ",
481
+ valueText(pillar.growthStage, lang)
482
+ ] }) : null,
483
+ pillar.voidBranches?.length ? /* @__PURE__ */ jsxs("div", { children: [
484
+ labelText("kongWang", lang),
485
+ ": ",
486
+ pillar.voidBranches.join("")
487
+ ] }) : null
488
+ ] }),
489
+ showShenSha && pillar.shenSha?.length ? /* @__PURE__ */ jsx("div", { style: { marginTop: 8 }, children: pillar.shenSha.map((s, i) => /* @__PURE__ */ jsx("span", { style: { ...chip, fontSize: 11 }, children: valueText(s, lang) }, i)) }) : null
490
+ ]
491
+ },
492
+ pillar.position
493
+ );
494
+ };
495
+ const pillars = /* @__PURE__ */ jsx("div", { style: { display: "flex", flexWrap: "wrap", gap: 10, marginTop: 14 }, children: chart.pillars.map(renderPillar) });
496
+ const renderFiveElements = (scores) => {
497
+ const max = Math.max(...scores.map((s) => s.score ?? 0), 1);
498
+ return /* @__PURE__ */ jsxs("div", { children: [
499
+ /* @__PURE__ */ jsx("div", { style: sectionTitle, children: labelText("wuXingFenZhi", lang) }),
500
+ /* @__PURE__ */ jsx("div", { style: { display: "flex", flexDirection: "column", gap: 6 }, children: scores.map((s, i) => {
501
+ const key = elementKeyOf(s.element);
502
+ const width = Math.round((s.score ?? 0) / max * 100);
503
+ const isDm = s.element === chart.dayMasterElement;
504
+ return /* @__PURE__ */ jsxs("div", { style: { display: "flex", alignItems: "center", gap: 8 }, children: [
505
+ /* @__PURE__ */ jsx("div", { style: { width: 88, fontSize: 12, color: elementColor(key, theme), fontWeight: isDm ? 700 : 400 }, children: valueText(s.element, lang) }),
506
+ /* @__PURE__ */ jsx("div", { style: { flex: 1, background: p.cardAlt, borderRadius: 6, height: 14, overflow: "hidden" }, children: /* @__PURE__ */ jsx("div", { style: { width: `${width}%`, height: "100%", background: elementColor(key, theme) } }) }),
507
+ /* @__PURE__ */ jsxs("div", { style: { width: 74, textAlign: "right", ...muted }, children: [
508
+ s.score != null ? s.score : "",
509
+ s.percent ? ` (${s.percent})` : ""
510
+ ] })
511
+ ] }, i);
512
+ }) })
513
+ ] });
514
+ };
515
+ const renderInteractions = (items) => /* @__PURE__ */ jsxs("div", { children: [
516
+ /* @__PURE__ */ jsx("div", { style: sectionTitle, children: labelText("interactions", lang) }),
517
+ /* @__PURE__ */ jsx("div", { children: items.map((it, i) => /* @__PURE__ */ jsxs("span", { style: chip, title: it.description ?? void 0, children: [
518
+ /* @__PURE__ */ jsx("strong", { children: it.typeKey ? labelText(it.typeKey, lang) : it.description ?? "" }),
519
+ it.typeKey && it.branches?.length ? ` ${it.branches.join("")}` : ""
520
+ ] }, i)) })
521
+ ] });
522
+ const renderDaYun = (cycles) => /* @__PURE__ */ jsxs("div", { children: [
523
+ /* @__PURE__ */ jsxs("div", { style: sectionTitle, children: [
524
+ labelText("daYun", lang),
525
+ chart.daYunDirection ? ` \xB7 ${labelText(chart.daYunDirection, lang)}` : "",
526
+ chart.daYunOnset ? /* @__PURE__ */ jsx("span", { style: { ...muted, textTransform: "none", marginLeft: 8 }, children: chart.daYunOnset }) : null
527
+ ] }),
528
+ /* @__PURE__ */ jsx("div", { style: { display: "flex", gap: 8, overflowX: "auto", paddingBottom: 6 }, children: cycles.map((c, i) => /* @__PURE__ */ jsxs(
529
+ "div",
530
+ {
531
+ style: {
532
+ ...card,
533
+ minWidth: 92,
534
+ flex: "0 0 auto",
535
+ textAlign: "center",
536
+ borderColor: c.isCurrent ? p.accent : p.border,
537
+ borderWidth: c.isCurrent ? 2 : 1
538
+ },
539
+ children: [
540
+ /* @__PURE__ */ jsxs("div", { style: { fontSize: 20, fontWeight: 700 }, children: [
541
+ /* @__PURE__ */ jsx("span", { style: { color: elementColor(stemElement(c.ganZhi[0]), theme) }, children: c.ganZhi[0] }),
542
+ /* @__PURE__ */ jsx("span", { style: { color: elementColor(branchElement(c.ganZhi[1]), theme) }, children: c.ganZhi[1] })
543
+ ] }),
544
+ c.stemTenGod ? /* @__PURE__ */ jsx("div", { style: { ...muted, fontSize: 11 }, children: valueText(c.stemTenGod, lang) }) : null,
545
+ /* @__PURE__ */ jsx("div", { style: { ...muted, fontSize: 11, marginTop: 4 }, children: c.startAge != null && c.endAge != null ? `${c.startAge}\u2013${c.endAge}` : "" }),
546
+ /* @__PURE__ */ jsx("div", { style: { ...muted, fontSize: 10 }, children: c.startYear != null && c.endYear != null ? `${c.startYear}\u2013${c.endYear}` : "" }),
547
+ c.isCurrent ? /* @__PURE__ */ jsx("div", { style: { fontSize: 10, color: p.accent, marginTop: 2 }, children: labelText("current", lang) }) : null
548
+ ]
549
+ },
550
+ i
551
+ )) })
552
+ ] });
553
+ const renderExtras = (chart2) => {
554
+ const ex = chart2.extras;
555
+ if (!ex) return null;
556
+ const rows = [
557
+ ["mingGong", ex.mingGong],
558
+ ["shenGong", ex.shenGong],
559
+ ["taiYuan", ex.taiYuan],
560
+ ["taiXi", ex.taiXi]
561
+ ];
562
+ const filled = rows.filter(([, v]) => v);
563
+ if (!filled.length) return null;
564
+ return /* @__PURE__ */ jsxs("div", { children: [
565
+ /* @__PURE__ */ jsx("div", { style: sectionTitle, children: combine("\u5BAB\u4F4D", "Palaces", lang) }),
566
+ /* @__PURE__ */ jsx("div", { style: { display: "flex", flexWrap: "wrap", gap: 8 }, children: filled.map(([k, v], i) => /* @__PURE__ */ jsxs("span", { style: chip, children: [
567
+ /* @__PURE__ */ jsxs("span", { style: muted, children: [
568
+ labelText(k, lang),
569
+ ":"
570
+ ] }),
571
+ " ",
572
+ /* @__PURE__ */ jsx("strong", { children: v })
573
+ ] }, i)) })
574
+ ] });
575
+ };
576
+ return /* @__PURE__ */ jsxs("div", { style: { ...box, ...style }, children: [
577
+ header,
578
+ metaBar,
579
+ pillars,
580
+ showFiveElements && chart.fiveElements?.length ? renderFiveElements(chart.fiveElements) : null,
581
+ showInteractions && chart.interactions.length ? renderInteractions(chart.interactions) : null,
582
+ showDaYun && chart.daYun.length ? renderDaYun(chart.daYun) : null,
583
+ renderExtras(chart)
584
+ ] });
585
+ }
586
+ export {
587
+ BaziChart,
588
+ ELEMENT_COLORS,
589
+ NEUTRAL_COLOR,
590
+ PALETTES,
591
+ branchElement,
592
+ branchZodiac,
593
+ combine,
594
+ detectEngine,
595
+ elementColor,
596
+ elementKeyOf,
597
+ fromBaziObject,
598
+ fromPillarMap,
599
+ labelText,
600
+ normalize,
601
+ stemElement,
602
+ valueText
603
+ };
604
+ //# sourceMappingURL=index.js.map