@open-feishu-card/adapter 0.3.1 → 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.
- package/dist/custom-colors.d.ts +22 -0
- package/dist/custom-colors.d.ts.map +1 -0
- package/dist/index.cjs +132 -2
- package/dist/index.d.ts +4 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +129 -3
- package/dist/normalize-stored-colors.d.ts +14 -0
- package/dist/normalize-stored-colors.d.ts.map +1 -0
- package/dist/raw-to-dsl.d.ts +2 -1
- package/dist/raw-to-dsl.d.ts.map +1 -1
- package/package.json +3 -2
|
@@ -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
|
|
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
|
|
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
|
}
|
|
@@ -1864,5 +1990,9 @@ function degradeUnknown(el) {
|
|
|
1864
1990
|
exports.degradeUnknown = degradeUnknown;
|
|
1865
1991
|
exports.dslToRaw = dslToRaw;
|
|
1866
1992
|
exports.isRawCardEnvelope = isRawCardEnvelope;
|
|
1993
|
+
exports.normalizeStoredCardColors = normalizeStoredCardColors;
|
|
1867
1994
|
exports.rawCardToDsl = rawCardToDsl;
|
|
1868
1995
|
exports.rawToDsl = rawToDsl;
|
|
1996
|
+
exports.readThemeColorLight = readThemeColorLight;
|
|
1997
|
+
exports.resolveCustomBackgroundLight = resolveCustomBackgroundLight;
|
|
1998
|
+
exports.resolveTextStyleColor = resolveTextStyleColor;
|
package/dist/index.d.ts
CHANGED
|
@@ -8,5 +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';
|
|
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';
|
|
11
15
|
export type { CardElement, ElementProperty, JsonCard } from './types.js';
|
|
12
16
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -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,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
|
|
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
|
|
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,4 +1985,4 @@ function degradeUnknown(el) {
|
|
|
1859
1985
|
return { tag: "unknown", raw_tag: rawTag, fallback: el };
|
|
1860
1986
|
}
|
|
1861
1987
|
|
|
1862
|
-
export { degradeUnknown, dslToRaw, isRawCardEnvelope, rawCardToDsl, rawToDsl };
|
|
1988
|
+
export { degradeUnknown, dslToRaw, isRawCardEnvelope, normalizeStoredCardColors, rawCardToDsl, rawToDsl, readThemeColorLight, resolveCustomBackgroundLight, resolveTextStyleColor };
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 飞书存储卡片时会将 config.style.color 的 cus-N 展开为 custom_background_style(#RRGGBBAA),
|
|
3
|
+
* 并丢弃 config.style 与 markdown.font_color。回读底稿后须 normalize,否则 modify 再发会丢色。
|
|
4
|
+
*/
|
|
5
|
+
export type CustomColorEntry = {
|
|
6
|
+
light_mode: string;
|
|
7
|
+
dark_mode: string;
|
|
8
|
+
};
|
|
9
|
+
/**
|
|
10
|
+
* 将飞书回读的 custom_background_style 还原为可再次发送的 background_style cus-N + config.style.color。
|
|
11
|
+
* 若 markdown 缺少 font_color,按 text_size / 加粗内容补 cus-accent / cus-muted(飞书回读会丢 font_color)。
|
|
12
|
+
*/
|
|
13
|
+
export declare function normalizeStoredCardColors(dsl: Record<string, unknown>): void;
|
|
14
|
+
//# sourceMappingURL=normalize-stored-colors.d.ts.map
|
|
@@ -0,0 +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"}
|
package/dist/raw-to-dsl.d.ts
CHANGED
|
@@ -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 `
|
|
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
|
package/dist/raw-to-dsl.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"raw-to-dsl.d.ts","sourceRoot":"","sources":["../src/raw-to-dsl.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6CG;
|
|
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.
|
|
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",
|
|
@@ -21,7 +21,8 @@
|
|
|
21
21
|
"tsup": "^8.3.5",
|
|
22
22
|
"tsx": "^4.19.3",
|
|
23
23
|
"typescript": "^7.0.2",
|
|
24
|
-
"vitest": "^2.1.9"
|
|
24
|
+
"vitest": "^2.1.9",
|
|
25
|
+
"@open-feishu-card/schema": "0.1.4"
|
|
25
26
|
},
|
|
26
27
|
"license": "MIT",
|
|
27
28
|
"publishConfig": {
|