dsh-motion-ui 0.6.0 → 0.7.1
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/CHANGELOG.md +88 -0
- package/README.md +55 -1
- package/VERIFICATION.md +46 -0
- package/client.js +2136 -1095
- package/examples/mechanism-assembly.json +50 -0
- package/examples/mechanism-crank.json +103 -0
- package/examples/mechanism-gears.json +103 -0
- package/index.js +132 -106
- package/lib/assets/standalone-runtime.js +3 -1
- package/lib/assets/visual.js +3 -1
- package/lib/author-expression.js +9 -8
- package/lib/authoring-guide.js +3 -16
- package/lib/build-info.js +1 -1
- package/lib/canvas-design.js +2 -2
- package/lib/canvas-system.js +1 -1
- package/lib/catalog.js +5 -6
- package/lib/components.js +2 -2
- package/lib/delivery.js +1 -1
- package/lib/export-runtime-bundle.js +1 -1
- package/lib/expressive-examples.js +6 -0
- package/lib/fence-feedback.js +8 -2
- package/lib/freeform.js +4 -9
- package/lib/inspection.js +11 -6
- package/lib/mechanism-catalog.js +24 -0
- package/lib/mechanism-css.js +13 -0
- package/lib/mechanism-entry.js +20 -0
- package/lib/mechanism-geometry.js +62 -0
- package/lib/mechanism-render.js +24 -0
- package/lib/mechanism-runtime-bundle.js +2 -0
- package/lib/mechanism-scenes.js +20 -0
- package/lib/motion-library.js +17 -0
- package/lib/normalize-authoring.js +15 -2
- package/lib/prompt-contract.js +22 -0
- package/lib/protocol.js +26 -11
- package/lib/refinement.js +3 -2
- package/lib/sandbox.js +2 -0
- package/lib/scene-entry.js +41 -0
- package/lib/style-system.js +28 -0
- package/lib/text-guide.js +9 -13
- package/lib/third-party/anatomy-LICENSE.txt +21 -0
- package/lib/third-party/anatomy-NOTICE.md +13 -0
- package/lib/third-party/anatomy-iso.mjs +674 -0
- package/lib/third-party/lucian-uxui-LICENSE.txt +21 -0
- package/lib/third-party/lucian-uxui-NOTICE.md +1 -0
- package/lib/third-party/taste-skill-NOTICE.md +10 -0
- package/lib/tool-schema.js +9 -9
- package/lib/ui-intent.js +4 -15
- package/lib/ui-skill.js +19 -25
- package/lib/visual-audit.js +15 -4
- package/lib/visual-styles.js +134 -22
- package/package.json +92 -92
- package/skills/intelligent-ui/SKILL.md +22 -102
package/index.js
CHANGED
|
@@ -1,109 +1,135 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
11
|
-
import {
|
|
12
|
-
import {
|
|
13
|
-
import
|
|
14
|
-
import {
|
|
15
|
-
import {
|
|
16
|
-
import {
|
|
17
|
-
import {
|
|
18
|
-
import {
|
|
19
|
-
import {
|
|
20
|
-
import
|
|
21
|
-
import {
|
|
22
|
-
import {
|
|
1
|
+
import {sceneDocument,SCENE_PARAMETERS,sceneReference} from './lib/scene-entry.js';
|
|
2
|
+
import {TEXT_GUIDE} from './lib/text-guide.js';
|
|
3
|
+
import {CANVAS_CONTRACT,TOOL_DIRECTORY} from './lib/prompt-contract.js';
|
|
4
|
+
import {mechanismDocument} from './lib/mechanism-entry.js';
|
|
5
|
+
import {mechanismCatalog} from './lib/mechanism-catalog.js';
|
|
6
|
+
import {motionCatalog} from './lib/motion-library.js';
|
|
7
|
+
import { defineTool } from '@deepseek-ai/dsh-tools';
|
|
8
|
+
import { dshHomePath } from '@deepseek-ai/dsh-home-paths';
|
|
9
|
+
import { validateDocument, fallbackText } from './lib/protocol.js';
|
|
10
|
+
import { UiStore, stateRoute, documentRoute, historyRoute } from './lib/store.js';
|
|
11
|
+
import { evaluate } from './lib/protocol.js';
|
|
12
|
+
import { componentCatalog } from './lib/components.js';
|
|
13
|
+
import {CANVAS_SYSTEM_GUIDE} from './lib/canvas-system.js';
|
|
14
|
+
import { CANVAS_DESIGN_GUIDE } from './lib/canvas-design.js';
|
|
15
|
+
import { architectureExample, scatterExample } from './lib/visual-examples.js';
|
|
16
|
+
import { BUILD_INFO } from './lib/build-info.js';
|
|
17
|
+
import { UI_SKILL_SECTIONS, promptSections } from './lib/ui-skill.js';
|
|
18
|
+
import {stylePrompt,styleExamples,DEFAULT_VISUAL_STYLE,VISUAL_STYLE_IDS} from './lib/visual-styles.js';
|
|
19
|
+
import { canvasDocument } from './lib/freeform.js';
|
|
20
|
+
import z from '@deepseek-ai/schemastery';
|
|
21
|
+
import { toolJson } from './lib/tool-json.js';
|
|
22
|
+
import { DOCUMENT_PARAMETER,TEXT_BLOCKS_PARAMETER } from './lib/tool-schema.js';
|
|
23
|
+
import {textDocument} from './lib/text-document.js';
|
|
24
|
+
import {TEXT_PRESETS} from './lib/typography.js';
|
|
25
|
+
import { inspectRecord } from './lib/inspection.js';
|
|
26
|
+
import {QUICK_EXAMPLES,QUICK_GUIDE} from './lib/quick-examples.js';
|
|
27
|
+
import { PROTOCOL_GUIDE, calculatorExample, comparisonExample, budgetExample, curveExample, sceneExamples, bicycleExample, oscillatorExample } from './lib/catalog.js';
|
|
28
|
+
import {VISUAL_GUIDE,VISUAL_EXAMPLES,visualCatalog} from './lib/visual.js';
|
|
29
|
+
import {registerVisualAssets} from './lib/visual-assets.js';
|
|
23
30
|
import {diagnosticsRoute} from './lib/diagnostics-route.js';
|
|
24
|
-
import {fenceRoute} from './lib/fence-route.js';
|
|
25
|
-
import {sceneCatalog
|
|
26
|
-
import {registerFenceFeedback} from './lib/fence-feedback.js';
|
|
27
|
-
import {diagnoseDelivery,deliveryDiagnostics} from './lib/delivery.js';
|
|
28
|
-
|
|
29
|
-
export const name = 'motion-ui';
|
|
30
|
-
export const inject = ['tools', 'connection', 'systemPrompt'];
|
|
31
|
-
function defineRenderTool(options) {
|
|
32
|
-
const tool=defineTool(options),execute=tool.execute;
|
|
33
|
-
return {...tool,async execute(args,exec){
|
|
34
|
-
// Legacy adapters may stringify JSON. Decode here, without advertising a
|
|
35
|
-
// string branch that encourages models to manually escape whole documents.
|
|
36
|
-
// Canonicalize adapter quirks before native schema checks, so a lossless
|
|
37
|
-
// items:{item:[...]} wrapper receives the same treatment as stored/replayed UI.
|
|
38
|
-
const normalized=args&&Object.hasOwn(args,'document')?{...args,document:validateDocument(toolJson(args.document,'document'))}:args&&Object.hasOwn(args,'blocks')?{...args,blocks:textDocument({...args,blocks:toolJson(args.blocks,'blocks')}).nodes}:args;
|
|
39
|
-
return execute(normalized,exec);
|
|
40
|
-
}};
|
|
41
|
-
}
|
|
42
|
-
export const Config=z.object({autoRepair:z.boolean().default(true).description('自动反馈无法交付的 UI 围栏、渲染失败及仅思考没有正文或工具的空交付,最多两次去重提醒;不限制模型思考。'),visualStyle:z.union(VISUAL_STYLE_IDS).default(DEFAULT_VISUAL_STYLE).description('引导模式的视觉风格;同步原生组件外观、风格提示词与案例,自由模式不应用。'),defaultPreset:z.union(TEXT_PRESETS).default('reading').description('兼容旧配置的保留字段,已停用;排版由模型按内容选择。'),designMode:z.union(['guided','free']).default('guided').description('guided:设计技能与示例引导;free:只注入画布接口与交互约束,由模型自主设计。'),displayMode:z.union(['tail','inline','sidebar']).default('inline').description('兼容旧配置的保留字段,已停用;统一使用正文标记,侧栏随时可打开。'),showDetails:z.boolean().default(false).description('显示参数状态、原始说明、视觉诊断和版本历史。默认关闭,保持界面简洁。')}).volatile();
|
|
43
|
-
export function apply(ctx,config={}) {
|
|
44
|
-
const store = new UiStore(dshHomePath('plugins', 'dsh-generative-ui'));
|
|
45
|
-
const settings=()=>typeof config.get==='function'?config.get():config;
|
|
46
|
-
const feedback=registerFenceFeedback(ctx,()=>settings().autoRepair!==false);
|
|
47
|
-
const placement=value=>`\nPlace this exact fenced marker in your answer at the intended UI position:\n\`\`\`dsh-ui\n${value.documentId}\n\`\`\``;
|
|
48
|
-
ctx.effect(()=>ctx.tools.register(defineRenderTool({
|
|
49
|
-
name:'render_text',description:
|
|
50
|
-
parameters:{title:{type:'string'},preset:{type:'string',enum:TEXT_PRESETS},accent:{type:'string',enum:['blue','teal','violet','amber','rose']},blocks:TEXT_BLOCKS_PARAMETER},
|
|
51
|
-
output:{schema:{type:'json'},render:(_a,v)=>[{type:'text',text:v.document.fallback+`\nUI documentId=${v.documentId}; documentRevision=${v.documentRevision??0}.`+placement(v)}],presentationMeta:(_a,v)=>({dshGenerativeUi:v})},
|
|
52
|
-
async execute(args,exec){exec.signal.throwIfAborted();for(const key of Object.keys(args))if(!['title','preset','accent','blocks'].includes(key))throw Error(`DSH UI: unknown render_text argument ${key}; put all content/styling inside blocks or children`);const document=textDocument({...args,blocks:toolJson(args.blocks,'blocks'),preset:args.preset??'reading'});fallbackText(document);const record=await store.create(document,{sessionId:exec.agent?.id??'unscoped',callId:exec.callId});exec.signal.throwIfAborted();return record;}
|
|
53
|
-
})));
|
|
54
|
-
ctx.effect(() => ctx.tools.register(defineRenderTool({
|
|
55
|
-
name: 'render_ui',
|
|
56
|
-
description:
|
|
57
|
-
parameters: { document: DOCUMENT_PARAMETER },
|
|
58
|
-
output: {
|
|
59
|
-
schema: { type: 'json' },
|
|
60
|
-
render: (_args, value) => [{ type: 'text', text: fallbackText(value.document)+`\nUI documentId=${value.documentId}; documentRevision=${value.documentRevision??0}. Use inspect_ui before refinements.`+placement(value)+(deliveryDiagnostics(value.document).length?'\nPARTIAL DELIVERY: '+JSON.stringify(deliveryDiagnostics(value.document))+'\nCorrect the rejected components using update_ui rather than generating another copy.':'') }],
|
|
61
|
-
presentationMeta: (_args, value) => ({ dshGenerativeUi: value })
|
|
62
|
-
},
|
|
63
|
-
async execute({ document }, exec) {
|
|
64
|
-
exec.signal.throwIfAborted();
|
|
65
|
-
const validated = validateDocument(toolJson(document,'document')); fallbackText(validated);
|
|
66
|
-
const record = await store.create(validated, { sessionId: exec.agent?.id ?? 'unscoped', callId: exec.callId });
|
|
67
|
-
exec.signal.throwIfAborted(); return record;
|
|
68
|
-
}
|
|
69
|
-
})));
|
|
70
|
-
ctx.effect(()=>ctx.tools.register(defineTool({
|
|
71
|
-
name:'render_canvas',description:
|
|
72
|
-
parameters:{title:{type:'string',required:true},fallback:{type:'string',required:true},state:{type:'json'},data:{type:'json'},derived:{type:'json'},height:{type:'number'},css:{type:'string',description:'Canvas CSS; use an empty string when no custom styles are needed. Styled static previews appear progressively; interaction activates after the assistant turn ends.'},html:{type:'string',required:true},script:{type:'string'}},
|
|
73
|
-
output:{schema:{type:'json'},render:(_a,v)=>[{type:'text',text:fallbackText(v.document)+`\nUI documentId=${v.documentId}; documentRevision=${v.documentRevision??0}; canvas nodeId=canvas.`+placement(v)}],presentationMeta:(_a,v)=>({dshGenerativeUi:v})},
|
|
74
|
-
async execute(args,exec){exec.signal.throwIfAborted();const record=await store.create(canvasDocument(args),{sessionId:exec.agent?.id??'unscoped',callId:exec.callId});exec.signal.throwIfAborted();return record;}
|
|
75
|
-
})));
|
|
76
|
-
ctx.effect(()
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
31
|
+
import {fenceRoute} from './lib/fence-route.js';
|
|
32
|
+
import {sceneCatalog} from './lib/scene-library.js';
|
|
33
|
+
import {registerFenceFeedback} from './lib/fence-feedback.js';
|
|
34
|
+
import {diagnoseDelivery,deliveryDiagnostics} from './lib/delivery.js';
|
|
35
|
+
|
|
36
|
+
export const name = 'motion-ui';
|
|
37
|
+
export const inject = ['tools', 'connection', 'systemPrompt'];
|
|
38
|
+
function defineRenderTool(options) {
|
|
39
|
+
const tool=defineTool(options),execute=tool.execute;
|
|
40
|
+
return {...tool,async execute(args,exec){
|
|
41
|
+
// Legacy adapters may stringify JSON. Decode here, without advertising a
|
|
42
|
+
// string branch that encourages models to manually escape whole documents.
|
|
43
|
+
// Canonicalize adapter quirks before native schema checks, so a lossless
|
|
44
|
+
// items:{item:[...]} wrapper receives the same treatment as stored/replayed UI.
|
|
45
|
+
const normalized=args&&Object.hasOwn(args,'document')?{...args,document:validateDocument(toolJson(args.document,'document'))}:args&&Object.hasOwn(args,'blocks')?{...args,blocks:textDocument({...args,blocks:toolJson(args.blocks,'blocks')}).nodes}:args;
|
|
46
|
+
return execute(normalized,exec);
|
|
47
|
+
}};
|
|
48
|
+
}
|
|
49
|
+
export const Config=z.object({autoRepair:z.boolean().default(true).description('自动反馈无法交付的 UI 围栏、渲染失败及仅思考没有正文或工具的空交付,最多两次去重提醒;不限制模型思考。'),visualStyle:z.union(VISUAL_STYLE_IDS).default(DEFAULT_VISUAL_STYLE).description('引导模式的视觉风格;同步原生组件外观、风格提示词与案例,自由模式不应用。'),defaultPreset:z.union(TEXT_PRESETS).default('reading').description('兼容旧配置的保留字段,已停用;排版由模型按内容选择。'),designMode:z.union(['guided','free']).default('guided').description('guided:设计技能与示例引导;free:只注入画布接口与交互约束,由模型自主设计。'),displayMode:z.union(['tail','inline','sidebar']).default('inline').description('兼容旧配置的保留字段,已停用;统一使用正文标记,侧栏随时可打开。'),showDetails:z.boolean().default(false).description('显示参数状态、原始说明、视觉诊断和版本历史。默认关闭,保持界面简洁。')}).volatile();
|
|
50
|
+
export function apply(ctx,config={}) {
|
|
51
|
+
const store = new UiStore(dshHomePath('plugins', 'dsh-generative-ui'));
|
|
52
|
+
const settings=()=>typeof config.get==='function'?config.get():config;
|
|
53
|
+
const feedback=registerFenceFeedback(ctx,()=>settings().autoRepair!==false);
|
|
54
|
+
const placement=value=>`\nPlace this exact fenced marker in your answer at the intended UI position:\n\`\`\`dsh-ui\n${value.documentId}\n\`\`\``;
|
|
55
|
+
ctx.effect(()=>ctx.tools.register(defineRenderTool({
|
|
56
|
+
name:'render_text',description:"Format native text, comparisons, steps, copyable text/code and link buttons without HTML. blocks is a direct array of strings/native nodes with optional IDs. State/formulas require render_ui; custom graphics require render_canvas. Several calls create independent documents.",
|
|
57
|
+
parameters:{title:{type:'string'},preset:{type:'string',enum:TEXT_PRESETS},accent:{type:'string',enum:['blue','teal','violet','amber','rose']},blocks:TEXT_BLOCKS_PARAMETER},
|
|
58
|
+
output:{schema:{type:'json'},render:(_a,v)=>[{type:'text',text:v.document.fallback+`\nUI documentId=${v.documentId}; documentRevision=${v.documentRevision??0}.`+placement(v)}],presentationMeta:(_a,v)=>({dshGenerativeUi:v})},
|
|
59
|
+
async execute(args,exec){exec.signal.throwIfAborted();for(const key of Object.keys(args))if(!['title','preset','accent','blocks'].includes(key))throw Error(`DSH UI: unknown render_text argument ${key}; put all content/styling inside blocks or children`);const document=textDocument({...args,blocks:toolJson(args.blocks,'blocks'),preset:args.preset??'reading'});fallbackText(document);const record=await store.create(document,{sessionId:exec.agent?.id??'unscoped',callId:exec.callId});exec.signal.throwIfAborted();return record;}
|
|
60
|
+
})));
|
|
61
|
+
ctx.effect(() => ctx.tools.register(defineRenderTool({
|
|
62
|
+
name: 'render_ui',
|
|
63
|
+
description: "Render one complete native v1 {version:1,title,fallback,nodes,state?,derived?} OR extended {title,items:[components]} document. Do not mix root languages. Use for useful static/interactive explanations; native formulas stay local. Direct call only. ui_catalog supplies optional fields/examples.",
|
|
64
|
+
parameters: { document: DOCUMENT_PARAMETER },
|
|
65
|
+
output: {
|
|
66
|
+
schema: { type: 'json' },
|
|
67
|
+
render: (_args, value) => [{ type: 'text', text: fallbackText(value.document)+`\nUI documentId=${value.documentId}; documentRevision=${value.documentRevision??0}. Use inspect_ui before refinements.`+placement(value)+(deliveryDiagnostics(value.document).length?'\nPARTIAL DELIVERY: '+JSON.stringify(deliveryDiagnostics(value.document))+'\nCorrect the rejected components using update_ui rather than generating another copy.':'') }],
|
|
68
|
+
presentationMeta: (_args, value) => ({ dshGenerativeUi: value })
|
|
69
|
+
},
|
|
70
|
+
async execute({ document }, exec) {
|
|
71
|
+
exec.signal.throwIfAborted();
|
|
72
|
+
const validated = validateDocument(toolJson(document,'document')); fallbackText(validated);
|
|
73
|
+
const record = await store.create(validated, { sessionId: exec.agent?.id ?? 'unscoped', callId: exec.callId });
|
|
74
|
+
exec.signal.throwIfAborted(); return record;
|
|
75
|
+
}
|
|
76
|
+
})));
|
|
77
|
+
ctx.effect(()=>ctx.tools.register(defineTool({
|
|
78
|
+
name:'render_canvas',description:"Render custom HTML/SVG/CSS/JS in an isolated canvas, with optional persisted state. Separate html/css/script fields; no external resources or host APIs. Use the injected canvas contract; libraries:[\"mechanism\"] enables the optional local helper.",
|
|
79
|
+
parameters:{title:{type:'string',required:true},fallback:{type:'string',required:true},state:{type:'json'},data:{type:'json'},derived:{type:'json'},libraries:{type:'array',items:{type:'string',enum:['mechanism']}},height:{type:'number'},css:{type:'string',description:'Canvas CSS; use an empty string when no custom styles are needed. Styled static previews appear progressively; interaction activates after the assistant turn ends.'},html:{type:'string',required:true},script:{type:'string'}},
|
|
80
|
+
output:{schema:{type:'json'},render:(_a,v)=>[{type:'text',text:fallbackText(v.document)+`\nUI documentId=${v.documentId}; documentRevision=${v.documentRevision??0}; canvas nodeId=canvas.`+placement(v)}],presentationMeta:(_a,v)=>({dshGenerativeUi:v})},
|
|
81
|
+
async execute(args,exec){exec.signal.throwIfAborted();const record=await store.create(canvasDocument(args),{sessionId:exec.agent?.id??'unscoped',callId:exec.callId});exec.signal.throwIfAborted();return record;}
|
|
82
|
+
})));
|
|
83
|
+
ctx.effect(()=>ctx.tools.register(defineTool({name:'render_scene',description:'Deliver a complete flow/comparison/allocation/budget UI from short task data; Host creates nodes, controls and formulas. No source or catalog needed. values/items must be complete; never invent prices. Custom UI remains render_ui/render_canvas.',parameters:SCENE_PARAMETERS,output:{schema:{type:'json'},render:(_a,v)=>[{type:'text',text:fallbackText(v.document)+'\nUI documentId='+v.documentId+'; documentRevision='+v.documentRevision+'. To revise this saved scene, use inspect_ui then patch_ui/update_ui with this documentId; calling render_scene again creates an extra UI.'+placement(v)}],presentationMeta:(_a,v)=>({dshGenerativeUi:v})},async execute(args,exec){exec.signal.throwIfAborted();const parsed={...args};for(const key of['items','values'])if(parsed[key]!==undefined)parsed[key]=toolJson(parsed[key],key);const record=await store.create(sceneDocument(parsed),{sessionId:exec.agent?.id??'unscoped',callId:exec.callId});exec.signal.throwIfAborted();return record;}})));
|
|
84
|
+
ctx.effect(()=>ctx.tools.register(defineTool({
|
|
85
|
+
name:'render_mechanism',description:"Create an adjustable assembly/gears/crank diagram from parameters, no source or catalog needed. Gear driver16 teeth; crank rod70. Educational geometry/kinematics. For other structures use render_canvas libraries:[\"mechanism\"] and ui_catalog topic=mechanism.",
|
|
86
|
+
parameters:{scene:{type:'string',required:true,enum:['assembly','gears','crank']},title:{type:'string'},rpm:{type:'number',description:'gears/crank: 0..90, default20'},teeth:{type:'number',description:'gears only: driven integer16..48, default32'},radius:{type:'number',description:'crank only: integer10..28, default20'},running:{type:'boolean',description:'gears/crank: defaultfalse'},angle:{type:'number',description:'gears/crank: integer0..360 degrees, default0'},explode:{type:'number',description:'0..1 in steps0.01; assembly default0.45, others0'}},
|
|
87
|
+
output:{schema:{type:'json'},render:(_a,v)=>[{type:'text',text:fallbackText(v.document)+'\nUI documentId='+v.documentId+'; documentRevision='+v.documentRevision+'.'+placement(v)}],presentationMeta:(_a,v)=>({dshGenerativeUi:v})},
|
|
88
|
+
async execute(args,exec){exec.signal.throwIfAborted();const record=await store.create(mechanismDocument(args),{sessionId:exec.agent?.id??'unscoped',callId:exec.callId});exec.signal.throwIfAborted();return record;}
|
|
89
|
+
})));
|
|
90
|
+
ctx.effect(() => ctx.tools.register(defineTool({
|
|
91
|
+
name: 'ui_catalog', description: "Read one optional reference topic or scene. text=native typography; native=v1 fields/formulas; visual=extended components; canvas=API/construction/examples; style=selected guided style/examples; templates/motion/mechanism=targeted recipes. overview/quick/data/scenes/all remain available; avoid all unless needed.",
|
|
92
|
+
parameters: { topic: { type: 'string', enum: ['overview','quick','text','native','style','visual','motion','mechanism','templates','canvas','data','scenes','all'], description:'Optional topic; default overview.' },scene:{type:'string',description:'Scene for canvas/templates/motion/mechanism, or explicit style ID for style. Omit to get summaries/current guided style.'} }, output: { schema: { type: 'json' }, render: (_args, value) => [{ type: 'text', text: JSON.stringify(value) }] },
|
|
93
|
+
isConcurrencySafe: () => true,
|
|
80
94
|
async execute({ topic = 'overview',scene } = {}) {
|
|
81
|
-
if(topic==='
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
95
|
+
if(topic==='text')return {topic,guide:TEXT_GUIDE};
|
|
96
|
+
if(topic==='native')return {topic,protocol:PROTOCOL_GUIDE,components:componentCatalog(),example:calculatorExample};
|
|
97
|
+
if(topic==='style'){if(settings().designMode==='free'&&!scene)return{topic,mode:'free',note:'No style is selected in free mode. An explicit scene equal to a style ID requests reference guidance only.',styles:VISUAL_STYLE_IDS};const id=scene??settings().visualStyle??DEFAULT_VISUAL_STYLE;return{topic,style:id,guide:stylePrompt(id),examples:styleExamples(id)}}
|
|
98
|
+
if(topic==='canvas'){
|
|
99
|
+
const docs={bicycle:bicycleExample,oscillator:oscillatorExample,architecture:architectureExample,scatter:scatterExample};
|
|
100
|
+
if(scene&&!Object.hasOwn(docs,scene))throw Error('Unknown canvas scene; use bicycle, oscillator, architecture or scatter');
|
|
101
|
+
return {topic,interface:CANVAS_CONTRACT,construction:CANVAS_SYSTEM_GUIDE,...(settings().designMode==='free'?{}:{design:CANVAS_DESIGN_GUIDE}),examples:scene?[docs[scene]]:Object.entries(docs).map(([scene,d])=>({scene,title:d.title,fallback:d.fallback})),usage:'Add scene to retrieve one complete example, not all four sources.'};
|
|
102
|
+
}
|
|
103
|
+
if(topic==='overview')return{topic,guide:TOOL_DIRECTORY,examples:QUICK_EXAMPLES.slice(0,2)};
|
|
104
|
+
if(topic==='quick')return{...sceneReference(),design:QUICK_GUIDE,fullDocuments:QUICK_EXAMPLES};
|
|
105
|
+
if(topic==='templates')return sceneCatalog(scene);
|
|
106
|
+
if(topic==='mechanism')return mechanismCatalog(scene);
|
|
107
|
+
if(topic==='motion')return motionCatalog(scene);
|
|
108
|
+
const groups = { overview: [calculatorExample, oscillatorExample], canvas: [bicycleExample, oscillatorExample, architectureExample, scatterExample], data: [calculatorExample, comparisonExample, budgetExample, curveExample, scatterExample], scenes: sceneExamples, all: [calculatorExample, comparisonExample, budgetExample, curveExample, ...sceneExamples, bicycleExample, oscillatorExample, architectureExample, scatterExample] };
|
|
109
|
+
groups.quick=QUICK_EXAMPLES;groups.overview=QUICK_EXAMPLES.slice(0,2);
|
|
110
|
+
groups.visual=VISUAL_EXAMPLES;
|
|
111
|
+
if (!Object.hasOwn(groups, topic)) throw new Error('Unknown ui_catalog topic; use text, native, style, templates, overview, quick, visual, canvas, data, scenes, motion, mechanism or all');
|
|
112
|
+
if(topic==='visual')return{build:BUILD_INFO,topic,protocol:VISUAL_GUIDE,components:visualCatalog(),examples:VISUAL_EXAMPLES};
|
|
113
|
+
return { build: BUILD_INFO, topic, protocol: PROTOCOL_GUIDE, components: componentCatalog(), design: topic === 'quick' ? QUICK_GUIDE : topic === 'canvas' || topic === 'all' ? CANVAS_DESIGN_GUIDE : 'Choose composition by the question: editorial reading, technical relationships, analytical data, exploratory objects, aligned comparisons or ordered instruction. Keep theme, accessible labels and readable Chinese. Use topic=canvas for the full visual design guide.', examples: groups[topic] };
|
|
114
|
+
}
|
|
115
|
+
})));
|
|
116
|
+
ctx.effect(() => ctx.connection.fetch.register({ path: '/api/plugins/dsh-generative-ui/state', methods: ['GET', 'POST'], requestBody: 'buffered', fetch: stateRoute(store) }));
|
|
117
|
+
ctx.effect(() => ctx.connection.fetch.register({ path: '/api/plugins/dsh-generative-ui/document', methods: ['GET', 'POST'], requestBody: 'buffered', fetch: documentRoute(store) }));
|
|
118
|
+
ctx.effect(() => ctx.connection.fetch.register({ path: '/api/plugins/dsh-generative-ui/history', methods: ['GET', 'POST'], requestBody: 'buffered', fetch: historyRoute(store) }));
|
|
93
119
|
registerVisualAssets(ctx);
|
|
94
|
-
ctx.effect(()=>ctx.connection.fetch.register({path:'/api/plugins/dsh-generative-ui/diagnostics',methods:['GET'],requestBody:'buffered',fetch:diagnosticsRoute(feedback)}));
|
|
95
|
-
ctx.effect(()=>ctx.connection.fetch.register({path:'/api/plugins/dsh-generative-ui/fence',methods:['POST'],requestBody:'buffered',fetch:fenceRoute(store)}));
|
|
96
|
-
ctx.effect(()=>ctx.tools.register(defineTool({name:'validate_ui',description:
|
|
97
|
-
ctx.effect(()=>ctx.tools.register(defineTool({
|
|
98
|
-
name:'inspect_ui',description:
|
|
99
|
-
parameters:{documentId:{type:'string',required:true},detail:{type:'string',enum:['summary','nodes','full']},nodeIds:{type:'json',description:'For nodes detail: up to 16 existing node IDs.'}},
|
|
100
|
-
output:{schema:{type:'json'},render:(_args,value)=>[{type:'text',text:JSON.stringify(value)}]},isConcurrencySafe:()=>true,
|
|
101
|
-
async execute({documentId,detail='summary',nodeIds=[]},exec){const record=await store.owned(documentId,exec.agent?.id);const saved=await store.readState(documentId,record.sessionId);return inspectRecord(record,saved.state,evaluate(record.document,saved.state).derived,await store.audits(documentId),{detail,nodeIds:toolJson(nodeIds,'nodeIds')});}
|
|
102
|
-
})));
|
|
103
|
-
ctx.effect(()=>ctx.tools.register(defineTool({name:'patch_ui',description:
|
|
104
|
-
ctx.effect(()=>ctx.tools.register(defineTool({name:'update_ui',description:
|
|
105
|
-
for
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
120
|
+
ctx.effect(()=>ctx.connection.fetch.register({path:'/api/plugins/dsh-generative-ui/diagnostics',methods:['GET'],requestBody:'buffered',fetch:diagnosticsRoute(feedback)}));
|
|
121
|
+
ctx.effect(()=>ctx.connection.fetch.register({path:'/api/plugins/dsh-generative-ui/fence',methods:['POST'],requestBody:'buffered',fetch:fenceRoute(store)}));
|
|
122
|
+
ctx.effect(()=>ctx.tools.register(defineTool({name:'validate_ui',description:"Validate native or extended UI without saving/displaying. valid with complete=false means rejected components. Returns canonical document/diagnostics; a rendering tool still delivers the UI.",parameters:{document:{type:'json',required:true}},output:{schema:{type:'json'},render:(_a,v)=>[{type:'text',text:JSON.stringify(v)}]},isConcurrencySafe:()=>true,async execute({document}){try{const report=diagnoseDelivery(toolJson(document,'document'));return {...report,...(report.valid?{fallback:fallbackText(report.document)}:{error:report.diagnostics[0].message})}}catch(e){return{valid:false,complete:false,error:e.message}}}})));
|
|
123
|
+
ctx.effect(()=>ctx.tools.register(defineTool({
|
|
124
|
+
name:'inspect_ui',description:"Read current revision/state/derived and heuristic observations. Summary includes node paths/positions/editable fields. query finds text/labels/types (max200 chars); detail=nodes with query OR nodeIds reads matching source. Full only when needed. Missing observations mean unobserved; do not poll. Inspect before editing.",
|
|
125
|
+
parameters:{documentId:{type:'string',required:true},detail:{type:'string',enum:['summary','nodes','full']},query:{type:'string',description:'Find by text/label/title/type; mutually exclusive with nodeIds. Up to16 matches; blank means all.'},nodeIds:{type:'json',description:'For nodes detail: up to 16 existing node IDs.'}},
|
|
126
|
+
output:{schema:{type:'json'},render:(_args,value)=>[{type:'text',text:JSON.stringify(value)}]},isConcurrencySafe:()=>true,
|
|
127
|
+
async execute({documentId,detail='summary',nodeIds=[],query=''},exec){const record=await store.owned(documentId,exec.agent?.id);const saved=await store.readState(documentId,record.sessionId);return inspectRecord(record,saved.state,evaluate(record.document,saved.state).derived,await store.audits(documentId),{detail,nodeIds:toolJson(nodeIds,'nodeIds'),query});}
|
|
128
|
+
})));
|
|
129
|
+
ctx.effect(()=>ctx.tools.register(defineTool({name:'patch_ui',description:"Edit existing scalar/source properties using the inspected documentRevision. changes:[{id,props}]. IDs/structure/bindings/actions stay unchanged; canvas source replacement restarts that frame. Saved parameters persist. Use update_ui for structure changes.",parameters:{documentId:{type:'string',required:true},documentRevision:{type:'number',required:true},changes:{type:'json',required:true}},output:{schema:{type:'json'},render:(_a,v)=>[{type:'text',text:`Updated ${v.document.title}; documentId=${v.documentId}; documentRevision=${v.documentRevision}. Saved parameters retained.`}],presentationMeta:(_a,v)=>({dshGenerativeUiPatch:v})},async execute({documentId,documentRevision,changes},exec){exec.signal.throwIfAborted();return store.refine(documentId,exec.agent?.id,documentRevision,toolJson(changes,'changes'));}})));
|
|
130
|
+
ctx.effect(()=>ctx.tools.register(defineTool({name:'update_ui',description:"Append/replace existing content at the inspected revision, keeping documentId and compatible state. targetId selects a node; an extended fragment appends to the sole visual when unambiguous. Supply a stable operationId; reuse only for an identical retry (latest64 replay IDs). Preserve state/derived definitions; new inputs get defaults.",parameters:{documentId:{type:'string',required:true},documentRevision:{type:'number',required:true},operationId:{type:'string',required:true},mode:{type:'string',enum:['append','replace'],required:true},targetId:{type:'string'},document:{type:'json',required:true}},output:{schema:{type:'json'},render:(_a,v)=>[{type:'text',text:'Updated existing UI '+v.documentId+'; documentRevision='+v.documentRevision+'. Keep its existing inline marker; do not duplicate it.'}],presentationMeta:(_a,v)=>({dshGenerativeUiPatch:v})},async execute({documentId,documentRevision,operationId,mode,targetId,document},exec){exec.signal.throwIfAborted();return store.update(documentId,exec.agent?.id,documentRevision,operationId,{mode,...(targetId?{targetId}:{}),document:toolJson(document,'document')})}})));
|
|
131
|
+
for(const[i,section]of UI_SKILL_SECTIONS.entries())ctx.effect(()=>ctx.systemPrompt.section({...section,text:()=>promptSections(settings().designMode??'guided',settings().visualStyle??DEFAULT_VISUAL_STYLE)[i].text}));
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
|
|
135
|
+
|
|
@@ -273,8 +273,10 @@ l0,-`+(r+144)+`c-2,-159.3,-10,-310.7,-24,-454c-53.3,-528,-210,-949.7,
|
|
|
273
273
|
.motion-copy-title{flex:1;min-width:0;overflow-wrap:anywhere}.motion-copy-button{display:inline-flex!important;align-items:center;justify-content:center;flex:none;width:32px;height:32px;padding:6px!important;border:0!important;border-radius:10px!important;background:transparent!important;color:inherit;font:inherit;cursor:pointer;margin-left:auto}
|
|
274
274
|
.motion-copy-button:hover{background:var(--du-line,#8882)!important;color:var(--du-ink,inherit)}.motion-copy-button:focus-visible{outline:2px solid var(--du-accent,#508bff);outline-offset:2px}.motion-copy-button:disabled{opacity:.45;cursor:default}.motion-copy-button[data-status=done]{color:var(--du-green,#17995a)}.motion-copy-button[data-status=error]{color:var(--du-red,#d54b5b)}
|
|
275
275
|
.motion-copy-body{white-space:pre-wrap;overflow-wrap:anywhere;line-height:1.8}.motion-copy-code{margin:0!important;padding:0!important;border:0!important;background:transparent!important;overflow:auto;white-space:pre!important;tab-size:2;font:14px/1.75 ui-monospace,SFMono-Regular,Consolas,monospace}.motion-copy-code[data-wrap]{white-space:pre-wrap!important;overflow-wrap:anywhere}.motion-copy-code code{font:inherit!important;background:none!important;padding:0!important;color:inherit!important}.motion-copy-sr{position:absolute;width:1px;height:1px;overflow:hidden;clip-path:inset(50%);white-space:nowrap}
|
|
276
|
+
.motion-copy-button[data-status=done] .dgui-icon{animation:motion-copy-confirm 420ms cubic-bezier(.34,1.45,.64,1)}.motion-copy-button[data-status=done] path{stroke-dasharray:28;animation:motion-check-draw 450ms ease-out}@keyframes motion-check-draw{from{stroke-dashoffset:28}to{stroke-dashoffset:0}}@keyframes motion-copy-confirm{from{opacity:.5;transform:scale(.8)}to{opacity:1;transform:none}}
|
|
277
|
+
@media(prefers-reduced-motion:reduce){.motion-copy-button .dgui-icon,.motion-copy-button path{animation:none!important;transition:none!important}}
|
|
276
278
|
@media(max-width:600px){.motion-copy-block{padding:14px 16px;border-radius:20px}}
|
|
277
|
-
`;function Bl({text:e,children:t,title:r,lang:n,code:a=!1,wrap:i=!1,disabled:s=!1,style:o,nodeId:l,copyLabel:u,copiedLabel:d}){let[p,m]=(0,Jn.useState)("idle"),g=(0,Jn.useRef)();(0,Jn.useEffect)(()=>()=>clearTimeout(g.current),[]);let A=p==="done"?d??"\u5DF2\u590D\u5236":p==="error"?"\u590D\u5236\u5931\u8D25\uFF0C\u8BF7\u624B\u52A8\u9009\u62E9\u5185\u5BB9":u??(a?"\u590D\u5236\u4EE3\u7801":"\u590D\u5236\u6587\u672C");async function N(){clearTimeout(g.current),m("copying");let R=await db(e);m(R?"done":"error"),g.current=setTimeout(()=>m("idle"),2e3)}return zr("section",{className:"motion-copy-block","data-code":a||void 0,"data-ui-node":l,style:o},zr("style",null,pb),zr("div",{className:"motion-copy-bar"},a&&zr("span",{"aria-hidden":!0},"\u3008/\u3009"),zr("span",{className:"motion-copy-title"},r??(a?n||"\u4EE3\u7801":"\u6587\u672C")),zr("button",{className:"motion-copy-button",type:"button",title:A,"aria-label":A,"data-status":p,disabled:s||p==="copying",onClick:N},zr(Kg,{name:p==="done"?"check":p==="error"?"warning":"copy"})),zr("span",{className:"motion-copy-sr",role:"status","aria-live":"polite"},p==="done"?"\u5DF2\u590D\u5236\u5230\u526A\u8D34\u677F":p==="error"?A:"")),a?zr("pre",{className:"motion-copy-code","data-wrap":i||void 0},zr("code",{"data-language":n},e)):zr("div",{className:"motion-copy-body"},t??e))}var hr=ie(Le()),Jg={overflow:"auto",padding:12,borderRadius:8,background:"var(--dsw-alias-bg-layer-2)",fontFamily:"ui-monospace, SFMono-Regular, Menlo, monospace",fontSize:12,lineHeight:1.5,whiteSpace:"pre-wrap"};function Zg({code:e,lang:t,title:r,wrap:n,copyLabel:a,copiedLabel:i}){return(0,hr.jsx)(Bl,{text:e,lang:t,title:r,wrap:n,code:!0,copyLabel:a,copiedLabel:i})}function e4({diffs:e}){return(0,hr.jsx)("div",{children:e.map((t,r)=>(0,hr.jsxs)("section",{children:[(0,hr.jsx)("strong",{children:t.path}),(0,hr.jsx)("pre",{style:Jg,children:(t.oldText??"").split(`
|
|
279
|
+
`;function Bl({text:e,children:t,title:r,lang:n,code:a=!1,wrap:i=!1,disabled:s=!1,style:o,nodeId:l,copyLabel:u,copiedLabel:d}){let[p,m]=(0,Jn.useState)("idle"),g=(0,Jn.useRef)();(0,Jn.useEffect)(()=>()=>clearTimeout(g.current),[]);let A=p==="done"?d??"\u5DF2\u590D\u5236":p==="error"?"\u590D\u5236\u5931\u8D25\uFF0C\u8BF7\u624B\u52A8\u9009\u62E9\u5185\u5BB9":u??(a?"\u590D\u5236\u4EE3\u7801":"\u590D\u5236\u6587\u672C");async function N(){clearTimeout(g.current),m("copying");let R=await db(e);m(R?"done":"error"),g.current=setTimeout(()=>m("idle"),2e3)}return zr("section",{className:"motion-copy-block","data-copy-status":p,"data-code":a||void 0,"data-ui-node":l,style:o},zr("style",null,pb),zr("div",{className:"motion-copy-bar"},a&&zr("span",{"aria-hidden":!0},"\u3008/\u3009"),zr("span",{className:"motion-copy-title"},r??(a?n||"\u4EE3\u7801":"\u6587\u672C")),zr("button",{className:"motion-copy-button",type:"button",title:A,"aria-label":A,"data-status":p,disabled:s||p==="copying",onClick:N},zr(Kg,{name:p==="done"?"check":p==="error"?"warning":"copy"})),zr("span",{className:"motion-copy-sr",role:"status","aria-live":"polite"},p==="done"?"\u5DF2\u590D\u5236\u5230\u526A\u8D34\u677F":p==="error"?A:"")),a?zr("pre",{className:"motion-copy-code","data-wrap":i||void 0},zr("code",{"data-language":n},e)):zr("div",{className:"motion-copy-body"},t??e))}var hr=ie(Le()),Jg={overflow:"auto",padding:12,borderRadius:8,background:"var(--dsw-alias-bg-layer-2)",fontFamily:"ui-monospace, SFMono-Regular, Menlo, monospace",fontSize:12,lineHeight:1.5,whiteSpace:"pre-wrap"};function Zg({code:e,lang:t,title:r,wrap:n,copyLabel:a,copiedLabel:i}){return(0,hr.jsx)(Bl,{text:e,lang:t,title:r,wrap:n,code:!0,copyLabel:a,copiedLabel:i})}function e4({diffs:e}){return(0,hr.jsx)("div",{children:e.map((t,r)=>(0,hr.jsxs)("section",{children:[(0,hr.jsx)("strong",{children:t.path}),(0,hr.jsx)("pre",{style:Jg,children:(t.oldText??"").split(`
|
|
278
280
|
`).map(n=>`- ${n}`).concat((t.newText??"").split(`
|
|
279
281
|
`).map(n=>`+ ${n}`)).join(`
|
|
280
282
|
`)})]},`${t.path}:${r}`))})}function t4({data:e,label:t,copyable:r,labels:n}){let[a,i]=(0,As.useState)(!0),[s,o]=(0,As.useState)(!1),l=JSON.stringify(e,null,2),u=async()=>{await Ns(l)&&(o(!0),window.setTimeout(()=>o(!1),1200))};return(0,hr.jsxs)("section",{children:[(0,hr.jsxs)("div",{style:{display:"flex",alignItems:"center",gap:8},children:[(0,hr.jsxs)("button",{type:"button","aria-expanded":a,onClick:()=>i(d=>!d),children:[a?re("label.collapse"):re("label.expandNode")," ",t??"JSON"]}),r&&(0,hr.jsx)("button",{type:"button",onClick:()=>void u(),children:s?n?.copied??re("label.copied"):n?.copyJson??re("label.copy")})]}),a&&(0,hr.jsx)("pre",{style:Jg,children:l})]})}async function Ns(e){if(typeof navigator.clipboard?.writeText=="function")try{return await navigator.clipboard.writeText(e),!0}catch{return!1}let t=document.createElement("textarea");t.value=e,t.setAttribute("readonly",""),t.style.position="fixed",t.style.left="-9999px",document.body.appendChild(t);try{return t.select(),document.execCommand("copy")}catch{return!1}finally{t.remove()}}function r4(e){}var n4=(0,As.createContext)(void 0);var bb=(0,Hl.createContext)(void 0),Id=n4??bb;function i4(){return(0,Hl.useContext)(Id)}var s4="dsh.genui.interaction";function Gd(){return{order:[],blocks:{}}}function o4(){try{let e=localStorage.getItem(s4);if(e===null)return Gd();let t=JSON.parse(e);return!Array.isArray(t.order)||typeof t.blocks!="object"||t.blocks===null?Gd():{order:t.order.filter(r=>typeof r=="string"),blocks:t.blocks}}catch{return Gd()}}function xb(e){try{localStorage.setItem(s4,JSON.stringify(e))}catch{}}function l4(e){return e===""?null:o4().blocks[e]??null}function u4(e,t){if(e==="")return;let r=o4(),n=r.order.filter(i=>i!==e);n.unshift(e);let a={...r.blocks,[e]:t};for(;n.length>200;){let i=n.pop();i!==void 0&&delete a[i]}xb({order:n,blocks:a})}function jl(){return{fences:0,panels:0,interactions:0,templates:0,charts:0,advanced:0}}var _l=e=>t=>t.fences>=e;function wb(e){return re(`ach.${e}.name`)}function kb(e){return re(`ach.${e}.desc`)}function gr(e,t,r,n=!1){return{id:e,rarity:t,check:r,...n?{hidden:!0}:{},get name(){return wb(e)},get description(){return kb(e)}}}var c4=[gr("first-fence","common",_l(1)),gr("fence-5","common",_l(5)),gr("fence-25","rare",_l(25)),gr("fence-50","legendary",_l(50),!0),gr("first-interaction","common",e=>e.interactions>=1),gr("interaction-10","rare",e=>e.interactions>=10),gr("first-panel","common",e=>e.panels>=1),gr("panel-5","rare",e=>e.panels>=5),gr("first-chart","common",e=>e.charts>=1),gr("chart-10","rare",e=>e.charts>=10),gr("first-advanced","rare",e=>e.advanced>=1),gr("template-1","common",e=>e.templates>=1)];function d4(e){let t=0,r=0,n=a=>{if(Array.isArray(a))for(let i of a){if(typeof i!="object"||i===null)continue;let s=i,o=s.type;if((o==="chart"||o==="plot"||o==="echart")&&(t+=1),(o==="scene3d"||o==="mermaid"||o==="diagram")&&(r+=1),Array.isArray(s.items)&&n(s.items),Array.isArray(s.tabs))for(let l of s.tabs)n(l.items)}};return n(e.items),{charts:t,advanced:r}}function p4(e,t){return c4.filter(r=>t[r.id]===void 0&&r.check(e))}var f4="dsh.genui.achievements",m4="dsh.genui.achievements.seen",Sb=200,Qr=Tb(),Ab=new Set,Nb=[];function Tb(){try{let e=localStorage.getItem(f4);if(e===null)return{state:jl(),unlocked:{}};let t=JSON.parse(e);return{state:{...jl(),...t.state??{}},unlocked:typeof t.unlocked=="object"&&t.unlocked!==null?t.unlocked:{}}}catch{return{state:jl(),unlocked:{}}}}function Cb(){try{localStorage.setItem(f4,JSON.stringify(Qr))}catch{}}function Mb(){try{let e=localStorage.getItem(m4);if(e===null)return[];let t=JSON.parse(e);return Array.isArray(t)?t.filter(r=>typeof r=="string"):[]}catch{return[]}}function zb(e){try{localStorage.setItem(m4,JSON.stringify(e.slice(0,Sb)))}catch{}}function Eb(){for(let e of Ab)e()}function h4(e){Qr.state={...Qr.state,...e};let t=p4(Qr.state,Qr.unlocked);for(let r of t)Qr.unlocked[r.id]=Date.now();t.length>0&&Nb.push(...t),Cb(),Eb()}function Rb(e){let t=JSON.stringify(e),r=3735928559,n=1103547991;for(let a=0;a<t.length;a++){let i=t.charCodeAt(a);r=Math.imul(r^i,2654435761),n=Math.imul(n^i,1597334677)}return`${(r>>>0).toString(36)}-${(n>>>0).toString(36)}`}function g4(e){let t=Rb(e),r=Mb();if(r.includes(t))return;zb([t,...r]);let n=d4(e);h4({fences:Qr.state.fences+1,charts:Qr.state.charts+(n.charts>0?1:0),advanced:Qr.state.advanced+(n.advanced>0?1:0)})}function v4(){h4({interactions:Qr.state.interactions+1})}var Q2=ie(_e(),1);var Er=ie(_e(),1),Pd=(0,Er.createContext)({path:"root"});function y4({id:e,answers:t,children:r}){let n=(0,Er.useContext)(Pd);return(0,Er.createElement)(Pd.Provider,{value:{path:n.path+"/"+e,answers:t??n.answers}},r)}function Bt(e,t,r=()=>!0,n=!0){let a=(0,Er.useContext)(Pd),i="__motion_widget_"+a.path+":"+e,[s,o]=(0,Er.useState)(()=>{let d=n?a.answers?.fields[i]:void 0;if(d!==void 0)try{let p=JSON.parse(d);if(r(p))return p}catch{}return typeof t=="function"?t():t}),l=(0,Er.useRef)(s);l.current=s;let u=(d,p)=>{let m=typeof d=="function"?d(l.current):d;if(!r(m))return;l.current=m,o(m);let g=JSON.stringify(m);n&&p&&g!==void 0&&g.length<=4096&&g!==a.answers?.fields[i]&&a.answers?.setField(i,g)};return[s,d=>u(d,!0),d=>u(d,!1)]}var r0=ie(_e(),1);var z={maxDepth:8,maxNodes:200,maxString:2e3,maxCode:12e3,maxMermaid:8e3,maxGridCols:12,maxTabs:12,maxAccordionItems:24,maxListItems:50,maxOptions:50,maxTableRows:50,maxTableCols:12,maxChartPoints:60,maxPlotSeries:8,maxPlotParams:6,maxMeshes:5,maxQuizOptions:8,maxSteps:24,maxTimelineItems:24,maxBreadcrumbItems:12,maxKeyValuePairs:24,maxTreeDepth:6,maxDiagramNodes:9,maxDiagramEdges:12,maxDiagramZones:3,maxDiagramFocal:2,maxDiagramLabel:14,maxEChartOptionDepth:10,maxEChartArrayLen:500,maxEChartOptionNodes:2e3};var Rr=ie(_e(),1);var Mt=ie(Le(),1),b4=["var(--dsw-static-deepseek-400)","var(--dsw-static-deepseek-450)","var(--dsw-static-blue-450)","var(--dsw-static-green-400)","var(--dsw-static-amber-400)","var(--dsw-static-red-400)","var(--dsw-static-deepseek-300)","var(--dsw-static-neutral-bluish-400)"];function x4(e){let t=0;for(let r=0;r<e.length;r++)t=t*31+e.charCodeAt(r)>>>0;return b4[t%b4.length]}function w4({className:e,disabled:t,onClick:r,children:n}){let a=tt(),[i,s]=(0,Rr.useState)(!1),o=(0,Rr.useRef)(null);return(0,Rr.useEffect)(()=>()=>{o.current!==null&&clearTimeout(o.current)},[]),(0,Mt.jsxs)(Mt.Fragment,{children:[(0,Mt.jsxs)("button",{type:"button",className:e,disabled:t,onClick:r===void 0?void 0:()=>{r(),o.current!==null&&clearTimeout(o.current),s(!0),o.current=setTimeout(()=>s(!1),1400)},children:[n,i&&(0,Mt.jsx)("span",{className:y.btnSent,"aria-hidden":!0,children:a("block.triggered")})]}),(0,Mt.jsx)("span",{className:y.visuallyHidden,role:"status",children:i?a("block.triggeredPlain"):""})]})}var k4=(0,Rr.memo)(function({node:t}){let r=tt(),[n,a]=(0,Rr.useState)(!1);return(0,Mt.jsxs)("figure",{className:y.media,children:[t.alt!==void 0&&(0,Mt.jsx)("figcaption",{className:y.mediaLabel,children:q(t.alt)}),n?(0,Mt.jsx)("div",{className:y.mediaError,role:"alert",children:r("block.audioError")}):(0,Mt.jsx)("audio",{className:y.mediaPlayer,src:t.src,"aria-label":t.alt??r("block.audio"),controls:!0,preload:"metadata",loop:t.loop===!0,onError:()=>a(!0)})]})}),S4=(0,Rr.memo)(function({node:t}){let r=tt(),[n,a]=(0,Rr.useState)(!1);return(0,Mt.jsxs)("figure",{className:y.media,children:[t.alt!==void 0&&(0,Mt.jsx)("figcaption",{className:y.mediaLabel,children:q(t.alt)}),n?(0,Mt.jsx)("div",{className:y.mediaError,role:"alert",children:r("block.videoError")}):(0,Mt.jsx)("video",{className:`${y.mediaPlayer} ${y.videoPlayer}`,src:t.src,poster:t.poster,"aria-label":t.alt??r("block.video"),controls:!0,preload:"metadata",playsInline:!0,loop:t.loop===!0,muted:t.muted===!0,style:t.aspectRatio===void 0?void 0:{aspectRatio:t.aspectRatio.replace(":"," / ")},onError:()=>a(!0)})]})});var qe=ie(_e(),1);function Fd(e){let t=e.columns,r=Array.isArray(t)&&t.length>0,n=r&&Array.isArray(t)&&typeof t[0]=="object"&&t[0]!==null?t.map(Gb):t,a=Db(n),i=e.rows!==void 0?e.rows:e.data;if(Array.isArray(i)&&i.length>0&&typeof i[0]=="object"&&i[0]!==null&&!Array.isArray(i[0])){let l=Array.isArray(e.columns)&&e.columns.length>0&&typeof e.columns[0]=="object"&&e.columns[0]!==null?e.columns.map(Lb).filter(u=>u!==void 0):Object.keys(i[0]);i=i.map(u=>l.map(d=>Ib(u[d])))}let s=null;if(!r&&Array.isArray(i)&&i.length>0&&Array.isArray(i[0])){let l=Od(i),u=l.length===0?null:$b(l);u!==null&&Od(u.rows).length===u.rows.length&&(s=u,a=u.columns.map(d=>d.slice(0,128)))}if(a.length===0&&!Array.isArray(e.columns))return null;let o=Od(s===null?i:s.rows);return Array.isArray(i)?{columns:a.slice(0,z.maxTableCols),rows:o}:null}function yn(e){return Fd(e)?.rows??[]}function Bd(e,t){return!Array.isArray(e)||!Array.isArray(t)||t[0]!=="group"?!1:String(e[0]??"").trim()!==""&&e.slice(1).every(r=>String(r??"").trim()==="")}function Dr(e,t){let r=yn(e);return t>=0&&t<r.length&&!Bd(r[t],e.types)}function Db(e){if(!Array.isArray(e))return[];let t=[];for(let r of e){if(t.length>=z.maxTableCols)break;if(typeof r=="string")t.push(r.slice(0,128));else if(r!==null&&typeof r=="object"){let n=r,a=typeof n.label=="string"?n.label:typeof n.value=="string"?n.value:typeof n.title=="string"?n.title:JSON.stringify(r);t.push(a.slice(0,128))}}return t}function Od(e){if(!Array.isArray(e))return[];let t=[];for(let r of e){if(t.length>=z.maxTableRows)break;if(!Array.isArray(r))continue;let n=[];for(let a of r){if(n.length>=z.maxTableCols)break;typeof a=="string"?n.push(a.slice(0,256)):typeof a=="number"&&Number.isFinite(a)&&n.push(a)}n.length>0&&t.push(n)}return t}function $b(e){let t=e[0];if(t===void 0||t.length===0)return null;let r=e.slice(1);if(r.length===0){let n=t.map(a=>String(a).trim());return n.every(a=>a!=="")?{columns:n,rows:[]}:null}return r.every(n=>n.length===t.length)?{columns:t.map(n=>String(n).trim()),rows:r}:{columns:Array.from({length:t.length},(n,a)=>`\u5217${a+1}`),rows:e}}function Lb(e){if(e===null||typeof e!="object"||Array.isArray(e))return;let t=e;for(let r of["key","dataIndex","title","label"])if(typeof t[r]=="string"&&t[r]!=="")return t[r]}function Ib(e){return typeof e=="string"||typeof e=="number"&&Number.isFinite(e)?e:e==null?"":JSON.stringify(e)}function Gb(e){if(e===null||typeof e!="object"||Array.isArray(e))return String(e);let t=e;for(let r of["title","label","key","dataIndex"])if(typeof t[r]=="string"&&t[r]!=="")return t[r];return JSON.stringify(e)}var E=ie(Le(),1),Ul=["var(--dsw-static-deepseek-400)","var(--dsw-static-green-400)","var(--dsw-static-amber-400)","var(--dsw-static-red-400)","var(--dsw-static-blue-450)","var(--dsw-static-deepseek-450)","var(--dsw-static-neutral-bluish-400)","var(--dsw-static-deepseek-300)"],Vl=(e,t,r,n)=>r??(n!==void 0&&n.length>0?n[e%n.length]:t>1?Ul[e%Ul.length]:void 0);function di(e){if(typeof e=="number")return Number.isFinite(e)?e:NaN;if(typeof e!="string")return NaN;let t=e.trim();if(t==="")return NaN;t=t.replace(/^[¥$€£]/,""),t.endsWith("%")&&(t=t.slice(0,-1));let n=1;if(t.endsWith("\u4E07"))n=1e4,t=t.slice(0,-1);else if(t.endsWith("\u4EBF"))n=1e8,t=t.slice(0,-1);else if(/[kmb]$/i.test(t)){let i=t.slice(-1).toLowerCase();n=i==="k"?1e3:i==="m"?1e6:1e9,t=t.slice(0,-1)}t=t.replace(/[,,\s]/g,"");let a=Number(t);return Number.isFinite(a)?a*n:NaN}function Pb(e,t){return Array.from({length:t},(r,n)=>{let a=!1;for(let i of e){let s=i[n];if(!(s==null||s==="")){if(!Number.isFinite(di(s)))return!1;a=!0}}return a})}function Ob(e){return typeof e=="string"&&/[\n\r]/.test(e)}function Fb(e){return typeof e!="string"?!1:/(^|\n)[ \t]/.test(e)||e.includes("```")}function qd(e){if(Ob(e))return Fb(e)?y.tdCode:y.tdMultiline}function Bb(e){if(typeof e!="string")return null;let t=e.trim();return!/^[+][\s]*[\d.]/.test(t)&&!/^[-−][\s]*[\d.]/.test(t)?null:t.startsWith("+")?"up":"down"}function qb({cell:e}){let t=String(e).split(/[\s,;]+/).map(Number).filter(Number.isFinite);if(t.length<2)return(0,E.jsx)(E.Fragment,{children:q(String(e),!1)});let r=88,n=22,a=2,i=Math.min(...t),o=Math.max(...t)-i||1,l=(r-a*2)/(t.length-1),u=t.map((g,A)=>[a+A*l,n-a-(g-i)/o*(n-a*2)]),d=u.map(([g,A])=>`${g.toFixed(1)},${A.toFixed(1)}`).join(" "),p=u[u.length-1],m=`M ${a},${n-a} L ${d.split(" ").join(" L ")} L ${p[0].toFixed(1)},${n-a} Z`;return(0,E.jsxs)("svg",{className:y.cellSpark,viewBox:`0 0 ${r} ${n}`,preserveAspectRatio:"none","aria-hidden":"true",children:[(0,E.jsx)("path",{d:m,fill:"var(--dsl-g-accent)",opacity:"0.14"}),(0,E.jsx)("polyline",{points:d,fill:"none",stroke:"var(--dsl-g-accent)",strokeWidth:"1.5",strokeLinejoin:"round",strokeLinecap:"round",vectorEffect:"non-scaling-stroke"}),(0,E.jsx)("path",{d:`M ${p[0].toFixed(1)} ${p[1].toFixed(1)} L ${p[0].toFixed(1)} ${p[1].toFixed(1)}`,stroke:"var(--dsl-g-accent)",strokeWidth:4,strokeLinecap:"round",vectorEffect:"non-scaling-stroke",fill:"none"})]})}function Hb({cell:e}){let t=di(e),r=Number.isFinite(t)?Math.max(0,Math.min(100,t)):0,n=11,a=2*Math.PI*n;return(0,E.jsxs)("span",{className:y.cellRing,children:[(0,E.jsxs)("svg",{width:28,height:28,viewBox:"0 0 28 28","aria-hidden":"true",children:[(0,E.jsx)("circle",{cx:14,cy:14,r:n,fill:"none",strokeWidth:4,className:y.ringTrack}),(0,E.jsx)("circle",{cx:14,cy:14,r:n,fill:"none",strokeWidth:4,strokeLinecap:"round",className:y.ringFill,strokeDasharray:`${r/100*a} ${a}`,transform:"rotate(-90 14 14)"})]}),(0,E.jsx)("span",{className:y.cellRingText,children:q(String(e),!1)})]})}function _b(e,t){let r=s=>String(s??"").replace(/\|/g,"\\|").replace(/\n/g," "),n=`| ${e.map(r).join(" | ")} |`,a=`| ${e.map(()=>"---").join(" | ")} |`,i=t.map(s=>`| ${e.map((o,l)=>r(s[l])).join(" | ")} |`);return[n,a,...i].join(`
|
package/lib/assets/visual.js
CHANGED
|
@@ -265,8 +265,10 @@ l0,-`+(r+144)+`c-2,-159.3,-10,-310.7,-24,-454c-53.3,-528,-210,-949.7,
|
|
|
265
265
|
.motion-copy-title{flex:1;min-width:0;overflow-wrap:anywhere}.motion-copy-button{display:inline-flex!important;align-items:center;justify-content:center;flex:none;width:32px;height:32px;padding:6px!important;border:0!important;border-radius:10px!important;background:transparent!important;color:inherit;font:inherit;cursor:pointer;margin-left:auto}
|
|
266
266
|
.motion-copy-button:hover{background:var(--du-line,#8882)!important;color:var(--du-ink,inherit)}.motion-copy-button:focus-visible{outline:2px solid var(--du-accent,#508bff);outline-offset:2px}.motion-copy-button:disabled{opacity:.45;cursor:default}.motion-copy-button[data-status=done]{color:var(--du-green,#17995a)}.motion-copy-button[data-status=error]{color:var(--du-red,#d54b5b)}
|
|
267
267
|
.motion-copy-body{white-space:pre-wrap;overflow-wrap:anywhere;line-height:1.8}.motion-copy-code{margin:0!important;padding:0!important;border:0!important;background:transparent!important;overflow:auto;white-space:pre!important;tab-size:2;font:14px/1.75 ui-monospace,SFMono-Regular,Consolas,monospace}.motion-copy-code[data-wrap]{white-space:pre-wrap!important;overflow-wrap:anywhere}.motion-copy-code code{font:inherit!important;background:none!important;padding:0!important;color:inherit!important}.motion-copy-sr{position:absolute;width:1px;height:1px;overflow:hidden;clip-path:inset(50%);white-space:nowrap}
|
|
268
|
+
.motion-copy-button[data-status=done] .dgui-icon{animation:motion-copy-confirm 420ms cubic-bezier(.34,1.45,.64,1)}.motion-copy-button[data-status=done] path{stroke-dasharray:28;animation:motion-check-draw 450ms ease-out}@keyframes motion-check-draw{from{stroke-dashoffset:28}to{stroke-dashoffset:0}}@keyframes motion-copy-confirm{from{opacity:.5;transform:scale(.8)}to{opacity:1;transform:none}}
|
|
269
|
+
@media(prefers-reduced-motion:reduce){.motion-copy-button .dgui-icon,.motion-copy-button path{animation:none!important;transition:none!important}}
|
|
268
270
|
@media(max-width:600px){.motion-copy-block{padding:14px 16px;border-radius:20px}}
|
|
269
|
-
`;function Qn({text:t,children:e,title:r,lang:n,code:a=!1,wrap:i=!1,disabled:s=!1,style:o,nodeId:l,copyLabel:m,copiedLabel:u}){let[p,b]=(0,lr.useState)("idle"),y=(0,lr.useRef)();(0,lr.useEffect)(()=>()=>clearTimeout(y.current),[]);let k=p==="done"?u??"\u5DF2\u590D\u5236":p==="error"?"\u590D\u5236\u5931\u8D25\uFF0C\u8BF7\u624B\u52A8\u9009\u62E9\u5185\u5BB9":m??(a?"\u590D\u5236\u4EE3\u7801":"\u590D\u5236\u6587\u672C");async function T(){clearTimeout(y.current),b("copying");let C=await cm(t);b(C?"done":"error"),y.current=setTimeout(()=>b("idle"),2e3)}return St("section",{className:"motion-copy-block","data-code":a||void 0,"data-ui-node":l,style:o},St("style",null,dm),St("div",{className:"motion-copy-bar"},a&&St("span",{"aria-hidden":!0},"\u3008/\u3009"),St("span",{className:"motion-copy-title"},r??(a?n||"\u4EE3\u7801":"\u6587\u672C")),St("button",{className:"motion-copy-button",type:"button",title:k,"aria-label":k,"data-status":p,disabled:s||p==="copying",onClick:T},St(u0,{name:p==="done"?"check":p==="error"?"warning":"copy"})),St("span",{className:"motion-copy-sr",role:"status","aria-live":"polite"},p==="done"?"\u5DF2\u590D\u5236\u5230\u526A\u8D34\u677F":p==="error"?k:"")),a?St("pre",{className:"motion-copy-code","data-wrap":i||void 0},St("code",{"data-language":n},t)):St("div",{className:"motion-copy-body"},e??t))}var bt=require("react/jsx-runtime"),m0={overflow:"auto",padding:12,borderRadius:8,background:"var(--dsw-alias-bg-layer-2)",fontFamily:"ui-monospace, SFMono-Regular, Menlo, monospace",fontSize:12,lineHeight:1.5,whiteSpace:"pre-wrap"};function p0({code:t,lang:e,title:r,wrap:n,copyLabel:a,copiedLabel:i}){return(0,bt.jsx)(Qn,{text:t,lang:e,title:r,wrap:n,code:!0,copyLabel:a,copiedLabel:i})}function f0({diffs:t}){return(0,bt.jsx)("div",{children:t.map((e,r)=>(0,bt.jsxs)("section",{children:[(0,bt.jsx)("strong",{children:e.path}),(0,bt.jsx)("pre",{style:m0,children:(e.oldText??"").split(`
|
|
271
|
+
`;function Qn({text:t,children:e,title:r,lang:n,code:a=!1,wrap:i=!1,disabled:s=!1,style:o,nodeId:l,copyLabel:m,copiedLabel:u}){let[p,b]=(0,lr.useState)("idle"),y=(0,lr.useRef)();(0,lr.useEffect)(()=>()=>clearTimeout(y.current),[]);let k=p==="done"?u??"\u5DF2\u590D\u5236":p==="error"?"\u590D\u5236\u5931\u8D25\uFF0C\u8BF7\u624B\u52A8\u9009\u62E9\u5185\u5BB9":m??(a?"\u590D\u5236\u4EE3\u7801":"\u590D\u5236\u6587\u672C");async function T(){clearTimeout(y.current),b("copying");let C=await cm(t);b(C?"done":"error"),y.current=setTimeout(()=>b("idle"),2e3)}return St("section",{className:"motion-copy-block","data-copy-status":p,"data-code":a||void 0,"data-ui-node":l,style:o},St("style",null,dm),St("div",{className:"motion-copy-bar"},a&&St("span",{"aria-hidden":!0},"\u3008/\u3009"),St("span",{className:"motion-copy-title"},r??(a?n||"\u4EE3\u7801":"\u6587\u672C")),St("button",{className:"motion-copy-button",type:"button",title:k,"aria-label":k,"data-status":p,disabled:s||p==="copying",onClick:T},St(u0,{name:p==="done"?"check":p==="error"?"warning":"copy"})),St("span",{className:"motion-copy-sr",role:"status","aria-live":"polite"},p==="done"?"\u5DF2\u590D\u5236\u5230\u526A\u8D34\u677F":p==="error"?k:"")),a?St("pre",{className:"motion-copy-code","data-wrap":i||void 0},St("code",{"data-language":n},t)):St("div",{className:"motion-copy-body"},e??t))}var bt=require("react/jsx-runtime"),m0={overflow:"auto",padding:12,borderRadius:8,background:"var(--dsw-alias-bg-layer-2)",fontFamily:"ui-monospace, SFMono-Regular, Menlo, monospace",fontSize:12,lineHeight:1.5,whiteSpace:"pre-wrap"};function p0({code:t,lang:e,title:r,wrap:n,copyLabel:a,copiedLabel:i}){return(0,bt.jsx)(Qn,{text:t,lang:e,title:r,wrap:n,code:!0,copyLabel:a,copiedLabel:i})}function f0({diffs:t}){return(0,bt.jsx)("div",{children:t.map((e,r)=>(0,bt.jsxs)("section",{children:[(0,bt.jsx)("strong",{children:e.path}),(0,bt.jsx)("pre",{style:m0,children:(e.oldText??"").split(`
|
|
270
272
|
`).map(n=>`- ${n}`).concat((e.newText??"").split(`
|
|
271
273
|
`).map(n=>`+ ${n}`)).join(`
|
|
272
274
|
`)})]},`${e.path}:${r}`))})}function h0({data:t,label:e,copyable:r,labels:n}){let[a,i]=(0,tn.useState)(!0),[s,o]=(0,tn.useState)(!1),l=JSON.stringify(t,null,2),m=async()=>{await rn(l)&&(o(!0),window.setTimeout(()=>o(!1),1200))};return(0,bt.jsxs)("section",{children:[(0,bt.jsxs)("div",{style:{display:"flex",alignItems:"center",gap:8},children:[(0,bt.jsxs)("button",{type:"button","aria-expanded":a,onClick:()=>i(u=>!u),children:[a?_("label.collapse"):_("label.expandNode")," ",e??"JSON"]}),r&&(0,bt.jsx)("button",{type:"button",onClick:()=>void m(),children:s?n?.copied??_("label.copied"):n?.copyJson??_("label.copy")})]}),a&&(0,bt.jsx)("pre",{style:m0,children:l})]})}async function rn(t){if(typeof navigator.clipboard?.writeText=="function")try{return await navigator.clipboard.writeText(t),!0}catch{return!1}let e=document.createElement("textarea");e.value=t,e.setAttribute("readonly",""),e.style.position="fixed",e.style.left="-9999px",document.body.appendChild(e);try{return e.select(),document.execCommand("copy")}catch{return!1}finally{e.remove()}}function g0(t){}var b0=(0,tn.createContext)(void 0);var um=(0,ea.createContext)(void 0),Ni=b0??um;function v0(){return(0,ea.useContext)(Ni)}var x0="dsh.genui.interaction";function Mi(){return{order:[],blocks:{}}}function w0(){try{let t=localStorage.getItem(x0);if(t===null)return Mi();let e=JSON.parse(t);return!Array.isArray(e.order)||typeof e.blocks!="object"||e.blocks===null?Mi():{order:e.order.filter(r=>typeof r=="string"),blocks:e.blocks}}catch{return Mi()}}function mm(t){try{localStorage.setItem(x0,JSON.stringify(t))}catch{}}function k0(t){return t===""?null:w0().blocks[t]??null}function S0(t,e){if(t==="")return;let r=w0(),n=r.order.filter(i=>i!==t);n.unshift(t);let a={...r.blocks,[t]:e};for(;n.length>200;){let i=n.pop();i!==void 0&&delete a[i]}mm({order:n,blocks:a})}function ra(){return{fences:0,panels:0,interactions:0,templates:0,charts:0,advanced:0}}var ta=t=>e=>e.fences>=t;function pm(t){return _(`ach.${t}.name`)}function fm(t){return _(`ach.${t}.desc`)}function yt(t,e,r,n=!1){return{id:t,rarity:e,check:r,...n?{hidden:!0}:{},get name(){return pm(t)},get description(){return fm(t)}}}var A0=[yt("first-fence","common",ta(1)),yt("fence-5","common",ta(5)),yt("fence-25","rare",ta(25)),yt("fence-50","legendary",ta(50),!0),yt("first-interaction","common",t=>t.interactions>=1),yt("interaction-10","rare",t=>t.interactions>=10),yt("first-panel","common",t=>t.panels>=1),yt("panel-5","rare",t=>t.panels>=5),yt("first-chart","common",t=>t.charts>=1),yt("chart-10","rare",t=>t.charts>=10),yt("first-advanced","rare",t=>t.advanced>=1),yt("template-1","common",t=>t.templates>=1)];function T0(t){let e=0,r=0,n=a=>{if(Array.isArray(a))for(let i of a){if(typeof i!="object"||i===null)continue;let s=i,o=s.type;if((o==="chart"||o==="plot"||o==="echart")&&(e+=1),(o==="scene3d"||o==="mermaid"||o==="diagram")&&(r+=1),Array.isArray(s.items)&&n(s.items),Array.isArray(s.tabs))for(let l of s.tabs)n(l.items)}};return n(t.items),{charts:e,advanced:r}}function N0(t,e){return A0.filter(r=>e[r.id]===void 0&&r.check(t))}var M0="dsh.genui.achievements",C0="dsh.genui.achievements.seen",hm=200,qt=ym(),gm=new Set,bm=[];function ym(){try{let t=localStorage.getItem(M0);if(t===null)return{state:ra(),unlocked:{}};let e=JSON.parse(t);return{state:{...ra(),...e.state??{}},unlocked:typeof e.unlocked=="object"&&e.unlocked!==null?e.unlocked:{}}}catch{return{state:ra(),unlocked:{}}}}function vm(){try{localStorage.setItem(M0,JSON.stringify(qt))}catch{}}function xm(){try{let t=localStorage.getItem(C0);if(t===null)return[];let e=JSON.parse(t);return Array.isArray(e)?e.filter(r=>typeof r=="string"):[]}catch{return[]}}function wm(t){try{localStorage.setItem(C0,JSON.stringify(t.slice(0,hm)))}catch{}}function km(){for(let t of gm)t()}function z0(t){qt.state={...qt.state,...t};let e=N0(qt.state,qt.unlocked);for(let r of e)qt.unlocked[r.id]=Date.now();e.length>0&&bm.push(...e),vm(),km()}function Sm(t){let e=JSON.stringify(t),r=3735928559,n=1103547991;for(let a=0;a<e.length;a++){let i=e.charCodeAt(a);r=Math.imul(r^i,2654435761),n=Math.imul(n^i,1597334677)}return`${(r>>>0).toString(36)}-${(n>>>0).toString(36)}`}function R0(t){let e=Sm(t),r=xm();if(r.includes(e))return;wm([e,...r]);let n=T0(t);z0({fences:qt.state.fences+1,charts:qt.state.charts+(n.charts>0?1:0),advanced:qt.state.advanced+(n.advanced>0?1:0)})}function G0(){z0({interactions:qt.state.interactions+1})}var cc=require("react");var At=require("react"),Ci=(0,At.createContext)({path:"root"});function $0({id:t,answers:e,children:r}){let n=(0,At.useContext)(Ci);return(0,At.createElement)(Ci.Provider,{value:{path:n.path+"/"+t,answers:e??n.answers}},r)}function st(t,e,r=()=>!0,n=!0){let a=(0,At.useContext)(Ci),i="__motion_widget_"+a.path+":"+t,[s,o]=(0,At.useState)(()=>{let u=n?a.answers?.fields[i]:void 0;if(u!==void 0)try{let p=JSON.parse(u);if(r(p))return p}catch{}return typeof e=="function"?e():e}),l=(0,At.useRef)(s);l.current=s;let m=(u,p)=>{let b=typeof u=="function"?u(l.current):u;if(!r(b))return;l.current=b,o(b);let y=JSON.stringify(b);n&&p&&y!==void 0&&y.length<=4096&&y!==a.answers?.fields[i]&&a.answers?.setField(i,y)};return[s,u=>m(u,!0),u=>m(u,!1)]}var fa=require("react");var A={maxDepth:8,maxNodes:200,maxString:2e3,maxCode:12e3,maxMermaid:8e3,maxGridCols:12,maxTabs:12,maxAccordionItems:24,maxListItems:50,maxOptions:50,maxTableRows:50,maxTableCols:12,maxChartPoints:60,maxPlotSeries:8,maxPlotParams:6,maxMeshes:5,maxQuizOptions:8,maxSteps:24,maxTimelineItems:24,maxBreadcrumbItems:12,maxKeyValuePairs:24,maxTreeDepth:6,maxDiagramNodes:9,maxDiagramEdges:12,maxDiagramZones:3,maxDiagramFocal:2,maxDiagramLabel:14,maxEChartOptionDepth:10,maxEChartArrayLen:500,maxEChartOptionNodes:2e3};var Tt=require("react");var Ze=require("react/jsx-runtime"),E0=["var(--dsw-static-deepseek-400)","var(--dsw-static-deepseek-450)","var(--dsw-static-blue-450)","var(--dsw-static-green-400)","var(--dsw-static-amber-400)","var(--dsw-static-red-400)","var(--dsw-static-deepseek-300)","var(--dsw-static-neutral-bluish-400)"];function D0(t){let e=0;for(let r=0;r<t.length;r++)e=e*31+t.charCodeAt(r)>>>0;return E0[e%E0.length]}function I0({className:t,disabled:e,onClick:r,children:n}){let a=Oe(),[i,s]=(0,Tt.useState)(!1),o=(0,Tt.useRef)(null);return(0,Tt.useEffect)(()=>()=>{o.current!==null&&clearTimeout(o.current)},[]),(0,Ze.jsxs)(Ze.Fragment,{children:[(0,Ze.jsxs)("button",{type:"button",className:t,disabled:e,onClick:r===void 0?void 0:()=>{r(),o.current!==null&&clearTimeout(o.current),s(!0),o.current=setTimeout(()=>s(!1),1400)},children:[n,i&&(0,Ze.jsx)("span",{className:g.btnSent,"aria-hidden":!0,children:a("block.triggered")})]}),(0,Ze.jsx)("span",{className:g.visuallyHidden,role:"status",children:i?a("block.triggeredPlain"):""})]})}var L0=(0,Tt.memo)(function({node:e}){let r=Oe(),[n,a]=(0,Tt.useState)(!1);return(0,Ze.jsxs)("figure",{className:g.media,children:[e.alt!==void 0&&(0,Ze.jsx)("figcaption",{className:g.mediaLabel,children:B(e.alt)}),n?(0,Ze.jsx)("div",{className:g.mediaError,role:"alert",children:r("block.audioError")}):(0,Ze.jsx)("audio",{className:g.mediaPlayer,src:e.src,"aria-label":e.alt??r("block.audio"),controls:!0,preload:"metadata",loop:e.loop===!0,onError:()=>a(!0)})]})}),B0=(0,Tt.memo)(function({node:e}){let r=Oe(),[n,a]=(0,Tt.useState)(!1);return(0,Ze.jsxs)("figure",{className:g.media,children:[e.alt!==void 0&&(0,Ze.jsx)("figcaption",{className:g.mediaLabel,children:B(e.alt)}),n?(0,Ze.jsx)("div",{className:g.mediaError,role:"alert",children:r("block.videoError")}):(0,Ze.jsx)("video",{className:`${g.mediaPlayer} ${g.videoPlayer}`,src:e.src,poster:e.poster,"aria-label":e.alt??r("block.video"),controls:!0,preload:"metadata",playsInline:!0,loop:e.loop===!0,muted:e.muted===!0,style:e.aspectRatio===void 0?void 0:{aspectRatio:e.aspectRatio.replace(":"," / ")},onError:()=>a(!0)})]})});var $e=require("react");function Ri(t){let e=t.columns,r=Array.isArray(e)&&e.length>0,n=r&&Array.isArray(e)&&typeof e[0]=="object"&&e[0]!==null?e.map(Cm):e,a=Am(n),i=t.rows!==void 0?t.rows:t.data;if(Array.isArray(i)&&i.length>0&&typeof i[0]=="object"&&i[0]!==null&&!Array.isArray(i[0])){let l=Array.isArray(t.columns)&&t.columns.length>0&&typeof t.columns[0]=="object"&&t.columns[0]!==null?t.columns.map(Nm).filter(m=>m!==void 0):Object.keys(i[0]);i=i.map(m=>l.map(u=>Mm(m[u])))}let s=null;if(!r&&Array.isArray(i)&&i.length>0&&Array.isArray(i[0])){let l=zi(i),m=l.length===0?null:Tm(l);m!==null&&zi(m.rows).length===m.rows.length&&(s=m,a=m.columns.map(u=>u.slice(0,128)))}if(a.length===0&&!Array.isArray(t.columns))return null;let o=zi(s===null?i:s.rows);return Array.isArray(i)?{columns:a.slice(0,A.maxTableCols),rows:o}:null}function Yt(t){return Ri(t)?.rows??[]}function Gi(t,e){return!Array.isArray(t)||!Array.isArray(e)||e[0]!=="group"?!1:String(t[0]??"").trim()!==""&&t.slice(1).every(r=>String(r??"").trim()==="")}function Nt(t,e){let r=Yt(t);return e>=0&&e<r.length&&!Gi(r[e],t.types)}function Am(t){if(!Array.isArray(t))return[];let e=[];for(let r of t){if(e.length>=A.maxTableCols)break;if(typeof r=="string")e.push(r.slice(0,128));else if(r!==null&&typeof r=="object"){let n=r,a=typeof n.label=="string"?n.label:typeof n.value=="string"?n.value:typeof n.title=="string"?n.title:JSON.stringify(r);e.push(a.slice(0,128))}}return e}function zi(t){if(!Array.isArray(t))return[];let e=[];for(let r of t){if(e.length>=A.maxTableRows)break;if(!Array.isArray(r))continue;let n=[];for(let a of r){if(n.length>=A.maxTableCols)break;typeof a=="string"?n.push(a.slice(0,256)):typeof a=="number"&&Number.isFinite(a)&&n.push(a)}n.length>0&&e.push(n)}return e}function Tm(t){let e=t[0];if(e===void 0||e.length===0)return null;let r=t.slice(1);if(r.length===0){let n=e.map(a=>String(a).trim());return n.every(a=>a!=="")?{columns:n,rows:[]}:null}return r.every(n=>n.length===e.length)?{columns:e.map(n=>String(n).trim()),rows:r}:{columns:Array.from({length:e.length},(n,a)=>`\u5217${a+1}`),rows:t}}function Nm(t){if(t===null||typeof t!="object"||Array.isArray(t))return;let e=t;for(let r of["key","dataIndex","title","label"])if(typeof e[r]=="string"&&e[r]!=="")return e[r]}function Mm(t){return typeof t=="string"||typeof t=="number"&&Number.isFinite(t)?t:t==null?"":JSON.stringify(t)}function Cm(t){if(t===null||typeof t!="object"||Array.isArray(t))return String(t);let e=t;for(let r of["title","label","key","dataIndex"])if(typeof e[r]=="string"&&e[r]!=="")return e[r];return JSON.stringify(t)}var N=require("react/jsx-runtime"),na=["var(--dsw-static-deepseek-400)","var(--dsw-static-green-400)","var(--dsw-static-amber-400)","var(--dsw-static-red-400)","var(--dsw-static-blue-450)","var(--dsw-static-deepseek-450)","var(--dsw-static-neutral-bluish-400)","var(--dsw-static-deepseek-300)"],aa=(t,e,r,n)=>r??(n!==void 0&&n.length>0?n[t%n.length]:e>1?na[t%na.length]:void 0);function Gr(t){if(typeof t=="number")return Number.isFinite(t)?t:NaN;if(typeof t!="string")return NaN;let e=t.trim();if(e==="")return NaN;e=e.replace(/^[¥$€£]/,""),e.endsWith("%")&&(e=e.slice(0,-1));let n=1;if(e.endsWith("\u4E07"))n=1e4,e=e.slice(0,-1);else if(e.endsWith("\u4EBF"))n=1e8,e=e.slice(0,-1);else if(/[kmb]$/i.test(e)){let i=e.slice(-1).toLowerCase();n=i==="k"?1e3:i==="m"?1e6:1e9,e=e.slice(0,-1)}e=e.replace(/[,,\s]/g,"");let a=Number(e);return Number.isFinite(a)?a*n:NaN}function zm(t,e){return Array.from({length:e},(r,n)=>{let a=!1;for(let i of t){let s=i[n];if(!(s==null||s==="")){if(!Number.isFinite(Gr(s)))return!1;a=!0}}return a})}function Rm(t){return typeof t=="string"&&/[\n\r]/.test(t)}function Gm(t){return typeof t!="string"?!1:/(^|\n)[ \t]/.test(t)||t.includes("```")}function $i(t){if(Rm(t))return Gm(t)?g.tdCode:g.tdMultiline}function $m(t){if(typeof t!="string")return null;let e=t.trim();return!/^[+][\s]*[\d.]/.test(e)&&!/^[-−][\s]*[\d.]/.test(e)?null:e.startsWith("+")?"up":"down"}function Em({cell:t}){let e=String(t).split(/[\s,;]+/).map(Number).filter(Number.isFinite);if(e.length<2)return(0,N.jsx)(N.Fragment,{children:B(String(t),!1)});let r=88,n=22,a=2,i=Math.min(...e),o=Math.max(...e)-i||1,l=(r-a*2)/(e.length-1),m=e.map((y,k)=>[a+k*l,n-a-(y-i)/o*(n-a*2)]),u=m.map(([y,k])=>`${y.toFixed(1)},${k.toFixed(1)}`).join(" "),p=m[m.length-1],b=`M ${a},${n-a} L ${u.split(" ").join(" L ")} L ${p[0].toFixed(1)},${n-a} Z`;return(0,N.jsxs)("svg",{className:g.cellSpark,viewBox:`0 0 ${r} ${n}`,preserveAspectRatio:"none","aria-hidden":"true",children:[(0,N.jsx)("path",{d:b,fill:"var(--dsl-g-accent)",opacity:"0.14"}),(0,N.jsx)("polyline",{points:u,fill:"none",stroke:"var(--dsl-g-accent)",strokeWidth:"1.5",strokeLinejoin:"round",strokeLinecap:"round",vectorEffect:"non-scaling-stroke"}),(0,N.jsx)("path",{d:`M ${p[0].toFixed(1)} ${p[1].toFixed(1)} L ${p[0].toFixed(1)} ${p[1].toFixed(1)}`,stroke:"var(--dsl-g-accent)",strokeWidth:4,strokeLinecap:"round",vectorEffect:"non-scaling-stroke",fill:"none"})]})}function Dm({cell:t}){let e=Gr(t),r=Number.isFinite(e)?Math.max(0,Math.min(100,e)):0,n=11,a=2*Math.PI*n;return(0,N.jsxs)("span",{className:g.cellRing,children:[(0,N.jsxs)("svg",{width:28,height:28,viewBox:"0 0 28 28","aria-hidden":"true",children:[(0,N.jsx)("circle",{cx:14,cy:14,r:n,fill:"none",strokeWidth:4,className:g.ringTrack}),(0,N.jsx)("circle",{cx:14,cy:14,r:n,fill:"none",strokeWidth:4,strokeLinecap:"round",className:g.ringFill,strokeDasharray:`${r/100*a} ${a}`,transform:"rotate(-90 14 14)"})]}),(0,N.jsx)("span",{className:g.cellRingText,children:B(String(t),!1)})]})}function Im(t,e){let r=s=>String(s??"").replace(/\|/g,"\\|").replace(/\n/g," "),n=`| ${t.map(r).join(" | ")} |`,a=`| ${t.map(()=>"---").join(" | ")} |`,i=e.map(s=>`| ${t.map((o,l)=>r(s[l])).join(" | ")} |`);return[n,a,...i].join(`
|
package/lib/author-expression.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// A small authoring language compiled to the existing interpreter; never eval.
|
|
2
2
|
import { IDENTIFIER_SOURCE, validIdentifier } from './identifiers.js';
|
|
3
3
|
export function compileExpression(source) {
|
|
4
|
-
const fail = () => { throw new Error('DSH UI: invalid formula; use state.x, data.x, derived.x, item.x, numbers, strings, + - * /, comparisons, ?: and min/max/round/abs'); };
|
|
4
|
+
const fail = () => { throw new Error('DSH UI: invalid formula; use state.x, data.x, derived.x, item.x, numbers, strings, + - * /, comparisons, ?: and min/max/round/ceil/floor/abs'); };
|
|
5
5
|
if (typeof source !== 'string' || !source.trim() || source.length > 2048) fail();
|
|
6
6
|
const tokens = []; let offset = 0;
|
|
7
7
|
const token = new RegExp(String.raw`\s*(?:(\d+(?:\.\d*)?|\.\d+)([eE][+-]?\d+)?|("(?:[^"\\]|\\.)*")|(${IDENTIFIER_SOURCE}(?:\.${IDENTIFIER_SOURCE})?)|(===|!==|<=|>=|==|!=|[+*/()?,:<>-]))`, 'uy');
|
|
@@ -23,7 +23,7 @@ export function compileExpression(source) {
|
|
|
23
23
|
else if (t === '(') { out = parse(0, depth + 1); take(')'); }
|
|
24
24
|
else if (t === '-' || t === '+') { const arg = parse(5, depth + 1); out = t === '-' ? { op: 'sub', args: [{ const: 0 }, arg] } : arg; }
|
|
25
25
|
else if (typeof t === 'string' && t.split('.').length === 2 && ['state','data','derived','item'].includes(t.split('.')[0]) && validIdentifier(t.split('.')[1])) out = { ref: t };
|
|
26
|
-
else if (['min', 'max', 'round', 'abs'].includes(t)) {
|
|
26
|
+
else if (['min', 'max', 'round', 'ceil', 'floor', 'abs'].includes(t)) {
|
|
27
27
|
take('('); const args = [parse(0, depth + 1)];
|
|
28
28
|
while (tokens[pos] === ',') { pos++; args.push(parse(0, depth + 1)); if (args.length > 8) fail(); }
|
|
29
29
|
take(')'); out = { op: t, args };
|
|
@@ -41,20 +41,21 @@ export function compileExpression(source) {
|
|
|
41
41
|
}
|
|
42
42
|
|
|
43
43
|
export function expandExpressions(doc) {
|
|
44
|
-
const expression = e => {
|
|
44
|
+
const expression = (e, at) => {
|
|
45
45
|
if (!e || typeof e !== 'object' || Array.isArray(e)) return e;
|
|
46
46
|
if (Object.hasOwn(e, 'expr')) {
|
|
47
47
|
if (Object.keys(e).length !== 1) throw new Error('DSH UI: expr must be the only formula field');
|
|
48
|
-
return compileExpression(e.expr);
|
|
48
|
+
try{return compileExpression(e.expr)}catch(error){error.message='DSH UI: '+at+': '+error.message.replace(/^DSH UI: /,'');error.path=at;throw error}
|
|
49
49
|
}
|
|
50
|
-
if (Array.isArray(e.args)) e.args = e.args.map(expression);
|
|
51
|
-
if (e.map?.fields) for (const k of Object.keys(e.map.fields)) e.map.fields[k] = expression(e.map.fields[k]);
|
|
50
|
+
if (Array.isArray(e.args)) e.args = e.args.map((v,i)=>expression(v,at+'.args['+i+']'));
|
|
51
|
+
if (e.map?.fields) for (const k of Object.keys(e.map.fields)) e.map.fields[k] = expression(e.map.fields[k],at+'.map.fields.'+k);
|
|
52
52
|
return e;
|
|
53
53
|
};
|
|
54
|
-
if (doc.derived && typeof doc.derived === 'object') for (const k of Object.keys(doc.derived)) doc.derived[k] = expression(doc.derived[k]);
|
|
54
|
+
if (doc.derived && typeof doc.derived === 'object') for (const k of Object.keys(doc.derived)) doc.derived[k] = expression(doc.derived[k],'derived.'+k);
|
|
55
55
|
const walk = nodes => { if (!Array.isArray(nodes)) return; for (const node of nodes) {
|
|
56
56
|
if (!node || typeof node !== 'object') continue;
|
|
57
|
-
for (const field of ['text', 'value', 'max', 'rows']) if (Object.hasOwn(node, field)) node[field] = expression(node[field]);
|
|
57
|
+
for (const field of ['text', 'value', 'max', 'rows']) if (Object.hasOwn(node, field)) node[field] = expression(node[field],'node.'+node.id+'.'+field);
|
|
58
|
+
if (['table','chart'].includes(node.type)&&Array.isArray(node.rows)) for(const [rowIndex,row] of node.rows.entries()) if(row&&typeof row==='object'&&!Array.isArray(row)) for(const k of Object.keys(row)) row[k]=expression(row[k],'node.'+node.id+'.rows['+rowIndex+'].'+k);
|
|
58
59
|
walk(node.children);
|
|
59
60
|
} };
|
|
60
61
|
walk(doc.nodes); return doc;
|
package/lib/authoring-guide.js
CHANGED
|
@@ -1,16 +1,3 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
- JSON object field order never matters. Every node, including each sandbox, must include a unique id. sandbox title/fallback default to the document's only when omitted; do not send null or empty values.
|
|
5
|
-
- Declaring state does NOT create controls. For each parameter the user should edit, add a native slider/input/select/toggle bound to state.key, or actual canvas HTML controls wired to DSHUI.setState with that key in stateKeys. A canvas subscribe callback only updates display; it does not create an input. Read-only state and static UI are valid; do not invent controls where the task does not need them. Check intended controls exist before calling the tool.
|
|
6
|
-
- Use render_ui/render_canvas directly for UI construction. This contract and ui_catalog are the protocol reference; installation source inspection is not a prerequisite. For unclear component/formula details consult ui_catalog, rather than grep/glob/shell searches of DSH checkouts or app.asar. File/search tools needed for the user's actual task or data remain appropriate.
|
|
7
|
-
- Formula round(x) takes ONE argument and uses JavaScript Math.round: nearest integer, ties toward positive infinity (round(2.5)=3, round(-2.5)=-2). It is not ceil/floor, which are not registered native formula functions. For ceiling/floor use Math.ceil/Math.floor in a canvas subscribed to declared shared state. Display decimals formats numbers without changing calculation precision.
|
|
8
|
-
- Pass tool JSON fields as objects, not hand-escaped JSON strings. For custom HTML/SVG use render_canvas({title,fallback,html,css,script}) to avoid nesting source in document JSON.
|
|
9
|
-
- Start with the smallest useful static UI. State/derived/actions are optional. A table can put its object rows directly in rows; reuse data/derived references only when useful. Example: {id:"t",type:"table",label:"方案比较",columns:[{key:"方案",label:"方案"}],rows:[{"方案":"A"}]}.
|
|
10
|
-
- For a short ordered process, use steps with a DIRECT items array: {id:"flow",type:"steps",items:[{title:"整理文件",description:"保留源码和说明,排除密钥。"},{title:"提交代码",description:"检查变更后提交。"}]}. Do not wrap items in {item:[...]}. status is optional: omit it for explanatory guides; use pending/active/done/error only for known task states. Keep one sentence per requested step; avoid extra command disclosures unless asked.
|
|
11
|
-
- Numeric controls need complete typed state: state:{people:{type:"number",default:2,min:1,max:12,step:1},days:{type:"number",default:5,min:2,max:15,step:1}}. Use numbers without quotes or units. Prefer derived:{food:{expr:"state.people * state.days * 100"}} to a deep op/args tree. children, options, columns and expression args are direct arrays. The host normalizes plain numeric strings only in explicitly numeric fields and exact {item:[...]} wrappers only at declared array positions; ordinary text/data retain their types.
|
|
12
|
-
- Host defaults use readable editorial typography, quiet backgrounds, light borders and restrained accents. For guided canvas designs prefer 12..18px radii and flat surfaces; gradients are optional and must not replace information hierarchy. Let content determine height: no empty spacer sections, min-height:100vh or large fixed min-heights. A canvas auto-fits its rendered content after commit, including shrinking after filtering; height is only the initial placeholder. Use SVG viewBox bounds close to actual graphics plus reasonable padding.
|
|
13
|
-
- metric.value accepts a finite number or display string/boolean. Numbers use decimals and unit; strings display verbatim ("约 12 GiB", "待确认"). Calculations and chart series still require real numbers, never formatted strings.
|
|
14
|
-
- IDs, data/state/derived keys, column keys and formula references support Chinese letters and underscores. Use 1..64 letters/numbers/underscores, start with a letter/underscore, no spaces/dots/hyphens; never constructor/prototype/__proto__. Labels/text can be natural language.
|
|
15
|
-
- Persist a canvas checklist/list/object with state:{checklist:{type:"json",default:[]}} and DSHUI.setState({checklist:nextArray}). json state allows bounded arrays/objects, no options; native input/select cannot edit it. A native checklist uses separate boolean states and toggle nodes. Static lists belong in nodes/data, not state. String state with an array/object default and no options is canonicalized to json without losing its structure.
|
|
16
|
-
- Do not guess capabilities. On validation failure, fix the named field in the original document; do not deliver tiny probe/test UIs or search the DSH installation with shell tools. ui_catalog is the protocol reference. Missing bounds/operands need a real correction, not arbitrary guesses. Unknown properties are not discarded; unsupported code is not executed. Never claim successful delivery before the tool succeeds. A canvas with undeclared private DOM state does not have host persistence or state/derived followup snapshots.`;
|
|
1
|
+
export const AUTHORING_GUIDE=`Authoring fast path:
|
|
2
|
+
Pass complete JSON objects, not serialized strings or partial documents. Object field order never matters. children/items/options/columns are direct arrays, not {item:[...]}. Every native node has a unique id (render_text auto-fills omitted IDs). Sandbox title/fallback may inherit only when omitted; do not send null/empty values.
|
|
3
|
+
Before submitting v1, include its REQUIRED nodes array with all visible content and matching controls; state/derived alone is incomplete. Native attributes are registered fields, not HTML/style/className/callbacks. UI source belongs in canvas html/css/script fields. Omit unused state/data/derived/actions. On validation failure fix the named field in the original document, preserving needed nodes/state/derived.`;
|
package/lib/build-info.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
// Generated by npm run build.
|
|
2
|
-
export const BUILD_INFO = Object.freeze({"version":"0.
|
|
2
|
+
export const BUILD_INFO = Object.freeze({"version":"0.7.1","id":"0.7.1+d92c9bf2bf64","sourceHash":"d92c9bf2bf6407506977357f099a9c7935c744d97606dc631267a62be10735eb"});
|
package/lib/canvas-design.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
export const CANVAS_DESIGN_GUIDE = `Design
|
|
1
|
+
export const CANVAS_DESIGN_GUIDE = `Design the explanation around its content. Follow the selected guided style for palette, typography, materials and surfaces; these functional principles do not replace it. Examples illustrate capabilities, not templates. Static readability and purposeful motion can coexist.
|
|
2
2
|
1. Identify the user's question, the visual relationship; add a primary interaction only if it helps. Reserve the largest region for the evidence or object being explored. Use a heading, a compact explanation and purposeful supporting details; don't repeat titles or put every paragraph inside another card.
|
|
3
3
|
2. Choose composition by task: mechanical explorer -> large SVG subject, optional disassembly slider and part focus; parameter experiment -> visualization plus compact controls and exact values; architecture/process -> role-based nodes and clear labelled relationships; data analysis -> chart and exact table with units/source; comparison -> aligned criteria, normally static; reading/guide -> editorial text with a single supporting illustration. Combine native components and canvases where useful.
|
|
4
|
-
3. Choose visual treatment by content: editorial (reading, minimal borders), technical (geometry, restrained grid, annotations), analytical (quiet surface, aligned numerals), exploratory (large interactive object), comparative (aligned criteria), instructional (ordered explanation). Variation must change hierarchy and composition, not randomly swap accent colors. Keep host theme and Chinese readability.
|
|
4
|
+
3. Choose visual treatment by content: editorial (reading, minimal borders), technical (geometry, restrained grid, annotations), analytical (quiet surface, aligned numerals), exploratory (large interactive object), comparative (aligned criteria), instructional (ordered explanation). Variation must change hierarchy and composition, not randomly swap accent colors. Keep host theme and Chinese readability. Accent treatment follows the selected style; semantic warning/success colors describe established meaning. Check foreground/background contrast in both themes; pale dark-theme accents need dark foregrounds.
|
|
5
5
|
4. Diagram grammar: distinguish hierarchy, flow, sequence, dependency and spatial assembly. Give each node one clear idea. Reserve space for labels before routing lines; avoid crossing text, ambiguity and clipped arrows. Prefer a focused overview plus details over dense spaghetti. Don't force every relation into identical cards. SVG labels and units must remain readable on mobile; use viewBox and responsive width. A diagram's numbers must not imply engineering or physical accuracy unless established by evidence.
|
|
6
6
|
5. Interaction: show an informative initial state; updates need visible feedback and matching explanation. Important inputs use document.state. Read the shared DSHUI snapshot instead of independently recalculating a host-derived result. Use DSHUI.subscribe to drive views, not to echo the same state back. Prefer a few labelled controls. Don't duplicate every native input inside the canvas. Make SVG hotspots keyboard-operable or provide equivalent labelled buttons.
|
|
7
7
|
6. Motion: animate the explanation, not every decoration. Prefer DSHUI.animate(({time,delta,reducedMotion,visible})=>{...}) and retain its cleanup callback. time/delta are seconds; integrate delta for pause/resume without jumps. The helper pauses offscreen/background, and supplies a static delta=0 frame for reduced motion. Keep reading and controls usable without animation; never save each animation frame to host state. Raw requestAnimationFrame remains available, but you own its lifecycle and reduced-motion handling.
|
package/lib/canvas-system.js
CHANGED
|
@@ -14,5 +14,5 @@ export const CANVAS_SYSTEM_GUIDE = `The canvas includes optional .ui-stack, .ui-
|
|
|
14
14
|
For a small static diagram, .ui-flow arranges .ui-step nodes separated by .ui-arrow; each step uses strong + span. .ui-callout emphasizes one sentence. These work with no custom CSS or JavaScript and adapt to narrow screens.
|
|
15
15
|
SVG construction: reserve label space first; center box labels with text-anchor=middle and dominant-baseline=central. Measure Chinese characters at roughly one font-size each, Latin letters about .6 font-size; mixed text needs combined width plus 24px padding on each side. These are estimates, not browser measurements. Give same-role nodes aligned dimensions. Route connectors around text and unrelated boxes, with explicit fill=none and visible arrowheads. Compute viewBox bounds from the furthest shape, label and arrow plus padding. A 680-unit diagram shown at 340px halves its fonts: reflow or move captions into HTML instead of shrinking important labels. Keep PC chat-column labels readable at actual rendered size. Use overview + focus detail for dense systems. Do not force this grammar on spatial/mechanical drawings.
|
|
16
16
|
For calculators validate blanks, finite values, ranges and zero denominators; show an actionable error, never a stale result as valid. Use one state source for filtering/sorting/reset and one animation loop with cleanup. A reset restores inputs and outputs together. For explanation show relationships and one useful variable; for comparison expose criteria/units/assumptions; for a tool provide working inputs, calculation, outputs and reset.
|
|
17
|
-
Keep CSS small and put a useful initial view in html. Source field order is arbitrary.
|
|
17
|
+
Keep CSS small and put a useful initial view in html. Source field order is arbitrary. Completed static content previews progressively as read-only during generation; scripts/controls activate only after the whole assistant turn ends and state restoration. Do not claim a saved document has been visually checked without evidence.
|
|
18
18
|
Small building example (adapt relationships and dimensions to the actual task, not a compulsory template): <svg viewBox="0 0 420 120" role="img" aria-label="输入转为输出"><path class="ui-edge" d="M160 60H260"/><path class="ui-edge" d="M250 54L260 60L250 66"/><rect class="ui-node" x="20" y="36" width="140" height="48" rx="8"/><text class="ui-label" x="90" y="60" text-anchor="middle" dominant-baseline="central">输入</text><rect class="ui-node ui-accent" x="260" y="36" width="140" height="48" rx="8"/><text class="ui-label" x="330" y="60" text-anchor="middle" dominant-baseline="central">输出</text></svg>. Use SVG label text only; explanatory paragraphs belong in responsive HTML. For a reset button connect addEventListener('click',()=>DSHUI.setState({yourDeclaredKey:yourDefault})); render results from DSHUI.subscribe(s=>...) rather than independently duplicating host-derived formulas.`;
|