dsh-markdown-bubble 0.1.4 → 0.1.5
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/README.md +21 -3
- package/package.json +2 -2
- package/src/client.js +85 -25
- package/src/index.js +1 -1
package/README.md
CHANGED
|
@@ -33,9 +33,9 @@ DSH 的用户消息气泡按原样显示你输入的文字(`white-space: pre-w
|
|
|
33
33
|
|
|
34
34
|
- **官方座位替换** —— 经 `ctx.slots` 在 `conversation.chat.node` 的 `user` / `steering` 两个 keyed 座位上以 `priority: -1` 遮蔽宿主渲染器;停用/卸载即恢复宿主自己的气泡,不改源码、不动日志
|
|
35
35
|
- **宿主同款渲染** —— 不自己造 Markdown 管线,直接调用 `@deepseek-ai/dsh-client-ui-primitives` 的 `MarkdownText`:与助手回复同一套解析、高亮、表格、公式与代码卡
|
|
36
|
-
- **引用 chip 保留** ——
|
|
36
|
+
- **引用 chip 保留** —— 调用宿主自己的文本工厂槽 `conversation.user.text`(0.2.1 起投影就住在那里),返回的片段按 chip / 纯文本拆分:chip 仍是可点击的文件 / 技能 chip,纯文本段逐个进 Markdown
|
|
37
37
|
- **操作条与三方插件兼容** —— 时间 + 复制按钮用官方 primitives 重建,操作条保留 `_actions` / `_action` 类名后缀与 `data-clock` 锚点;dsh-edit-turn、dsh-delete-turn、dsh-rerun-turn 的按钮注入照常工作
|
|
38
|
-
- **附件与补充块** ——
|
|
38
|
+
- **附件与补充块** —— 图片走官方的图片画廊工厂槽 `conversation.images.content`,文件卡、引用摘要、`JsonBlock` 补充块与宿主同款
|
|
39
39
|
- **软换行保留** —— 仅对围栏代码之外的续行补 GFM 两空格硬换行;代码块一个字节不动,缩进代码与表格行不误伤
|
|
40
40
|
- **出错兜底** —— 单条消息的渲染错误被错误边界接住,回退为宿主的原始投影,不会连累整条座位被槽位机制摘除
|
|
41
41
|
- **中英双语** 随系统语言切换(代码卡文案复用宿主 `chat` 字典)
|
|
@@ -89,12 +89,30 @@ const a = 1
|
|
|
89
89
|
|
|
90
90
|
### 兼容性
|
|
91
91
|
|
|
92
|
-
- 实测 DSH `0.2.
|
|
92
|
+
- 实测 DSH `0.2.1-rc.2`(web profile,Chromium)。依赖:keyed 槽位 `conversation.chat.node`(`user` / `steering`)、座位上的 `renderFactorySlot` 绑定、行锚点 `data-chat-flow-kind` / `data-pending-steering` / `data-submission-echo`、primitives 导出的 `MarkdownText` / `writeClipboard`。
|
|
93
|
+
- **0.2.1 把扩展点往里挪了**,本插件 0.1.5 已按新契约移植(旧契约的三样东西都不在了):`primitives.projectUserText` 被删除 → 改调文本工厂槽 `conversation.user.text`;座位 props 从 `{ node, renderMessageImages, openFile, openSkill, t }` 变成 `{ node, renderFactorySlot, loadImage, t }` → 图片改调图片画廊工厂槽 `conversation.images.content`。
|
|
94
|
+
- **为什么不能去换内容工厂槽**:`conversation.chat.user.content` 由宿主注册,插件再注册同名工厂会让**宿主自己的聊天插件启动失败**(实测 `web boot: 1 entry did not activate @deepseek-ai/dsh-client-ui-chat: failed`),所以「只换气泡内部」这条路走不通;同理,`conversation.chat.user.images` 这个子槽也不能由插件声明(实测 `slot "conversation.chat.user.images" is already declared (by factory "conversation.chat.user.content")`)。座位替换 + 两个工厂槽调用是当前版本唯一可行且不伤宿主的组合。
|
|
93
95
|
- 与 `dsh-edit-turn`、`dsh-delete-turn`、`dsh-rerun-turn` 协同:三者的按钮注入基于 `[class*="_actions"]` / `[class*="_action"]`,本插件保留该契约;被 dsh-edit-turn 改写(rollback)的消息显示其自己的改写气泡,与本插件无关。
|
|
94
96
|
- 宿主半区为惰性入口(无运行时行为),全部逻辑在 `./client` 浏览器半区;不修改官方源码,不写私有事件类型。
|
|
95
97
|
|
|
98
|
+
### 为什么现在不能换成「替换内容工厂」(B 方案)
|
|
99
|
+
|
|
100
|
+
理想做法是替换宿主的内容工厂槽 `conversation.chat.user.content`:气泡内部(附件 + 气泡 + 引用摘要)全部交回宿主,本插件只换掉正文那一段。这样能删掉自建的行外壳、时间/复制操作条与相关样式约 200 行,也不再依赖座位 props 的形状。**现在做不了,卡在下面三条**(都在 DSH `0.2.1-rc.2` 上实测过;等哪天宿主放开了任意一条,就可以改成 B):
|
|
101
|
+
|
|
102
|
+
| 缺什么 | 实测结果 | 放开之后 |
|
|
103
|
+
|---|---|---|
|
|
104
|
+
| 工厂槽能被插件**遮蔽/替换** | 注册同名工厂不是遮蔽而是硬错误,且会让**宿主自己的聊天插件启动失败**:`web boot: 1 entry did not activate @deepseek-ai/dsh-client-ui-chat: failed` | 直接换成注册 `conversation.chat.user.content`,删掉自建行外壳与操作条 |
|
|
105
|
+
| 子槽能由**多个**声明方共享 | 想让座位条目自己声明 `conversation.chat.user.images` 以拿到 `renderSlot`,被拒:`slot "conversation.chat.user.images" is already declared (by factory "conversation.chat.user.content")`,且整条注册一起失败 | 图片可以用官方的座位/子槽渲染,不必绕工厂槽 |
|
|
106
|
+
| 有一个**公开的**「渲染一条用户消息」入口 | 0.2.1 删掉了 `primitives.projectUserText`,投影只存在于工厂槽内部(现在只能调 `conversation.user.text` / `conversation.images.content` 这两个工厂槽) | 插件插入的气泡(例如 dsh-edit-turn 改写后的提示词)也能走同一条管线,见 [deepseek-harness#10704](https://github.com/deepseek-ai/deepseek-harness/discussions/10704) |
|
|
107
|
+
|
|
108
|
+
也就是说:**座位替换(A)+ 调两个工厂槽**是当前版本唯一不伤宿主的组合;上面三条任意一条放开,都可以迁到 B。
|
|
109
|
+
|
|
96
110
|
### 修复记录
|
|
97
111
|
|
|
112
|
+
- **0.1.5** —— 按 DSH `0.2.1-rc.2` 的新契约移植,并把 `engines.dsh` 从开口的 `>=0.2.0-rc.1` 收成 `>=0.2.1-rc.2`(旧区间会让它在 0.2.1 上照样安装、只静默降级)。
|
|
113
|
+
- **引用 chip 回来了**:`primitives.projectUserText` 在 0.2.1 被删除(真机报 `TypeError: primitives.projectUserText is not a function`),投影改成调用宿主的文本工厂槽 `conversation.user.text`(`facts.sessionLabels` / `facts.skillNames` + `interactive`),chip 拆分逻辑不变。真机复验:控制台里那条降级告警不再出现(0 条),25/25 条用户气泡仍由本插件渲染。
|
|
114
|
+
- **图片附件回来了**:座位 props 里的 `renderMessageImages` 已不存在,改调图片画廊工厂槽 `conversation.images.content`(附件插件自己注册的那个;它的 `MessageImages` 也只是这一步调用)。三条看起来更顺的路都被堵着,README 的「兼容性」一节记了实测报错原文。
|
|
115
|
+
- **性能**:降级投影从「每帧算两次」改成只算一次(`MarkdownBoundary` 的 fallback 改成惰性 thunk,只有真失败时才构造);`toMarkdown()` 加 64 条 LRU 缓存(流式期间同一条消息会被反复重排,而准备源码是 split/join + 逐行正则);传给 `MarkdownText` 的 labels 对象按 `t` 记忆化(宿主自己的 `ReasoningContent` 正是这么做的,每次新建对象会让下游 memo 失效)。
|
|
98
116
|
- **0.1.4** —— 按评审意见把降级路径**合成一个函数**:此前「合成失败」「宿主投影抛错」「最后兜底」各自写了一份降级逻辑(一份调宿主投影、一份内联拼裸文本),三处要人工保持同步。现在只有 `degradedBody()` 一处:先试宿主自己的投影(保住引用 chip 等宿主渲染),投影也抛才退到裸文本;三条降级路径全部走它。内容优先这一点写进函数契约:裸文本是最后一步,只有宿主自己拒绝投影时才到。新增回归:断言 `projectUserText` 全仓只有一次调用、裸文本 span 只有一处构造、降级调用方都走同一函数(再造一份降级该测试转红)。
|
|
99
117
|
- **0.1.3** —— 把「座位 render 绝不抛」这条不变式补完:0.1.2 守住了合成与文案查询,但仍有形状会在**座位自己的渲染里**抛错(`node` 缺失 → `node.data`、`props` 缺失 → 解构本身、`new Date(time)` 遇到 Symbol / BigInt / 抛错的 valueOf、宿主图片渲染器抛错)。这些同样冒泡到槽位机制、退掉整条条目,症状与 0.1.2 修的完全一样。现在三层兜底:座位本体一层 try 并把 `node` / `data` 的取用改成防御式;时钟与附件卡在各自调用点兜底;最后一层 `renderPlainRow` 保证最坏情况只是这一行退回纯文本,而操作条与兄弟插件锚点仍在。新增回归:21 种恶意宿主形状逐一断言不抛、且行与操作条都在。
|
|
100
118
|
- **0.1.2** — 座位组件不再可能因渲染期异常被槽位机制摘除:`composeUserMarkdown` / `buildMarkdownLabels` 在座位渲染过程中运行,抛错不会被错误边界接住(错误边界只能接住其后代,接不住创建它的那次渲染),会冒泡到槽位机制并把该条目整条退掉——屏幕上就是气泡交还给宿主、Markdown 变回源码。现在合成与所有文案查询都在座位内部兜底:任何宿主形状不符(节点结构异常、投影返回不可识别、locale 席位不可调用)都退回宿主原始投影,气泡外壳、操作条与兄弟插件锚点全部保留。`data.content` 非数组、`t` 不可调用等情形一并加进回归测试。
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dsh-markdown-bubble",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.5",
|
|
4
4
|
"description": "Markdown rendering for DeepSeek Harness sent user messages: every message bubble renders lists, code, tables, quotes and inline formatting through the host's own Markdown pipeline, while queues, previews and the composer keep their plain projection.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "src/index.js",
|
|
@@ -48,7 +48,7 @@
|
|
|
48
48
|
]
|
|
49
49
|
},
|
|
50
50
|
"engines": {
|
|
51
|
-
"dsh": ">=0.2.
|
|
51
|
+
"dsh": ">=0.2.1-rc.2"
|
|
52
52
|
}
|
|
53
53
|
}
|
|
54
54
|
}
|
package/src/client.js
CHANGED
|
@@ -49,7 +49,7 @@ window.__ModuleLoader__.load({
|
|
|
49
49
|
const NS = 'dsh-markdown-bubble'
|
|
50
50
|
|
|
51
51
|
/** Keep in sync with package.json and src/index.js. */
|
|
52
|
-
const PLUGIN_VERSION = '0.1.
|
|
52
|
+
const PLUGIN_VERSION = '0.1.5'
|
|
53
53
|
|
|
54
54
|
/** Presence marker the live verifier reads. */
|
|
55
55
|
const DEBUG_KEY = '__DSH_MARKDOWN_BUBBLE__'
|
|
@@ -189,7 +189,27 @@ window.__ModuleLoader__.load({
|
|
|
189
189
|
* @param text - raw logged message text.
|
|
190
190
|
* @returns markdown source for the renderer.
|
|
191
191
|
*/
|
|
192
|
+
// Prepared markdown source, keyed by the raw text. A bubble repaints on
|
|
193
|
+
// every transcript update (a streaming turn re-renders constantly) and the
|
|
194
|
+
// preparation is a split/join plus a regex per line, so the same message was
|
|
195
|
+
// re-walked dozens of times while an unrelated row streamed. Cleared whole
|
|
196
|
+
// when it grows past the cap: the entries are strings, and a long transcript
|
|
197
|
+
// has far fewer distinct message texts than it has repaints.
|
|
198
|
+
const markdownSourceCache = new Map()
|
|
199
|
+
const MARKDOWN_CACHE_LIMIT = 64
|
|
200
|
+
|
|
192
201
|
function toMarkdown(text) {
|
|
202
|
+
const key = typeof text === 'string' ? text : ''
|
|
203
|
+
const cached = markdownSourceCache.get(key)
|
|
204
|
+
if (cached !== undefined) return cached
|
|
205
|
+
const source = prepareMarkdown(key)
|
|
206
|
+
if (markdownSourceCache.size >= MARKDOWN_CACHE_LIMIT) markdownSourceCache.clear()
|
|
207
|
+
markdownSourceCache.set(key, source)
|
|
208
|
+
return source
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
/** The uncached preparation: CRLF, session wire links, soft breaks. */
|
|
212
|
+
function prepareMarkdown(text) {
|
|
193
213
|
const normalized = text.replace(/\r\n?/gu, '\n')
|
|
194
214
|
return walkOutsideFences(normalized, (line, next) => hardBreakLine(line.replace(SESSION_WIRE_RE, '$1'), next))
|
|
195
215
|
}
|
|
@@ -267,12 +287,24 @@ window.__ModuleLoader__.load({
|
|
|
267
287
|
* @param text - the message text.
|
|
268
288
|
* @param referenceLabels - session recall labels.
|
|
269
289
|
* @param skillNames - skill names.
|
|
270
|
-
* @param
|
|
290
|
+
* @param renderFactorySlot - the seat's Factory binding (chips + plain runs).
|
|
271
291
|
* @returns the degraded body, never null and never a throw.
|
|
272
292
|
*/
|
|
273
|
-
function degradedBody(text, referenceLabels, skillNames,
|
|
293
|
+
function degradedBody(text, referenceLabels, skillNames, renderFactorySlot) {
|
|
274
294
|
try {
|
|
275
|
-
|
|
295
|
+
if (typeof renderFactorySlot !== 'function') throw new Error('the seat handed over no renderFactorySlot')
|
|
296
|
+
// The projection moved into the host's own Factory in 0.2.1-rc.2
|
|
297
|
+
// (`conversation.user.text`, registered by dsh-client-ui-conversation;
|
|
298
|
+
// it owns the keyed child slot that renders a reference chip). The old
|
|
299
|
+
// public primitive `primitives.projectUserText` was REMOVED in the same
|
|
300
|
+
// release, which is why this call used to throw and chips degraded to
|
|
301
|
+
// plain text.
|
|
302
|
+
return renderFactorySlot('conversation.user.text', {
|
|
303
|
+
text,
|
|
304
|
+
facts: { sessionLabels: referenceLabels, skillNames },
|
|
305
|
+
interactive: true,
|
|
306
|
+
ellipsis: false,
|
|
307
|
+
})
|
|
276
308
|
} catch (error) {
|
|
277
309
|
warnOnce('the host user-text projection failed; showing raw text', error)
|
|
278
310
|
return h('span', { className: 'dshmb-plain' }, text)
|
|
@@ -296,13 +328,12 @@ window.__ModuleLoader__.load({
|
|
|
296
328
|
* @param t - the injected chat translator.
|
|
297
329
|
* @param referenceLabels - session recall labels.
|
|
298
330
|
* @param skillNames - skill names.
|
|
299
|
-
* @param
|
|
331
|
+
* @param renderFactorySlot - the seat's Factory binding.
|
|
300
332
|
* @returns the composed body, or null when markdown cannot be produced.
|
|
301
333
|
*/
|
|
302
|
-
function safeMarkdownBody(text, t, referenceLabels, skillNames,
|
|
334
|
+
function safeMarkdownBody(text, t, referenceLabels, skillNames, renderFactorySlot, labels) {
|
|
303
335
|
try {
|
|
304
|
-
|
|
305
|
-
return composeUserMarkdown(text, labels, referenceLabels, skillNames, references)
|
|
336
|
+
return composeUserMarkdown(text, labels, referenceLabels, skillNames, renderFactorySlot)
|
|
306
337
|
} catch (error) {
|
|
307
338
|
warnOnce('markdown composition failed; showing the degraded projection', error)
|
|
308
339
|
return null
|
|
@@ -341,14 +372,14 @@ window.__ModuleLoader__.load({
|
|
|
341
372
|
* @param labels - markdown chrome labels.
|
|
342
373
|
* @param referenceLabels - session recall labels the host associates with the message.
|
|
343
374
|
* @param skillNames - skill names the host loaded for the message.
|
|
344
|
-
* @param
|
|
375
|
+
* @param renderFactorySlot - the seat's Factory binding.
|
|
345
376
|
* @returns the composed body, or null for empty text.
|
|
346
377
|
*/
|
|
347
|
-
function composeUserMarkdown(text, labels, referenceLabels, skillNames,
|
|
378
|
+
function composeUserMarkdown(text, labels, referenceLabels, skillNames, renderFactorySlot) {
|
|
348
379
|
if (typeof text !== 'string' || text === '') return null
|
|
349
380
|
// The same single degraded projection, so a projection that throws inside
|
|
350
381
|
// composition degrades exactly as one that throws on the healthy path.
|
|
351
|
-
const projected = degradedBody(text, referenceLabels, skillNames,
|
|
382
|
+
const projected = degradedBody(text, referenceLabels, skillNames, renderFactorySlot)
|
|
352
383
|
const pieces =
|
|
353
384
|
react.isValidElement(projected) && projected.type === Fragment && Array.isArray(projected.props.children)
|
|
354
385
|
? projected.props.children
|
|
@@ -525,7 +556,12 @@ window.__ModuleLoader__.load({
|
|
|
525
556
|
}
|
|
526
557
|
|
|
527
558
|
render() {
|
|
528
|
-
|
|
559
|
+
if (!this.state.failed) return this.props.children
|
|
560
|
+
const { fallback } = this.props
|
|
561
|
+
// A thunk is called only when it is actually needed: building the
|
|
562
|
+
// degraded projection on every healthy render is wasted work (and, on a
|
|
563
|
+
// host whose projection is gone, a caught throw every time).
|
|
564
|
+
return typeof fallback === 'function' ? fallback() : fallback
|
|
529
565
|
}
|
|
530
566
|
}
|
|
531
567
|
|
|
@@ -615,9 +651,24 @@ window.__ModuleLoader__.load({
|
|
|
615
651
|
}
|
|
616
652
|
}
|
|
617
653
|
|
|
618
|
-
function renderAttachmentEntry({ attachment,
|
|
654
|
+
function renderAttachmentEntry({ attachment, renderFactorySlot, loadImage, compactImages }) {
|
|
619
655
|
if (attachment.type === 'image') {
|
|
620
|
-
|
|
656
|
+
// The host's image gallery, through the SAME Factory seam as the text
|
|
657
|
+
// projection. The three routes that look obvious are all closed on
|
|
658
|
+
// 0.2.1-rc.2: the `renderMessageImages` seat prop is gone, the child
|
|
659
|
+
// slot `conversation.chat.user.images` cannot be declared by a plugin
|
|
660
|
+
// ("already declared (by factory conversation.chat.user.content)",
|
|
661
|
+
// verified live), and `@deepseek-ai/dsh-client-ui-attachment` exports
|
|
662
|
+
// only apply/inject. The gallery Factory is the one that works: the
|
|
663
|
+
// attachment plugin registers `conversation.images.content` at root
|
|
664
|
+
// scope and its own `MessageImages` is nothing but a call to it.
|
|
665
|
+
if (typeof renderFactorySlot !== 'function') throw new Error('the seat handed over no renderFactorySlot')
|
|
666
|
+
return h(Fragment, null, renderFactorySlot('conversation.images.content', {
|
|
667
|
+
images: [attachment.image],
|
|
668
|
+
loadImage,
|
|
669
|
+
align: 'end',
|
|
670
|
+
compact: compactImages,
|
|
671
|
+
}))
|
|
621
672
|
}
|
|
622
673
|
const file = attachment.file ?? {}
|
|
623
674
|
const name = typeof file.name === 'string' ? file.name : ''
|
|
@@ -668,23 +719,31 @@ window.__ModuleLoader__.load({
|
|
|
668
719
|
function renderMarkdownBubble(props) {
|
|
669
720
|
const safeProps = props !== null && typeof props === 'object' ? props : {}
|
|
670
721
|
const node = safeProps.node !== null && typeof safeProps.node === 'object' ? safeProps.node : {}
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
722
|
+
// The seat's props on 0.2.1-rc.2: the two renderer bindings and the image
|
|
723
|
+
// loader. The old `renderMessageImages` / `openFile` / `openSkill` pair is
|
|
724
|
+
// gone; images now go through the declared child slot and reference chips
|
|
725
|
+
// through the `conversation.user.text` Factory.
|
|
726
|
+
const renderFactorySlot = safeProps.renderFactorySlot
|
|
727
|
+
const renderSlot = safeProps.renderSlot
|
|
728
|
+
const loadImage = safeProps.loadImage
|
|
674
729
|
const t = safeProps.t
|
|
675
730
|
const data = node.data !== null && typeof node.data === 'object' ? node.data : {}
|
|
676
731
|
const { text, attachments, rest } = contentParts(Array.isArray(data.content) ? data.content : [])
|
|
677
732
|
const referenceLabels = Array.isArray(data.referenceLabels) ? data.referenceLabels : []
|
|
678
733
|
const skillNames = Array.isArray(data.skillNames) ? data.skillNames : []
|
|
679
|
-
const references = react.useMemo(() => ({ openFile, openSkill }), [openFile, openSkill])
|
|
680
734
|
const compactImages = attachments.length > 1
|
|
681
735
|
const showBubble = text !== '' || rest.length > 0
|
|
736
|
+
// The host memoizes its own label object before handing it to MarkdownText
|
|
737
|
+
// (`ReasoningContent` does exactly this); a fresh object every render
|
|
738
|
+
// defeats that memoization and re-renders the whole markdown tree.
|
|
739
|
+
const labels = react.useMemo(() => buildMarkdownLabels(t), [t])
|
|
682
740
|
|
|
683
741
|
// Never let composition throw out of this render — see safeMarkdownBody.
|
|
684
|
-
//
|
|
685
|
-
// boundary's
|
|
686
|
-
|
|
687
|
-
const
|
|
742
|
+
// ONE degraded body per render: it is the composition guard's projection
|
|
743
|
+
// and the boundary's fallback, so building it eagerly (as this used to)
|
|
744
|
+
// ran the projection twice per render and, on 0.2.1-rc.2, threw twice.
|
|
745
|
+
const body = safeMarkdownBody(text, t, referenceLabels, skillNames, renderFactorySlot, labels)
|
|
746
|
+
const degraded = () => degradedBody(text, referenceLabels, skillNames, renderFactorySlot)
|
|
688
747
|
|
|
689
748
|
// The action strip leads the row in DOM order and is pushed below the
|
|
690
749
|
// bubble by flex `order`. Sibling plugins pick their bar with
|
|
@@ -708,7 +767,8 @@ window.__ModuleLoader__.load({
|
|
|
708
767
|
h(AttachmentEntry, {
|
|
709
768
|
key: `${attachment.type}:${index}`,
|
|
710
769
|
attachment,
|
|
711
|
-
|
|
770
|
+
renderFactorySlot,
|
|
771
|
+
loadImage,
|
|
712
772
|
compactImages,
|
|
713
773
|
}),
|
|
714
774
|
),
|
|
@@ -717,7 +777,7 @@ window.__ModuleLoader__.load({
|
|
|
717
777
|
h(
|
|
718
778
|
'div',
|
|
719
779
|
{ className: 'dshmb-bubble' },
|
|
720
|
-
h(MarkdownBoundary, { key: text, fallback: degraded }, body === null ? degraded : body),
|
|
780
|
+
h(MarkdownBoundary, { key: text, fallback: degraded }, body === null ? degraded() : body),
|
|
721
781
|
rest.map((block, index) =>
|
|
722
782
|
h(primitives.JsonBlock, {
|
|
723
783
|
key: 'rest' + index,
|
|
@@ -762,7 +822,7 @@ window.__ModuleLoader__.load({
|
|
|
762
822
|
text,
|
|
763
823
|
Array.isArray(data.referenceLabels) ? data.referenceLabels : [],
|
|
764
824
|
Array.isArray(data.skillNames) ? data.skillNames : [],
|
|
765
|
-
|
|
825
|
+
safeProps.renderFactorySlot,
|
|
766
826
|
)
|
|
767
827
|
return h(
|
|
768
828
|
'div',
|
package/src/index.js
CHANGED
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
export const PLUGIN_ID = 'dsh-markdown-bubble'
|
|
16
16
|
|
|
17
17
|
/** Keep in sync with package.json and src/client.js. */
|
|
18
|
-
export const PLUGIN_VERSION = '0.1.
|
|
18
|
+
export const PLUGIN_VERSION = '0.1.5'
|
|
19
19
|
|
|
20
20
|
/** Cordis plugin name; the bundle patch resolves the package by this row. */
|
|
21
21
|
export const name = PLUGIN_ID
|