@open-feishu-card/renderer 0.2.15 → 0.2.17

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 CHANGED
@@ -306,6 +306,33 @@
306
306
  margin: 8px 0;
307
307
  }
308
308
 
309
+ .universal-card-collapse-divider {
310
+ width: 100%;
311
+ height: 1px;
312
+ background-color: #dee0e3;
313
+ border: none;
314
+ margin: 8px 0;
315
+ }
316
+
317
+ .universal-card-avatar {
318
+ display: inline-flex;
319
+ align-items: center;
320
+ vertical-align: middle;
321
+ }
322
+
323
+ .universal-card-avatar__img {
324
+ border-radius: 50%;
325
+ object-fit: cover;
326
+ display: block;
327
+ background: #eff0f1;
328
+ }
329
+
330
+ .universal-card-fallback-text {
331
+ color: #646a73;
332
+ font-size: 14px;
333
+ line-height: 22px;
334
+ }
335
+
309
336
  /* ---- div / note ---- */
310
337
  .universal-card-div > * + * { margin-top: 8px; }
311
338
  /* div 带前置图标:icon 在左、文本在右排成一行(复刻网页版 .universal-card-div 布局) */
@@ -531,6 +558,7 @@
531
558
  box-sizing: border-box; overflow: hidden;
532
559
  }
533
560
  /* header(<summary>):可点击整行;去掉浏览器默认三角标记。
561
+ 真机 color:var(--text-caption) → N600;标题/箭头继承此色。
534
562
  默认 title flex:1 把箭头推到右侧(icon_position=right);
535
563
  icon_position=left 时靠 DOM 顺序在左。 */
536
564
  .universal-card-collapsible-panel__header {
@@ -538,11 +566,12 @@
538
566
  padding: 8px 12px;
539
567
  cursor: pointer; box-sizing: border-box;
540
568
  list-style: none; user-select: none;
569
+ color: var(--N600);
541
570
  }
542
571
  .universal-card-collapsible-panel__header::-webkit-details-marker { display: none; }
543
572
  .universal-card-collapsible-panel__header::marker { content: ''; }
544
573
  .universal-card-collapsible-panel__title {
545
- flex: 1; min-width: 0; font-size: 14px; line-height: 22px; color: #1f2329;
574
+ flex: 1; min-width: 0; font-size: 14px; line-height: 22px;
546
575
  word-break: break-word;
547
576
  }
548
577
  /* follow_text:箭头紧贴文字(真机 __header-content--icon-follow),不拉满整行 */
@@ -554,10 +583,10 @@
554
583
  width: auto;
555
584
  }
556
585
  /* 箭头图标包裹:收起态角度 0;展开态(details[open])旋转到 --panel-icon-angle(内联给出,默认 -180deg)。
557
- 由用户点击 <summary> 切换 [open],箭头方向随之自动更新,无需 JS。 */
586
+ 由用户点击 <summary> 切换 [open],箭头方向随之自动更新,无需 JS。颜色继承 header caption。 */
558
587
  .universal-card-collapsible-panel__icon {
559
588
  flex-shrink: 0; display: inline-flex; align-items: center; justify-content: center;
560
- transition: transform .2s; color: #646a73; transform: rotate(0deg);
589
+ transition: transform .2s; transform: rotate(0deg);
561
590
  }
