@open-feishu-card/adapter 0.3.2 → 0.3.3

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,22 @@
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 uses config.style.color aliases (cus-N) for backgrounds after
7
+ * normalizeStoredCardColors; inline text accepts enum names or #RRGGBBAA in
8
+ * `<font color='…'>`. These helpers pick the light-mode value for projection
9
+ * and rendering (dark mode follows Feishu client theme — out of scope here).
10
+ */
11
+ export type ThemeColorPair = {
12
+ light_mode?: string;
13
+ lightMode?: string;
14
+ dark_mode?: string;
15
+ darkMode?: string;
16
+ };
17
+ export declare function readThemeColorLight(pair: unknown): string | undefined;
18
+ /** Enum `color` wins; else fall back to customColor light hex/rgba. */
19
+ export declare function resolveTextStyleColor(textStyle: unknown): string | undefined;
20
+ /** Light hex/rgba from column (or container) custom background, if any. */
21
+ export declare function resolveCustomBackgroundLight(property: unknown): string | undefined;
22
+ //# 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;;;;;;;;;GASG;AAEH,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,uEAAuE;AACvE,wBAAgB,qBAAqB,CAAC,SAAS,EAAE,OAAO,GAAG,MAAM,GAAG,SAAS,CAO5E;AAED,2EAA2E;AAC3E,wBAAgB,4BAA4B,CAAC,QAAQ,EAAE,OAAO,GAAG,MAAM,GAAG,SAAS,CAKlF"}
package/dist/index.cjs CHANGED
@@ -868,6 +868,130 @@ function isRecord(v) {
868
868
  return typeof v === "object" && v !== null && !Array.isArray(v);
869
869
  }
870
870
 
