@open-feishu-card/adapter 0.3.2 → 0.3.4

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.
@@ -0,0 +1,26 @@
1
+ /**
2
+ * Feishu RAW editor fields for theme-aware custom colors:
3
+ * customBackgroundStyle / custom_background_style → column backgrounds
4
+ * textStyle.customColor / textStyle.custom_color → inline text color
5
+ *
6
+ * Public DSL stores custom colors in config.style.color (cus-accent / cus-bg-N …)
7
+ * and references them via markdown.font_color / background_style — not inline #hex.
8
+ */
9
+ import type { CustomColorEntry } from './normalize-stored-colors.js';
10
+ export type ThemeColorPair = {
11
+ light_mode?: string;
12
+ lightMode?: string;
13
+ dark_mode?: string;
14
+ darkMode?: string;
15
+ };
16
+ export declare function readThemeColorLight(pair: unknown): string | undefined;
17
+ export declare function readThemeColorDark(pair: unknown): string | undefined;
18
+ export declare function isCustomHexColor(color: string): boolean;
19
+ /** Enum `color` wins; else fall back to customColor light hex/rgba. */
20
+ export declare function resolveTextStyleColor(textStyle: unknown): string | undefined;
21
+ /** When text color comes from customColor (not enum), return the full light/dark pair. */
22
+ export declare function resolveTextStyleCustomColorPair(textStyle: unknown): ThemeColorPair | undefined;
23
+ export declare function themePairToColorEntry(pair: ThemeColorPair): CustomColorEntry | undefined;
24
+ /** Light hex/rgba from column (or container) custom background, if any. */
25
+ export declare function resolveCustomBackgroundLight(property: unknown): string | undefined;
26
+ //# sourceMappingURL=custom-colors.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"custom-colors.d.ts","sourceRoot":"","sources":["../src/custom-colors.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,8BAA8B,CAAC;AAGrE,MAAM,MAAM,cAAc,GAAG;IAC3B,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB,CAAC;AAEF,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,OAAO,GAAG,MAAM,GAAG,SAAS,CAOrE;AAED,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,OAAO,GAAG,MAAM,GAAG,SAAS,CAOpE;AAED,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAGvD;AAED,uEAAuE;AACvE,wBAAgB,qBAAqB,CAAC,SAAS,EAAE,OAAO,GAAG,MAAM,GAAG,SAAS,CAO5E;AAED,0FAA0F;AAC1F,wBAAgB,+BAA+B,CAAC,SAAS,EAAE,OAAO,GAAG,cAAc,GAAG,SAAS,CAQ9F;AAED,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,cAAc,GAAG,gBAAgB,GAAG,SAAS,CAQxF;AAED,2EAA2E;AAC3E,wBAAgB,4BAA4B,CAAC,QAAQ,EAAE,OAAO,GAAG,MAAM,GAAG,SAAS,CAKlF"}
package/dist/index.cjs CHANGED
@@ -868,6 +868,256 @@ function isRecord(v) {
868
868
  return typeof v === "object" && v !== null && !Array.isArray(v);
869
869
  }
870
870
 