562
591
  .universal-card-collapsible-panel[open] .universal-card-collapsible-panel__icon {
563
592
  transform: rotate(var(--panel-icon-angle, -180deg));
package/dist/index.cjs CHANGED
@@ -1228,6 +1228,33 @@ var BASE_STYLES_CSS = `/**
1228
1228
  margin: 8px 0;
1229
1229
  }
1230
1230
 
1231
+ .universal-card-collapse-divider {
1232
+ width: 100%;
1233
+ height: 1px;
1234
+ background-color: #dee0e3;
1235
+ border: none;
1236
+ margin: 8px 0;
1237
+ }
1238
+
1239
+ .universal-card-avatar {
1240
+ display: inline-flex;
1241
+ align-items: center;
1242
+ vertical-align: middle;
1243
+ }
1244
+
1245
+ .universal-card-avatar__img {
1246
+ border-radius: 50%;
1247
+ object-fit: cover;
1248
+ display: block;
1249
+ background: #eff0f1;
1250
+ }
1251
+
1252
+ .universal-card-fallback-text {
1253
+ color: #646a73;
1254
+ font-size: 14px;
1255
+ line-height: 22px;
1256
+ }
1257
+
1231
1258
  /* ---- div / note ---- */
1232
1259
  .universal-card-div > * + * { margin-top: 8px; }
1233
1260
  /* 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 */
@@ -1453,6 +1480,7 @@ var BASE_STYLES_CSS = `/**
1453
1480
  box-sizing: border-box; overflow: hidden;
1454
1481
  }
1455
1482
  /* header\uFF08<summary>\uFF09\uFF1A\u53EF\u70B9\u51FB\u6574\u884C\uFF1B\u53BB\u6389\u6D4F\u89C8\u5668\u9ED8\u8BA4\u4E09\u89D2\u6807\u8BB0\u3002
1483
+ \u771F\u673A color:var(--text-caption) \u2192 N600\uFF1B\u6807\u9898/\u7BAD\u5934\u7EE7\u627F\u6B64\u8272\u3002
1456
1484
  \u9ED8\u8BA4 title flex:1 \u628A\u7BAD\u5934\u63A8\u5230\u53F3\u4FA7\uFF08icon_position=right\uFF09\uFF1B
1457
1485
  icon_position=left \u65F6\u9760 DOM \u987A\u5E8F\u5728\u5DE6\u3002 */
1458
1486
  .universal-card-collapsible-panel__header {
@@ -1460,11 +1488,12 @@ var BASE_STYLES_CSS = `/**
1460
1488
  padding: 8px 12px;
1461
1489
  cursor: pointer; box-sizing: border-box;
1462
1490
  list-style: none; user-select: none;
1491
+ color: var(--N600);
1463
1492
  }
1464
1493
  .universal-card-collapsible-panel__header::-webkit-details-marker { display: none; }
1465
1494
  .universal-card-collapsible-panel__header::marker { content: ''; }
1466
1495
  .universal-card-collapsible-panel__title {
1467
- flex: 1; min-width: 0; font-size: 14px; line-height: 22px; color: #1f2329;
1496
+ flex: 1; min-width: 0; font-size: 14px; line-height: 22px;
1468
1497
  word-break: break-word;
1469
1498
  }
1470
1499
  /* follow_text\uFF1A\u7BAD\u5934\u7D27\u8D34\u6587\u5B57\uFF08\u771F\u673A __header-content--icon-follow\uFF09\uFF0C\u4E0D\u62C9\u6EE1\u6574\u884C */
@@ -1476,10 +1505,10 @@ var BASE_STYLES_CSS = `/**
1476
1505
  width: auto;
1477
1506
  }
1478
1507
  /* \u7BAD\u5934\u56FE\u6807\u5305\u88F9\uFF1A\u6536\u8D77\u6001\u89D2\u5EA6 0\uFF1B\u5C55\u5F00\u6001\uFF08details[open]\uFF09\u65CB\u8F6C\u5230 --panel-icon-angle\uFF08\u5185\u8054\u7ED9\u51FA\uFF0C\u9ED8\u8BA4 -180deg\uFF09\u3002
1479
- \u7531\u7528\u6237\u70B9\u51FB <summary> \u5207\u6362 [open]\uFF0C\u7BAD\u5934\u65B9\u5411\u968F\u4E4B\u81EA\u52A8\u66F4\u65B0\uFF0C\u65E0\u9700 JS\u3002 */
1508
+ \u7531\u7528\u6237\u70B9\u51FB <summary> \u5207\u6362 [open]\uFF0C\u7BAD\u5934\u65B9\u5411\u968F\u4E4B\u81EA\u52A8\u66F4\u65B0\uFF0C\u65E0\u9700 JS\u3002\u989C\u8272\u7EE7\u627F header caption\u3002 */
1480
1509
  .universal-card-collapsible-panel__icon {
1481
1510
  flex-shrink: 0; display: inline-flex; align-items: center; justify-content: center;
1482
- transition: transform .2s; color: #646a73; transform: rotate(0deg);
1511
+ transition: transform .2s; transform: rotate(0deg);
1483
1512
  }
1484
1513
  .universal-card-collapsible-panel[open] .universal-card-collapsible-panel__icon {
1485
1514
  transform: rotate(var(--panel-icon-angle, -180deg));
@@ -5956,6 +5985,11 @@ function registerBuiltins() {
5956
5985
  registerComponent("input", (el) => renderStaticField(el));
5957
5986
  registerComponent("multi_select_static", (el) => renderStaticField(el));
5958
5987
  registerComponent("select_static", (el) => renderStaticField(el));
5988
+ registerComponent("date_picker", (el) => renderStaticField(el));
5989
+ registerComponent("picker_time", (el) => renderStaticField(el));
5990
+ registerComponent("picker_datetime", (el) => renderStaticField(el));
5991
+ registerComponent("select_person", (el) => renderStaticField(el));
5992
+ registerComponent("multi_select_person", (el) => renderStaticField(el));
5959
5993
  registerComponent("checker", (el, ctx) => {
5960
5994
  const p = el.property || {};
5961
5995
  const checked = p.checked === true;
@@ -6103,6 +6137,40 @@ function registerBuiltins() {
6103
6137
  const p = el.property || {};
6104
6138
  return renderPersonChip(p.userID, p, ctx);
6105
6139
  });
6140
+ const AVATAR_SIZE_PX = {
6141
+ tiny: 16,
6142
+ small: 24,
6143
+ medium: 32,
6144
+ large: 40,
6145
+ huge: 48
6146
+ };
6147
+ registerComponent("avatar", (el, ctx) => {
6148
+ const p = el.property || {};
6149
+ const userID = p.userID || p.user_id;
6150
+ const sizeKey = String(p.size ?? "medium");
6151
+ const custom = typeof p.customSize === "number" ? p.customSize : typeof p.custom_size === "number" ? p.custom_size : void 0;
6152
+ const px = sizeKey === "custom" && typeof custom === "number" && custom > 0 ? custom : AVATAR_SIZE_PX[sizeKey] || AVATAR_SIZE_PX.medium;
6153
+ const { name, src } = resolvePersonDisplay(userID, ctx);
6154
+ return h(
6155
+ "div",
6156
+ { className: `${CLS}-avatar`, title: name },
6157
+ renderAvatarNode(`${CLS}-avatar__img`, px, src, name)
6158
+ );
6159
+ });
6160
+ registerComponent(
6161
+ "collapse_divider",
6162
+ () => h("div", { className: `${CLS}-collapse-divider` })
6163
+ );
6164
+ registerComponent("fallback_text", (el, ctx) => {
6165
+ const p = el.property || {};
6166
+ const textEl = p.text;
6167
+ if (textEl && typeof textEl === "object" && textEl.tag) {
6168
+ return h("div", { className: `${CLS}-fallback-text` }, renderElement(textEl, ctx));
6169
+ }
6170
+ const content = extractPlainText(p.text);
6171
+ if (!content) return null;
6172
+ return h("div", { className: `${CLS}-fallback-text` }, content);
6173
+ });
6106
6174
  registerComponent("person_list", (el, ctx) => {
6107
6175
  const p = el.property || {};
6108
6176
  const list = Array.isArray(p.persons) ? p.persons : [];
package/dist/index.js CHANGED
@@ -1227,6 +1227,33 @@ var BASE_STYLES_CSS = `/**
1227
1227
  margin: 8px 0;
1228
1228
  }
1229
1229
 
1230
+ .universal-card-collapse-divider {
1231
+ width: 100%;
1232
+ height: 1px;
1233
+ background-color: #dee0e3;
1234
+ border: none;
1235
+ margin: 8px 0;
1236
+ }
1237
+
1238
+ .universal-card-avatar {
1239
+ display: inline-flex;
1240
+ align-items: center;
1241
+ vertical-align: middle;
1242
+ }
1243
+
1244
+ .universal-card-avatar__img {
1245
+ border-radius: 50%;
1246
+ object-fit: cover;
1247
+ display: block;
1248
+ background: #eff0f1;
1249
+ }
1250
+
1251
+ .universal-card-fallback-text {
1252
+ color: #646a73;
1253
+ font-size: 14px;
1254
+ line-height: 22px;
1255
+ }
1256
+
1230
1257
  /* ---- div / note ---- */
1231
1258
  .universal-card-div > * + * { margin-top: 8px; }
1232
1259
  /* 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 */
@@ -1452,6 +1479,7 @@ var BASE_STYLES_CSS = `/**
1452
1479
  box-sizing: border-box; overflow: hidden;
1453
1480
  }
1454
1481
  /* header\uFF08<summary>\uFF09\uFF1A\u53EF\u70B9\u51FB\u6574\u884C\uFF1B\u53BB\u6389\u6D4F\u89C8\u5668\u9ED8\u8BA4\u4E09\u89D2\u6807\u8BB0\u3002
1482
+ \u771F\u673A color:var(--text-caption) \u2192 N600\uFF1B\u6807\u9898/\u7BAD\u5934\u7EE7\u627F\u6B64\u8272\u3002
1455
1483
  \u9ED8\u8BA4 title flex:1 \u628A\u7BAD\u5934\u63A8\u5230\u53F3\u4FA7\uFF08icon_position=right\uFF09\uFF1B
1456
1484
  icon_position=left \u65F6\u9760 DOM \u987A\u5E8F\u5728\u5DE6\u3002 */
1457
1485
  .universal-card-collapsible-panel__header {
@@ -1459,11 +1487,12 @@ var BASE_STYLES_CSS = `/**
1459
1487
  padding: 8px 12px;
1460
1488
  cursor: pointer; box-sizing: border-box;
1461
1489
  list-style: none; user-select: none;
1490
+ color: var(--N600);
1462
1491
  }
1463
1492
  .universal-card-collapsible-panel__header::-webkit-details-marker { display: none; }
1464
1493
  .universal-card-collapsible-panel__header::marker { content: ''; }
1465
1494
  .universal-card-collapsible-panel__title {
1466
- flex: 1; min-width: 0; font-size: 14px; line-height: 22px; color: #1f2329;
1495
+ flex: 1; min-width: 0; font-size: 14px; line-height: 22px;
1467
1496
  word-break: break-word;
1468
1497
  }
1469
1498
  /* follow_text\uFF1A\u7BAD\u5934\u7D27\u8D34\u6587\u5B57\uFF08\u771F\u673A __header-content--icon-follow\uFF09\uFF0C\u4E0D\u62C9\u6EE1\u6574\u884C */
@@ -1475,10 +1504,10 @@ var BASE_STYLES_CSS = `/**
1475
1504
  width: auto;
1476
1505
  }
1477
1506
  /* \u7BAD\u5934\u56FE\u6807\u5305\u88F9\uFF1A\u6536\u8D77\u6001\u89D2\u5EA6 0\uFF1B\u5C55\u5F00\u6001\uFF08details[open]\uFF09\u65CB\u8F6C\u5230 --panel-icon-angle\uFF08\u5185\u8054\u7ED9\u51FA\uFF0C\u9ED8\u8BA4 -180deg\uFF09\u3002
1478
- \u7531\u7528\u6237\u70B9\u51FB <summary> \u5207\u6362 [open]\uFF0C\u7BAD\u5934\u65B9\u5411\u968F\u4E4B\u81EA\u52A8\u66F4\u65B0\uFF0C\u65E0\u9700 JS\u3002 */
1507
+ \u7531\u7528\u6237\u70B9\u51FB <summary> \u5207\u6362 [open]\uFF0C\u7BAD\u5934\u65B9\u5411\u968F\u4E4B\u81EA\u52A8\u66F4\u65B0\uFF0C\u65E0\u9700 JS\u3002\u989C\u8272\u7EE7\u627F header caption\u3002 */
1479
1508
  .universal-card-collapsible-panel__icon {
1480
1509
  flex-shrink: 0; display: inline-flex; align-items: center; justify-content: center;
1481
- transition: transform .2s; color: #646a73; transform: rotate(0deg);
1510
+ transition: transform .2s; transform: rotate(0deg);
1482
1511
  }
1483
1512
  .universal-card-collapsible-panel[open] .universal-card-collapsible-panel__icon {
1484
1513
  transform: rotate(var(--panel-icon-angle, -180deg));
@@ -5955,6 +5984,11 @@ function registerBuiltins() {
5955
5984
  registerComponent("input", (el) => renderStaticField(el));
5956
5985
  registerComponent("multi_select_static", (el) => renderStaticField(el));
5957
5986
  registerComponent("select_static", (el) => renderStaticField(el));
5987
+ registerComponent("date_picker", (el) => renderStaticField(el));
5988
+ registerComponent("picker_time", (el) => renderStaticField(el));
5989
+ registerComponent("picker_datetime", (el) => renderStaticField(el));
5990
+ registerComponent("select_person", (el) => renderStaticField(el));
5991
+ registerComponent("multi_select_person", (el) => renderStaticField(el));
5958
5992
  registerComponent("checker", (el, ctx) => {
5959
5993
  const p = el.property || {};
5960
5994
  const checked = p.checked === true;
@@ -6102,6 +6136,40 @@ function registerBuiltins() {
6102
6136
  const p = el.property || {};
6103
6137
  return renderPersonChip(p.userID, p, ctx);
6104
6138
  });
6139
+ const AVATAR_SIZE_PX = {
6140
+ tiny: 16,
6141
+ small: 24,
6142
+ medium: 32,
6143
+ large: 40,
6144
+ huge: 48
6145
+ };
6146
+ registerComponent("avatar", (el, ctx) => {
6147
+ const p = el.property || {};
6148
+ const userID = p.userID || p.user_id;
6149
+ const sizeKey = String(p.size ?? "medium");
6150
+ const custom = typeof p.customSize === "number" ? p.customSize : typeof p.custom_size === "number" ? p.custom_size : void 0;
6151
+ const px = sizeKey === "custom" && typeof custom === "number" && custom > 0 ? custom : AVATAR_SIZE_PX[sizeKey] || AVATAR_SIZE_PX.medium;
6152
+ const { name, src } = resolvePersonDisplay(userID, ctx);
6153
+ return h(
6154
+ "div",
6155
+ { className: `${CLS}-avatar`, title: name },
6156
+ renderAvatarNode(`${CLS}-avatar__img`, px, src, name)
6157
+ );
6158
+ });
6159
+ registerComponent(
6160
+ "collapse_divider",
6161
+ () => h("div", { className: `${CLS}-collapse-divider` })
6162
+ );
6163
+ registerComponent("fallback_text", (el, ctx) => {
6164
+ const p = el.property || {};
6165
+ const textEl = p.text;
6166
+ if (textEl && typeof textEl === "object" && textEl.tag) {
6167
+ return h("div", { className: `${CLS}-fallback-text` }, renderElement(textEl, ctx));
6168
+ }
6169
+ const content = extractPlainText(p.text);
6170
+ if (!content) return null;
6171
+ return h("div", { className: `${CLS}-fallback-text` }, content);
6172
+ });
6105
6173
  registerComponent("person_list", (el, ctx) => {
6106
6174
  const p = el.property || {};
6107
6175
  const list = Array.isArray(p.persons) ? p.persons : [];
package/dist/styles.css CHANGED
@@ -306,6 +306,33 @@
306
306
  margin: 8px 0;
307
307
  }
308
308
 
309
+ .universal-card-collapse-divider {
310
+ width: 100%;
311
+ height: 1px;
312
+ background-color: #dee0e3;
313
+ border: none;
314
+ margin: 8px 0;
315
+ }
316
+
317
+ .universal-card-avatar {
318
+ display: inline-flex;
319
+ align-items: center;
320
+ vertical-align: middle;
321
+ }
322
+
323
+ .universal-card-avatar__img {
324
+ border-radius: 50%;
325
+ object-fit: cover;
326
+ display: block;
327
+ background: #eff0f1;
328
+ }
329
+
330
+ .universal-card-fallback-text {
331
+ color: #646a73;
332
+ font-size: 14px;
333
+ line-height: 22px;
334
+ }
335
+
309
336
  /* ---- div / note ---- */
310
337
  .universal-card-div > * + * { margin-top: 8px; }
311
338
  /* div 带前置图标:icon 在左、文本在右排成一行(复刻网页版 .universal-card-div 布局) */
@@ -531,6 +558,7 @@
531
558
  box-sizing: border-box; overflow: hidden;
532
559
  }
533
560
  /* header(<summary>):可点击整行;去掉浏览器默认三角标记。
561
+ 真机 color:var(--text-caption) → N600;标题/箭头继承此色。
534
562
  默认 title flex:1 把箭头推到右侧(icon_position=right);
535
563
  icon_position=left 时靠 DOM 顺序在左。 */
536
564
  .universal-card-collapsible-panel__header {
@@ -538,11 +566,12 @@
538
566
  padding: 8px 12px;
539
567
  cursor: pointer; box-sizing: border-box;
540
568
  list-style: none; user-select: none;
569
+ color: var(--N600);
541
570
  }
542
571
  .universal-card-collapsible-panel__header::-webkit-details-marker { display: none; }
543
572
  .universal-card-collapsible-panel__header::marker { content: ''; }
544
573
  .universal-card-collapsible-panel__title {
545
- flex: 1; min-width: 0; font-size: 14px; line-height: 22px; color: #1f2329;
574
+ flex: 1; min-width: 0; font-size: 14px; line-height: 22px;
546
575
  word-break: break-word;
547
576
  }
548
577
  /* follow_text:箭头紧贴文字(真机 __header-content--icon-follow),不拉满整行 */
@@ -554,10 +583,10 @@
554
583
  width: auto;
555
584
  }
556
585
  /* 箭头图标包裹:收起态角度 0;展开态(details[open])旋转到 --panel-icon-angle(内联给出,默认 -180deg)。
557
- 由用户点击 <summary> 切换 [open],箭头方向随之自动更新,无需 JS。 */
586
+ 由用户点击 <summary> 切换 [open],箭头方向随之自动更新,无需 JS。颜色继承 header caption。 */
558
587
  .universal-card-collapsible-panel__icon {
559
588
  flex-shrink: 0; display: inline-flex; align-items: center; justify-content: center;
560
- transition: transform .2s; color: #646a73; transform: rotate(0deg);
589
+ transition: transform .2s; transform: rotate(0deg);
561
590
  }
562
591
  .universal-card-collapsible-panel[open] .universal-card-collapsible-panel__icon {
563
592
  transform: rotate(var(--panel-icon-angle, -180deg));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@open-feishu-card/renderer",
3
- "version": "0.2.15",
3
+ "version": "0.2.17",
4
4
  "description": "零框架依赖的飞书卡片渲染引擎:Web / DOM / SSR,输入 RAW 或公开 DSL,输出真实 DOM 或 HTML 字符串",
5
5
  "type": "module",
6
6
  "main": "./dist/index.cjs",
@@ -28,7 +28,7 @@
28
28
  "./dist/*.cjs"
29
29
  ],
30
30
  "dependencies": {
31
- "@open-feishu-card/adapter": "0.3.11"
31
+ "@open-feishu-card/adapter": "0.3.12"
32
32
  },
33
33
  "devDependencies": {
34
34
  "tsup": "^8.3.5",