871
+ // src/custom-colors.ts
872
+ function readThemeColorLight(pair) {
873
+ if (!pair || typeof pair !== "object") return void 0;
874
+ const o = pair;
875
+ const raw = o.light_mode ?? o.lightMode;
876
+ if (typeof raw !== "string") return void 0;
877
+ const v = raw.trim();
878
+ return v || void 0;
879
+ }
880
+ function resolveTextStyleColor(textStyle) {
881
+ if (!textStyle || typeof textStyle !== "object") return void 0;
882
+ const ts = textStyle;
883
+ const enumColor = typeof ts.color === "string" ? ts.color.trim() : void 0;
884
+ if (enumColor && enumColor !== "default") return enumColor;
885
+ const custom = ts.custom_color ?? ts.customColor;
886
+ return readThemeColorLight(custom);
887
+ }
888
+ function resolveCustomBackgroundLight(property) {
889
+ if (!property || typeof property !== "object") return void 0;
890
+ const p = property;
891
+ const custom = p.custom_background_style ?? p.customBackgroundStyle;
892
+ return readThemeColorLight(custom);
893
+ }
894
+
895
+ // src/normalize-stored-colors.ts
896
+ function hexColorToRgba(hex) {
897
+ const h = hex.trim().replace(/^#/, "");
898
+ if (h.length === 8) {
899
+ const r = parseInt(h.slice(0, 2), 16);
900
+ const g = parseInt(h.slice(2, 4), 16);
901
+ const b = parseInt(h.slice(4, 6), 16);
902
+ const a = Math.round(parseInt(h.slice(6, 8), 16) / 255 * 100) / 100;
903
+ return `rgba(${r},${g},${b},${a})`;
904
+ }
905
+ if (h.length === 6) {
906
+ const r = parseInt(h.slice(0, 2), 16);
907
+ const g = parseInt(h.slice(2, 4), 16);
908
+ const b = parseInt(h.slice(4, 6), 16);
909
+ return `rgba(${r},${g},${b},1)`;
910
+ }
911
+ return void 0;
912
+ }
913
+ function readCustomBackgroundStyle(node) {
914
+ const raw = node.custom_background_style;
915
+ if (!raw || typeof raw !== "object") return void 0;
916
+ const o = raw;
917
+ const lightRaw = typeof o.light_mode === "string" ? o.light_mode : void 0;
918
+ const darkRaw = typeof o.dark_mode === "string" ? o.dark_mode : void 0;
919
+ if (!lightRaw || !darkRaw) return void 0;
920
+ const light = lightRaw.startsWith("#") ? hexColorToRgba(lightRaw) : lightRaw;
921
+ const dark = darkRaw.startsWith("#") ? hexColorToRgba(darkRaw) : darkRaw;
922
+ if (!light || !dark) return void 0;
923
+ return { light_mode: light, dark_mode: dark };
924
+ }
925
+ function normalizeStoredCardColors(dsl) {
926
+ const colorEntries = {};
927
+ const styleKey = (entry) => `${entry.light_mode}|${entry.dark_mode}`;
928
+ const keyToAlias = /* @__PURE__ */ new Map();
929
+ let bgSeq = 0;
930
+ const ensureAlias = (prefix, entry) => {
931
+ const existing2 = keyToAlias.get(styleKey(entry));
932
+ if (existing2) return existing2;
933
+ const alias = `${prefix}-${bgSeq++}`;
934
+ colorEntries[alias] = entry;
935
+ keyToAlias.set(styleKey(entry), alias);
936
+ return alias;
937
+ };
938
+ const walk = (node) => {
939
+ if (Array.isArray(node)) {
940
+ for (const child of node) walk(child);
941
+ return;
942
+ }
943
+ if (!node || typeof node !== "object") return;
944
+ const obj = node;
945
+ if (obj.tag === "column") {
946
+ const custom = readCustomBackgroundStyle(obj);
947
+ if (custom) {
948
+ obj.background_style = ensureAlias("cus-bg", custom);
949
+ delete obj.custom_background_style;
950
+ }
951
+ }
952
+ for (const value of Object.values(obj)) walk(value);
953
+ };
954
+ walk(dsl.body);
955
+ if (Object.keys(colorEntries).length === 0) return;
956
+ const firstBg = colorEntries["cus-bg-0"] ?? Object.values(colorEntries)[0];
957
+ if (firstBg) {
958
+ const m = firstBg.light_mode.match(/^rgba\((\d+),(\d+),(\d+),/);
959
+ if (m) {
960
+ colorEntries["cus-accent"] = {
961
+ light_mode: `rgba(${m[1]},${m[2]},${m[3]},1)`,
962
+ dark_mode: firstBg.dark_mode.replace(/,\s*[\d.]+\)$/, ",1)")
963
+ };
964
+ }
965
+ }
966
+ colorEntries["cus-muted"] ??= {
967
+ light_mode: "rgba(100,106,115,1)",
968
+ dark_mode: "rgba(166,166,166,1)"
969
+ };
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
+
871
995
  // src/raw-to-dsl.ts
872
996
  function isRawCardEnvelope(value) {
873
997
  if (typeof value !== "object" || value === null) return false;
@@ -976,6 +1100,7 @@ function convertRoot(root, ctx) {
976
1100
  out.config = convertConfig(isRecord2(root.config) ? root.config : {});
977
1101
  if (isRecord2(root.body)) out.body = convertBody2(root.body, ctx);
978
1102
  if (isRecord2(root.header)) out.header = convertHeader2(root.header, ctx);
1103
+ normalizeStoredCardColors(out);
979
1104
  return out;
980
1105
  }
981
1106
  function convertConfig(_node) {
@@ -1528,7 +1653,7 @@ function childToInlineSegment(child, ctx) {
1528
1653
  const prop = isRecord2(child.property) ? child.property : {};
1529
1654
  const ts = isRecord2(prop.textStyle) ? prop.textStyle : void 0;
1530
1655
  const bold = !!(ts && Array.isArray(ts.attributes) && ts.attributes.includes("bold"));
1531
- const rawColor = ts && typeof ts.color === "string" ? ts.color : void 0;
1656
+ const rawColor = resolveTextStyleColor(ts);
1532
1657
  const color = rawColor === "default" ? void 0 : rawColor;
1533
1658
  switch (tag) {
1534
1659
  case "plain_text":
@@ -1587,7 +1712,8 @@ function childToMarkdown(child, ctx) {
1587
1712
  case "plain_text": {
1588
1713
  const content = typeof prop.content === "string" ? prop.content : "";
1589
1714
  const ts = isRecord2(prop.textStyle) ? prop.textStyle : void 0;
1590
- const color = ts && typeof ts.color === "string" ? ts.color : void 0;
1715
+ const rawColor = resolveTextStyleColor(ts);
1716
+ const color = rawColor === "default" ? void 0 : rawColor;
1591
1717
  const attrs = ts && Array.isArray(ts.attributes) ? ts.attributes : [];
1592
1718
  return wrapEmphasis(content, attrs.includes("bold"), color);
1593
1719
  }
@@ -1861,109 +1987,12 @@ function degradeUnknown(el) {
1861
1987
  return { tag: "unknown", raw_tag: rawTag, fallback: el };
1862
1988
  }
1863
1989
 
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
-
1964
1990
  exports.degradeUnknown = degradeUnknown;
1965
1991
  exports.dslToRaw = dslToRaw;
1966
1992
  exports.isRawCardEnvelope = isRawCardEnvelope;
1967
1993
  exports.normalizeStoredCardColors = normalizeStoredCardColors;
1968
1994
  exports.rawCardToDsl = rawCardToDsl;
1969
1995
  exports.rawToDsl = rawToDsl;
1996
+ exports.readThemeColorLight = readThemeColorLight;
1997
+ exports.resolveCustomBackgroundLight = resolveCustomBackgroundLight;
1998
+ exports.resolveTextStyleColor = resolveTextStyleColor;
package/dist/index.d.ts CHANGED
@@ -10,5 +10,7 @@ export { dslToRaw } from './dsl-to-raw.js';
10
10
  export { rawToDsl, rawCardToDsl, isRawCardEnvelope, degradeUnknown, } from './raw-to-dsl.js';
11
11
  export { normalizeStoredCardColors } from './normalize-stored-colors.js';
12
12
  export type { CustomColorEntry } from './normalize-stored-colors.js';
13
+ export { readThemeColorLight, resolveCustomBackgroundLight, resolveTextStyleColor, } 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,MAAM,8BAA8B,CAAC;AACzE,YAAY,EAAE,gBAAgB,EAAE,MAAM,8BAA8B,CAAC;AACrE,OAAO,EACL,mBAAmB,EACnB,4BAA4B,EAC5B,qBAAqB,GACtB,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,130 @@ function isRecord(v) {
866
866
  return typeof v === "object" && v !== null && !Array.isArray(v);
867
867
  }
868
868
 
869
+ // src/custom-colors.ts
870
+ function readThemeColorLight(pair) {
871
+ if (!pair || typeof pair !== "object") return void 0;
872
+ const o = pair;
873
+ const raw = o.light_mode ?? o.lightMode;
874
+ if (typeof raw !== "string") return void 0;
875
+ const v = raw.trim();
876
+ return v || void 0;
877
+ }
878
+ function resolveTextStyleColor(textStyle) {
879
+ if (!textStyle || typeof textStyle !== "object") return void 0;
880
+ const ts = textStyle;
881
+ const enumColor = typeof ts.color === "string" ? ts.color.trim() : void 0;
882
+ if (enumColor && enumColor !== "default") return enumColor;
883
+ const custom = ts.custom_color ?? ts.customColor;
884
+ return readThemeColorLight(custom);
885
+ }
886
+ function resolveCustomBackgroundLight(property) {
887
+ if (!property || typeof property !== "object") return void 0;
888
+ const p = property;
889
+ const custom = p.custom_background_style ?? p.customBackgroundStyle;
890
+ return readThemeColorLight(custom);
891
+ }
892
+
893
+ // src/normalize-stored-colors.ts
894
+ function hexColorToRgba(hex) {
895
+ const h = hex.trim().replace(/^#/, "");
896
+ if (h.length === 8) {
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
+ const a = Math.round(parseInt(h.slice(6, 8), 16) / 255 * 100) / 100;
901
+ return `rgba(${r},${g},${b},${a})`;
902
+ }
903
+ if (h.length === 6) {
904
+ const r = parseInt(h.slice(0, 2), 16);
905
+ const g = parseInt(h.slice(2, 4), 16);
906
+ const b = parseInt(h.slice(4, 6), 16);
907
+ return `rgba(${r},${g},${b},1)`;
908
+ }
909
+ return void 0;
910
+ }
911
+ function readCustomBackgroundStyle(node) {
912
+ const raw = node.custom_background_style;
913
+ if (!raw || typeof raw !== "object") return void 0;
914
+ const o = raw;
915
+ const lightRaw = typeof o.light_mode === "string" ? o.light_mode : void 0;
916
+ const darkRaw = typeof o.dark_mode === "string" ? o.dark_mode : void 0;
917
+ if (!lightRaw || !darkRaw) return void 0;
918
+ const light = lightRaw.startsWith("#") ? hexColorToRgba(lightRaw) : lightRaw;
919
+ const dark = darkRaw.startsWith("#") ? hexColorToRgba(darkRaw) : darkRaw;
920
+ if (!light || !dark) return void 0;
921
+ return { light_mode: light, dark_mode: dark };
922
+ }
923
+ function normalizeStoredCardColors(dsl) {
924
+ const colorEntries = {};
925
+ const styleKey = (entry) => `${entry.light_mode}|${entry.dark_mode}`;
926
+ const keyToAlias = /* @__PURE__ */ new Map();
927
+ let bgSeq = 0;
928
+ const ensureAlias = (prefix, entry) => {
929
+ const existing2 = keyToAlias.get(styleKey(entry));
930
+ if (existing2) return existing2;
931
+ const alias = `${prefix}-${bgSeq++}`;
932
+ colorEntries[alias] = entry;
933
+ keyToAlias.set(styleKey(entry), alias);
934
+ return alias;
935
+ };
936
+ const walk = (node) => {
937
+ if (Array.isArray(node)) {
938
+ for (const child of node) walk(child);
939
+ return;
940
+ }
941
+ if (!node || typeof node !== "object") return;
942
+ const obj = node;
943
+ if (obj.tag === "column") {
944
+ const custom = readCustomBackgroundStyle(obj);
945
+ if (custom) {
946
+ obj.background_style = ensureAlias("cus-bg", custom);
947
+ delete obj.custom_background_style;
948
+ }
949
+ }
950
+ for (const value of Object.values(obj)) walk(value);
951
+ };
952
+ walk(dsl.body);
953
+ if (Object.keys(colorEntries).length === 0) return;
954
+ const firstBg = colorEntries["cus-bg-0"] ?? Object.values(colorEntries)[0];
955
+ if (firstBg) {
956
+ const m = firstBg.light_mode.match(/^rgba\((\d+),(\d+),(\d+),/);
957
+ if (m) {
958
+ colorEntries["cus-accent"] = {
959
+ light_mode: `rgba(${m[1]},${m[2]},${m[3]},1)`,
960
+ dark_mode: firstBg.dark_mode.replace(/,\s*[\d.]+\)$/, ",1)")
961
+ };
962
+ }
963
+ }
964
+ colorEntries["cus-muted"] ??= {
965
+ light_mode: "rgba(100,106,115,1)",
966
+ dark_mode: "rgba(166,166,166,1)"
967
+ };
968
+ const config = dsl.config && typeof dsl.config === "object" ? dsl.config : {};
969
+ dsl.config = config;
970
+ const style = config.style && typeof config.style === "object" ? config.style : {};
971
+ config.style = style;
972
+ const existing = style.color && typeof style.color === "object" ? style.color : {};
973
+ style.color = { ...colorEntries, ...existing };
974
+ if (!colorEntries["cus-accent"]) return;
975
+ const applyDefaultFontColors = (node) => {
976
+ if (Array.isArray(node)) {
977
+ for (const child of node) applyDefaultFontColors(child);
978
+ return;
979
+ }
980
+ if (!node || typeof node !== "object") return;
981
+ const obj = node;
982
+ if (obj.tag === "markdown" && obj.font_color === void 0) {
983
+ const size = obj.text_size;
984
+ const content = typeof obj.content === "string" ? obj.content : "";
985
+ if (size === "small") obj.font_color = "cus-muted";
986
+ else if (size === "heading" || content.includes("**")) obj.font_color = "cus-accent";
987
+ }
988
+ for (const value of Object.values(obj)) applyDefaultFontColors(value);
989
+ };
990
+ applyDefaultFontColors(dsl.body);
991
+ }
992
+
869
993
  // src/raw-to-dsl.ts
870
994
  function isRawCardEnvelope(value) {
871
995
  if (typeof value !== "object" || value === null) return false;
@@ -974,6 +1098,7 @@ function convertRoot(root, ctx) {
974
1098
  out.config = convertConfig(isRecord2(root.config) ? root.config : {});
975
1099
  if (isRecord2(root.body)) out.body = convertBody2(root.body, ctx);
976
1100
  if (isRecord2(root.header)) out.header = convertHeader2(root.header, ctx);
1101
+ normalizeStoredCardColors(out);
977
1102
  return out;
978
1103
  }
979
1104
  function convertConfig(_node) {
@@ -1526,7 +1651,7 @@ function childToInlineSegment(child, ctx) {
1526
1651
  const prop = isRecord2(child.property) ? child.property : {};
1527
1652
  const ts = isRecord2(prop.textStyle) ? prop.textStyle : void 0;
1528
1653
  const bold = !!(ts && Array.isArray(ts.attributes) && ts.attributes.includes("bold"));
1529
- const rawColor = ts && typeof ts.color === "string" ? ts.color : void 0;
1654
+ const rawColor = resolveTextStyleColor(ts);
1530
1655
  const color = rawColor === "default" ? void 0 : rawColor;
1531
1656
  switch (tag) {
1532
1657
  case "plain_text":
@@ -1585,7 +1710,8 @@ function childToMarkdown(child, ctx) {
1585
1710
  case "plain_text": {
1586
1711
  const content = typeof prop.content === "string" ? prop.content : "";
1587
1712
  const ts = isRecord2(prop.textStyle) ? prop.textStyle : void 0;
1588
- const color = ts && typeof ts.color === "string" ? ts.color : void 0;
1713
+ const rawColor = resolveTextStyleColor(ts);
1714
+ const color = rawColor === "default" ? void 0 : rawColor;
1589
1715
  const attrs = ts && Array.isArray(ts.attributes) ? ts.attributes : [];
1590
1716
  return wrapEmphasis(content, attrs.includes("bold"), color);
1591
1717
  }
@@ -1859,104 +1985,4 @@ function degradeUnknown(el) {
1859
1985
  return { tag: "unknown", raw_tag: rawTag, fallback: el };
1860
1986
  }
1861
1987
 
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 };
1988
+ export { degradeUnknown, dslToRaw, isRawCardEnvelope, normalizeStoredCardColors, rawCardToDsl, rawToDsl, readThemeColorLight, resolveCustomBackgroundLight, resolveTextStyleColor };
@@ -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;AAcH,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAIzD;AAED,wBAAgB,YAAY,CAAC,QAAQ,EAAE,OAAO,GAAG,OAAO,CAcvD;AAkgDD;;;;;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.3",
4
4
  "description": "公开 DSL 与飞书内部 RAW JSON 的双向适配器;raw→DSL 对齐 feishu-raw-card-to-dsl",
5
5
  "type": "module",
6
6
  "main": "./dist/index.cjs",