871
+ // src/normalize-stored-colors.ts
872
+ function createColorRegistry() {
873
+ return { entries: {}, keyToAlias: /* @__PURE__ */ new Map(), bgSeq: 0, textSeq: 0 };
874
+ }
875
+ function colorEntryKey(entry) {
876
+ return `${entry.light_mode}|${entry.dark_mode}`;
877
+ }
878
+ function registerColorEntry(registry, entry, prefix) {
879
+ const key = colorEntryKey(entry);
880
+ const existing = registry.keyToAlias.get(key);
881
+ if (existing) return existing;
882
+ const alias = prefix === "cus-bg" ? `cus-bg-${registry.bgSeq++}` : `cus-text-${registry.textSeq++}`;
883
+ registry.entries[alias] = entry;
884
+ registry.keyToAlias.set(key, alias);
885
+ return alias;
886
+ }
887
+ function hexColorToRgba(hex) {
888
+ const h = hex.trim().replace(/^#/, "");
889
+ if (h.length === 8) {
890
+ const r = parseInt(h.slice(0, 2), 16);
891
+ const g = parseInt(h.slice(2, 4), 16);
892
+ const b = parseInt(h.slice(4, 6), 16);
893
+ const a = Math.round(parseInt(h.slice(6, 8), 16) / 255 * 100) / 100;
894
+ return `rgba(${r},${g},${b},${a})`;
895
+ }
896
+ if (h.length === 6) {
897
+ const r = parseInt(h.slice(0, 2), 16);
898
+ const g = parseInt(h.slice(2, 4), 16);
899
+ const b = parseInt(h.slice(4, 6), 16);
900
+ return `rgba(${r},${g},${b},1)`;
901
+ }
902
+ return void 0;
903
+ }
904
+ function readCustomBackgroundStyle(node) {
905
+ const raw = node.custom_background_style;
906
+ if (!raw || typeof raw !== "object") return void 0;
907
+ const o = raw;
908
+ const lightRaw = typeof o.light_mode === "string" ? o.light_mode : void 0;
909
+ const darkRaw = typeof o.dark_mode === "string" ? o.dark_mode : void 0;
910
+ if (!lightRaw || !darkRaw) return void 0;
911
+ const light = lightRaw.startsWith("#") ? hexColorToRgba(lightRaw) : lightRaw;
912
+ const dark = darkRaw.startsWith("#") ? hexColorToRgba(darkRaw) : darkRaw;
913
+ if (!light || !dark) return void 0;
914
+ return { light_mode: light, dark_mode: dark };
915
+ }
916
+ function normalizeStoredCardColors(dsl, preRegistered) {
917
+ const colorEntries = { ...preRegistered?.entries ?? {} };
918
+ const keyToAlias = new Map(preRegistered?.keyToAlias ?? []);
919
+ let bgSeq = preRegistered?.bgSeq ?? 0;
920
+ let textSeq = preRegistered?.textSeq ?? 0;
921
+ const ensureAlias = (prefix, entry) => {
922
+ const existing2 = keyToAlias.get(colorEntryKey(entry));
923
+ if (existing2) return existing2;
924
+ const alias = prefix === "cus-bg" ? `cus-bg-${bgSeq++}` : `cus-text-${textSeq++}`;
925
+ colorEntries[alias] = entry;
926
+ keyToAlias.set(colorEntryKey(entry), alias);
927
+ return alias;
928
+ };
929
+ const walk = (node) => {
930
+ if (Array.isArray(node)) {
931
+ for (const child of node) walk(child);
932
+ return;
933
+ }
934
+ if (!node || typeof node !== "object") return;
935
+ const obj = node;
936
+ if (obj.tag === "column") {
937
+ const custom = readCustomBackgroundStyle(obj);
938
+ if (custom) {
939
+ obj.background_style = ensureAlias("cus-bg", custom);
940
+ delete obj.custom_background_style;
941
+ }
942
+ }
943
+ if (obj.tag === "markdown" && typeof obj.content === "string") {
944
+ normalizeMarkdownInlineHexColors(obj, ensureAlias);
945
+ }
946
+ for (const value of Object.values(obj)) walk(value);
947
+ };
948
+ walk(dsl.body);
949
+ if (Object.keys(colorEntries).length === 0) return;
950
+ const firstBgKey = Object.keys(colorEntries).find((k) => k.startsWith("cus-bg-"));
951
+ const firstBg = firstBgKey ? colorEntries[firstBgKey] : void 0;
952
+ if (firstBg) {
953
+ const m = firstBg.light_mode.match(/^rgba\((\d+),(\d+),(\d+),/);
954
+ if (m) {
955
+ colorEntries["cus-accent"] = {
956
+ light_mode: `rgba(${m[1]},${m[2]},${m[3]},1)`,
957
+ dark_mode: firstBg.dark_mode.replace(/,\s*[\d.]+\)$/, ",1)")
958
+ };
959
+ }
960
+ }
961
+ colorEntries["cus-muted"] ??= {
962
+ light_mode: "rgba(100,106,115,1)",
963
+ dark_mode: "rgba(166,166,166,1)"
964
+ };
965
+ const aliasRenames = /* @__PURE__ */ new Map();
966
+ for (const to of ["cus-accent", "cus-muted"]) {
967
+ for (const [from, target] of unifyMatchingAlias(colorEntries, "cus-text", to)) {
968
+ aliasRenames.set(from, target);
969
+ }
970
+ }
971
+ remapColorReferences(dsl.body, aliasRenames);
972
+ const config = dsl.config && typeof dsl.config === "object" ? dsl.config : {};
973
+ dsl.config = config;
974
+ const style = config.style && typeof config.style === "object" ? config.style : {};
975
+ config.style = style;
976
+ const existing = style.color && typeof style.color === "object" ? style.color : {};
977
+ style.color = { ...colorEntries, ...existing };
978
+ if (!colorEntries["cus-accent"]) return;
979
+ const applyDefaultFontColors = (node) => {
980
+ if (Array.isArray(node)) {
981
+ for (const child of node) applyDefaultFontColors(child);
982
+ return;
983
+ }
984
+ if (!node || typeof node !== "object") return;
985
+ const obj = node;
986
+ if (obj.tag === "markdown" && obj.font_color === void 0) {
987
+ const size = obj.text_size;
988
+ const content = typeof obj.content === "string" ? obj.content : "";
989
+ if (size === "small") obj.font_color = "cus-muted";
990
+ else if (size === "heading" || content.includes("**")) obj.font_color = "cus-accent";
991
+ }
992
+ for (const value of Object.values(obj)) applyDefaultFontColors(value);
993
+ };
994
+ applyDefaultFontColors(dsl.body);
995
+ }
996
+ function unifyMatchingAlias(entries, fromPrefix, to) {
997
+ const renames = /* @__PURE__ */ new Map();
998
+ const target = entries[to];
999
+ if (!target) return renames;
1000
+ for (const alias of Object.keys(entries)) {
1001
+ if (alias === to) continue;
1002
+ if (!alias.startsWith(`${fromPrefix}-`) && alias !== fromPrefix) continue;
1003
+ const entry = entries[alias];
1004
+ const matches = to === "cus-accent" || to === "cus-muted" ? entry.light_mode === target.light_mode : colorEntryKey(entry) === colorEntryKey(target);
1005
+ if (matches) {
1006
+ renames.set(alias, to);
1007
+ delete entries[alias];
1008
+ }
1009
+ }
1010
+ return renames;
1011
+ }
1012
+ function remapColorReferences(node, aliasRenames) {
1013
+ const remap = (alias) => {
1014
+ if (!alias) return alias;
1015
+ return aliasRenames.get(alias) ?? alias;
1016
+ };
1017
+ const walk = (n) => {
1018
+ if (Array.isArray(n)) {
1019
+ for (const c of n) walk(c);
1020
+ return;
1021
+ }
1022
+ if (!n || typeof n !== "object") return;
1023
+ const obj = n;
1024
+ if (typeof obj.font_color === "string") obj.font_color = remap(obj.font_color);
1025
+ if (typeof obj.content === "string" && obj.content.includes("<font")) {
1026
+ obj.content = obj.content.replace(
1027
+ /<font color=['"]([^'"]+)['"]>/g,
1028
+ (_m, color) => {
1029
+ const next = remap(color);
1030
+ return next ? `<font color='${next}'>` : _m;
1031
+ }
1032
+ );
1033
+ }
1034
+ for (const value of Object.values(obj)) walk(value);
1035
+ };
1036
+ walk(node);
1037
+ }
1038
+ function normalizeMarkdownInlineHexColors(obj, ensureAlias) {
1039
+ const content = obj.content;
1040
+ const hexColor = (raw) => {
1041
+ const v = raw.trim();
1042
+ if (v.startsWith("#")) {
1043
+ const rgba = hexColorToRgba(v);
1044
+ return rgba ? { light_mode: rgba, dark_mode: rgba } : void 0;
1045
+ }
1046
+ if (/^rgba?\(/i.test(v)) return { light_mode: v, dark_mode: v };
1047
+ return void 0;
1048
+ };
1049
+ const single = content.match(/^<font color=['"]([^'"]+)['"]\s*>([\s\S]*)<\/font>$/);
1050
+ if (single) {
1051
+ const entry = hexColor(single[1]);
1052
+ if (entry) {
1053
+ const alias = ensureAlias("cus-text", entry);
1054
+ if (obj.font_color === void 0) obj.font_color = alias;
1055
+ obj.content = single[2];
1056
+ return;
1057
+ }
1058
+ }
1059
+ obj.content = content.replace(/<font color=['"]([^'"]+)['"]>/g, (match, raw) => {
1060
+ const entry = hexColor(raw);
1061
+ if (!entry) return match;
1062
+ const alias = ensureAlias("cus-text", entry);
1063
+ return `<font color='${alias}'>`;
1064
+ });
1065
+ }
1066
+
1067
+ // src/custom-colors.ts
1068
+ function readThemeColorLight(pair) {
1069
+ if (!pair || typeof pair !== "object") return void 0;
1070
+ const o = pair;
1071
+ const raw = o.light_mode ?? o.lightMode;
1072
+ if (typeof raw !== "string") return void 0;
1073
+ const v = raw.trim();
1074
+ return v || void 0;
1075
+ }
1076
+ function readThemeColorDark(pair) {
1077
+ if (!pair || typeof pair !== "object") return void 0;
1078
+ const o = pair;
1079
+ const raw = o.dark_mode ?? o.darkMode;
1080
+ if (typeof raw !== "string") return void 0;
1081
+ const v = raw.trim();
1082
+ return v || void 0;
1083
+ }
1084
+ function isCustomHexColor(color) {
1085
+ const v = color.trim();
1086
+ return v.startsWith("#") || /^rgba?\(/i.test(v);
1087
+ }
1088
+ function resolveTextStyleColor(textStyle) {
1089
+ if (!textStyle || typeof textStyle !== "object") return void 0;
1090
+ const ts = textStyle;
1091
+ const enumColor = typeof ts.color === "string" ? ts.color.trim() : void 0;
1092
+ if (enumColor && enumColor !== "default") return enumColor;
1093
+ const custom = ts.custom_color ?? ts.customColor;
1094
+ return readThemeColorLight(custom);
1095
+ }
1096
+ function resolveTextStyleCustomColorPair(textStyle) {
1097
+ if (!textStyle || typeof textStyle !== "object") return void 0;
1098
+ const ts = textStyle;
1099
+ const enumColor = typeof ts.color === "string" ? ts.color.trim() : void 0;
1100
+ if (enumColor && enumColor !== "default") return void 0;
1101
+ const custom = ts.custom_color ?? ts.customColor;
1102
+ if (!custom || typeof custom !== "object") return void 0;
1103
+ return custom;
1104
+ }
1105
+ function themePairToColorEntry(pair) {
1106
+ const lightRaw = readThemeColorLight(pair);
1107
+ const darkRaw = readThemeColorDark(pair);
1108
+ if (!lightRaw || !darkRaw) return void 0;
1109
+ const light = lightRaw.startsWith("#") ? hexColorToRgba(lightRaw) : lightRaw;
1110
+ const dark = darkRaw.startsWith("#") ? hexColorToRgba(darkRaw) : darkRaw;
1111
+ if (!light || !dark) return void 0;
1112
+ return { light_mode: light, dark_mode: dark };
1113
+ }
1114
+ function resolveCustomBackgroundLight(property) {
1115
+ if (!property || typeof property !== "object") return void 0;
1116
+ const p = property;
1117
+ const custom = p.custom_background_style ?? p.customBackgroundStyle;
1118
+ return readThemeColorLight(custom);
1119
+ }
1120
+
871
1121
  // src/raw-to-dsl.ts
872
1122
  function isRawCardEnvelope(value) {
873
1123
  if (typeof value !== "object" || value === null) return false;
@@ -883,12 +1133,19 @@ function rawCardToDsl(envelope) {
883
1133
  } catch {
884
1134
  return envelope;
885
1135
  }
886
- const ctx = {
1136
+ const ctx = makeCtx({
887
1137
  images: env.json_attachment?.images ?? {},
888
1138
  atUsers: env.json_attachment?.at_users ?? {}
889
- };
1139
+ });
890
1140
  return convertRoot(inner, ctx);
891
1141
  }
1142
+ function makeCtx(partial) {
1143
+ return {
1144
+ images: partial?.images ?? {},
1145
+ atUsers: partial?.atUsers ?? {},
1146
+ colors: createColorRegistry()
1147
+ };
1148
+ }
892
1149
  var RAW_ONLY_FIELDS = /* @__PURE__ */ new Set([
893
1150
  "new_body",
894
1151
  "source",
@@ -976,6 +1233,7 @@ function convertRoot(root, ctx) {
976
1233
  out.config = convertConfig(isRecord2(root.config) ? root.config : {});
977
1234
  if (isRecord2(root.body)) out.body = convertBody2(root.body, ctx);
978
1235
  if (isRecord2(root.header)) out.header = convertHeader2(root.header, ctx);
1236
+ normalizeStoredCardColors(out, ctx.colors);
979
1237
  return out;
980
1238
  }
981
1239
  function convertConfig(_node) {
@@ -1077,7 +1335,7 @@ function unwrap(node, ctx) {
1077
1335
  let value = isRecord2(cell) && "data" in cell ? cell.data : cell;
1078
1336
  if (isRecord2(value) && value.tag === "markdown" && isRecord2(value.property)) {
1079
1337
  const elements = Array.isArray(value.property.elements) ? value.property.elements : [];
1080
- value = renderChildren(elements, ctx);
1338
+ value = renderChildren(elements, ctx).content;
1081
1339
  }
1082
1340
  r[k] = value;
1083
1341
  }
@@ -1452,8 +1710,9 @@ function resolveAtUserId(prop, ctx) {
1452
1710
  function rebuildMarkdown(property, ctx) {
1453
1711
  const out = { tag: "markdown" };
1454
1712
  const elements = Array.isArray(property.elements) ? property.elements : [];
1455
- const content = renderChildren(elements, ctx);
1713
+ const { content, uniformFontColor } = renderChildren(elements, ctx);
1456
1714
  if (content) out.content = content;
1715
+ if (uniformFontColor) out.font_color = uniformFontColor;
1457
1716
  for (const [rawKey, rawValue] of Object.entries(property)) {
1458
1717
  if (rawKey === "elements" || rawKey === "markdownElements" || rawKey === "originTag") continue;
1459
1718
  if (rawKey === "udIcon") continue;
@@ -1471,7 +1730,7 @@ function rebuildMarkdown(property, ctx) {
1471
1730
  }
1472
1731
  return out;
1473
1732
  }
1474
- function wrapEmphasis(text, bold, color) {
1733
+ function wrapEmphasis(text, bold, color, colorKind, inlineCustomFont = false) {
1475
1734
  if (!bold && !color) return text;
1476
1735
  const lead = text.match(/^\s*/)[0];
1477
1736
  const trail = text.match(/\s*$/)[0];
@@ -1479,20 +1738,51 @@ function wrapEmphasis(text, bold, color) {
1479
1738
  if (core.length === 0) return text;
1480
1739
  let wrapped = core;
1481
1740
  if (bold) wrapped = `**${wrapped}**`;
1482
- if (color) wrapped = `<font color='${color}'>${wrapped}</font>`;
1741
+ if (color) {
1742
+ if (colorKind === "enum") wrapped = `<font color='${color}'>${wrapped}</font>`;
1743
+ else if (colorKind === "custom" && inlineCustomFont) wrapped = `<font color='${color}'>${wrapped}</font>`;
1744
+ }
1483
1745
  return lead + wrapped + trail;
1484
1746
  }
1747
+ function resolveInlineStyle(ts, ctx) {
1748
+ const bold = !!(ts && Array.isArray(ts.attributes) && ts.attributes.includes("bold"));
1749
+ const customPair = resolveTextStyleCustomColorPair(ts);
1750
+ if (customPair) {
1751
+ const entry = themePairToColorEntry(customPair);
1752
+ if (entry) {
1753
+ const alias = registerColorEntry(ctx.colors, entry, "cus-text");
1754
+ return { bold, color: alias, colorKind: "custom" };
1755
+ }
1756
+ }
1757
+ const rawColor = resolveTextStyleColor(ts);
1758
+ const color = rawColor === "default" ? void 0 : rawColor;
1759
+ if (!color) return { bold };
1760
+ if (isCustomHexColor(color)) {
1761
+ const rgba = color.startsWith("#") ? themePairToColorEntry({ lightMode: color, darkMode: color }) : { light_mode: color, dark_mode: color };
1762
+ if (rgba) {
1763
+ const alias = registerColorEntry(ctx.colors, rgba, "cus-text");
1764
+ return { bold, color: alias, colorKind: "custom" };
1765
+ }
1766
+ }
1767
+ return { bold, color, colorKind: "enum" };
1768
+ }
1485
1769
  function renderChildren(children, ctx) {
1486
1770
  let out = "";
1487
1771
  let buffer = [];
1772
+ let uniformFontColor;
1488
1773
  function flushBuffer() {
1489
1774
  if (buffer.length === 0) return;
1775
+ const customColors = buffer.filter((s) => s.colorKind === "custom" && s.color).map((s) => s.color);
1776
+ const hasEnumColor = buffer.some((s) => s.colorKind === "enum" && s.color);
1777
+ const uniformCustom = customColors.length > 0 && !hasEnumColor && customColors.every((c) => c === customColors[0]) ? customColors[0] : void 0;
1778
+ if (uniformCustom) uniformFontColor = uniformCustom;
1490
1779
  let group = [];
1491
1780
  function emitGroup() {
1492
1781
  if (group.length === 0) return;
1493
1782
  const inner = group.map((s) => s.content).join("");
1494
- const { bold, color } = group[0];
1495
- out += wrapEmphasis(inner, bold, color);
1783
+ const { bold, color, colorKind } = group[0];
1784
+ const inlineCustomFont = colorKind === "custom" && !!color && color !== uniformCustom;
1785
+ out += wrapEmphasis(inner, bold, color, colorKind, inlineCustomFont);
1496
1786
  group = [];
1497
1787
  }
1498
1788
  for (const seg of buffer) {
@@ -1501,8 +1791,9 @@ function renderChildren(children, ctx) {
1501
1791
  continue;
1502
1792
  }
1503
1793
  const head = group[0];
1504
- if (head.bold === seg.bold && head.color === seg.color) group.push(seg);
1505
- else {
1794
+ if (head.bold === seg.bold && head.color === seg.color && head.colorKind === seg.colorKind) {
1795
+ group.push(seg);
1796
+ } else {
1506
1797
  emitGroup();
1507
1798
  group.push(seg);
1508
1799
  }
@@ -1521,33 +1812,33 @@ function renderChildren(children, ctx) {
1521
1812
  out += childToMarkdown(child, ctx);
1522
1813
  }
1523
1814
  flushBuffer();
1524
- return out;
1815
+ return { content: out, uniformFontColor };
1525
1816
  }
1526
1817
  function childToInlineSegment(child, ctx) {
1527
1818
  const tag = child.tag;
1528
1819
  const prop = isRecord2(child.property) ? child.property : {};
1529
1820
  const ts = isRecord2(prop.textStyle) ? prop.textStyle : void 0;
1530
- const bold = !!(ts && Array.isArray(ts.attributes) && ts.attributes.includes("bold"));
1531
- const rawColor = ts && typeof ts.color === "string" ? ts.color : void 0;
1532
- const color = rawColor === "default" ? void 0 : rawColor;
1821
+ const { bold, color, colorKind } = resolveInlineStyle(ts, ctx);
1533
1822
  switch (tag) {
1534
1823
  case "plain_text":
1535
1824
  return {
1536
1825
  content: typeof prop.content === "string" ? prop.content : "",
1537
1826
  bold,
1538
- color
1827
+ color,
1828
+ colorKind
1539
1829
  };
1540
1830
  case "code_span":
1541
1831
  return {
1542
1832
  content: `\`${typeof prop.content === "string" ? prop.content : ""}\``,
1543
1833
  bold,
1544
- color
1834
+ color,
1835
+ colorKind
1545
1836
  };
1546
1837
  case "link": {
1547
1838
  const text = typeof prop.content === "string" ? prop.content : "";
1548
1839
  const urlObj = isRecord2(prop.url) ? prop.url : void 0;
1549
1840
  const url = urlObj && typeof urlObj.url === "string" ? urlObj.url : "";
1550
- return { content: `[${text}](${url})`, bold, color };
1841
+ return { content: `[${text}](${url})`, bold, color, colorKind };
1551
1842
  }
1552
1843
  case "at_all":
1553
1844
  return { content: "<at id=all></at>", bold, color };
@@ -1587,9 +1878,8 @@ function childToMarkdown(child, ctx) {
1587
1878
  case "plain_text": {
1588
1879
  const content = typeof prop.content === "string" ? prop.content : "";
1589
1880
  const ts = isRecord2(prop.textStyle) ? prop.textStyle : void 0;
1590
- const color = ts && typeof ts.color === "string" ? ts.color : void 0;
1591
- const attrs = ts && Array.isArray(ts.attributes) ? ts.attributes : [];
1592
- return wrapEmphasis(content, attrs.includes("bold"), color);
1881
+ const { bold, color, colorKind } = resolveInlineStyle(ts, ctx);
1882
+ return wrapEmphasis(content, bold, color, colorKind, colorKind === "custom");
1593
1883
  }
1594
1884
  case "br":
1595
1885
  return "\n";
@@ -1715,7 +2005,7 @@ ${"#".repeat(level)} ${body}
1715
2005
  if (!data || data.tag !== "markdown") return "";
1716
2006
  const cellProp = isRecord2(data.property) ? data.property : {};
1717
2007
  const inner = Array.isArray(cellProp.elements) ? cellProp.elements : [];
1718
- const text = renderChildren(inner, ctx);
2008
+ const { content: text } = renderChildren(inner, ctx);
1719
2009
  return text.replace(/\|/g, "\\|").replace(/\n/g, " ");
1720
2010
  });
1721
2011
  return `| ${cells.join(" | ")} |`;
@@ -1838,10 +2128,10 @@ function rawToDsl(raw) {
1838
2128
  }
1839
2129
  }
1840
2130
  const attachment = isRecord2(raw.json_attachment) ? raw.json_attachment : {};
1841
- const ctx = {
2131
+ const ctx = makeCtx({
1842
2132
  images: isRecord2(attachment.images) ? attachment.images : {},
1843
2133
  atUsers: isRecord2(attachment.at_users) ? attachment.at_users : {}
1844
- };
2134
+ });
1845
2135
  return convertRoot(inner, ctx);
1846
2136
  }
1847
2137
  if (isRecord2(raw.card)) {
@@ -1849,10 +2139,10 @@ function rawToDsl(raw) {
1849
2139
  if (typeof card.json_card === "string" || isRecord2(card.json_card)) {
1850
2140
  return rawToDsl(card);
1851
2141
  }
1852
- return convertRoot(card, { images: {}, atUsers: {} });
2142
+ return convertRoot(card, makeCtx());
1853
2143
  }
1854
2144
  if ("body" in raw || "header" in raw || "schema" in raw) {
1855
- return convertRoot(raw, { images: {}, atUsers: {} });
2145
+ return convertRoot(raw, makeCtx());
1856
2146
  }
1857
2147
  return raw;
1858
2148
  }
@@ -1861,109 +2151,18 @@ function degradeUnknown(el) {
1861
2151
  return { tag: "unknown", raw_tag: rawTag, fallback: el };
1862
2152
  }
1863
2153
 
1864
- // src/normalize-stored-colors.ts
1865
- function hexColorToRgba(hex) {
1866
- const h = hex.trim().replace(/^#/, "");
1867
- if (h.length === 8) {
1868
- const r = parseInt(h.slice(0, 2), 16);
1869
- const g = parseInt(h.slice(2, 4), 16);
1870
- const b = parseInt(h.slice(4, 6), 16);
1871
- const a = Math.round(parseInt(h.slice(6, 8), 16) / 255 * 100) / 100;
1872
- return `rgba(${r},${g},${b},${a})`;
1873
- }
1874
- if (h.length === 6) {
1875
- const r = parseInt(h.slice(0, 2), 16);
1876
- const g = parseInt(h.slice(2, 4), 16);
1877
- const b = parseInt(h.slice(4, 6), 16);
1878
- return `rgba(${r},${g},${b},1)`;
1879
- }
1880
- return void 0;
1881
- }
1882
- function readCustomBackgroundStyle(node) {
1883
- const raw = node.custom_background_style;
1884
- if (!raw || typeof raw !== "object") return void 0;
1885
- const o = raw;
1886
- const lightRaw = typeof o.light_mode === "string" ? o.light_mode : void 0;
1887
- const darkRaw = typeof o.dark_mode === "string" ? o.dark_mode : void 0;
1888
- if (!lightRaw || !darkRaw) return void 0;
1889
- const light = lightRaw.startsWith("#") ? hexColorToRgba(lightRaw) : lightRaw;
1890
- const dark = darkRaw.startsWith("#") ? hexColorToRgba(darkRaw) : darkRaw;
1891
- if (!light || !dark) return void 0;
1892
- return { light_mode: light, dark_mode: dark };
1893
- }
1894
- function normalizeStoredCardColors(dsl) {
1895
- const colorEntries = {};
1896
- const styleKey = (entry) => `${entry.light_mode}|${entry.dark_mode}`;
1897
- const keyToAlias = /* @__PURE__ */ new Map();
1898
- let bgSeq = 0;
1899
- const ensureAlias = (prefix, entry) => {
1900
- const existing2 = keyToAlias.get(styleKey(entry));
1901
- if (existing2) return existing2;
1902
- const alias = `${prefix}-${bgSeq++}`;
1903
- colorEntries[alias] = entry;
1904
- keyToAlias.set(styleKey(entry), alias);
1905
- return alias;
1906
- };
1907
- const walk = (node) => {
1908
- if (Array.isArray(node)) {
1909
- for (const child of node) walk(child);
1910
- return;
1911
- }
1912
- if (!node || typeof node !== "object") return;
1913
- const obj = node;
1914
- if (obj.tag === "column") {
1915
- const custom = readCustomBackgroundStyle(obj);
1916
- if (custom) {
1917
- obj.background_style = ensureAlias("cus-bg", custom);
1918
- delete obj.custom_background_style;
1919
- }
1920
- }
1921
- for (const value of Object.values(obj)) walk(value);
1922
- };
1923
- walk(dsl.body);
1924
- if (Object.keys(colorEntries).length === 0) return;
1925
- const firstBg = colorEntries["cus-bg-0"] ?? Object.values(colorEntries)[0];
1926
- if (firstBg) {
1927
- const m = firstBg.light_mode.match(/^rgba\((\d+),(\d+),(\d+),/);
1928
- if (m) {
1929
- colorEntries["cus-accent"] = {
1930
- light_mode: `rgba(${m[1]},${m[2]},${m[3]},1)`,
1931
- dark_mode: firstBg.dark_mode.replace(/,\s*[\d.]+\)$/, ",1)")
1932
- };
1933
- }
1934
- }
1935
- colorEntries["cus-muted"] ??= {
1936
- light_mode: "rgba(100,106,115,1)",
1937
- dark_mode: "rgba(166,166,166,1)"
1938
- };
1939
- const config = dsl.config && typeof dsl.config === "object" ? dsl.config : {};
1940
- dsl.config = config;
1941
- const style = config.style && typeof config.style === "object" ? config.style : {};
1942
- config.style = style;
1943
- const existing = style.color && typeof style.color === "object" ? style.color : {};
1944
- style.color = { ...colorEntries, ...existing };
1945
- if (!colorEntries["cus-accent"]) return;
1946
- const applyDefaultFontColors = (node) => {
1947
- if (Array.isArray(node)) {
1948
- for (const child of node) applyDefaultFontColors(child);
1949
- return;
1950
- }
1951
- if (!node || typeof node !== "object") return;
1952
- const obj = node;
1953
- if (obj.tag === "markdown" && obj.font_color === void 0) {
1954
- const size = obj.text_size;
1955
- const content = typeof obj.content === "string" ? obj.content : "";
1956
- if (size === "small") obj.font_color = "cus-muted";
1957
- else if (size === "heading" || content.includes("**")) obj.font_color = "cus-accent";
1958
- }
1959
- for (const value of Object.values(obj)) applyDefaultFontColors(value);
1960
- };
1961
- applyDefaultFontColors(dsl.body);
1962
- }
1963
-
2154
+ exports.createColorRegistry = createColorRegistry;
1964
2155
  exports.degradeUnknown = degradeUnknown;
1965
2156
  exports.dslToRaw = dslToRaw;
2157
+ exports.isCustomHexColor = isCustomHexColor;
1966
2158
  exports.isRawCardEnvelope = isRawCardEnvelope;
1967
2159
  exports.normalizeStoredCardColors = normalizeStoredCardColors;
1968
2160
  exports.rawCardToDsl = rawCardToDsl;
1969
2161
  exports.rawToDsl = rawToDsl;
2162
+ exports.readThemeColorDark = readThemeColorDark;
2163
+ exports.readThemeColorLight = readThemeColorLight;
2164
+ exports.registerColorEntry = registerColorEntry;
2165
+ exports.resolveCustomBackgroundLight = resolveCustomBackgroundLight;
2166
+ exports.resolveTextStyleColor = resolveTextStyleColor;
2167
+ exports.resolveTextStyleCustomColorPair = resolveTextStyleCustomColorPair;
2168
+ exports.themePairToColorEntry = themePairToColorEntry;
package/dist/index.d.ts CHANGED
@@ -8,7 +8,9 @@
8
8
  */
9
9
  export { dslToRaw } from './dsl-to-raw.js';
10
10
  export { rawToDsl, rawCardToDsl, isRawCardEnvelope, degradeUnknown, } from './raw-to-dsl.js';
11
- export { normalizeStoredCardColors } from './normalize-stored-colors.js';
11
+ export { normalizeStoredCardColors, createColorRegistry, registerColorEntry } from './normalize-stored-colors.js';
12
12
  export type { CustomColorEntry } from './normalize-stored-colors.js';
13
+ export { readThemeColorLight, readThemeColorDark, resolveCustomBackgroundLight, resolveTextStyleColor, resolveTextStyleCustomColorPair, themePairToColorEntry, isCustomHexColor, } from './custom-colors.js';
14
+ export type { ThemeColorPair } from './custom-colors.js';
13
15
  export type { CardElement, ElementProperty, JsonCard } from './types.js';
14
16
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,OAAO,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AAC3C,OAAO,EACL,QAAQ,EACR,YAAY,EACZ,iBAAiB,EACjB,cAAc,GACf,MAAM,iBAAiB,CAAC;AACzB,OAAO,EAAE,yBAAyB,EAAE,MAAM,8BAA8B,CAAC;AACzE,YAAY,EAAE,gBAAgB,EAAE,MAAM,8BAA8B,CAAC;AACrE,YAAY,EAAE,WAAW,EAAE,eAAe,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,OAAO,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AAC3C,OAAO,EACL,QAAQ,EACR,YAAY,EACZ,iBAAiB,EACjB,cAAc,GACf,MAAM,iBAAiB,CAAC;AACzB,OAAO,EAAE,yBAAyB,EAAE,mBAAmB,EAAE,kBAAkB,EAAE,MAAM,8BAA8B,CAAC;AAClH,YAAY,EAAE,gBAAgB,EAAE,MAAM,8BAA8B,CAAC;AACrE,OAAO,EACL,mBAAmB,EACnB,kBAAkB,EAClB,4BAA4B,EAC5B,qBAAqB,EACrB,+BAA+B,EAC/B,qBAAqB,EACrB,gBAAgB,GACjB,MAAM,oBAAoB,CAAC;AAC5B,YAAY,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AACzD,YAAY,EAAE,WAAW,EAAE,eAAe,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC"}
package/dist/index.js CHANGED
@@ -866,6 +866,256 @@ function isRecord(v) {
866
866
  return typeof v === "object" && v !== null && !Array.isArray(v);
867
867
  }
868
868
 
869
+ // src/normalize-stored-colors.ts
870
+ function createColorRegistry() {
871
+ return { entries: {}, keyToAlias: /* @__PURE__ */ new Map(), bgSeq: 0, textSeq: 0 };
872
+ }
873
+ function colorEntryKey(entry) {
874
+ return `${entry.light_mode}|${entry.dark_mode}`;
875
+ }
876
+ function registerColorEntry(registry, entry, prefix) {
877
+ const key = colorEntryKey(entry);
878
+ const existing = registry.keyToAlias.get(key);
879
+ if (existing) return existing;
880
+ const alias = prefix === "cus-bg" ? `cus-bg-${registry.bgSeq++}` : `cus-text-${registry.textSeq++}`;
881
+ registry.entries[alias] = entry;
882
+ registry.keyToAlias.set(key, alias);
883
+ return alias;
884
+ }
885
+ function hexColorToRgba(hex) {
886
+ const h = hex.trim().replace(/^#/, "");
887
+ if (h.length === 8) {
888
+ const r = parseInt(h.slice(0, 2), 16);
889
+ const g = parseInt(h.slice(2, 4), 16);
890
+ const b = parseInt(h.slice(4, 6), 16);
891
+ const a = Math.round(parseInt(h.slice(6, 8), 16) / 255 * 100) / 100;
892
+ return `rgba(${r},${g},${b},${a})`;
893
+ }
894
+ if (h.length === 6) {
895
+ const r = parseInt(h.slice(0, 2), 16);
896
+ const g = parseInt(h.slice(2, 4), 16);
897
+ const b = parseInt(h.slice(4, 6), 16);
898
+ return `rgba(${r},${g},${b},1)`;
899
+ }
900
+ return void 0;
901
+ }
902
+ function readCustomBackgroundStyle(node) {
903
+ const raw = node.custom_background_style;
904
+ if (!raw || typeof raw !== "object") return void 0;
905
+ const o = raw;
906
+ const lightRaw = typeof o.light_mode === "string" ? o.light_mode : void 0;
907
+ const darkRaw = typeof o.dark_mode === "string" ? o.dark_mode : void 0;
908
+ if (!lightRaw || !darkRaw) return void 0;
909
+ const light = lightRaw.startsWith("#") ? hexColorToRgba(lightRaw) : lightRaw;
910
+ const dark = darkRaw.startsWith("#") ? hexColorToRgba(darkRaw) : darkRaw;
911
+ if (!light || !dark) return void 0;
912
+ return { light_mode: light, dark_mode: dark };
913
+ }
914
+ function normalizeStoredCardColors(dsl, preRegistered) {
915
+ const colorEntries = { ...preRegistered?.entries ?? {} };
916
+ const keyToAlias = new Map(preRegistered?.keyToAlias ?? []);
917
+ let bgSeq = preRegistered?.bgSeq ?? 0;
918
+ let textSeq = preRegistered?.textSeq ?? 0;
919
+ const ensureAlias = (prefix, entry) => {
920
+ const existing2 = keyToAlias.get(colorEntryKey(entry));
921
+ if (existing2) return existing2;
922
+ const alias = prefix === "cus-bg" ? `cus-bg-${bgSeq++}` : `cus-text-${textSeq++}`;
923
+ colorEntries[alias] = entry;
924
+ keyToAlias.set(colorEntryKey(entry), alias);
925
+ return alias;
926
+ };
927
+ const walk = (node) => {
928
+ if (Array.isArray(node)) {
929
+ for (const child of node) walk(child);
930
+ return;
931
+ }
932
+ if (!node || typeof node !== "object") return;
933
+ const obj = node;
934
+ if (obj.tag === "column") {
935
+ const custom = readCustomBackgroundStyle(obj);
936
+ if (custom) {
937
+ obj.background_style = ensureAlias("cus-bg", custom);
938
+ delete obj.custom_background_style;
939
+ }
940
+ }
941
+ if (obj.tag === "markdown" && typeof obj.content === "string") {
942
+ normalizeMarkdownInlineHexColors(obj, ensureAlias);
943
+ }
944
+ for (const value of Object.values(obj)) walk(value);
945
+ };
946
+ walk(dsl.body);
947
+ if (Object.keys(colorEntries).length === 0) return;
948
+ const firstBgKey = Object.keys(colorEntries).find((k) => k.startsWith("cus-bg-"));
949
+ const firstBg = firstBgKey ? colorEntries[firstBgKey] : void 0;
950
+ if (firstBg) {
951
+ const m = firstBg.light_mode.match(/^rgba\((\d+),(\d+),(\d+),/);
952
+ if (m) {
953
+ colorEntries["cus-accent"] = {
954
+ light_mode: `rgba(${m[1]},${m[2]},${m[3]},1)`,
955
+ dark_mode: firstBg.dark_mode.replace(/,\s*[\d.]+\)$/, ",1)")
956
+ };
957
+ }
958
+ }
959
+ colorEntries["cus-muted"] ??= {
960
+ light_mode: "rgba(100,106,115,1)",
961
+ dark_mode: "rgba(166,166,166,1)"
962
+ };
963
+ const aliasRenames = /* @__PURE__ */ new Map();
964
+ for (const to of ["cus-accent", "cus-muted"]) {
965
+ for (const [from, target] of unifyMatchingAlias(colorEntries, "cus-text", to)) {
966
+ aliasRenames.set(from, target);
967
+ }
968
+ }
969
+ remapColorReferences(dsl.body, aliasRenames);
970
+ const config = dsl.config && typeof dsl.config === "object" ? dsl.config : {};
971
+ dsl.config = config;
972
+ const style = config.style && typeof config.style === "object" ? config.style : {};
973
+ config.style = style;
974
+ const existing = style.color && typeof style.color === "object" ? style.color : {};
975
+ style.color = { ...colorEntries, ...existing };
976
+ if (!colorEntries["cus-accent"]) return;
977
+ const applyDefaultFontColors = (node) => {
978
+ if (Array.isArray(node)) {
979
+ for (const child of node) applyDefaultFontColors(child);
980
+ return;
981
+ }
982
+ if (!node || typeof node !== "object") return;
983
+ const obj = node;
984
+ if (obj.tag === "markdown" && obj.font_color === void 0) {
985
+ const size = obj.text_size;
986
+ const content = typeof obj.content === "string" ? obj.content : "";
987
+ if (size === "small") obj.font_color = "cus-muted";
988
+ else if (size === "heading" || content.includes("**")) obj.font_color = "cus-accent";
989
+ }
990
+ for (const value of Object.values(obj)) applyDefaultFontColors(value);
991
+ };
992
+ applyDefaultFontColors(dsl.body);
993
+ }
994
+ function unifyMatchingAlias(entries, fromPrefix, to) {
995
+ const renames = /* @__PURE__ */ new Map();
996
+ const target = entries[to];
997
+ if (!target) return renames;
998
+ for (const alias of Object.keys(entries)) {
999
+ if (alias === to) continue;
1000
+ if (!alias.startsWith(`${fromPrefix}-`) && alias !== fromPrefix) continue;
1001
+ const entry = entries[alias];
1002
+ const matches = to === "cus-accent" || to === "cus-muted" ? entry.light_mode === target.light_mode : colorEntryKey(entry) === colorEntryKey(target);
1003
+ if (matches) {
1004
+ renames.set(alias, to);
1005
+ delete entries[alias];
1006
+ }
1007
+ }
1008
+ return renames;
1009
+ }
1010
+ function remapColorReferences(node, aliasRenames) {
1011
+ const remap = (alias) => {
1012
+ if (!alias) return alias;
1013
+ return aliasRenames.get(alias) ?? alias;
1014
+ };
1015
+ const walk = (n) => {
1016
+ if (Array.isArray(n)) {
1017
+ for (const c of n) walk(c);
1018
+ return;
1019
+ }
1020
+ if (!n || typeof n !== "object") return;
1021
+ const obj = n;
1022
+ if (typeof obj.font_color === "string") obj.font_color = remap(obj.font_color);
1023
+ if (typeof obj.content === "string" && obj.content.includes("<font")) {
1024
+ obj.content = obj.content.replace(
1025
+ /<font color=['"]([^'"]+)['"]>/g,
1026
+ (_m, color) => {
1027
+ const next = remap(color);
1028
+ return next ? `<font color='${next}'>` : _m;
1029
+ }
1030
+ );
1031
+ }
1032
+ for (const value of Object.values(obj)) walk(value);
1033
+ };
1034
+ walk(node);
1035
+ }
1036
+ function normalizeMarkdownInlineHexColors(obj, ensureAlias) {
1037
+ const content = obj.content;
1038
+ const hexColor = (raw) => {
1039
+ const v = raw.trim();
1040
+ if (v.startsWith("#")) {
1041
+ const rgba = hexColorToRgba(v);
1042
+ return rgba ? { light_mode: rgba, dark_mode: rgba } : void 0;
1043
+ }
1044
+ if (/^rgba?\(/i.test(v)) return { light_mode: v, dark_mode: v };
1045
+ return void 0;
1046
+ };
1047
+ const single = content.match(/^<font color=['"]([^'"]+)['"]\s*>([\s\S]*)<\/font>$/);
1048
+ if (single) {
1049
+ const entry = hexColor(single[1]);
1050
+ if (entry) {
1051
+ const alias = ensureAlias("cus-text", entry);
1052
+ if (obj.font_color === void 0) obj.font_color = alias;
1053
+ obj.content = single[2];
1054
+ return;
1055
+ }
1056
+ }
1057
+ obj.content = content.replace(/<font color=['"]([^'"]+)['"]>/g, (match, raw) => {
1058
+ const entry = hexColor(raw);
1059
+ if (!entry) return match;
1060
+ const alias = ensureAlias("cus-text", entry);
1061
+ return `<font color='${alias}'>`;
1062
+ });
1063
+ }
1064
+
1065
+ // src/custom-colors.ts
1066
+ function readThemeColorLight(pair) {
1067
+ if (!pair || typeof pair !== "object") return void 0;
1068
+ const o = pair;
1069
+ const raw = o.light_mode ?? o.lightMode;
1070
+ if (typeof raw !== "string") return void 0;
1071
+ const v = raw.trim();
1072
+ return v || void 0;
1073
+ }
1074
+ function readThemeColorDark(pair) {
1075
+ if (!pair || typeof pair !== "object") return void 0;
1076
+ const o = pair;
1077
+ const raw = o.dark_mode ?? o.darkMode;
1078
+ if (typeof raw !== "string") return void 0;
1079
+ const v = raw.trim();
1080
+ return v || void 0;
1081
+ }
1082
+ function isCustomHexColor(color) {
1083
+ const v = color.trim();
1084
+ return v.startsWith("#") || /^rgba?\(/i.test(v);
1085
+ }
1086
+ function resolveTextStyleColor(textStyle) {
1087
+ if (!textStyle || typeof textStyle !== "object") return void 0;
1088
+ const ts = textStyle;
1089
+ const enumColor = typeof ts.color === "string" ? ts.color.trim() : void 0;
1090
+ if (enumColor && enumColor !== "default") return enumColor;
1091
+ const custom = ts.custom_color ?? ts.customColor;
1092
+ return readThemeColorLight(custom);
1093
+ }
1094
+ function resolveTextStyleCustomColorPair(textStyle) {
1095
+ if (!textStyle || typeof textStyle !== "object") return void 0;
1096
+ const ts = textStyle;
1097
+ const enumColor = typeof ts.color === "string" ? ts.color.trim() : void 0;
1098
+ if (enumColor && enumColor !== "default") return void 0;
1099
+ const custom = ts.custom_color ?? ts.customColor;
1100
+ if (!custom || typeof custom !== "object") return void 0;
1101
+ return custom;
1102
+ }
1103
+ function themePairToColorEntry(pair) {
1104
+ const lightRaw = readThemeColorLight(pair);
1105
+ const darkRaw = readThemeColorDark(pair);
1106
+ if (!lightRaw || !darkRaw) return void 0;
1107
+ const light = lightRaw.startsWith("#") ? hexColorToRgba(lightRaw) : lightRaw;
1108
+ const dark = darkRaw.startsWith("#") ? hexColorToRgba(darkRaw) : darkRaw;
1109
+ if (!light || !dark) return void 0;
1110
+ return { light_mode: light, dark_mode: dark };
1111
+ }
1112
+ function resolveCustomBackgroundLight(property) {
1113
+ if (!property || typeof property !== "object") return void 0;
1114
+ const p = property;
1115
+ const custom = p.custom_background_style ?? p.customBackgroundStyle;
1116
+ return readThemeColorLight(custom);
1117
+ }
1118
+
869
1119
  // src/raw-to-dsl.ts
870
1120
  function isRawCardEnvelope(value) {
871
1121
  if (typeof value !== "object" || value === null) return false;
@@ -881,12 +1131,19 @@ function rawCardToDsl(envelope) {
881
1131
  } catch {
882
1132
  return envelope;
883
1133
  }
884
- const ctx = {
1134
+ const ctx = makeCtx({
885
1135
  images: env.json_attachment?.images ?? {},
886
1136
  atUsers: env.json_attachment?.at_users ?? {}
887
- };
1137
+ });
888
1138
  return convertRoot(inner, ctx);
889
1139
  }
1140
+ function makeCtx(partial) {
1141
+ return {
1142
+ images: partial?.images ?? {},
1143
+ atUsers: partial?.atUsers ?? {},
1144
+ colors: createColorRegistry()
1145
+ };
1146
+ }
890
1147
  var RAW_ONLY_FIELDS = /* @__PURE__ */ new Set([
891
1148
  "new_body",
892
1149
  "source",
@@ -974,6 +1231,7 @@ function convertRoot(root, ctx) {
974
1231
  out.config = convertConfig(isRecord2(root.config) ? root.config : {});
975
1232
  if (isRecord2(root.body)) out.body = convertBody2(root.body, ctx);
976
1233
  if (isRecord2(root.header)) out.header = convertHeader2(root.header, ctx);
1234
+ normalizeStoredCardColors(out, ctx.colors);
977
1235
  return out;
978
1236
  }
979
1237
  function convertConfig(_node) {
@@ -1075,7 +1333,7 @@ function unwrap(node, ctx) {
1075
1333
  let value = isRecord2(cell) && "data" in cell ? cell.data : cell;
1076
1334
  if (isRecord2(value) && value.tag === "markdown" && isRecord2(value.property)) {
1077
1335
  const elements = Array.isArray(value.property.elements) ? value.property.elements : [];
1078
- value = renderChildren(elements, ctx);
1336
+ value = renderChildren(elements, ctx).content;
1079
1337
  }
1080
1338
  r[k] = value;
1081
1339
  }
@@ -1450,8 +1708,9 @@ function resolveAtUserId(prop, ctx) {
1450
1708
  function rebuildMarkdown(property, ctx) {
1451
1709
  const out = { tag: "markdown" };
1452
1710
  const elements = Array.isArray(property.elements) ? property.elements : [];
1453
- const content = renderChildren(elements, ctx);
1711
+ const { content, uniformFontColor } = renderChildren(elements, ctx);
1454
1712
  if (content) out.content = content;
1713
+ if (uniformFontColor) out.font_color = uniformFontColor;
1455
1714
  for (const [rawKey, rawValue] of Object.entries(property)) {
1456
1715
  if (rawKey === "elements" || rawKey === "markdownElements" || rawKey === "originTag") continue;
1457
1716
  if (rawKey === "udIcon") continue;
@@ -1469,7 +1728,7 @@ function rebuildMarkdown(property, ctx) {
1469
1728
  }
1470
1729
  return out;
1471
1730
  }
1472
- function wrapEmphasis(text, bold, color) {
1731
+ function wrapEmphasis(text, bold, color, colorKind, inlineCustomFont = false) {
1473
1732
  if (!bold && !color) return text;
1474
1733
  const lead = text.match(/^\s*/)[0];
1475
1734
  const trail = text.match(/\s*$/)[0];
@@ -1477,20 +1736,51 @@ function wrapEmphasis(text, bold, color) {
1477
1736
  if (core.length === 0) return text;
1478
1737
  let wrapped = core;
1479
1738
  if (bold) wrapped = `**${wrapped}**`;
1480
- if (color) wrapped = `<font color='${color}'>${wrapped}</font>`;
1739
+ if (color) {
1740
+ if (colorKind === "enum") wrapped = `<font color='${color}'>${wrapped}</font>`;
1741
+ else if (colorKind === "custom" && inlineCustomFont) wrapped = `<font color='${color}'>${wrapped}</font>`;
1742
+ }
1481
1743
  return lead + wrapped + trail;
1482
1744
  }
1745
+ function resolveInlineStyle(ts, ctx) {
1746
+ const bold = !!(ts && Array.isArray(ts.attributes) && ts.attributes.includes("bold"));
1747
+ const customPair = resolveTextStyleCustomColorPair(ts);
1748
+ if (customPair) {
1749
+ const entry = themePairToColorEntry(customPair);
1750
+ if (entry) {
1751
+ const alias = registerColorEntry(ctx.colors, entry, "cus-text");
1752
+ return { bold, color: alias, colorKind: "custom" };
1753
+ }
1754
+ }
1755
+ const rawColor = resolveTextStyleColor(ts);
1756
+ const color = rawColor === "default" ? void 0 : rawColor;
1757
+ if (!color) return { bold };
1758
+ if (isCustomHexColor(color)) {
1759
+ const rgba = color.startsWith("#") ? themePairToColorEntry({ lightMode: color, darkMode: color }) : { light_mode: color, dark_mode: color };
1760
+ if (rgba) {
1761
+ const alias = registerColorEntry(ctx.colors, rgba, "cus-text");
1762
+ return { bold, color: alias, colorKind: "custom" };
1763
+ }
1764
+ }
1765
+ return { bold, color, colorKind: "enum" };
1766
+ }
1483
1767
  function renderChildren(children, ctx) {
1484
1768
  let out = "";
1485
1769
  let buffer = [];
1770
+ let uniformFontColor;
1486
1771
  function flushBuffer() {
1487
1772
  if (buffer.length === 0) return;
1773
+ const customColors = buffer.filter((s) => s.colorKind === "custom" && s.color).map((s) => s.color);
1774
+ const hasEnumColor = buffer.some((s) => s.colorKind === "enum" && s.color);
1775
+ const uniformCustom = customColors.length > 0 && !hasEnumColor && customColors.every((c) => c === customColors[0]) ? customColors[0] : void 0;
1776
+ if (uniformCustom) uniformFontColor = uniformCustom;
1488
1777
  let group = [];
1489
1778
  function emitGroup() {
1490
1779
  if (group.length === 0) return;
1491
1780
  const inner = group.map((s) => s.content).join("");
1492
- const { bold, color } = group[0];
1493
- out += wrapEmphasis(inner, bold, color);
1781
+ const { bold, color, colorKind } = group[0];
1782
+ const inlineCustomFont = colorKind === "custom" && !!color && color !== uniformCustom;
1783
+ out += wrapEmphasis(inner, bold, color, colorKind, inlineCustomFont);
1494
1784
  group = [];
1495
1785
  }
1496
1786
  for (const seg of buffer) {
@@ -1499,8 +1789,9 @@ function renderChildren(children, ctx) {
1499
1789
  continue;
1500
1790
  }
1501
1791
  const head = group[0];
1502
- if (head.bold === seg.bold && head.color === seg.color) group.push(seg);
1503
- else {
1792
+ if (head.bold === seg.bold && head.color === seg.color && head.colorKind === seg.colorKind) {
1793
+ group.push(seg);
1794
+ } else {
1504
1795
  emitGroup();
1505
1796
  group.push(seg);
1506
1797
  }
@@ -1519,33 +1810,33 @@ function renderChildren(children, ctx) {
1519
1810
  out += childToMarkdown(child, ctx);
1520
1811
  }
1521
1812
  flushBuffer();
1522
- return out;
1813
+ return { content: out, uniformFontColor };
1523
1814
  }
1524
1815
  function childToInlineSegment(child, ctx) {
1525
1816
  const tag = child.tag;
1526
1817
  const prop = isRecord2(child.property) ? child.property : {};
1527
1818
  const ts = isRecord2(prop.textStyle) ? prop.textStyle : void 0;
1528
- const bold = !!(ts && Array.isArray(ts.attributes) && ts.attributes.includes("bold"));
1529
- const rawColor = ts && typeof ts.color === "string" ? ts.color : void 0;
1530
- const color = rawColor === "default" ? void 0 : rawColor;
1819
+ const { bold, color, colorKind } = resolveInlineStyle(ts, ctx);
1531
1820
  switch (tag) {
1532
1821
  case "plain_text":
1533
1822
  return {
1534
1823
  content: typeof prop.content === "string" ? prop.content : "",
1535
1824
  bold,
1536
- color
1825
+ color,
1826
+ colorKind
1537
1827
  };
1538
1828
  case "code_span":
1539
1829
  return {
1540
1830
  content: `\`${typeof prop.content === "string" ? prop.content : ""}\``,
1541
1831
  bold,
1542
- color
1832
+ color,
1833
+ colorKind
1543
1834
  };
1544
1835
  case "link": {
1545
1836
  const text = typeof prop.content === "string" ? prop.content : "";
1546
1837
  const urlObj = isRecord2(prop.url) ? prop.url : void 0;
1547
1838
  const url = urlObj && typeof urlObj.url === "string" ? urlObj.url : "";
1548
- return { content: `[${text}](${url})`, bold, color };
1839
+ return { content: `[${text}](${url})`, bold, color, colorKind };
1549
1840
  }
1550
1841
  case "at_all":
1551
1842
  return { content: "<at id=all></at>", bold, color };
@@ -1585,9 +1876,8 @@ function childToMarkdown(child, ctx) {
1585
1876
  case "plain_text": {
1586
1877
  const content = typeof prop.content === "string" ? prop.content : "";
1587
1878
  const ts = isRecord2(prop.textStyle) ? prop.textStyle : void 0;
1588
- const color = ts && typeof ts.color === "string" ? ts.color : void 0;
1589
- const attrs = ts && Array.isArray(ts.attributes) ? ts.attributes : [];
1590
- return wrapEmphasis(content, attrs.includes("bold"), color);
1879
+ const { bold, color, colorKind } = resolveInlineStyle(ts, ctx);
1880
+ return wrapEmphasis(content, bold, color, colorKind, colorKind === "custom");
1591
1881
  }
1592
1882
  case "br":
1593
1883
  return "\n";
@@ -1713,7 +2003,7 @@ ${"#".repeat(level)} ${body}
1713
2003
  if (!data || data.tag !== "markdown") return "";
1714
2004
  const cellProp = isRecord2(data.property) ? data.property : {};
1715
2005
  const inner = Array.isArray(cellProp.elements) ? cellProp.elements : [];
1716
- const text = renderChildren(inner, ctx);
2006
+ const { content: text } = renderChildren(inner, ctx);
1717
2007
  return text.replace(/\|/g, "\\|").replace(/\n/g, " ");
1718
2008
  });
1719
2009
  return `| ${cells.join(" | ")} |`;
@@ -1836,10 +2126,10 @@ function rawToDsl(raw) {
1836
2126
  }
1837
2127
  }
1838
2128
  const attachment = isRecord2(raw.json_attachment) ? raw.json_attachment : {};
1839
- const ctx = {
2129
+ const ctx = makeCtx({
1840
2130
  images: isRecord2(attachment.images) ? attachment.images : {},
1841
2131
  atUsers: isRecord2(attachment.at_users) ? attachment.at_users : {}
1842
- };
2132
+ });
1843
2133
  return convertRoot(inner, ctx);
1844
2134
  }
1845
2135
  if (isRecord2(raw.card)) {
@@ -1847,10 +2137,10 @@ function rawToDsl(raw) {
1847
2137
  if (typeof card.json_card === "string" || isRecord2(card.json_card)) {
1848
2138
  return rawToDsl(card);
1849
2139
  }
1850
- return convertRoot(card, { images: {}, atUsers: {} });
2140
+ return convertRoot(card, makeCtx());
1851
2141
  }
1852
2142
  if ("body" in raw || "header" in raw || "schema" in raw) {
1853
- return convertRoot(raw, { images: {}, atUsers: {} });
2143
+ return convertRoot(raw, makeCtx());
1854
2144
  }
1855
2145
  return raw;
1856
2146
  }
@@ -1859,104 +2149,4 @@ function degradeUnknown(el) {
1859
2149
  return { tag: "unknown", raw_tag: rawTag, fallback: el };
1860
2150
  }
1861
2151
 
1862
- // src/normalize-stored-colors.ts
1863
- function hexColorToRgba(hex) {
1864
- const h = hex.trim().replace(/^#/, "");
1865
- if (h.length === 8) {
1866
- const r = parseInt(h.slice(0, 2), 16);
1867
- const g = parseInt(h.slice(2, 4), 16);
1868
- const b = parseInt(h.slice(4, 6), 16);
1869
- const a = Math.round(parseInt(h.slice(6, 8), 16) / 255 * 100) / 100;
1870
- return `rgba(${r},${g},${b},${a})`;
1871
- }
1872
- if (h.length === 6) {
1873
- const r = parseInt(h.slice(0, 2), 16);
1874
- const g = parseInt(h.slice(2, 4), 16);
1875
- const b = parseInt(h.slice(4, 6), 16);
1876
- return `rgba(${r},${g},${b},1)`;
1877
- }
1878
- return void 0;
1879
- }
1880
- function readCustomBackgroundStyle(node) {
1881
- const raw = node.custom_background_style;
1882
- if (!raw || typeof raw !== "object") return void 0;
1883
- const o = raw;
1884
- const lightRaw = typeof o.light_mode === "string" ? o.light_mode : void 0;
1885
- const darkRaw = typeof o.dark_mode === "string" ? o.dark_mode : void 0;
1886
- if (!lightRaw || !darkRaw) return void 0;
1887
- const light = lightRaw.startsWith("#") ? hexColorToRgba(lightRaw) : lightRaw;
1888
- const dark = darkRaw.startsWith("#") ? hexColorToRgba(darkRaw) : darkRaw;
1889
- if (!light || !dark) return void 0;
1890
- return { light_mode: light, dark_mode: dark };
1891
- }
1892
- function normalizeStoredCardColors(dsl) {
1893
- const colorEntries = {};
1894
- const styleKey = (entry) => `${entry.light_mode}|${entry.dark_mode}`;
1895
- const keyToAlias = /* @__PURE__ */ new Map();
1896
- let bgSeq = 0;
1897
- const ensureAlias = (prefix, entry) => {
1898
- const existing2 = keyToAlias.get(styleKey(entry));
1899
- if (existing2) return existing2;
1900
- const alias = `${prefix}-${bgSeq++}`;
1901
- colorEntries[alias] = entry;
1902
- keyToAlias.set(styleKey(entry), alias);
1903
- return alias;
1904
- };
1905
- const walk = (node) => {
1906
- if (Array.isArray(node)) {
1907
- for (const child of node) walk(child);
1908
- return;
1909
- }
1910
- if (!node || typeof node !== "object") return;
1911
- const obj = node;
1912
- if (obj.tag === "column") {
1913
- const custom = readCustomBackgroundStyle(obj);
1914
- if (custom) {
1915
- obj.background_style = ensureAlias("cus-bg", custom);
1916
- delete obj.custom_background_style;
1917
- }
1918
- }
1919
- for (const value of Object.values(obj)) walk(value);
1920
- };
1921
- walk(dsl.body);
1922
- if (Object.keys(colorEntries).length === 0) return;
1923
- const firstBg = colorEntries["cus-bg-0"] ?? Object.values(colorEntries)[0];
1924
- if (firstBg) {
1925
- const m = firstBg.light_mode.match(/^rgba\((\d+),(\d+),(\d+),/);
1926
- if (m) {
1927
- colorEntries["cus-accent"] = {
1928
- light_mode: `rgba(${m[1]},${m[2]},${m[3]},1)`,
1929
- dark_mode: firstBg.dark_mode.replace(/,\s*[\d.]+\)$/, ",1)")
1930
- };
1931
- }
1932
- }
1933
- colorEntries["cus-muted"] ??= {
1934
- light_mode: "rgba(100,106,115,1)",
1935
- dark_mode: "rgba(166,166,166,1)"
1936
- };
1937
- const config = dsl.config && typeof dsl.config === "object" ? dsl.config : {};
1938
- dsl.config = config;
1939
- const style = config.style && typeof config.style === "object" ? config.style : {};
1940
- config.style = style;
1941
- const existing = style.color && typeof style.color === "object" ? style.color : {};
1942
- style.color = { ...colorEntries, ...existing };
1943
- if (!colorEntries["cus-accent"]) return;
1944
- const applyDefaultFontColors = (node) => {
1945
- if (Array.isArray(node)) {
1946
- for (const child of node) applyDefaultFontColors(child);
1947
- return;
1948
- }
1949
- if (!node || typeof node !== "object") return;
1950
- const obj = node;
1951
- if (obj.tag === "markdown" && obj.font_color === void 0) {
1952
- const size = obj.text_size;
1953
- const content = typeof obj.content === "string" ? obj.content : "";
1954
- if (size === "small") obj.font_color = "cus-muted";
1955
- else if (size === "heading" || content.includes("**")) obj.font_color = "cus-accent";
1956
- }
1957
- for (const value of Object.values(obj)) applyDefaultFontColors(value);
1958
- };
1959
- applyDefaultFontColors(dsl.body);
1960
- }
1961
-
1962
- export { degradeUnknown, dslToRaw, isRawCardEnvelope, normalizeStoredCardColors, rawCardToDsl, rawToDsl };
2152
+ export { createColorRegistry, degradeUnknown, dslToRaw, isCustomHexColor, isRawCardEnvelope, normalizeStoredCardColors, rawCardToDsl, rawToDsl, readThemeColorDark, readThemeColorLight, registerColorEntry, resolveCustomBackgroundLight, resolveTextStyleColor, resolveTextStyleCustomColorPair, themePairToColorEntry };
@@ -6,9 +6,20 @@ export type CustomColorEntry = {
6
6
  light_mode: string;
7
7
  dark_mode: string;
8
8
  };
9
+ export type ColorRegistry = {
10
+ entries: Record<string, CustomColorEntry>;
11
+ keyToAlias: Map<string, string>;
12
+ bgSeq: number;
13
+ textSeq: number;
14
+ };
15
+ export declare function createColorRegistry(): ColorRegistry;
16
+ export declare function colorEntryKey(entry: CustomColorEntry): string;
17
+ export declare function registerColorEntry(registry: ColorRegistry, entry: CustomColorEntry, prefix: 'cus-bg' | 'cus-text'): string;
18
+ export declare function hexColorToRgba(hex: string): string | undefined;
9
19
  /**
10
20
  * 将飞书回读的 custom_background_style 还原为可再次发送的 background_style cus-N + config.style.color。
11
21
  * 若 markdown 缺少 font_color,按 text_size / 加粗内容补 cus-accent / cus-muted(飞书回读会丢 font_color)。
22
+ * rawToDsl 可传入已登记的文字自定义色(preRegistered),与背景色一并写入 config.style.color。
12
23
  */
13
- export declare function normalizeStoredCardColors(dsl: Record<string, unknown>): void;
24
+ export declare function normalizeStoredCardColors(dsl: Record<string, unknown>, preRegistered?: ColorRegistry): void;
14
25
  //# sourceMappingURL=normalize-stored-colors.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"normalize-stored-colors.d.ts","sourceRoot":"","sources":["../src/normalize-stored-colors.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,MAAM,MAAM,gBAAgB,GAAG;IAAE,UAAU,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAA;CAAE,CAAC;AAmCzE;;;GAGG;AACH,wBAAgB,yBAAyB,CAAC,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAoF5E"}
1
+ {"version":3,"file":"normalize-stored-colors.d.ts","sourceRoot":"","sources":["../src/normalize-stored-colors.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,MAAM,MAAM,gBAAgB,GAAG;IAAE,UAAU,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAA;CAAE,CAAC;AAEzE,MAAM,MAAM,aAAa,GAAG;IAC1B,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,gBAAgB,CAAC,CAAC;IAC1C,UAAU,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAChC,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;CACjB,CAAC;AAEF,wBAAgB,mBAAmB,IAAI,aAAa,CAEnD;AAED,wBAAgB,aAAa,CAAC,KAAK,EAAE,gBAAgB,GAAG,MAAM,CAE7D;AAED,wBAAgB,kBAAkB,CAChC,QAAQ,EAAE,aAAa,EACvB,KAAK,EAAE,gBAAgB,EACvB,MAAM,EAAE,QAAQ,GAAG,UAAU,GAC5B,MAAM,CAUR;AAED,wBAAgB,cAAc,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAgB9D;AAiBD;;;;GAIG;AACH,wBAAgB,yBAAyB,CACvC,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC5B,aAAa,CAAC,EAAE,aAAa,GAC5B,IAAI,CAiGN"}
@@ -56,7 +56,8 @@ export declare function rawToDsl(raw: unknown): unknown;
56
56
  /**
57
57
  * Optional helper: wrap a private/unknown element as
58
58
  * `{ tag: 'unknown', raw_tag, fallback }`.
59
- * Not applied automatically by `rawToDsl` / `rawCardToDsl` (parity with upstream).
59
+ * Not applied automatically by `degradeUnknown` (parity with upstream feishu-raw-card-to-dsl).
60
+ * `convertRoot` / `rawCardToDsl` always run `normalizeStoredCardColors` on output.
60
61
  */
61
62
  export declare function degradeUnknown(el: Record<string, unknown>): Record<string, unknown>;
62
63
  //# sourceMappingURL=raw-to-dsl.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"raw-to-dsl.d.ts","sourceRoot":"","sources":["../src/raw-to-dsl.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6CG;AAWH,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAIzD;AAED,wBAAgB,YAAY,CAAC,QAAQ,EAAE,OAAO,GAAG,OAAO,CAcvD;AAmgDD;;;;;GAKG;AACH,wBAAgB,QAAQ,CAAC,GAAG,EAAE,OAAO,GAAG,OAAO,CA8C9C;AAED;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,EAAE,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAGnF"}
1
+ {"version":3,"file":"raw-to-dsl.d.ts","sourceRoot":"","sources":["../src/raw-to-dsl.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6CG;AAwBH,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAIzD;AAED,wBAAgB,YAAY,CAAC,QAAQ,EAAE,OAAO,GAAG,OAAO,CAcvD;AAwkDD;;;;;GAKG;AACH,wBAAgB,QAAQ,CAAC,GAAG,EAAE,OAAO,GAAG,OAAO,CA8C9C;AAED;;;;;GAKG;AACH,wBAAgB,cAAc,CAAC,EAAE,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAGnF"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@open-feishu-card/adapter",
3
- "version": "0.3.2",
3
+ "version": "0.3.4",
4
4
  "description": "公开 DSL 与飞书内部 RAW JSON 的双向适配器;raw→DSL 对齐 feishu-raw-card-to-dsl",
5
5
  "type": "module",
6
6
  "main": "./dist/index.cjs",