@open-feishu-card/renderer 0.2.25 → 0.2.27
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/all.css +15 -23
- package/dist/index.cjs +123 -48
- package/dist/index.d.cts +6 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.js +123 -48
- package/dist/styles.css +15 -23
- package/package.json +2 -2
package/dist/index.cjs
CHANGED
|
@@ -1127,8 +1127,6 @@ var BASE_STYLES_CSS = `/**
|
|
|
1127
1127
|
.universal-card-header {
|
|
1128
1128
|
width: 100%;
|
|
1129
1129
|
overflow: hidden;
|
|
1130
|
-
border-top-left-radius: 8px;
|
|
1131
|
-
border-top-right-radius: 8px;
|
|
1132
1130
|
}
|
|
1133
1131
|
.universal-card-header__bg {
|
|
1134
1132
|
box-sizing: border-box;
|
|
@@ -1262,7 +1260,7 @@ var BASE_STYLES_CSS = `/**
|
|
|
1262
1260
|
line-height: 22px;
|
|
1263
1261
|
}
|
|
1264
1262
|
|
|
1265
|
-
/* ---- div
|
|
1263
|
+
/* ---- div ---- */
|
|
1266
1264
|
.universal-card-div > * + * { margin-top: 8px; }
|
|
1267
1265
|
/* div \u5E26\u524D\u7F6E\u56FE\u6807\uFF1Aicon \u5728\u5DE6\u3001\u6587\u672C\u5728\u53F3\u6392\u6210\u4E00\u884C\uFF08\u590D\u523B\u7F51\u9875\u7248 .universal-card-div \u5E03\u5C40\uFF09 */
|
|
1268
1266
|
.universal-card-div--with-icon {
|
|
@@ -1274,10 +1272,6 @@ var BASE_STYLES_CSS = `/**
|
|
|
1274
1272
|
display: flex; align-items: center; overflow: hidden;
|
|
1275
1273
|
}
|
|
1276
1274
|
.universal-card-div__content { flex: 1; min-width: 0; }
|
|
1277
|
-
.universal-card-note {
|
|
1278
|
-
font-size: 12px;
|
|
1279
|
-
color: #8f959e;
|
|
1280
|
-
}
|
|
1281
1275
|
|
|
1282
1276
|
/* ---- \u5E03\u5C40\uFF1Acolumn_set / column ---- */
|
|
1283
1277
|
.universal-card-column-set { display: flex; }
|
|
@@ -1306,6 +1300,7 @@ var BASE_STYLES_CSS = `/**
|
|
|
1306
1300
|
display: inline-flex; align-items: center; justify-content: center;
|
|
1307
1301
|
gap: 4px;
|
|
1308
1302
|
min-height: 28px; padding: 4px 12px;
|
|
1303
|
+
font-family: inherit;
|
|
1309
1304
|
font-size: 14px; line-height: 22px; border-radius: 6px;
|
|
1310
1305
|
border: 1px solid transparent; background: transparent; color: #1f2329;
|
|
1311
1306
|
cursor: pointer; text-decoration: none; box-sizing: border-box;
|
|
@@ -1318,14 +1313,9 @@ var BASE_STYLES_CSS = `/**
|
|
|
1318
1313
|
flex-shrink: 0; height: 1.2em; color: inherit;
|
|
1319
1314
|
}
|
|
1320
1315
|
.universal-card-button__icon .universal-card-icon { color: inherit; }
|
|
1321
|
-
/*
|
|
1322
|
-
|
|
1323
|
-
|
|
1324
|
-
width: auto;
|
|
1325
|
-
max-width: 100%;
|
|
1326
|
-
align-self: flex-start;
|
|
1327
|
-
}
|
|
1328
|
-
/* fill\uFF08width:"fill"\uFF09\uFF1A\u6491\u6EE1\u6240\u5728\u5217 */
|
|
1316
|
+
/* \u5BBD\u5EA6\uFF1A\u5BF9\u9F50\u771F\u673A\u2014\u2014body > * { width:100% }\u3001\u5217 flex stretch \u4F1A\u628A\u6309\u94AE\u6491\u6EE1\u6240\u5728\u884C/\u5217\u3002
|
|
1317
|
+
\u4E0D\u518D\u5F3A\u5236 width:auto\uFF08\u90A3\u662F\u7F51\u9875\u7248\u89C2\u611F\uFF1B\u771F\u673A\u72EC\u7ACB\u6210\u884C\u7684\u6309\u94AE\u9ED8\u8BA4\u5360\u6EE1\u6574\u884C\uFF09\u3002
|
|
1318
|
+
width:"fill" \u663E\u5F0F\u6302 --block\uFF0C\u4E0E\u7F3A\u7701\u6491\u6EE1\u540C\u5BBD\uFF0C\u5E76\u4F9B margin calc \u8BC6\u522B\u3002 */
|
|
1329
1319
|
.universal-card-button--block { width: 100%; }
|
|
1330
1320
|
|
|
1331
1321
|
/* \u2014\u2014 outlined \u63CF\u8FB9\u65CF \u2014\u2014 */
|
|
@@ -1347,11 +1337,12 @@ var BASE_STYLES_CSS = `/**
|
|
|
1347
1337
|
}
|
|
1348
1338
|
.universal-card-button--danger:not(.universal-card-button--static):hover { background: #fef0f0; }
|
|
1349
1339
|
|
|
1350
|
-
/* \u2014\u2014 text \u7EAF\u6587\u5B57\u65CF\uFF08\u65E0\u8FB9\u6846/\u65E0\u5E95\u8272\uFF0C\
|
|
1340
|
+
/* \u2014\u2014 text \u7EAF\u6587\u5B57\u65CF\uFF08\u65E0\u8FB9\u6846/\u65E0\u5E95\u8272\uFF1B\u6491\u6EE1\u65F6\u6587\u5B57\u9760\u5DE6\uFF0C\u5BF9\u9F50\u771F\u673A\uFF09 \u2014\u2014 */
|
|
1351
1341
|
.universal-card-button--text,
|
|
1352
1342
|
.universal-card-button--primary_text,
|
|
1353
1343
|
.universal-card-button--danger_text {
|
|
1354
1344
|
border-color: transparent; background: transparent; padding: 4px 8px;
|
|
1345
|
+
justify-content: flex-start;
|
|
1355
1346
|
}
|
|
1356
1347
|
.universal-card-button--text { color: #1f2329; }
|
|
1357
1348
|
.universal-card-button--primary_text { color: #1456f0; }
|
|
@@ -1384,17 +1375,19 @@ var BASE_STYLES_CSS = `/**
|
|
|
1384
1375
|
/* ---- \u8868\u5355\uFF08\u9884\u89C8\uFF1A\u4EC5\u900F\u4F20\uFF0C\u65E0\u8868\u5355\u8BED\u4E49\uFF09 ---- */
|
|
1385
1376
|
.universal-card-form { display: flex; flex-direction: column; row-gap: 8px; }
|
|
1386
1377
|
.universal-card-form > * { width: 100%; }
|
|
1387
|
-
/* input / select
|
|
1378
|
+
/* input / select\uFF1A\u9759\u6001\u9884\u89C8\u662F\u53EA\u8BFB\u6846\uFF1Binteractive \u53BB\u6389 --static\uFF0C\u6210\u4E3A\u53EF\u8F93\u5165\u63A7\u4EF6 */
|
|
1379
|
+
.universal-card-input,
|
|
1388
1380
|
.universal-card-input--static {
|
|
1389
1381
|
min-height: 32px; padding: 6px 12px; box-sizing: border-box;
|
|
1390
|
-
font-size: 14px; line-height: 20px;
|
|
1391
|
-
background: #
|
|
1382
|
+
font-family: inherit; font-size: 14px; line-height: 20px;
|
|
1383
|
+
background: #fff; border: 1px solid #dee0e3; border-radius: 6px;
|
|
1384
|
+
color: #1f2329; width: 100%;
|
|
1385
|
+
}
|
|
1386
|
+
.universal-card-input--static {
|
|
1387
|
+
color: #8f959e; background: #f5f6f7;
|
|
1392
1388
|
cursor: default; pointer-events: none;
|
|
1393
1389
|
}
|
|
1394
1390
|
|
|
1395
|
-
/* ---- action \u5BB9\u5668 ---- */
|
|
1396
|
-
.universal-card-action { display: flex; flex-wrap: wrap; gap: 12px; }
|
|
1397
|
-
|
|
1398
1391
|
/* ---- checker \u52FE\u9009\u5668\uFF08\u5BF9\u9F50\u7F51\u9875\u7248 universal-card-checker\uFF09 ---- */
|
|
1399
1392
|
.universal-card-checker {
|
|
1400
1393
|
display: flex; box-sizing: border-box; overflow: hidden; align-items: flex-start;
|
|
@@ -1985,7 +1978,6 @@ var BASE_STYLES_CSS = `/**
|
|
|
1985
1978
|
}
|
|
1986
1979
|
.universal-card-root.theme-dark .universal-card-markdown { color: #d6d6d6; }
|
|
1987
1980
|
.universal-card-root.theme-dark .universal-card-hr { background-color: #2e2e30; }
|
|
1988
|
-
.universal-card-root.theme-dark .universal-card-note { color: #8a8a8a; }
|
|
1989
1981
|
`;
|
|
1990
1982
|
|
|
1991
1983
|
// src/icon-font.ts
|
|
@@ -5612,10 +5604,6 @@ function registerBuiltins() {
|
|
|
5612
5604
|
}
|
|
5613
5605
|
return h("div", { className: `${CLS}-div` }, content);
|
|
5614
5606
|
});
|
|
5615
|
-
registerComponent(
|
|
5616
|
-
"note",
|
|
5617
|
-
(el, ctx) => h("div", { className: `${CLS}-note` }, renderElements(el.property?.elements, ctx))
|
|
5618
|
-
);
|
|
5619
5607
|
registerComponent("column_set", (el, ctx) => {
|
|
5620
5608
|
const p = el.property || {};
|
|
5621
5609
|
const gapRaw = p.horizontalSpacingValue?.value ?? p.horizontal_spacing;
|
|
@@ -5638,8 +5626,26 @@ function registerBuiltins() {
|
|
|
5638
5626
|
const pad = boxToStyle(p.padding);
|
|
5639
5627
|
if (pad) style.padding = pad;
|
|
5640
5628
|
const cls = `${CLS}-column-set` + (bg ? ` ${CLS}-column-set--bg` : "");
|
|
5629
|
+
if (isStateHost(el)) {
|
|
5630
|
+
style.position = "absolute";
|
|
5631
|
+
style.width = "0";
|
|
5632
|
+
style.height = "0";
|
|
5633
|
+
style.overflow = "hidden";
|
|
5634
|
+
style.margin = "0";
|
|
5635
|
+
style.padding = "0";
|
|
5636
|
+
}
|
|
5641
5637
|
return h("div", { className: cls, style }, renderElements(p.columns, ctx));
|
|
5642
5638
|
});
|
|
5639
|
+
function isStateHost(el) {
|
|
5640
|
+
if (el.id === "card_state") return true;
|
|
5641
|
+
const actions = el.property?.actions;
|
|
5642
|
+
if (!Array.isArray(actions)) return false;
|
|
5643
|
+
return actions.some((item) => {
|
|
5644
|
+
if (!item || typeof item !== "object") return false;
|
|
5645
|
+
const action = item.action;
|
|
5646
|
+
return typeof action?.url === "string" && action.url.includes("msgcard/unsupported_action#s1.");
|
|
5647
|
+
});
|
|
5648
|
+
}
|
|
5643
5649
|
registerComponent("column", (el, ctx) => {
|
|
5644
5650
|
const p = el.property || {};
|
|
5645
5651
|
const style = {
|
|
@@ -5978,40 +5984,115 @@ function registerBuiltins() {
|
|
|
5978
5984
|
const children = iconVNode ? [iconVNode, label] : [label];
|
|
5979
5985
|
const actionUrl = Array.isArray(p.actions) ? resolveURL(p.actions.find((a) => a.type === "open_url")?.action?.url) : "";
|
|
5980
5986
|
const url = actionUrl || resolveURL(p.url) || p.behaviors?.[0]?.default_url?.url;
|
|
5981
|
-
const isText = type === "text" || type === "primary_text" || type === "danger_text";
|
|
5982
5987
|
const wv = p.widthValue;
|
|
5983
5988
|
const widthTok = p.width ?? wv?.value;
|
|
5984
|
-
const block = widthTok === "fill"
|
|
5989
|
+
const block = widthTok === "fill";
|
|
5985
5990
|
const base = `${CLS}-button ${CLS}-button--${type}${block ? ` ${CLS}-button--block` : ""}`;
|
|
5986
5991
|
const style = {};
|
|
5987
5992
|
if (p.margin) {
|
|
5988
|
-
style.width =
|
|
5993
|
+
style.width = "100%";
|
|
5989
5994
|
applyOuterMargin(style, p.margin);
|
|
5990
5995
|
}
|
|
5991
5996
|
const styleProp = Object.keys(style).length ? { style } : {};
|
|
5997
|
+
const extra = p;
|
|
5998
|
+
const callback = readCallbackValue(extra);
|
|
5999
|
+
const formAction = String(extra.form_action_type ?? extra.formActionType ?? "");
|
|
6000
|
+
if (ctx.options.interactive && callback && !p.disabled && !url) {
|
|
6001
|
+
return h("button", {
|
|
6002
|
+
type: formAction === "reset" ? "reset" : formAction === "submit" ? "submit" : "button",
|
|
6003
|
+
className: base,
|
|
6004
|
+
"data-feishu-action": JSON.stringify(callback),
|
|
6005
|
+
"data-feishu-tag": "button",
|
|
6006
|
+
...styleProp
|
|
6007
|
+
}, children);
|
|
6008
|
+
}
|
|
5992
6009
|
if (url && !p.disabled) {
|
|
5993
6010
|
return h("a", { className: base, href: url, target: "_blank", rel: "noopener", ...styleProp }, children);
|
|
5994
6011
|
}
|
|
5995
6012
|
const cls = `${base} ${CLS}-button--static` + (p.disabled ? ` ${CLS}-button--disabled` : "");
|
|
5996
6013
|
return h("span", { className: cls, ...styleProp }, children);
|
|
5997
6014
|
});
|
|
5998
|
-
|
|
5999
|
-
"
|
|
6000
|
-
|
|
6001
|
-
)
|
|
6015
|
+
function isRecord(value) {
|
|
6016
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
6017
|
+
}
|
|
6018
|
+
function readCallbackValue(p) {
|
|
6019
|
+
const fromList = (list) => {
|
|
6020
|
+
if (!Array.isArray(list)) return null;
|
|
6021
|
+
for (const item of list) {
|
|
6022
|
+
if (!isRecord(item) || item.type !== "callback") continue;
|
|
6023
|
+
const inner = isRecord(item.action) ? item.action : item;
|
|
6024
|
+
if (isRecord(inner.value)) return inner.value;
|
|
6025
|
+
}
|
|
6026
|
+
return null;
|
|
6027
|
+
};
|
|
6028
|
+
return fromList(p.actions) ?? fromList(p.behaviors) ?? (isRecord(p.value) ? p.value : null);
|
|
6029
|
+
}
|
|
6030
|
+
registerComponent("form", (el, ctx) => {
|
|
6031
|
+
const children = renderElements(el.property?.elements, ctx);
|
|
6032
|
+
const className = `${CLS}-form`;
|
|
6033
|
+
if (!ctx.options.interactive) return h("div", { className }, children);
|
|
6034
|
+
const name = typeof el.property?.name === "string" ? el.property.name : "";
|
|
6035
|
+
return h("form", { className, "data-feishu-form": name }, children);
|
|
6036
|
+
});
|
|
6002
6037
|
function renderStaticField(el) {
|
|
6003
6038
|
const p = el.property || {};
|
|
6004
6039
|
const ph = extractPlainText(p.placeholder) || "";
|
|
6005
6040
|
return h("div", { className: `${CLS}-input ${CLS}-input--static` }, ph);
|
|
6006
6041
|
}
|
|
6007
|
-
|
|
6008
|
-
|
|
6009
|
-
|
|
6010
|
-
|
|
6011
|
-
|
|
6012
|
-
|
|
6013
|
-
|
|
6014
|
-
|
|
6042
|
+
function fieldText(value) {
|
|
6043
|
+
if (typeof value === "string") return value;
|
|
6044
|
+
return extractPlainText(value);
|
|
6045
|
+
}
|
|
6046
|
+
function renderInteractiveField(el) {
|
|
6047
|
+
const p = el.property || {};
|
|
6048
|
+
const ph = extractPlainText(p.placeholder) || "";
|
|
6049
|
+
const name = typeof p.name === "string" ? p.name : void 0;
|
|
6050
|
+
const nameProp = name ? { name } : {};
|
|
6051
|
+
const callback = readCallbackValue(p);
|
|
6052
|
+
const actionProp = callback ? { "data-feishu-action": JSON.stringify(callback), "data-feishu-tag": el.tag } : {};
|
|
6053
|
+
if (el.tag === "select_static" || el.tag === "multi_select_static") {
|
|
6054
|
+
const initial = p.initial_option ?? p.initialOption;
|
|
6055
|
+
const options = Array.isArray(p.options) ? p.options : [];
|
|
6056
|
+
return h("select", {
|
|
6057
|
+
className: `${CLS}-input`,
|
|
6058
|
+
...nameProp,
|
|
6059
|
+
...el.tag === "multi_select_static" ? { multiple: true } : {},
|
|
6060
|
+
...actionProp
|
|
6061
|
+
}, [
|
|
6062
|
+
h("option", { value: "" }, ph),
|
|
6063
|
+
...options.map((option) => {
|
|
6064
|
+
const item = isRecord(option) ? option : {};
|
|
6065
|
+
const value = typeof item.value === "string" ? item.value : fieldText(item.text ?? item);
|
|
6066
|
+
const label = fieldText(item.text ?? item.label) || value;
|
|
6067
|
+
return h("option", {
|
|
6068
|
+
value,
|
|
6069
|
+
...value !== "" && value === initial ? { selected: true } : {}
|
|
6070
|
+
}, label);
|
|
6071
|
+
})
|
|
6072
|
+
]);
|
|
6073
|
+
}
|
|
6074
|
+
const def = p.default_value ?? p.defaultValue;
|
|
6075
|
+
const inputType = el.tag === "date_picker" ? "date" : el.tag === "picker_time" ? "time" : "text";
|
|
6076
|
+
return h("input", {
|
|
6077
|
+
className: `${CLS}-input`,
|
|
6078
|
+
type: inputType,
|
|
6079
|
+
placeholder: ph,
|
|
6080
|
+
value: typeof def === "string" ? def : "",
|
|
6081
|
+
...nameProp,
|
|
6082
|
+
...actionProp
|
|
6083
|
+
});
|
|
6084
|
+
}
|
|
6085
|
+
function renderField(el, ctx) {
|
|
6086
|
+
return ctx.options.interactive ? renderInteractiveField(el) : renderStaticField(el);
|
|
6087
|
+
}
|
|
6088
|
+
registerComponent("input", (el, ctx) => renderField(el, ctx));
|
|
6089
|
+
registerComponent("multi_select_static", (el, ctx) => renderField(el, ctx));
|
|
6090
|
+
registerComponent("select_static", (el, ctx) => renderField(el, ctx));
|
|
6091
|
+
registerComponent("date_picker", (el, ctx) => renderField(el, ctx));
|
|
6092
|
+
registerComponent("picker_time", (el, ctx) => renderField(el, ctx));
|
|
6093
|
+
registerComponent("picker_datetime", (el, ctx) => renderField(el, ctx));
|
|
6094
|
+
registerComponent("select_person", (el, ctx) => renderField(el, ctx));
|
|
6095
|
+
registerComponent("multi_select_person", (el, ctx) => renderField(el, ctx));
|
|
6015
6096
|
registerComponent("checker", (el, ctx) => {
|
|
6016
6097
|
const p = el.property || {};
|
|
6017
6098
|
const checked = p.checked === true;
|
|
@@ -6083,12 +6164,6 @@ function registerBuiltins() {
|
|
|
6083
6164
|
const Tag = overall && !disabled ? "label" : "div";
|
|
6084
6165
|
return h(Tag, props, checkbox, content, buttonsVNode);
|
|
6085
6166
|
});
|
|
6086
|
-
registerComponent("action", (el, ctx) => {
|
|
6087
|
-
const p = el.property || {};
|
|
6088
|
-
const layout = p.layout || "flow";
|
|
6089
|
-
const style = { display: "flex", flexWrap: "wrap", gap: "12px" };
|
|
6090
|
-
return h("div", { className: `${CLS}-action ${CLS}-action--${layout}`, style }, renderElements(p.actions, ctx));
|
|
6091
|
-
});
|
|
6092
6167
|
registerComponent("at", (el, ctx) => {
|
|
6093
6168
|
const p = el.property || {};
|
|
6094
6169
|
if (p.userID === "all") {
|
package/dist/index.d.cts
CHANGED
|
@@ -305,6 +305,12 @@ interface RenderOptions {
|
|
|
305
305
|
avatarURLSuffix?: string;
|
|
306
306
|
/** 自定义头像地址解析:入参为命中的 PersonInfo,返回最终 src(优先级最高) */
|
|
307
307
|
resolvePersonAvatar?: (person: PersonInfo) => string | null | undefined;
|
|
308
|
+
/**
|
|
309
|
+
* 交互预览。默认关闭:回调按钮是不可点的 span,输入框是静态占位。
|
|
310
|
+
* 打开后,回调按钮变成带 data-feishu-action 的 button,输入框/下拉框变成真实表单控件。
|
|
311
|
+
* 宿主监听这些控件,自己把点击发回卡片服务。
|
|
312
|
+
*/
|
|
313
|
+
interactive?: boolean;
|
|
308
314
|
}
|
|
309
315
|
/**
|
|
310
316
|
* 人员信息:person_v1 / person_list / at 元素只带 ID,姓名与头像 key 在这里。
|
package/dist/index.d.ts
CHANGED
|
@@ -305,6 +305,12 @@ interface RenderOptions {
|
|
|
305
305
|
avatarURLSuffix?: string;
|
|
306
306
|
/** 自定义头像地址解析:入参为命中的 PersonInfo,返回最终 src(优先级最高) */
|
|
307
307
|
resolvePersonAvatar?: (person: PersonInfo) => string | null | undefined;
|
|
308
|
+
/**
|
|
309
|
+
* 交互预览。默认关闭:回调按钮是不可点的 span,输入框是静态占位。
|
|
310
|
+
* 打开后,回调按钮变成带 data-feishu-action 的 button,输入框/下拉框变成真实表单控件。
|
|
311
|
+
* 宿主监听这些控件,自己把点击发回卡片服务。
|
|
312
|
+
*/
|
|
313
|
+
interactive?: boolean;
|
|
308
314
|
}
|
|
309
315
|
/**
|
|
310
316
|
* 人员信息:person_v1 / person_list / at 元素只带 ID,姓名与头像 key 在这里。
|
package/dist/index.js
CHANGED
|
@@ -1126,8 +1126,6 @@ var BASE_STYLES_CSS = `/**
|
|
|
1126
1126
|
.universal-card-header {
|
|
1127
1127
|
width: 100%;
|
|
1128
1128
|
overflow: hidden;
|
|
1129
|
-
border-top-left-radius: 8px;
|
|
1130
|
-
border-top-right-radius: 8px;
|
|
1131
1129
|
}
|
|
1132
1130
|
.universal-card-header__bg {
|
|
1133
1131
|
box-sizing: border-box;
|
|
@@ -1261,7 +1259,7 @@ var BASE_STYLES_CSS = `/**
|
|
|
1261
1259
|
line-height: 22px;
|
|
1262
1260
|
}
|
|
1263
1261
|
|
|
1264
|
-
/* ---- div
|
|
1262
|
+
/* ---- div ---- */
|
|
1265
1263
|
.universal-card-div > * + * { margin-top: 8px; }
|
|
1266
1264
|
/* div \u5E26\u524D\u7F6E\u56FE\u6807\uFF1Aicon \u5728\u5DE6\u3001\u6587\u672C\u5728\u53F3\u6392\u6210\u4E00\u884C\uFF08\u590D\u523B\u7F51\u9875\u7248 .universal-card-div \u5E03\u5C40\uFF09 */
|
|
1267
1265
|
.universal-card-div--with-icon {
|
|
@@ -1273,10 +1271,6 @@ var BASE_STYLES_CSS = `/**
|
|
|
1273
1271
|
display: flex; align-items: center; overflow: hidden;
|
|
1274
1272
|
}
|
|
1275
1273
|
.universal-card-div__content { flex: 1; min-width: 0; }
|
|
1276
|
-
.universal-card-note {
|
|
1277
|
-
font-size: 12px;
|
|
1278
|
-
color: #8f959e;
|
|
1279
|
-
}
|
|
1280
1274
|
|
|
1281
1275
|
/* ---- \u5E03\u5C40\uFF1Acolumn_set / column ---- */
|
|
1282
1276
|
.universal-card-column-set { display: flex; }
|
|
@@ -1305,6 +1299,7 @@ var BASE_STYLES_CSS = `/**
|
|
|
1305
1299
|
display: inline-flex; align-items: center; justify-content: center;
|
|
1306
1300
|
gap: 4px;
|
|
1307
1301
|
min-height: 28px; padding: 4px 12px;
|
|
1302
|
+
font-family: inherit;
|
|
1308
1303
|
font-size: 14px; line-height: 22px; border-radius: 6px;
|
|
1309
1304
|
border: 1px solid transparent; background: transparent; color: #1f2329;
|
|
1310
1305
|
cursor: pointer; text-decoration: none; box-sizing: border-box;
|
|
@@ -1317,14 +1312,9 @@ var BASE_STYLES_CSS = `/**
|
|
|
1317
1312
|
flex-shrink: 0; height: 1.2em; color: inherit;
|
|
1318
1313
|
}
|
|
1319
1314
|
.universal-card-button__icon .universal-card-icon { color: inherit; }
|
|
1320
|
-
/*
|
|
1321
|
-
|
|
1322
|
-
|
|
1323
|
-
width: auto;
|
|
1324
|
-
max-width: 100%;
|
|
1325
|
-
align-self: flex-start;
|
|
1326
|
-
}
|
|
1327
|
-
/* fill\uFF08width:"fill"\uFF09\uFF1A\u6491\u6EE1\u6240\u5728\u5217 */
|
|
1315
|
+
/* \u5BBD\u5EA6\uFF1A\u5BF9\u9F50\u771F\u673A\u2014\u2014body > * { width:100% }\u3001\u5217 flex stretch \u4F1A\u628A\u6309\u94AE\u6491\u6EE1\u6240\u5728\u884C/\u5217\u3002
|
|
1316
|
+
\u4E0D\u518D\u5F3A\u5236 width:auto\uFF08\u90A3\u662F\u7F51\u9875\u7248\u89C2\u611F\uFF1B\u771F\u673A\u72EC\u7ACB\u6210\u884C\u7684\u6309\u94AE\u9ED8\u8BA4\u5360\u6EE1\u6574\u884C\uFF09\u3002
|
|
1317
|
+
width:"fill" \u663E\u5F0F\u6302 --block\uFF0C\u4E0E\u7F3A\u7701\u6491\u6EE1\u540C\u5BBD\uFF0C\u5E76\u4F9B margin calc \u8BC6\u522B\u3002 */
|
|
1328
1318
|
.universal-card-button--block { width: 100%; }
|
|
1329
1319
|
|
|
1330
1320
|
/* \u2014\u2014 outlined \u63CF\u8FB9\u65CF \u2014\u2014 */
|
|
@@ -1346,11 +1336,12 @@ var BASE_STYLES_CSS = `/**
|
|
|
1346
1336
|
}
|
|
1347
1337
|
.universal-card-button--danger:not(.universal-card-button--static):hover { background: #fef0f0; }
|
|
1348
1338
|
|
|
1349
|
-
/* \u2014\u2014 text \u7EAF\u6587\u5B57\u65CF\uFF08\u65E0\u8FB9\u6846/\u65E0\u5E95\u8272\uFF0C\
|
|
1339
|
+
/* \u2014\u2014 text \u7EAF\u6587\u5B57\u65CF\uFF08\u65E0\u8FB9\u6846/\u65E0\u5E95\u8272\uFF1B\u6491\u6EE1\u65F6\u6587\u5B57\u9760\u5DE6\uFF0C\u5BF9\u9F50\u771F\u673A\uFF09 \u2014\u2014 */
|
|
1350
1340
|
.universal-card-button--text,
|
|
1351
1341
|
.universal-card-button--primary_text,
|
|
1352
1342
|
.universal-card-button--danger_text {
|
|
1353
1343
|
border-color: transparent; background: transparent; padding: 4px 8px;
|
|
1344
|
+
justify-content: flex-start;
|
|
1354
1345
|
}
|
|
1355
1346
|
.universal-card-button--text { color: #1f2329; }
|
|
1356
1347
|
.universal-card-button--primary_text { color: #1456f0; }
|
|
@@ -1383,17 +1374,19 @@ var BASE_STYLES_CSS = `/**
|
|
|
1383
1374
|
/* ---- \u8868\u5355\uFF08\u9884\u89C8\uFF1A\u4EC5\u900F\u4F20\uFF0C\u65E0\u8868\u5355\u8BED\u4E49\uFF09 ---- */
|
|
1384
1375
|
.universal-card-form { display: flex; flex-direction: column; row-gap: 8px; }
|
|
1385
1376
|
.universal-card-form > * { width: 100%; }
|
|
1386
|
-
/* input / select
|
|
1377
|
+
/* input / select\uFF1A\u9759\u6001\u9884\u89C8\u662F\u53EA\u8BFB\u6846\uFF1Binteractive \u53BB\u6389 --static\uFF0C\u6210\u4E3A\u53EF\u8F93\u5165\u63A7\u4EF6 */
|
|
1378
|
+
.universal-card-input,
|
|
1387
1379
|
.universal-card-input--static {
|
|
1388
1380
|
min-height: 32px; padding: 6px 12px; box-sizing: border-box;
|
|
1389
|
-
font-size: 14px; line-height: 20px;
|
|
1390
|
-
background: #
|
|
1381
|
+
font-family: inherit; font-size: 14px; line-height: 20px;
|
|
1382
|
+
background: #fff; border: 1px solid #dee0e3; border-radius: 6px;
|
|
1383
|
+
color: #1f2329; width: 100%;
|
|
1384
|
+
}
|
|
1385
|
+
.universal-card-input--static {
|
|
1386
|
+
color: #8f959e; background: #f5f6f7;
|
|
1391
1387
|
cursor: default; pointer-events: none;
|
|
1392
1388
|
}
|
|
1393
1389
|
|
|
1394
|
-
/* ---- action \u5BB9\u5668 ---- */
|
|
1395
|
-
.universal-card-action { display: flex; flex-wrap: wrap; gap: 12px; }
|
|
1396
|
-
|
|
1397
1390
|
/* ---- checker \u52FE\u9009\u5668\uFF08\u5BF9\u9F50\u7F51\u9875\u7248 universal-card-checker\uFF09 ---- */
|
|
1398
1391
|
.universal-card-checker {
|
|
1399
1392
|
display: flex; box-sizing: border-box; overflow: hidden; align-items: flex-start;
|
|
@@ -1984,7 +1977,6 @@ var BASE_STYLES_CSS = `/**
|
|
|
1984
1977
|
}
|
|
1985
1978
|
.universal-card-root.theme-dark .universal-card-markdown { color: #d6d6d6; }
|
|
1986
1979
|
.universal-card-root.theme-dark .universal-card-hr { background-color: #2e2e30; }
|
|
1987
|
-
.universal-card-root.theme-dark .universal-card-note { color: #8a8a8a; }
|
|
1988
1980
|
`;
|
|
1989
1981
|
|
|
1990
1982
|
// src/icon-font.ts
|
|
@@ -5611,10 +5603,6 @@ function registerBuiltins() {
|
|
|
5611
5603
|
}
|
|
5612
5604
|
return h("div", { className: `${CLS}-div` }, content);
|
|
5613
5605
|
});
|
|
5614
|
-
registerComponent(
|
|
5615
|
-
"note",
|
|
5616
|
-
(el, ctx) => h("div", { className: `${CLS}-note` }, renderElements(el.property?.elements, ctx))
|
|
5617
|
-
);
|
|
5618
5606
|
registerComponent("column_set", (el, ctx) => {
|
|
5619
5607
|
const p = el.property || {};
|
|
5620
5608
|
const gapRaw = p.horizontalSpacingValue?.value ?? p.horizontal_spacing;
|
|
@@ -5637,8 +5625,26 @@ function registerBuiltins() {
|
|
|
5637
5625
|
const pad = boxToStyle(p.padding);
|
|
5638
5626
|
if (pad) style.padding = pad;
|
|
5639
5627
|
const cls = `${CLS}-column-set` + (bg ? ` ${CLS}-column-set--bg` : "");
|
|
5628
|
+
if (isStateHost(el)) {
|
|
5629
|
+
style.position = "absolute";
|
|
5630
|
+
style.width = "0";
|
|
5631
|
+
style.height = "0";
|
|
5632
|
+
style.overflow = "hidden";
|
|
5633
|
+
style.margin = "0";
|
|
5634
|
+
style.padding = "0";
|
|
5635
|
+
}
|
|
5640
5636
|
return h("div", { className: cls, style }, renderElements(p.columns, ctx));
|
|
5641
5637
|
});
|
|
5638
|
+
function isStateHost(el) {
|
|
5639
|
+
if (el.id === "card_state") return true;
|
|
5640
|
+
const actions = el.property?.actions;
|
|
5641
|
+
if (!Array.isArray(actions)) return false;
|
|
5642
|
+
return actions.some((item) => {
|
|
5643
|
+
if (!item || typeof item !== "object") return false;
|
|
5644
|
+
const action = item.action;
|
|
5645
|
+
return typeof action?.url === "string" && action.url.includes("msgcard/unsupported_action#s1.");
|
|
5646
|
+
});
|
|
5647
|
+
}
|
|
5642
5648
|
registerComponent("column", (el, ctx) => {
|
|
5643
5649
|
const p = el.property || {};
|
|
5644
5650
|
const style = {
|
|
@@ -5977,40 +5983,115 @@ function registerBuiltins() {
|
|
|
5977
5983
|
const children = iconVNode ? [iconVNode, label] : [label];
|
|
5978
5984
|
const actionUrl = Array.isArray(p.actions) ? resolveURL(p.actions.find((a) => a.type === "open_url")?.action?.url) : "";
|
|
5979
5985
|
const url = actionUrl || resolveURL(p.url) || p.behaviors?.[0]?.default_url?.url;
|
|
5980
|
-
const isText = type === "text" || type === "primary_text" || type === "danger_text";
|
|
5981
5986
|
const wv = p.widthValue;
|
|
5982
5987
|
const widthTok = p.width ?? wv?.value;
|
|
5983
|
-
const block = widthTok === "fill"
|
|
5988
|
+
const block = widthTok === "fill";
|
|
5984
5989
|
const base = `${CLS}-button ${CLS}-button--${type}${block ? ` ${CLS}-button--block` : ""}`;
|
|
5985
5990
|
const style = {};
|
|
5986
5991
|
if (p.margin) {
|
|
5987
|
-
style.width =
|
|
5992
|
+
style.width = "100%";
|
|
5988
5993
|
applyOuterMargin(style, p.margin);
|
|
5989
5994
|
}
|
|
5990
5995
|
const styleProp = Object.keys(style).length ? { style } : {};
|
|
5996
|
+
const extra = p;
|
|
5997
|
+
const callback = readCallbackValue(extra);
|
|
5998
|
+
const formAction = String(extra.form_action_type ?? extra.formActionType ?? "");
|
|
5999
|
+
if (ctx.options.interactive && callback && !p.disabled && !url) {
|
|
6000
|
+
return h("button", {
|
|
6001
|
+
type: formAction === "reset" ? "reset" : formAction === "submit" ? "submit" : "button",
|
|
6002
|
+
className: base,
|
|
6003
|
+
"data-feishu-action": JSON.stringify(callback),
|
|
6004
|
+
"data-feishu-tag": "button",
|
|
6005
|
+
...styleProp
|
|
6006
|
+
}, children);
|
|
6007
|
+
}
|
|
5991
6008
|
if (url && !p.disabled) {
|
|
5992
6009
|
return h("a", { className: base, href: url, target: "_blank", rel: "noopener", ...styleProp }, children);
|
|
5993
6010
|
}
|
|
5994
6011
|
const cls = `${base} ${CLS}-button--static` + (p.disabled ? ` ${CLS}-button--disabled` : "");
|
|
5995
6012
|
return h("span", { className: cls, ...styleProp }, children);
|
|
5996
6013
|
});
|
|
5997
|
-
|
|
5998
|
-
"
|
|
5999
|
-
|
|
6000
|
-
)
|
|
6014
|
+
function isRecord(value) {
|
|
6015
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
6016
|
+
}
|
|
6017
|
+
function readCallbackValue(p) {
|
|
6018
|
+
const fromList = (list) => {
|
|
6019
|
+
if (!Array.isArray(list)) return null;
|
|
6020
|
+
for (const item of list) {
|
|
6021
|
+
if (!isRecord(item) || item.type !== "callback") continue;
|
|
6022
|
+
const inner = isRecord(item.action) ? item.action : item;
|
|
6023
|
+
if (isRecord(inner.value)) return inner.value;
|
|
6024
|
+
}
|
|
6025
|
+
return null;
|
|
6026
|
+
};
|
|
6027
|
+
return fromList(p.actions) ?? fromList(p.behaviors) ?? (isRecord(p.value) ? p.value : null);
|
|
6028
|
+
}
|
|
6029
|
+
registerComponent("form", (el, ctx) => {
|
|
6030
|
+
const children = renderElements(el.property?.elements, ctx);
|
|
6031
|
+
const className = `${CLS}-form`;
|
|
6032
|
+
if (!ctx.options.interactive) return h("div", { className }, children);
|
|
6033
|
+
const name = typeof el.property?.name === "string" ? el.property.name : "";
|
|
6034
|
+
return h("form", { className, "data-feishu-form": name }, children);
|
|
6035
|
+
});
|
|
6001
6036
|
function renderStaticField(el) {
|
|
6002
6037
|
const p = el.property || {};
|
|
6003
6038
|
const ph = extractPlainText(p.placeholder) || "";
|
|
6004
6039
|
return h("div", { className: `${CLS}-input ${CLS}-input--static` }, ph);
|
|
6005
6040
|
}
|
|
6006
|
-
|
|
6007
|
-
|
|
6008
|
-
|
|
6009
|
-
|
|
6010
|
-
|
|
6011
|
-
|
|
6012
|
-
|
|
6013
|
-
|
|
6041
|
+
function fieldText(value) {
|
|
6042
|
+
if (typeof value === "string") return value;
|
|
6043
|
+
return extractPlainText(value);
|
|
6044
|
+
}
|
|
6045
|
+
function renderInteractiveField(el) {
|
|
6046
|
+
const p = el.property || {};
|
|
6047
|
+
const ph = extractPlainText(p.placeholder) || "";
|
|
6048
|
+
const name = typeof p.name === "string" ? p.name : void 0;
|
|
6049
|
+
const nameProp = name ? { name } : {};
|
|
6050
|
+
const callback = readCallbackValue(p);
|
|
6051
|
+
const actionProp = callback ? { "data-feishu-action": JSON.stringify(callback), "data-feishu-tag": el.tag } : {};
|
|
6052
|
+
if (el.tag === "select_static" || el.tag === "multi_select_static") {
|
|
6053
|
+
const initial = p.initial_option ?? p.initialOption;
|
|
6054
|
+
const options = Array.isArray(p.options) ? p.options : [];
|
|
6055
|
+
return h("select", {
|
|
6056
|
+
className: `${CLS}-input`,
|
|
6057
|
+
...nameProp,
|
|
6058
|
+
...el.tag === "multi_select_static" ? { multiple: true } : {},
|
|
6059
|
+
...actionProp
|
|
6060
|
+
}, [
|
|
6061
|
+
h("option", { value: "" }, ph),
|
|
6062
|
+
...options.map((option) => {
|
|
6063
|
+
const item = isRecord(option) ? option : {};
|
|
6064
|
+
const value = typeof item.value === "string" ? item.value : fieldText(item.text ?? item);
|
|
6065
|
+
const label = fieldText(item.text ?? item.label) || value;
|
|
6066
|
+
return h("option", {
|
|
6067
|
+
value,
|
|
6068
|
+
...value !== "" && value === initial ? { selected: true } : {}
|
|
6069
|
+
}, label);
|
|
6070
|
+
})
|
|
6071
|
+
]);
|
|
6072
|
+
}
|
|
6073
|
+
const def = p.default_value ?? p.defaultValue;
|
|
6074
|
+
const inputType = el.tag === "date_picker" ? "date" : el.tag === "picker_time" ? "time" : "text";
|
|
6075
|
+
return h("input", {
|
|
6076
|
+
className: `${CLS}-input`,
|
|
6077
|
+
type: inputType,
|
|
6078
|
+
placeholder: ph,
|
|
6079
|
+
value: typeof def === "string" ? def : "",
|
|
6080
|
+
...nameProp,
|
|
6081
|
+
...actionProp
|
|
6082
|
+
});
|
|
6083
|
+
}
|
|
6084
|
+
function renderField(el, ctx) {
|
|
6085
|
+
return ctx.options.interactive ? renderInteractiveField(el) : renderStaticField(el);
|
|
6086
|
+
}
|
|
6087
|
+
registerComponent("input", (el, ctx) => renderField(el, ctx));
|
|
6088
|
+
registerComponent("multi_select_static", (el, ctx) => renderField(el, ctx));
|
|
6089
|
+
registerComponent("select_static", (el, ctx) => renderField(el, ctx));
|
|
6090
|
+
registerComponent("date_picker", (el, ctx) => renderField(el, ctx));
|
|
6091
|
+
registerComponent("picker_time", (el, ctx) => renderField(el, ctx));
|
|
6092
|
+
registerComponent("picker_datetime", (el, ctx) => renderField(el, ctx));
|
|
6093
|
+
registerComponent("select_person", (el, ctx) => renderField(el, ctx));
|
|
6094
|
+
registerComponent("multi_select_person", (el, ctx) => renderField(el, ctx));
|
|
6014
6095
|
registerComponent("checker", (el, ctx) => {
|
|
6015
6096
|
const p = el.property || {};
|
|
6016
6097
|
const checked = p.checked === true;
|
|
@@ -6082,12 +6163,6 @@ function registerBuiltins() {
|
|
|
6082
6163
|
const Tag = overall && !disabled ? "label" : "div";
|
|
6083
6164
|
return h(Tag, props, checkbox, content, buttonsVNode);
|
|
6084
6165
|
});
|
|
6085
|
-
registerComponent("action", (el, ctx) => {
|
|
6086
|
-
const p = el.property || {};
|
|
6087
|
-
const layout = p.layout || "flow";
|
|
6088
|
-
const style = { display: "flex", flexWrap: "wrap", gap: "12px" };
|
|
6089
|
-
return h("div", { className: `${CLS}-action ${CLS}-action--${layout}`, style }, renderElements(p.actions, ctx));
|
|
6090
|
-
});
|
|
6091
6166
|
registerComponent("at", (el, ctx) => {
|
|
6092
6167
|
const p = el.property || {};
|
|
6093
6168
|
if (p.userID === "all") {
|