@open-feishu-card/adapter 0.3.3 → 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.
- package/dist/custom-colors.d.ts +8 -4
- package/dist/custom-colors.d.ts.map +1 -1
- package/dist/index.cjs +228 -58
- package/dist/index.d.ts +2 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +223 -59
- package/dist/normalize-stored-colors.d.ts +12 -1
- package/dist/normalize-stored-colors.d.ts.map +1 -1
- package/dist/raw-to-dsl.d.ts.map +1 -1
- package/package.json +1 -1
package/dist/custom-colors.d.ts
CHANGED
|
@@ -3,11 +3,10 @@
|
|
|
3
3
|
* customBackgroundStyle / custom_background_style → column backgrounds
|
|
4
4
|
* textStyle.customColor / textStyle.custom_color → inline text color
|
|
5
5
|
*
|
|
6
|
-
* Public DSL
|
|
7
|
-
*
|
|
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).
|
|
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.
|
|
10
8
|
*/
|
|
9
|
+
import type { CustomColorEntry } from './normalize-stored-colors.js';
|
|
11
10
|
export type ThemeColorPair = {
|
|
12
11
|
light_mode?: string;
|
|
13
12
|
lightMode?: string;
|
|
@@ -15,8 +14,13 @@ export type ThemeColorPair = {
|
|
|
15
14
|
darkMode?: string;
|
|
16
15
|
};
|
|
17
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;
|
|
18
19
|
/** Enum `color` wins; else fall back to customColor light hex/rgba. */
|
|
19
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;
|
|
20
24
|
/** Light hex/rgba from column (or container) custom background, if any. */
|
|
21
25
|
export declare function resolveCustomBackgroundLight(property: unknown): string | undefined;
|
|
22
26
|
//# sourceMappingURL=custom-colors.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"custom-colors.d.ts","sourceRoot":"","sources":["../src/custom-colors.ts"],"names":[],"mappings":"AAAA
|
|
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,31 +868,22 @@ function isRecord(v) {
|
|
|
868
868
|
return typeof v === "object" && v !== null && !Array.isArray(v);
|
|
869
869
|
}
|
|
870
870
|
|
|
871
|
-
// src/
|
|
872
|
-
function
|
|
873
|
-
|
|
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;
|
|
871
|
+
// src/normalize-stored-colors.ts
|
|
872
|
+
function createColorRegistry() {
|
|
873
|
+
return { entries: {}, keyToAlias: /* @__PURE__ */ new Map(), bgSeq: 0, textSeq: 0 };
|
|
879
874
|
}
|
|
880
|
-
function
|
|
881
|
-
|
|
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);
|
|
875
|
+
function colorEntryKey(entry) {
|
|
876
|
+
return `${entry.light_mode}|${entry.dark_mode}`;
|
|
887
877
|
}
|
|
888
|
-
function
|
|
889
|
-
|
|
890
|
-
const
|
|
891
|
-
|
|
892
|
-
|
|
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;
|
|
893
886
|
}
|
|
894
|
-
|
|
895
|
-
// src/normalize-stored-colors.ts
|
|
896
887
|
function hexColorToRgba(hex) {
|
|
897
888
|
const h = hex.trim().replace(/^#/, "");
|
|
898
889
|
if (h.length === 8) {
|
|
@@ -922,17 +913,17 @@ function readCustomBackgroundStyle(node) {
|
|
|
922
913
|
if (!light || !dark) return void 0;
|
|
923
914
|
return { light_mode: light, dark_mode: dark };
|
|
924
915
|
}
|
|
925
|
-
function normalizeStoredCardColors(dsl) {
|
|
926
|
-
const colorEntries = {};
|
|
927
|
-
const
|
|
928
|
-
|
|
929
|
-
let
|
|
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;
|
|
930
921
|
const ensureAlias = (prefix, entry) => {
|
|
931
|
-
const existing2 = keyToAlias.get(
|
|
922
|
+
const existing2 = keyToAlias.get(colorEntryKey(entry));
|
|
932
923
|
if (existing2) return existing2;
|
|
933
|
-
const alias =
|
|
924
|
+
const alias = prefix === "cus-bg" ? `cus-bg-${bgSeq++}` : `cus-text-${textSeq++}`;
|
|
934
925
|
colorEntries[alias] = entry;
|
|
935
|
-
keyToAlias.set(
|
|
926
|
+
keyToAlias.set(colorEntryKey(entry), alias);
|
|
936
927
|
return alias;
|
|
937
928
|
};
|
|
938
929
|
const walk = (node) => {
|
|
@@ -949,11 +940,15 @@ function normalizeStoredCardColors(dsl) {
|
|
|
949
940
|
delete obj.custom_background_style;
|
|
950
941
|
}
|
|
951
942
|
}
|
|
943
|
+
if (obj.tag === "markdown" && typeof obj.content === "string") {
|
|
944
|
+
normalizeMarkdownInlineHexColors(obj, ensureAlias);
|
|
945
|
+
}
|
|
952
946
|
for (const value of Object.values(obj)) walk(value);
|
|
953
947
|
};
|
|
954
948
|
walk(dsl.body);
|
|
955
949
|
if (Object.keys(colorEntries).length === 0) return;
|
|
956
|
-
const
|
|
950
|
+
const firstBgKey = Object.keys(colorEntries).find((k) => k.startsWith("cus-bg-"));
|
|
951
|
+
const firstBg = firstBgKey ? colorEntries[firstBgKey] : void 0;
|
|
957
952
|
if (firstBg) {
|
|
958
953
|
const m = firstBg.light_mode.match(/^rgba\((\d+),(\d+),(\d+),/);
|
|
959
954
|
if (m) {
|
|
@@ -967,6 +962,13 @@ function normalizeStoredCardColors(dsl) {
|
|
|
967
962
|
light_mode: "rgba(100,106,115,1)",
|
|
968
963
|
dark_mode: "rgba(166,166,166,1)"
|
|
969
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);
|
|
970
972
|
const config = dsl.config && typeof dsl.config === "object" ? dsl.config : {};
|
|
971
973
|
dsl.config = config;
|
|
972
974
|
const style = config.style && typeof config.style === "object" ? config.style : {};
|
|
@@ -991,6 +993,130 @@ function normalizeStoredCardColors(dsl) {
|
|
|
991
993
|
};
|
|
992
994
|
applyDefaultFontColors(dsl.body);
|
|
993
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
|
+
}
|
|
994
1120
|
|
|
995
1121
|
// src/raw-to-dsl.ts
|
|
996
1122
|
function isRawCardEnvelope(value) {
|
|
@@ -1007,12 +1133,19 @@ function rawCardToDsl(envelope) {
|
|
|
1007
1133
|
} catch {
|
|
1008
1134
|
return envelope;
|
|
1009
1135
|
}
|
|
1010
|
-
const ctx = {
|
|
1136
|
+
const ctx = makeCtx({
|
|
1011
1137
|
images: env.json_attachment?.images ?? {},
|
|
1012
1138
|
atUsers: env.json_attachment?.at_users ?? {}
|
|
1013
|
-
};
|
|
1139
|
+
});
|
|
1014
1140
|
return convertRoot(inner, ctx);
|
|
1015
1141
|
}
|
|
1142
|
+
function makeCtx(partial) {
|
|
1143
|
+
return {
|
|
1144
|
+
images: partial?.images ?? {},
|
|
1145
|
+
atUsers: partial?.atUsers ?? {},
|
|
1146
|
+
colors: createColorRegistry()
|
|
1147
|
+
};
|
|
1148
|
+
}
|
|
1016
1149
|
var RAW_ONLY_FIELDS = /* @__PURE__ */ new Set([
|
|
1017
1150
|
"new_body",
|
|
1018
1151
|
"source",
|
|
@@ -1100,7 +1233,7 @@ function convertRoot(root, ctx) {
|
|
|
1100
1233
|
out.config = convertConfig(isRecord2(root.config) ? root.config : {});
|
|
1101
1234
|
if (isRecord2(root.body)) out.body = convertBody2(root.body, ctx);
|
|
1102
1235
|
if (isRecord2(root.header)) out.header = convertHeader2(root.header, ctx);
|
|
1103
|
-
normalizeStoredCardColors(out);
|
|
1236
|
+
normalizeStoredCardColors(out, ctx.colors);
|
|
1104
1237
|
return out;
|
|
1105
1238
|
}
|
|
1106
1239
|
function convertConfig(_node) {
|
|
@@ -1202,7 +1335,7 @@ function unwrap(node, ctx) {
|
|
|
1202
1335
|
let value = isRecord2(cell) && "data" in cell ? cell.data : cell;
|
|
1203
1336
|
if (isRecord2(value) && value.tag === "markdown" && isRecord2(value.property)) {
|
|
1204
1337
|
const elements = Array.isArray(value.property.elements) ? value.property.elements : [];
|
|
1205
|
-
value = renderChildren(elements, ctx);
|
|
1338
|
+
value = renderChildren(elements, ctx).content;
|
|
1206
1339
|
}
|
|
1207
1340
|
r[k] = value;
|
|
1208
1341
|
}
|
|
@@ -1577,8 +1710,9 @@ function resolveAtUserId(prop, ctx) {
|
|
|
1577
1710
|
function rebuildMarkdown(property, ctx) {
|
|
1578
1711
|
const out = { tag: "markdown" };
|
|
1579
1712
|
const elements = Array.isArray(property.elements) ? property.elements : [];
|
|
1580
|
-
const content = renderChildren(elements, ctx);
|
|
1713
|
+
const { content, uniformFontColor } = renderChildren(elements, ctx);
|
|
1581
1714
|
if (content) out.content = content;
|
|
1715
|
+
if (uniformFontColor) out.font_color = uniformFontColor;
|
|
1582
1716
|
for (const [rawKey, rawValue] of Object.entries(property)) {
|
|
1583
1717
|
if (rawKey === "elements" || rawKey === "markdownElements" || rawKey === "originTag") continue;
|
|
1584
1718
|
if (rawKey === "udIcon") continue;
|
|
@@ -1596,7 +1730,7 @@ function rebuildMarkdown(property, ctx) {
|
|
|
1596
1730
|
}
|
|
1597
1731
|
return out;
|
|
1598
1732
|
}
|
|
1599
|
-
function wrapEmphasis(text, bold, color) {
|
|
1733
|
+
function wrapEmphasis(text, bold, color, colorKind, inlineCustomFont = false) {
|
|
1600
1734
|
if (!bold && !color) return text;
|
|
1601
1735
|
const lead = text.match(/^\s*/)[0];
|
|
1602
1736
|
const trail = text.match(/\s*$/)[0];
|
|
@@ -1604,20 +1738,51 @@ function wrapEmphasis(text, bold, color) {
|
|
|
1604
1738
|
if (core.length === 0) return text;
|
|
1605
1739
|
let wrapped = core;
|
|
1606
1740
|
if (bold) wrapped = `**${wrapped}**`;
|
|
1607
|
-
if (color)
|
|
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
|
+
}
|
|
1608
1745
|
return lead + wrapped + trail;
|
|
1609
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
|
+
}
|
|
1610
1769
|
function renderChildren(children, ctx) {
|
|
1611
1770
|
let out = "";
|
|
1612
1771
|
let buffer = [];
|
|
1772
|
+
let uniformFontColor;
|
|
1613
1773
|
function flushBuffer() {
|
|
1614
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;
|
|
1615
1779
|
let group = [];
|
|
1616
1780
|
function emitGroup() {
|
|
1617
1781
|
if (group.length === 0) return;
|
|
1618
1782
|
const inner = group.map((s) => s.content).join("");
|
|
1619
|
-
const { bold, color } = group[0];
|
|
1620
|
-
|
|
1783
|
+
const { bold, color, colorKind } = group[0];
|
|
1784
|
+
const inlineCustomFont = colorKind === "custom" && !!color && color !== uniformCustom;
|
|
1785
|
+
out += wrapEmphasis(inner, bold, color, colorKind, inlineCustomFont);
|
|
1621
1786
|
group = [];
|
|
1622
1787
|
}
|
|
1623
1788
|
for (const seg of buffer) {
|
|
@@ -1626,8 +1791,9 @@ function renderChildren(children, ctx) {
|
|
|
1626
1791
|
continue;
|
|
1627
1792
|
}
|
|
1628
1793
|
const head = group[0];
|
|
1629
|
-
if (head.bold === seg.bold && head.color === seg.color
|
|
1630
|
-
|
|
1794
|
+
if (head.bold === seg.bold && head.color === seg.color && head.colorKind === seg.colorKind) {
|
|
1795
|
+
group.push(seg);
|
|
1796
|
+
} else {
|
|
1631
1797
|
emitGroup();
|
|
1632
1798
|
group.push(seg);
|
|
1633
1799
|
}
|
|
@@ -1646,33 +1812,33 @@ function renderChildren(children, ctx) {
|
|
|
1646
1812
|
out += childToMarkdown(child, ctx);
|
|
1647
1813
|
}
|
|
1648
1814
|
flushBuffer();
|
|
1649
|
-
return out;
|
|
1815
|
+
return { content: out, uniformFontColor };
|
|
1650
1816
|
}
|
|
1651
1817
|
function childToInlineSegment(child, ctx) {
|
|
1652
1818
|
const tag = child.tag;
|
|
1653
1819
|
const prop = isRecord2(child.property) ? child.property : {};
|
|
1654
1820
|
const ts = isRecord2(prop.textStyle) ? prop.textStyle : void 0;
|
|
1655
|
-
const bold
|
|
1656
|
-
const rawColor = resolveTextStyleColor(ts);
|
|
1657
|
-
const color = rawColor === "default" ? void 0 : rawColor;
|
|
1821
|
+
const { bold, color, colorKind } = resolveInlineStyle(ts, ctx);
|
|
1658
1822
|
switch (tag) {
|
|
1659
1823
|
case "plain_text":
|
|
1660
1824
|
return {
|
|
1661
1825
|
content: typeof prop.content === "string" ? prop.content : "",
|
|
1662
1826
|
bold,
|
|
1663
|
-
color
|
|
1827
|
+
color,
|
|
1828
|
+
colorKind
|
|
1664
1829
|
};
|
|
1665
1830
|
case "code_span":
|
|
1666
1831
|
return {
|
|
1667
1832
|
content: `\`${typeof prop.content === "string" ? prop.content : ""}\``,
|
|
1668
1833
|
bold,
|
|
1669
|
-
color
|
|
1834
|
+
color,
|
|
1835
|
+
colorKind
|
|
1670
1836
|
};
|
|
1671
1837
|
case "link": {
|
|
1672
1838
|
const text = typeof prop.content === "string" ? prop.content : "";
|
|
1673
1839
|
const urlObj = isRecord2(prop.url) ? prop.url : void 0;
|
|
1674
1840
|
const url = urlObj && typeof urlObj.url === "string" ? urlObj.url : "";
|
|
1675
|
-
return { content: `[${text}](${url})`, bold, color };
|
|
1841
|
+
return { content: `[${text}](${url})`, bold, color, colorKind };
|
|
1676
1842
|
}
|
|
1677
1843
|
case "at_all":
|
|
1678
1844
|
return { content: "<at id=all></at>", bold, color };
|
|
@@ -1712,10 +1878,8 @@ function childToMarkdown(child, ctx) {
|
|
|
1712
1878
|
case "plain_text": {
|
|
1713
1879
|
const content = typeof prop.content === "string" ? prop.content : "";
|
|
1714
1880
|
const ts = isRecord2(prop.textStyle) ? prop.textStyle : void 0;
|
|
1715
|
-
const
|
|
1716
|
-
|
|
1717
|
-
const attrs = ts && Array.isArray(ts.attributes) ? ts.attributes : [];
|
|
1718
|
-
return wrapEmphasis(content, attrs.includes("bold"), color);
|
|
1881
|
+
const { bold, color, colorKind } = resolveInlineStyle(ts, ctx);
|
|
1882
|
+
return wrapEmphasis(content, bold, color, colorKind, colorKind === "custom");
|
|
1719
1883
|
}
|
|
1720
1884
|
case "br":
|
|
1721
1885
|
return "\n";
|
|
@@ -1841,7 +2005,7 @@ ${"#".repeat(level)} ${body}
|
|
|
1841
2005
|
if (!data || data.tag !== "markdown") return "";
|
|
1842
2006
|
const cellProp = isRecord2(data.property) ? data.property : {};
|
|
1843
2007
|
const inner = Array.isArray(cellProp.elements) ? cellProp.elements : [];
|
|
1844
|
-
const text = renderChildren(inner, ctx);
|
|
2008
|
+
const { content: text } = renderChildren(inner, ctx);
|
|
1845
2009
|
return text.replace(/\|/g, "\\|").replace(/\n/g, " ");
|
|
1846
2010
|
});
|
|
1847
2011
|
return `| ${cells.join(" | ")} |`;
|
|
@@ -1964,10 +2128,10 @@ function rawToDsl(raw) {
|
|
|
1964
2128
|
}
|
|
1965
2129
|
}
|
|
1966
2130
|
const attachment = isRecord2(raw.json_attachment) ? raw.json_attachment : {};
|
|
1967
|
-
const ctx = {
|
|
2131
|
+
const ctx = makeCtx({
|
|
1968
2132
|
images: isRecord2(attachment.images) ? attachment.images : {},
|
|
1969
2133
|
atUsers: isRecord2(attachment.at_users) ? attachment.at_users : {}
|
|
1970
|
-
};
|
|
2134
|
+
});
|
|
1971
2135
|
return convertRoot(inner, ctx);
|
|
1972
2136
|
}
|
|
1973
2137
|
if (isRecord2(raw.card)) {
|
|
@@ -1975,10 +2139,10 @@ function rawToDsl(raw) {
|
|
|
1975
2139
|
if (typeof card.json_card === "string" || isRecord2(card.json_card)) {
|
|
1976
2140
|
return rawToDsl(card);
|
|
1977
2141
|
}
|
|
1978
|
-
return convertRoot(card,
|
|
2142
|
+
return convertRoot(card, makeCtx());
|
|
1979
2143
|
}
|
|
1980
2144
|
if ("body" in raw || "header" in raw || "schema" in raw) {
|
|
1981
|
-
return convertRoot(raw,
|
|
2145
|
+
return convertRoot(raw, makeCtx());
|
|
1982
2146
|
}
|
|
1983
2147
|
return raw;
|
|
1984
2148
|
}
|
|
@@ -1987,12 +2151,18 @@ function degradeUnknown(el) {
|
|
|
1987
2151
|
return { tag: "unknown", raw_tag: rawTag, fallback: el };
|
|
1988
2152
|
}
|
|
1989
2153
|
|
|
2154
|
+
exports.createColorRegistry = createColorRegistry;
|
|
1990
2155
|
exports.degradeUnknown = degradeUnknown;
|
|
1991
2156
|
exports.dslToRaw = dslToRaw;
|
|
2157
|
+
exports.isCustomHexColor = isCustomHexColor;
|
|
1992
2158
|
exports.isRawCardEnvelope = isRawCardEnvelope;
|
|
1993
2159
|
exports.normalizeStoredCardColors = normalizeStoredCardColors;
|
|
1994
2160
|
exports.rawCardToDsl = rawCardToDsl;
|
|
1995
2161
|
exports.rawToDsl = rawToDsl;
|
|
2162
|
+
exports.readThemeColorDark = readThemeColorDark;
|
|
1996
2163
|
exports.readThemeColorLight = readThemeColorLight;
|
|
2164
|
+
exports.registerColorEntry = registerColorEntry;
|
|
1997
2165
|
exports.resolveCustomBackgroundLight = resolveCustomBackgroundLight;
|
|
1998
2166
|
exports.resolveTextStyleColor = resolveTextStyleColor;
|
|
2167
|
+
exports.resolveTextStyleCustomColorPair = resolveTextStyleCustomColorPair;
|
|
2168
|
+
exports.themePairToColorEntry = themePairToColorEntry;
|
package/dist/index.d.ts
CHANGED
|
@@ -8,9 +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, resolveCustomBackgroundLight, resolveTextStyleColor, } from './custom-colors.js';
|
|
13
|
+
export { readThemeColorLight, readThemeColorDark, resolveCustomBackgroundLight, resolveTextStyleColor, resolveTextStyleCustomColorPair, themePairToColorEntry, isCustomHexColor, } from './custom-colors.js';
|
|
14
14
|
export type { ThemeColorPair } from './custom-colors.js';
|
|
15
15
|
export type { CardElement, ElementProperty, JsonCard } from './types.js';
|
|
16
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,OAAO,EAAE,yBAAyB,EAAE,MAAM,8BAA8B,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,31 +866,22 @@ function isRecord(v) {
|
|
|
866
866
|
return typeof v === "object" && v !== null && !Array.isArray(v);
|
|
867
867
|
}
|
|
868
868
|
|
|
869
|
-
// src/
|
|
870
|
-
function
|
|
871
|
-
|
|
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;
|
|
869
|
+
// src/normalize-stored-colors.ts
|
|
870
|
+
function createColorRegistry() {
|
|
871
|
+
return { entries: {}, keyToAlias: /* @__PURE__ */ new Map(), bgSeq: 0, textSeq: 0 };
|
|
877
872
|
}
|
|
878
|
-
function
|
|
879
|
-
|
|
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);
|
|
873
|
+
function colorEntryKey(entry) {
|
|
874
|
+
return `${entry.light_mode}|${entry.dark_mode}`;
|
|
885
875
|
}
|
|
886
|
-
function
|
|
887
|
-
|
|
888
|
-
const
|
|
889
|
-
|
|
890
|
-
|
|
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;
|
|
891
884
|
}
|
|
892
|
-
|
|
893
|
-
// src/normalize-stored-colors.ts
|
|
894
885
|
function hexColorToRgba(hex) {
|
|
895
886
|
const h = hex.trim().replace(/^#/, "");
|
|
896
887
|
if (h.length === 8) {
|
|
@@ -920,17 +911,17 @@ function readCustomBackgroundStyle(node) {
|
|
|
920
911
|
if (!light || !dark) return void 0;
|
|
921
912
|
return { light_mode: light, dark_mode: dark };
|
|
922
913
|
}
|
|
923
|
-
function normalizeStoredCardColors(dsl) {
|
|
924
|
-
const colorEntries = {};
|
|
925
|
-
const
|
|
926
|
-
|
|
927
|
-
let
|
|
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;
|
|
928
919
|
const ensureAlias = (prefix, entry) => {
|
|
929
|
-
const existing2 = keyToAlias.get(
|
|
920
|
+
const existing2 = keyToAlias.get(colorEntryKey(entry));
|
|
930
921
|
if (existing2) return existing2;
|
|
931
|
-
const alias =
|
|
922
|
+
const alias = prefix === "cus-bg" ? `cus-bg-${bgSeq++}` : `cus-text-${textSeq++}`;
|
|
932
923
|
colorEntries[alias] = entry;
|
|
933
|
-
keyToAlias.set(
|
|
924
|
+
keyToAlias.set(colorEntryKey(entry), alias);
|
|
934
925
|
return alias;
|
|
935
926
|
};
|
|
936
927
|
const walk = (node) => {
|
|
@@ -947,11 +938,15 @@ function normalizeStoredCardColors(dsl) {
|
|
|
947
938
|
delete obj.custom_background_style;
|
|
948
939
|
}
|
|
949
940
|
}
|
|
941
|
+
if (obj.tag === "markdown" && typeof obj.content === "string") {
|
|
942
|
+
normalizeMarkdownInlineHexColors(obj, ensureAlias);
|
|
943
|
+
}
|
|
950
944
|
for (const value of Object.values(obj)) walk(value);
|
|
951
945
|
};
|
|
952
946
|
walk(dsl.body);
|
|
953
947
|
if (Object.keys(colorEntries).length === 0) return;
|
|
954
|
-
const
|
|
948
|
+
const firstBgKey = Object.keys(colorEntries).find((k) => k.startsWith("cus-bg-"));
|
|
949
|
+
const firstBg = firstBgKey ? colorEntries[firstBgKey] : void 0;
|
|
955
950
|
if (firstBg) {
|
|
956
951
|
const m = firstBg.light_mode.match(/^rgba\((\d+),(\d+),(\d+),/);
|
|
957
952
|
if (m) {
|
|
@@ -965,6 +960,13 @@ function normalizeStoredCardColors(dsl) {
|
|
|
965
960
|
light_mode: "rgba(100,106,115,1)",
|
|
966
961
|
dark_mode: "rgba(166,166,166,1)"
|
|
967
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);
|
|
968
970
|
const config = dsl.config && typeof dsl.config === "object" ? dsl.config : {};
|
|
969
971
|
dsl.config = config;
|
|
970
972
|
const style = config.style && typeof config.style === "object" ? config.style : {};
|
|
@@ -989,6 +991,130 @@ function normalizeStoredCardColors(dsl) {
|
|
|
989
991
|
};
|
|
990
992
|
applyDefaultFontColors(dsl.body);
|
|
991
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
|
+
}
|
|
992
1118
|
|
|
993
1119
|
// src/raw-to-dsl.ts
|
|
994
1120
|
function isRawCardEnvelope(value) {
|
|
@@ -1005,12 +1131,19 @@ function rawCardToDsl(envelope) {
|
|
|
1005
1131
|
} catch {
|
|
1006
1132
|
return envelope;
|
|
1007
1133
|
}
|
|
1008
|
-
const ctx = {
|
|
1134
|
+
const ctx = makeCtx({
|
|
1009
1135
|
images: env.json_attachment?.images ?? {},
|
|
1010
1136
|
atUsers: env.json_attachment?.at_users ?? {}
|
|
1011
|
-
};
|
|
1137
|
+
});
|
|
1012
1138
|
return convertRoot(inner, ctx);
|
|
1013
1139
|
}
|
|
1140
|
+
function makeCtx(partial) {
|
|
1141
|
+
return {
|
|
1142
|
+
images: partial?.images ?? {},
|
|
1143
|
+
atUsers: partial?.atUsers ?? {},
|
|
1144
|
+
colors: createColorRegistry()
|
|
1145
|
+
};
|
|
1146
|
+
}
|
|
1014
1147
|
var RAW_ONLY_FIELDS = /* @__PURE__ */ new Set([
|
|
1015
1148
|
"new_body",
|
|
1016
1149
|
"source",
|
|
@@ -1098,7 +1231,7 @@ function convertRoot(root, ctx) {
|
|
|
1098
1231
|
out.config = convertConfig(isRecord2(root.config) ? root.config : {});
|
|
1099
1232
|
if (isRecord2(root.body)) out.body = convertBody2(root.body, ctx);
|
|
1100
1233
|
if (isRecord2(root.header)) out.header = convertHeader2(root.header, ctx);
|
|
1101
|
-
normalizeStoredCardColors(out);
|
|
1234
|
+
normalizeStoredCardColors(out, ctx.colors);
|
|
1102
1235
|
return out;
|
|
1103
1236
|
}
|
|
1104
1237
|
function convertConfig(_node) {
|
|
@@ -1200,7 +1333,7 @@ function unwrap(node, ctx) {
|
|
|
1200
1333
|
let value = isRecord2(cell) && "data" in cell ? cell.data : cell;
|
|
1201
1334
|
if (isRecord2(value) && value.tag === "markdown" && isRecord2(value.property)) {
|
|
1202
1335
|
const elements = Array.isArray(value.property.elements) ? value.property.elements : [];
|
|
1203
|
-
value = renderChildren(elements, ctx);
|
|
1336
|
+
value = renderChildren(elements, ctx).content;
|
|
1204
1337
|
}
|
|
1205
1338
|
r[k] = value;
|
|
1206
1339
|
}
|
|
@@ -1575,8 +1708,9 @@ function resolveAtUserId(prop, ctx) {
|
|
|
1575
1708
|
function rebuildMarkdown(property, ctx) {
|
|
1576
1709
|
const out = { tag: "markdown" };
|
|
1577
1710
|
const elements = Array.isArray(property.elements) ? property.elements : [];
|
|
1578
|
-
const content = renderChildren(elements, ctx);
|
|
1711
|
+
const { content, uniformFontColor } = renderChildren(elements, ctx);
|
|
1579
1712
|
if (content) out.content = content;
|
|
1713
|
+
if (uniformFontColor) out.font_color = uniformFontColor;
|
|
1580
1714
|
for (const [rawKey, rawValue] of Object.entries(property)) {
|
|
1581
1715
|
if (rawKey === "elements" || rawKey === "markdownElements" || rawKey === "originTag") continue;
|
|
1582
1716
|
if (rawKey === "udIcon") continue;
|
|
@@ -1594,7 +1728,7 @@ function rebuildMarkdown(property, ctx) {
|
|
|
1594
1728
|
}
|
|
1595
1729
|
return out;
|
|
1596
1730
|
}
|
|
1597
|
-
function wrapEmphasis(text, bold, color) {
|
|
1731
|
+
function wrapEmphasis(text, bold, color, colorKind, inlineCustomFont = false) {
|
|
1598
1732
|
if (!bold && !color) return text;
|
|
1599
1733
|
const lead = text.match(/^\s*/)[0];
|
|
1600
1734
|
const trail = text.match(/\s*$/)[0];
|
|
@@ -1602,20 +1736,51 @@ function wrapEmphasis(text, bold, color) {
|
|
|
1602
1736
|
if (core.length === 0) return text;
|
|
1603
1737
|
let wrapped = core;
|
|
1604
1738
|
if (bold) wrapped = `**${wrapped}**`;
|
|
1605
|
-
if (color)
|
|
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
|
+
}
|
|
1606
1743
|
return lead + wrapped + trail;
|
|
1607
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
|
+
}
|
|
1608
1767
|
function renderChildren(children, ctx) {
|
|
1609
1768
|
let out = "";
|
|
1610
1769
|
let buffer = [];
|
|
1770
|
+
let uniformFontColor;
|
|
1611
1771
|
function flushBuffer() {
|
|
1612
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;
|
|
1613
1777
|
let group = [];
|
|
1614
1778
|
function emitGroup() {
|
|
1615
1779
|
if (group.length === 0) return;
|
|
1616
1780
|
const inner = group.map((s) => s.content).join("");
|
|
1617
|
-
const { bold, color } = group[0];
|
|
1618
|
-
|
|
1781
|
+
const { bold, color, colorKind } = group[0];
|
|
1782
|
+
const inlineCustomFont = colorKind === "custom" && !!color && color !== uniformCustom;
|
|
1783
|
+
out += wrapEmphasis(inner, bold, color, colorKind, inlineCustomFont);
|
|
1619
1784
|
group = [];
|
|
1620
1785
|
}
|
|
1621
1786
|
for (const seg of buffer) {
|
|
@@ -1624,8 +1789,9 @@ function renderChildren(children, ctx) {
|
|
|
1624
1789
|
continue;
|
|
1625
1790
|
}
|
|
1626
1791
|
const head = group[0];
|
|
1627
|
-
if (head.bold === seg.bold && head.color === seg.color
|
|
1628
|
-
|
|
1792
|
+
if (head.bold === seg.bold && head.color === seg.color && head.colorKind === seg.colorKind) {
|
|
1793
|
+
group.push(seg);
|
|
1794
|
+
} else {
|
|
1629
1795
|
emitGroup();
|
|
1630
1796
|
group.push(seg);
|
|
1631
1797
|
}
|
|
@@ -1644,33 +1810,33 @@ function renderChildren(children, ctx) {
|
|
|
1644
1810
|
out += childToMarkdown(child, ctx);
|
|
1645
1811
|
}
|
|
1646
1812
|
flushBuffer();
|
|
1647
|
-
return out;
|
|
1813
|
+
return { content: out, uniformFontColor };
|
|
1648
1814
|
}
|
|
1649
1815
|
function childToInlineSegment(child, ctx) {
|
|
1650
1816
|
const tag = child.tag;
|
|
1651
1817
|
const prop = isRecord2(child.property) ? child.property : {};
|
|
1652
1818
|
const ts = isRecord2(prop.textStyle) ? prop.textStyle : void 0;
|
|
1653
|
-
const bold
|
|
1654
|
-
const rawColor = resolveTextStyleColor(ts);
|
|
1655
|
-
const color = rawColor === "default" ? void 0 : rawColor;
|
|
1819
|
+
const { bold, color, colorKind } = resolveInlineStyle(ts, ctx);
|
|
1656
1820
|
switch (tag) {
|
|
1657
1821
|
case "plain_text":
|
|
1658
1822
|
return {
|
|
1659
1823
|
content: typeof prop.content === "string" ? prop.content : "",
|
|
1660
1824
|
bold,
|
|
1661
|
-
color
|
|
1825
|
+
color,
|
|
1826
|
+
colorKind
|
|
1662
1827
|
};
|
|
1663
1828
|
case "code_span":
|
|
1664
1829
|
return {
|
|
1665
1830
|
content: `\`${typeof prop.content === "string" ? prop.content : ""}\``,
|
|
1666
1831
|
bold,
|
|
1667
|
-
color
|
|
1832
|
+
color,
|
|
1833
|
+
colorKind
|
|
1668
1834
|
};
|
|
1669
1835
|
case "link": {
|
|
1670
1836
|
const text = typeof prop.content === "string" ? prop.content : "";
|
|
1671
1837
|
const urlObj = isRecord2(prop.url) ? prop.url : void 0;
|
|
1672
1838
|
const url = urlObj && typeof urlObj.url === "string" ? urlObj.url : "";
|
|
1673
|
-
return { content: `[${text}](${url})`, bold, color };
|
|
1839
|
+
return { content: `[${text}](${url})`, bold, color, colorKind };
|
|
1674
1840
|
}
|
|
1675
1841
|
case "at_all":
|
|
1676
1842
|
return { content: "<at id=all></at>", bold, color };
|
|
@@ -1710,10 +1876,8 @@ function childToMarkdown(child, ctx) {
|
|
|
1710
1876
|
case "plain_text": {
|
|
1711
1877
|
const content = typeof prop.content === "string" ? prop.content : "";
|
|
1712
1878
|
const ts = isRecord2(prop.textStyle) ? prop.textStyle : void 0;
|
|
1713
|
-
const
|
|
1714
|
-
|
|
1715
|
-
const attrs = ts && Array.isArray(ts.attributes) ? ts.attributes : [];
|
|
1716
|
-
return wrapEmphasis(content, attrs.includes("bold"), color);
|
|
1879
|
+
const { bold, color, colorKind } = resolveInlineStyle(ts, ctx);
|
|
1880
|
+
return wrapEmphasis(content, bold, color, colorKind, colorKind === "custom");
|
|
1717
1881
|
}
|
|
1718
1882
|
case "br":
|
|
1719
1883
|
return "\n";
|
|
@@ -1839,7 +2003,7 @@ ${"#".repeat(level)} ${body}
|
|
|
1839
2003
|
if (!data || data.tag !== "markdown") return "";
|
|
1840
2004
|
const cellProp = isRecord2(data.property) ? data.property : {};
|
|
1841
2005
|
const inner = Array.isArray(cellProp.elements) ? cellProp.elements : [];
|
|
1842
|
-
const text = renderChildren(inner, ctx);
|
|
2006
|
+
const { content: text } = renderChildren(inner, ctx);
|
|
1843
2007
|
return text.replace(/\|/g, "\\|").replace(/\n/g, " ");
|
|
1844
2008
|
});
|
|
1845
2009
|
return `| ${cells.join(" | ")} |`;
|
|
@@ -1962,10 +2126,10 @@ function rawToDsl(raw) {
|
|
|
1962
2126
|
}
|
|
1963
2127
|
}
|
|
1964
2128
|
const attachment = isRecord2(raw.json_attachment) ? raw.json_attachment : {};
|
|
1965
|
-
const ctx = {
|
|
2129
|
+
const ctx = makeCtx({
|
|
1966
2130
|
images: isRecord2(attachment.images) ? attachment.images : {},
|
|
1967
2131
|
atUsers: isRecord2(attachment.at_users) ? attachment.at_users : {}
|
|
1968
|
-
};
|
|
2132
|
+
});
|
|
1969
2133
|
return convertRoot(inner, ctx);
|
|
1970
2134
|
}
|
|
1971
2135
|
if (isRecord2(raw.card)) {
|
|
@@ -1973,10 +2137,10 @@ function rawToDsl(raw) {
|
|
|
1973
2137
|
if (typeof card.json_card === "string" || isRecord2(card.json_card)) {
|
|
1974
2138
|
return rawToDsl(card);
|
|
1975
2139
|
}
|
|
1976
|
-
return convertRoot(card,
|
|
2140
|
+
return convertRoot(card, makeCtx());
|
|
1977
2141
|
}
|
|
1978
2142
|
if ("body" in raw || "header" in raw || "schema" in raw) {
|
|
1979
|
-
return convertRoot(raw,
|
|
2143
|
+
return convertRoot(raw, makeCtx());
|
|
1980
2144
|
}
|
|
1981
2145
|
return raw;
|
|
1982
2146
|
}
|
|
@@ -1985,4 +2149,4 @@ function degradeUnknown(el) {
|
|
|
1985
2149
|
return { tag: "unknown", raw_tag: rawTag, fallback: el };
|
|
1986
2150
|
}
|
|
1987
2151
|
|
|
1988
|
-
export { degradeUnknown, dslToRaw, isRawCardEnvelope, normalizeStoredCardColors, rawCardToDsl, rawToDsl, readThemeColorLight, resolveCustomBackgroundLight, resolveTextStyleColor };
|
|
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
|
|
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;
|
|
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"}
|
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;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"}
|