@npmjsdnt/turn-reply 0.0.0-stage → 0.1.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/dist/tr.css ADDED
@@ -0,0 +1,89 @@
1
+ .trw{
2
+ --c-bg:var(--surface-2);--c-sunken:var(--surface-1);
3
+ --c-hover:var(--fill-ghost-hover,var(--surface-1));--c-soft:var(--fill-ghost-selected,var(--surface-1));
4
+ --c-solid:var(--fill-primary,var(--text-primary));--c-on-solid:var(--on-primary,var(--surface-2));
5
+ --c-line:var(--border);--c-line-s:var(--border-strong);--c-line-x:var(--border-stronger,var(--border-strong));
6
+ --c-ink1:var(--text-primary);--c-ink2:var(--text-secondary);--c-ink3:var(--text-muted);--c-ink4:var(--text-disabled,var(--text-muted));
7
+ --c-attn:var(--text-warning);--c-ok:var(--text-success);--c-focus:var(--border-accent,var(--text-accent));--c-r:6px;
8
+ --c-track:color-mix(in srgb,var(--c-ink1,currentColor) 5%,transparent);--c-lift:var(--surface-3,var(--surface-2));--c-hov:color-mix(in srgb,var(--c-ink1,currentColor) 4%,transparent);
9
+ container-type:inline-size;position:relative;box-sizing:border-box;
10
+ font-family:var(--font-sans);font-size:13px;line-height:20px;font-weight:400;
11
+ font-variant-numeric:tabular-nums;-webkit-font-smoothing:antialiased;
12
+ color:var(--c-ink1);background:transparent;border:0;border-radius:0;padding:0
13
+ }
14
+ .trw.dark{--c-lift:color-mix(in srgb,var(--c-ink1,currentColor) 15%,transparent);--c-hov:color-mix(in srgb,var(--c-ink1,currentColor) 8%,transparent)}
15
+ .trw *,.trw *::before,.trw *::after{box-sizing:border-box}
16
+ .trw [hidden]{display:none!important}
17
+ .trw .mono{font-family:var(--font-mono);font-size:12px}
18
+ .trw .grp{display:flex;align-items:flex-start;padding:6px 0;border-top:0.5px solid var(--c-line)}
19
+ .trw .bd>.grp:first-child{border-top:0}
20
+ .trw .gl{flex:0 0 60px;padding-top:6px;font-size:11px;line-height:16px;color:var(--c-ink2);white-space:nowrap;cursor:default}
21
+ .trw .rs{flex:1 1 auto;min-width:0}
22
+ .trw .it{margin:0 -6px;padding:0 6px;border-radius:0}
23
+ .trw .it:hover,.trw.kb .it:focus-within{background:var(--c-hover)}
24
+ .trw .ln{display:flex;flex-wrap:wrap;align-items:center;gap:2px 8px;min-height:28px}
25
+ .trw .bd>.grp:first-child .it:first-child .ln{padding-right:40px}
26
+ .trw .q{flex:0 0 var(--qw,240px);min-width:0;display:flex;align-items:center;gap:6px;white-space:nowrap;overflow:hidden}
27
+ .trw.measuring .q{flex:none!important;width:max-content!important}
28
+ .trw .qt{min-width:0;overflow:hidden;text-overflow:ellipsis}
29
+ .trw .n{flex:none;min-width:14px;color:var(--c-ink2)}
30
+ .trw .it.core .qt{font-weight:500}
31
+ .trw .q.info .qt{font-size:12px;color:var(--c-ink2)}
32
+ .trw a.tk{font-family:var(--font-mono);font-size:12px;color:var(--c-ink1);text-decoration:underline;text-decoration-color:var(--c-line-x);text-underline-offset:2px}
33
+ .trw .ctl{flex:none;display:flex;flex-wrap:wrap;align-items:center;gap:4px 6px;padding:0 4px;margin:0 -4px}
34
+ .trw .cb{flex:none;width:9px;height:9px;background:var(--c-attn);clip-path:polygon(50% 0,100% 50%,50% 100%,0 50%)}
35
+ .trw .seg{display:inline-flex;align-items:center;gap:2px;height:26px;padding:2px;border:0;border-radius:7px;background:var(--c-track)}
36
+ .trw button.sg{position:relative;font-family:inherit!important;font-size:12px!important;font-weight:400!important;line-height:20px!important;height:22px!important;min-height:0!important;margin:0!important;padding:0 9px!important;border:0!important;border-radius:5px!important;background:transparent!important;color:var(--c-ink2)!important;box-shadow:none!important;cursor:pointer;white-space:nowrap;text-align:center;justify-content:center}
37
+ .trw button.sg[aria-checked="false"]:hover{background:var(--c-hov)!important;color:var(--c-ink1)!important}
38
+ .trw .ck.rec>span::before{content:"";display:inline-block;width:4px;height:4px;border-radius:50%;background:currentColor;margin-right:5px;vertical-align:2px}
39
+ .trw button.sg.rec{padding:0 4px 0 14px!important}
40
+ .trw button.sg.rec::before{content:"";position:absolute;left:6px;top:50%;width:4px;height:4px;margin-top:-2px;border-radius:50%;background:currentColor;opacity:.4}
41
+ .trw button.sg.sk{color:var(--c-ink3)!important}
42
+ .trw button.sg[aria-checked="true"]{background:var(--c-lift)!important;color:var(--c-ink1)!important;box-shadow:none!important}
43
+ .trw .dseg button.sg[aria-checked="true"]:hover::before{content:"×";position:absolute;left:4px;top:0;width:8px;height:auto;margin:0;border-radius:0;background:none;line-height:22px;text-align:center;opacity:1;color:var(--c-ink3)}
44
+ .trw .k{display:none;position:absolute;top:-8px;right:-4px;font:11px/14px var(--font-mono);padding:0 3px;border-radius:4px;background:var(--c-bg);color:var(--c-ink3);border:0.5px solid var(--c-line-s);pointer-events:none;z-index:1}
45
+ .trw.kb .it:focus-within .k{display:block}
46
+ .trw .ck{display:inline-flex;align-items:center;gap:6px;height:26px;padding:0 6px;border-radius:var(--c-r);font-size:12px;color:var(--c-ink2);cursor:pointer;white-space:nowrap;user-select:none}
47
+ .trw .ck:hover{background:var(--c-hover);color:var(--c-ink1)}
48
+ .trw .ck input{width:13px;height:13px;margin:0;accent-color:var(--c-solid);cursor:pointer}
49
+ .trw .ck:has(input:checked){color:var(--c-ink1)}
50
+ .trw button.gh{display:inline-flex;align-items:center;gap:5px;font-family:inherit!important;font-size:12px!important;font-weight:500!important;line-height:20px!important;height:26px!important;min-height:0!important;margin:0!important;padding:0 8px!important;border:0.5px solid transparent!important;border-radius:var(--c-r)!important;background:transparent!important;color:var(--c-ink2)!important;box-shadow:none!important;cursor:pointer;white-space:nowrap}
51
+ .trw button.gh:hover{background:var(--c-hover)!important;color:var(--c-ink1)!important}
52
+ .trw svg.i{width:14px;height:14px;flex:none;fill:none;stroke:currentColor;stroke-width:1.3;stroke-linecap:round;stroke-linejoin:round}
53
+ .trw .ed{display:flex;padding:4px 0 8px calc(var(--qw,240px) + 8px)}
54
+ .trw .it:last-child>.ed{padding-bottom:4px}
55
+ .trw .ed textarea,.trw textarea.ask{display:block;flex:1;min-width:0;min-height:28px;height:28px;resize:none!important;overflow:hidden;margin:0!important;padding:4px 10px!important;font:12px/18px var(--font-sans,system-ui)!important;white-space:pre-wrap;overflow-wrap:anywhere;border:0.5px solid var(--c-line-s)!important;border-radius:var(--c-r)!important;background:var(--c-bg)!important;color:var(--c-ink1)!important;box-shadow:none!important}
56
+ .trw .ed textarea::placeholder,.trw textarea.ask::placeholder{color:var(--c-ink3)}
57
+ .trw textarea.ask{flex:1 1 160px;min-height:26px;height:26px;padding:3px 10px!important}
58
+ .trw .ln.top{align-items:flex-start}
59
+ .trw .ln.top .q{min-height:26px}
60
+ .trw .foot{display:flex;flex-wrap:wrap;align-items:center;gap:6px 8px;padding:8px 0 2px;border-top:0.5px solid var(--c-line)}
61
+ .trw .sum{flex:1 1 auto;display:inline-flex;align-items:center;gap:8px;font-size:12px;line-height:18px;color:var(--c-ink3);white-space:nowrap}
62
+ .trw .sum b{font-weight:500;color:var(--c-ink2)}
63
+ .trw button.lk{font-family:inherit!important;font-size:12px!important;font-weight:400!important;line-height:18px!important;height:auto!important;min-height:0!important;margin:0!important;padding:0 2px!important;border:0!important;border-radius:4px!important;background:transparent!important;color:var(--c-ink2)!important;box-shadow:none!important;cursor:pointer;text-decoration:underline;text-decoration-color:var(--c-line-x);text-underline-offset:3px}
64
+ .trw button.btn{display:inline-flex;align-items:center;gap:6px;font-family:inherit!important;font-size:12px!important;font-weight:500!important;line-height:20px!important;height:28px!important;min-height:0!important;margin:0!important;padding:0 12px!important;border:0.5px solid transparent!important;border-radius:var(--c-r)!important;background:transparent!important;color:var(--c-ink2)!important;box-shadow:none!important;cursor:pointer;white-space:nowrap}
65
+ .trw button.btn:hover{background:var(--c-hover)!important;color:var(--c-ink1)!important}
66
+ .trw button.btn.pri{border-color:var(--c-line-x)!important;color:var(--c-ink1)!important}
67
+ .trw button.btn:disabled,.trw button.gh:disabled{color:var(--c-ink4)!important;background:transparent!important;cursor:default}
68
+ .trw pre.pv{font:12px/18px var(--font-mono);white-space:pre-wrap;overflow-wrap:anywhere;background:var(--c-sunken);padding:8px 10px;border-radius:var(--c-r);margin:0 0 8px;color:var(--c-ink2)}
69
+ .trw .fold{display:none;align-items:center;gap:6px;min-height:34px;font-size:12px;color:var(--c-ink2);cursor:pointer;padding:0 40px 0 6px;margin:0 -6px}
70
+ .trw .fold .fs{flex:0 1 auto;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
71
+ .trw .mk-ok{flex:none;width:10px;height:8px;background:var(--c-ok);clip-path:polygon(0 56%,15% 38%,38% 62%,85% 0,100% 19%,38% 100%)}
72
+ .trw.folded .fold{display:flex}
73
+ .trw.folded>:not(.fold){display:none!important}
74
+ .trw.folded:hover{background:var(--c-hover);border-radius:0}
75
+ .trw button:focus-visible{outline:2px solid var(--c-focus)!important;outline-offset:-2px}
76
+ .trw .ed textarea:focus,.trw textarea.ask:focus{outline:none!important;border-color:var(--c-focus)!important;box-shadow:inset 0 0 0 1px var(--c-focus)!important}
77
+ @container (max-width:480px){
78
+ .trw .grp{display:block}
79
+ .trw .ln{flex-wrap:wrap;row-gap:2px;padding-bottom:2px}
80
+ .trw .q{flex:1 1 auto;white-space:normal}
81
+ .trw .ed{padding-left:0}
82
+ }
83
+ .trw .err{padding:6px 0;font-size:12px;line-height:18px;color:var(--c-attn);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
84
+ /* 0.1.1:暗色模式加大轨道、选中块与建议点的对比;宿主拒收提示行 */
85
+ .trw.dark{--c-track:color-mix(in srgb,var(--c-ink1,currentColor) 8%,transparent);--c-lift:color-mix(in srgb,var(--c-ink1,currentColor) 26%,transparent);--c-hov:color-mix(in srgb,var(--c-ink1,currentColor) 12%,transparent)}
86
+ .trw.dark button.sg.rec::before{opacity:.75}
87
+ .trw.dark button.sg[aria-checked="true"]{font-weight:500!important}
88
+ .trw .ns{display:none;font-size:12px;line-height:18px;color:var(--c-attn);padding:6px 0 0}
89
+ .trw.notsent .ns{display:block}
package/dist/tr.js ADDED
@@ -0,0 +1,962 @@
1
+ /*! @npmjsdnt/turn-reply@0.1.1 turn-reply panel */
2
+ (() => {
3
+ // trw:css
4
+ var css_default = `.trw{
5
+ --c-bg:var(--surface-2);--c-sunken:var(--surface-1);
6
+ --c-hover:var(--fill-ghost-hover,var(--surface-1));--c-soft:var(--fill-ghost-selected,var(--surface-1));
7
+ --c-solid:var(--fill-primary,var(--text-primary));--c-on-solid:var(--on-primary,var(--surface-2));
8
+ --c-line:var(--border);--c-line-s:var(--border-strong);--c-line-x:var(--border-stronger,var(--border-strong));
9
+ --c-ink1:var(--text-primary);--c-ink2:var(--text-secondary);--c-ink3:var(--text-muted);--c-ink4:var(--text-disabled,var(--text-muted));
10
+ --c-attn:var(--text-warning);--c-ok:var(--text-success);--c-focus:var(--border-accent,var(--text-accent));--c-r:6px;
11
+ --c-track:color-mix(in srgb,var(--c-ink1,currentColor) 5%,transparent);--c-lift:var(--surface-3,var(--surface-2));--c-hov:color-mix(in srgb,var(--c-ink1,currentColor) 4%,transparent);
12
+ container-type:inline-size;position:relative;box-sizing:border-box;
13
+ font-family:var(--font-sans);font-size:13px;line-height:20px;font-weight:400;
14
+ font-variant-numeric:tabular-nums;-webkit-font-smoothing:antialiased;
15
+ color:var(--c-ink1);background:transparent;border:0;border-radius:0;padding:0
16
+ }
17
+ .trw.dark{--c-lift:color-mix(in srgb,var(--c-ink1,currentColor) 15%,transparent);--c-hov:color-mix(in srgb,var(--c-ink1,currentColor) 8%,transparent)}
18
+ .trw *,.trw *::before,.trw *::after{box-sizing:border-box}
19
+ .trw [hidden]{display:none!important}
20
+ .trw .mono{font-family:var(--font-mono);font-size:12px}
21
+ .trw .grp{display:flex;align-items:flex-start;padding:6px 0;border-top:0.5px solid var(--c-line)}
22
+ .trw .bd>.grp:first-child{border-top:0}
23
+ .trw .gl{flex:0 0 60px;padding-top:6px;font-size:11px;line-height:16px;color:var(--c-ink2);white-space:nowrap;cursor:default}
24
+ .trw .rs{flex:1 1 auto;min-width:0}
25
+ .trw .it{margin:0 -6px;padding:0 6px;border-radius:0}
26
+ .trw .it:hover,.trw.kb .it:focus-within{background:var(--c-hover)}
27
+ .trw .ln{display:flex;flex-wrap:wrap;align-items:center;gap:2px 8px;min-height:28px}
28
+ .trw .bd>.grp:first-child .it:first-child .ln{padding-right:40px}
29
+ .trw .q{flex:0 0 var(--qw,240px);min-width:0;display:flex;align-items:center;gap:6px;white-space:nowrap;overflow:hidden}
30
+ .trw.measuring .q{flex:none!important;width:max-content!important}
31
+ .trw .qt{min-width:0;overflow:hidden;text-overflow:ellipsis}
32
+ .trw .n{flex:none;min-width:14px;color:var(--c-ink2)}
33
+ .trw .it.core .qt{font-weight:500}
34
+ .trw .q.info .qt{font-size:12px;color:var(--c-ink2)}
35
+ .trw a.tk{font-family:var(--font-mono);font-size:12px;color:var(--c-ink1);text-decoration:underline;text-decoration-color:var(--c-line-x);text-underline-offset:2px}
36
+ .trw .ctl{flex:none;display:flex;flex-wrap:wrap;align-items:center;gap:4px 6px;padding:0 4px;margin:0 -4px}
37
+ .trw .cb{flex:none;width:9px;height:9px;background:var(--c-attn);clip-path:polygon(50% 0,100% 50%,50% 100%,0 50%)}
38
+ .trw .seg{display:inline-flex;align-items:center;gap:2px;height:26px;padding:2px;border:0;border-radius:7px;background:var(--c-track)}
39
+ .trw button.sg{position:relative;font-family:inherit!important;font-size:12px!important;font-weight:400!important;line-height:20px!important;height:22px!important;min-height:0!important;margin:0!important;padding:0 9px!important;border:0!important;border-radius:5px!important;background:transparent!important;color:var(--c-ink2)!important;box-shadow:none!important;cursor:pointer;white-space:nowrap;text-align:center;justify-content:center}
40
+ .trw button.sg[aria-checked="false"]:hover{background:var(--c-hov)!important;color:var(--c-ink1)!important}
41
+ .trw .ck.rec>span::before{content:"";display:inline-block;width:4px;height:4px;border-radius:50%;background:currentColor;margin-right:5px;vertical-align:2px}
42
+ .trw button.sg.rec{padding:0 4px 0 14px!important}
43
+ .trw button.sg.rec::before{content:"";position:absolute;left:6px;top:50%;width:4px;height:4px;margin-top:-2px;border-radius:50%;background:currentColor;opacity:.4}
44
+ .trw button.sg.sk{color:var(--c-ink3)!important}
45
+ .trw button.sg[aria-checked="true"]{background:var(--c-lift)!important;color:var(--c-ink1)!important;box-shadow:none!important}
46
+ .trw .dseg button.sg[aria-checked="true"]:hover::before{content:"×";position:absolute;left:4px;top:0;width:8px;height:auto;margin:0;border-radius:0;background:none;line-height:22px;text-align:center;opacity:1;color:var(--c-ink3)}
47
+ .trw .k{display:none;position:absolute;top:-8px;right:-4px;font:11px/14px var(--font-mono);padding:0 3px;border-radius:4px;background:var(--c-bg);color:var(--c-ink3);border:0.5px solid var(--c-line-s);pointer-events:none;z-index:1}
48
+ .trw.kb .it:focus-within .k{display:block}
49
+ .trw .ck{display:inline-flex;align-items:center;gap:6px;height:26px;padding:0 6px;border-radius:var(--c-r);font-size:12px;color:var(--c-ink2);cursor:pointer;white-space:nowrap;user-select:none}
50
+ .trw .ck:hover{background:var(--c-hover);color:var(--c-ink1)}
51
+ .trw .ck input{width:13px;height:13px;margin:0;accent-color:var(--c-solid);cursor:pointer}
52
+ .trw .ck:has(input:checked){color:var(--c-ink1)}
53
+ .trw button.gh{display:inline-flex;align-items:center;gap:5px;font-family:inherit!important;font-size:12px!important;font-weight:500!important;line-height:20px!important;height:26px!important;min-height:0!important;margin:0!important;padding:0 8px!important;border:0.5px solid transparent!important;border-radius:var(--c-r)!important;background:transparent!important;color:var(--c-ink2)!important;box-shadow:none!important;cursor:pointer;white-space:nowrap}
54
+ .trw button.gh:hover{background:var(--c-hover)!important;color:var(--c-ink1)!important}
55
+ .trw svg.i{width:14px;height:14px;flex:none;fill:none;stroke:currentColor;stroke-width:1.3;stroke-linecap:round;stroke-linejoin:round}
56
+ .trw .ed{display:flex;padding:4px 0 8px calc(var(--qw,240px) + 8px)}
57
+ .trw .it:last-child>.ed{padding-bottom:4px}
58
+ .trw .ed textarea,.trw textarea.ask{display:block;flex:1;min-width:0;min-height:28px;height:28px;resize:none!important;overflow:hidden;margin:0!important;padding:4px 10px!important;font:12px/18px var(--font-sans,system-ui)!important;white-space:pre-wrap;overflow-wrap:anywhere;border:0.5px solid var(--c-line-s)!important;border-radius:var(--c-r)!important;background:var(--c-bg)!important;color:var(--c-ink1)!important;box-shadow:none!important}
59
+ .trw .ed textarea::placeholder,.trw textarea.ask::placeholder{color:var(--c-ink3)}
60
+ .trw textarea.ask{flex:1 1 160px;min-height:26px;height:26px;padding:3px 10px!important}
61
+ .trw .ln.top{align-items:flex-start}
62
+ .trw .ln.top .q{min-height:26px}
63
+ .trw .foot{display:flex;flex-wrap:wrap;align-items:center;gap:6px 8px;padding:8px 0 2px;border-top:0.5px solid var(--c-line)}
64
+ .trw .sum{flex:1 1 auto;display:inline-flex;align-items:center;gap:8px;font-size:12px;line-height:18px;color:var(--c-ink3);white-space:nowrap}
65
+ .trw .sum b{font-weight:500;color:var(--c-ink2)}
66
+ .trw button.lk{font-family:inherit!important;font-size:12px!important;font-weight:400!important;line-height:18px!important;height:auto!important;min-height:0!important;margin:0!important;padding:0 2px!important;border:0!important;border-radius:4px!important;background:transparent!important;color:var(--c-ink2)!important;box-shadow:none!important;cursor:pointer;text-decoration:underline;text-decoration-color:var(--c-line-x);text-underline-offset:3px}
67
+ .trw button.btn{display:inline-flex;align-items:center;gap:6px;font-family:inherit!important;font-size:12px!important;font-weight:500!important;line-height:20px!important;height:28px!important;min-height:0!important;margin:0!important;padding:0 12px!important;border:0.5px solid transparent!important;border-radius:var(--c-r)!important;background:transparent!important;color:var(--c-ink2)!important;box-shadow:none!important;cursor:pointer;white-space:nowrap}
68
+ .trw button.btn:hover{background:var(--c-hover)!important;color:var(--c-ink1)!important}
69
+ .trw button.btn.pri{border-color:var(--c-line-x)!important;color:var(--c-ink1)!important}
70
+ .trw button.btn:disabled,.trw button.gh:disabled{color:var(--c-ink4)!important;background:transparent!important;cursor:default}
71
+ .trw pre.pv{font:12px/18px var(--font-mono);white-space:pre-wrap;overflow-wrap:anywhere;background:var(--c-sunken);padding:8px 10px;border-radius:var(--c-r);margin:0 0 8px;color:var(--c-ink2)}
72
+ .trw .fold{display:none;align-items:center;gap:6px;min-height:34px;font-size:12px;color:var(--c-ink2);cursor:pointer;padding:0 40px 0 6px;margin:0 -6px}
73
+ .trw .fold .fs{flex:0 1 auto;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
74
+ .trw .mk-ok{flex:none;width:10px;height:8px;background:var(--c-ok);clip-path:polygon(0 56%,15% 38%,38% 62%,85% 0,100% 19%,38% 100%)}
75
+ .trw.folded .fold{display:flex}
76
+ .trw.folded>:not(.fold){display:none!important}
77
+ .trw.folded:hover{background:var(--c-hover);border-radius:0}
78
+ .trw button:focus-visible{outline:2px solid var(--c-focus)!important;outline-offset:-2px}
79
+ .trw .ed textarea:focus,.trw textarea.ask:focus{outline:none!important;border-color:var(--c-focus)!important;box-shadow:inset 0 0 0 1px var(--c-focus)!important}
80
+ @container (max-width:480px){
81
+ .trw .grp{display:block}
82
+ .trw .ln{flex-wrap:wrap;row-gap:2px;padding-bottom:2px}
83
+ .trw .q{flex:1 1 auto;white-space:normal}
84
+ .trw .ed{padding-left:0}
85
+ }
86
+ .trw .err{padding:6px 0;font-size:12px;line-height:18px;color:var(--c-attn);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
87
+ /* 0.1.1:暗色模式加大轨道、选中块与建议点的对比;宿主拒收提示行 */
88
+ .trw.dark{--c-track:color-mix(in srgb,var(--c-ink1,currentColor) 8%,transparent);--c-lift:color-mix(in srgb,var(--c-ink1,currentColor) 26%,transparent);--c-hov:color-mix(in srgb,var(--c-ink1,currentColor) 12%,transparent)}
89
+ .trw.dark button.sg.rec::before{opacity:.75}
90
+ .trw.dark button.sg[aria-checked="true"]{font-weight:500!important}
91
+ .trw .ns{display:none;font-size:12px;line-height:18px;color:var(--c-attn);padding:6px 0 0}
92
+ .trw.notsent .ns{display:block}
93
+ `;
94
+
95
+ // ../schema/validate.ts
96
+ var isStr = (x, max = Infinity, min = 1) => typeof x === "string" && x.length >= min && x.length <= max;
97
+ var only = (o, keys, at, e) => {
98
+ for (const k of Object.keys(o))
99
+ if (!keys.includes(k))
100
+ e.push(`${at}.${k} 未定义的字段`);
101
+ };
102
+ function validate(s) {
103
+ const e = [];
104
+ if (!s || typeof s !== "object" || Array.isArray(s))
105
+ return ["$ 不是对象"];
106
+ only(s, ["v", "turn", "ticketUrl", "decisions", "actions", "delivery", "optional"], "$", e);
107
+ if (s.v !== 1)
108
+ e.push("$.v 必须为 1");
109
+ if (!isStr(s.turn, 40) || !/^[\w.:-]+$/.test(s.turn))
110
+ e.push("$.turn 缺失或含非法字符");
111
+ if (s.ticketUrl !== undefined && !(isStr(s.ticketUrl) && s.ticketUrl.startsWith("https://")))
112
+ e.push("$.ticketUrl 须为 https:// 前缀");
113
+ const seen = new Set;
114
+ (s.decisions ?? []).forEach((d, i) => {
115
+ const at = `$.decisions[${i}]`;
116
+ if (!d || typeof d !== "object")
117
+ return e.push(`${at} 不是对象`);
118
+ only(d, ["n", "group", "core", "q", "opts", "rec", "def", "multi", "ask", "ph"], at, e);
119
+ if (!Number.isInteger(d.n) || d.n < 1)
120
+ e.push(`${at}.n 须为正整数`);
121
+ else if (seen.has(d.n))
122
+ e.push(`${at}.n=${d.n} 重复`);
123
+ else
124
+ seen.add(d.n);
125
+ if (!["now", "defaulted", "pending"].includes(d.group))
126
+ e.push(`${at}.group 非法`);
127
+ if (!isStr(d.q, 40))
128
+ e.push(`${at}.q 须为 1–40 字`);
129
+ if (d.core !== undefined && typeof d.core !== "boolean")
130
+ e.push(`${at}.core 须为布尔`);
131
+ if (d.def !== undefined && !isStr(d.def, 60))
132
+ e.push(`${at}.def 须为 ≤60 字`);
133
+ if (d.multi !== undefined && d.multi !== true)
134
+ e.push(`${at}.multi 只能为 true`);
135
+ if (d.ask !== undefined && d.ask !== true)
136
+ e.push(`${at}.ask 只能为 true`);
137
+ const opts = d.opts;
138
+ if (opts !== undefined && !(Array.isArray(opts) && opts.every((o) => isStr(o, 12))))
139
+ e.push(`${at}.opts 须为 1–12 字的字符串数组`);
140
+ const n = Array.isArray(opts) ? opts.length : 0;
141
+ const kind = d.group === "defaulted" ? "defaulted" : d.ask ? "ask" : d.multi ? "multi" : "one";
142
+ if (d.ask && d.multi)
143
+ e.push(`${at} ask 与 multi 不能同时出现`);
144
+ if (kind === "defaulted" && (opts || d.rec !== undefined || d.ask || d.multi))
145
+ e.push(`${at} defaulted 条目只有「推翻」,不带 opts/rec/ask/multi`);
146
+ if (kind === "ask" && (opts || d.rec !== undefined))
147
+ e.push(`${at} ask 条目不带 opts/rec`);
148
+ if (d.ph !== undefined && (kind !== "ask" || !isStr(d.ph, 40)))
149
+ e.push(`${at}.ph 只用于 ask,≤40 字`);
150
+ if (kind === "one" && (n < 2 || n > 4))
151
+ e.push(`${at} 单选须有 2–4 个 opts(现 ${n})`);
152
+ if (kind === "multi" && (n < 2 || n > 8))
153
+ e.push(`${at} 多选须有 2–8 个 opts(现 ${n})`);
154
+ if (kind === "one" && d.rec !== undefined && !(Number.isInteger(d.rec) && d.rec >= 0 && d.rec < n))
155
+ e.push(`${at}.rec 须为 opts 下标`);
156
+ if (kind === "multi" && d.rec !== undefined && !(Array.isArray(d.rec) && d.rec.every((r) => Number.isInteger(r) && r >= 0 && r < n) && new Set(d.rec).size === d.rec.length))
157
+ e.push(`${at}.rec 须为不重复的 opts 下标数组`);
158
+ if (Array.isArray(opts) && new Set(opts).size !== n)
159
+ e.push(`${at}.opts 有重复`);
160
+ });
161
+ const ns = [...seen].sort((a, b) => a - b);
162
+ if (ns.length && ns.some((x, k) => k && x !== ns[k - 1] + 1))
163
+ e.push(`$.decisions 编号不连续:${ns.join(",")}`);
164
+ (s.actions ?? []).forEach((a, i) => {
165
+ const at = `$.actions[${i}]`;
166
+ if (!a || typeof a !== "object")
167
+ return e.push(`${at} 不是对象`);
168
+ only(a, ["text", "short", "cmd"], at, e);
169
+ if (!isStr(a.text, 120))
170
+ e.push(`${at}.text 须为 1–120 字`);
171
+ if (!isStr(a.short, 24))
172
+ e.push(`${at}.short 须为 1–24 字`);
173
+ if (a.cmd !== undefined && !isStr(a.cmd))
174
+ e.push(`${at}.cmd 须为非空字符串`);
175
+ });
176
+ if (s.delivery !== undefined) {
177
+ const d = s.delivery;
178
+ if (!d || typeof d !== "object")
179
+ e.push("$.delivery 不是对象");
180
+ else {
181
+ only(d, ["info", "toggles"], "$.delivery", e);
182
+ if (d.info !== undefined && !isStr(d.info, 120))
183
+ e.push("$.delivery.info 须为 ≤120 字");
184
+ (d.toggles ?? []).forEach((t, i) => {
185
+ only(t ?? {}, ["label", "rec"], `$.delivery.toggles[${i}]`, e);
186
+ if (!isStr(t?.label, 20))
187
+ e.push(`$.delivery.toggles[${i}].label 须为 1–20 字`);
188
+ if (t?.rec !== undefined && typeof t.rec !== "boolean")
189
+ e.push(`$.delivery.toggles[${i}].rec 须为布尔`);
190
+ });
191
+ }
192
+ }
193
+ (s.optional ?? []).forEach((o, i) => {
194
+ only(o ?? {}, ["text"], `$.optional[${i}]`, e);
195
+ if (!isStr(o?.text, 120))
196
+ e.push(`$.optional[${i}].text 须为 1–120 字`);
197
+ });
198
+ for (const k of ["decisions", "actions", "optional"])
199
+ if (s[k] !== undefined && !Array.isArray(s[k]))
200
+ e.push(`$.${k} 须为数组`);
201
+ return e;
202
+ }
203
+ if (false) {}
204
+
205
+ // src/panel.js
206
+ var renderPanel = (() => {
207
+ const el = (t, a = {}, ...k) => {
208
+ const e = document.createElement(t);
209
+ for (const [x, v] of Object.entries(a)) {
210
+ if (v == null || v === false)
211
+ continue;
212
+ if (x === "cls")
213
+ e.className = v;
214
+ else
215
+ e.setAttribute(x, v);
216
+ }
217
+ k.flat().forEach((c) => {
218
+ if (c != null && c !== false)
219
+ e.append(c);
220
+ });
221
+ return e;
222
+ };
223
+ const ICON = {
224
+ copy: '<rect x="5.5" y="5.5" width="7.5" height="7.5" rx="1.2"/><path d="M10.5 3.5V3a.5.5 0 0 0-.5-.5H3a.5.5 0 0 0-.5.5v7a.5.5 0 0 0 .5.5h.5"/>',
225
+ reset: '<path d="M3.2 8a4.8 4.8 0 1 0 1.4-3.4"/><path d="M3.2 2.6v2.6h2.6"/>'
226
+ };
227
+ const icon = (n) => {
228
+ const s = document.createElementNS("http://www.w3.org/2000/svg", "svg");
229
+ s.setAttribute("viewBox", "0 0 16 16");
230
+ s.setAttribute("class", "i");
231
+ s.setAttribute("aria-hidden", "true");
232
+ s.innerHTML = ICON[n];
233
+ return s;
234
+ };
235
+ let LIN = null;
236
+ const linkify = (s) => {
237
+ if (!s)
238
+ return [];
239
+ const out = [];
240
+ let last = 0;
241
+ s.replace(/\b[A-Z]{2,6}-\d+\b|\b[0-9a-f]{7,40}\b/g, (m, i) => {
242
+ const tk = /^[A-Z]/.test(m);
243
+ if (!tk && !(/\d/.test(m) && /[a-f]/.test(m)))
244
+ return m;
245
+ if (tk && !LIN)
246
+ return m;
247
+ out.push(s.slice(last, i), tk ? el("a", { cls: "tk", href: LIN + m, target: "_blank", rel: "noopener" }, m) : el("span", { cls: "mono" }, m.slice(0, 7)));
248
+ last = i + m.length;
249
+ return m;
250
+ });
251
+ out.push(s.slice(last));
252
+ return out;
253
+ };
254
+ const copyText = (t) => {
255
+ const fb = () => {
256
+ const a = el("textarea", { style: "position:absolute;left:-9999px;top:0", "aria-hidden": "true" });
257
+ a.value = t;
258
+ document.body.append(a);
259
+ a.select();
260
+ try {
261
+ document.execCommand("copy");
262
+ } catch (_) {}
263
+ a.remove();
264
+ };
265
+ try {
266
+ navigator.clipboard.writeText(t).catch(fb);
267
+ } catch (_) {
268
+ fb();
269
+ }
270
+ };
271
+ const flash = (lb, t) => {
272
+ if (!lb.dataset.l)
273
+ lb.dataset.l = lb.textContent;
274
+ lb.textContent = t;
275
+ clearTimeout(lb._t);
276
+ lb._t = setTimeout(() => {
277
+ lb.textContent = lb.dataset.l;
278
+ }, 1400);
279
+ };
280
+ const count = (t) => t ? t.split(`
281
+ `).filter(Boolean).length : 0;
282
+ const cut = (s, n) => s.length > n ? s.slice(0, n) + "…" : s;
283
+ const sameSet = (a, b) => a.size === b.size && [...a].every((v) => b.has(v));
284
+ const LAB = { done: "已做", issue: "有问题", no: "没做", you: "你来做" };
285
+ function render(root, spec) {
286
+ root.replaceChildren();
287
+ root.classList.remove("folded", "kb");
288
+ {
289
+ const c = (getComputedStyle(root).color.match(/\d+/g) || [0, 0, 0]).slice(0, 3).map(Number);
290
+ root.classList.toggle("dark", (c[0] * 299 + c[1] * 587 + c[2] * 114) / 1000 > 140);
291
+ }
292
+ LIN = spec.ticketUrl || null;
293
+ const TURN = spec.turn ? String(spec.turn).replace(/[^\w.:-]/g, "") : "";
294
+ const hasSend = typeof sendPrompt === "function";
295
+ const S = { dec: [], act: [], del: [], opt: [] };
296
+ const items = [];
297
+ const bd = el("div", { cls: "bd" });
298
+ const group = (label, hint) => {
299
+ const rs = el("div", { cls: "rs" });
300
+ bd.append(el("div", { cls: "grp" }, el("div", { cls: "gl", title: hint || null }, label), rs));
301
+ return rs;
302
+ };
303
+ const item = (rs, ln, extra) => {
304
+ const it = el("div", { cls: "it" }, ln, ...extra || []);
305
+ rs.append(it);
306
+ items.push(it);
307
+ return it;
308
+ };
309
+ const qcell = (d, text) => {
310
+ const qt = el("span", { cls: "qt" }, ...linkify(text));
311
+ const q = el("div", { cls: "q", title: text || null }, d && d.n != null ? el("span", { cls: "n" }, d.n + ".") : null, d && d.core ? el("span", { cls: "cb", role: "img", "aria-label": "核心决策", title: "核心决策" }) : null, qt);
312
+ return { q, qt };
313
+ };
314
+ const grow = (t) => {
315
+ if (!t.value) {
316
+ t.style.removeProperty("height");
317
+ return;
318
+ }
319
+ t.style.setProperty("height", "auto", "important");
320
+ t.style.setProperty("height", t.scrollHeight + (t.offsetHeight - t.clientHeight) + "px", "important");
321
+ };
322
+ const area = (ph, cls) => {
323
+ const t = el("textarea", { rows: "1", cls: cls || null, placeholder: ph, "aria-label": ph });
324
+ t.addEventListener("input", () => grow(t));
325
+ return t;
326
+ };
327
+ const editor = (st, ph) => {
328
+ const box = el("div", { cls: "ed" });
329
+ const i = area(ph);
330
+ i.addEventListener("input", () => {
331
+ st.text = i.value;
332
+ upd();
333
+ });
334
+ box.append(i);
335
+ box.hidden = true;
336
+ st.ed = box;
337
+ return { box, i, show(on, focus) {
338
+ box.hidden = !on;
339
+ if (on) {
340
+ grow(i);
341
+ if (focus)
342
+ i.focus();
343
+ }
344
+ upd();
345
+ } };
346
+ };
347
+ const txt = (st) => st.ed && !st.ed.hidden ? (st.text || "").trim() : "";
348
+ const seg = (opts, st, o = {}) => {
349
+ const init = o.init === undefined ? null : o.init;
350
+ const w = el("div", { cls: "seg" + (o.cls ? " " + o.cls : ""), role: "radiogroup", "aria-label": o.label || null, title: o.title || null });
351
+ const bs = opts.map((op, i) => el("button", { type: "button", role: "radio", cls: "sg" + (op.rec ? " rec" : ""), "data-col": String(i), title: op.title || null }, op.label, el("span", { cls: "k", "aria-hidden": "true" }, String(i + 1))));
352
+ const paint = () => {
353
+ const idx = opts.findIndex((x) => x.v === st.pick);
354
+ const chg = st.pick !== init;
355
+ bs.forEach((b, i) => {
356
+ b.setAttribute("aria-checked", String(i === idx));
357
+ b.classList.toggle("chg", i === idx && chg);
358
+ b.tabIndex = i === (idx < 0 ? 0 : idx) ? 0 : -1;
359
+ });
360
+ };
361
+ const set = (v, kb) => {
362
+ st.pick = v;
363
+ paint();
364
+ if (o.onChange)
365
+ o.onChange(kb);
366
+ upd();
367
+ };
368
+ const choose = (i, kb) => {
369
+ if (opts[i])
370
+ set(o.toggle && st.pick === opts[i].v ? null : opts[i].v, kb);
371
+ };
372
+ bs.forEach((b, i) => b.addEventListener("click", () => choose(i, false)));
373
+ w.addEventListener("keydown", (e) => {
374
+ if (e.key !== "ArrowRight" && e.key !== "ArrowLeft")
375
+ return;
376
+ e.preventDefault();
377
+ const c = Math.max(0, bs.indexOf(document.activeElement));
378
+ const n = (c + (e.key === "ArrowRight" ? 1 : -1) + bs.length) % bs.length;
379
+ set(opts[n].v, true);
380
+ bs[n].focus();
381
+ });
382
+ paint();
383
+ w.append(...bs);
384
+ return { w, set, choose, focus: () => (bs.find((b) => b.tabIndex === 0) || bs[0]).focus() };
385
+ };
386
+ const check = (label, on, o = {}) => {
387
+ const i = el("input", { type: "checkbox" });
388
+ i.checked = !!on;
389
+ const lb = el("label", { cls: "ck" + (o.rec ? " rec" : ""), title: o.title || null }, i, el("span", {}, label));
390
+ return { lb, i };
391
+ };
392
+ const multi = (labels, recs, st, initOn) => {
393
+ const w = el("div", { cls: "ctl", role: "group" });
394
+ const cs = labels.map((l, i) => check(l, initOn.has(i), { rec: recs.includes(i), title: recs.includes(i) ? "建议" : null }));
395
+ const paint = () => cs.forEach((c, i) => c.lb.classList.toggle("chg", st.sel.has(i) !== initOn.has(i)));
396
+ cs.forEach((c, i) => c.i.addEventListener("change", () => {
397
+ c.i.checked ? st.sel.add(i) : st.sel.delete(i);
398
+ paint();
399
+ upd();
400
+ }));
401
+ w.append(...cs.map((c) => c.lb));
402
+ return { w, set: (s) => {
403
+ st.sel = new Set(s);
404
+ cs.forEach((c, i) => {
405
+ c.i.checked = st.sel.has(i);
406
+ });
407
+ paint();
408
+ upd();
409
+ }, toggle: (i) => {
410
+ if (cs[i])
411
+ cs[i].i.click();
412
+ }, focus: () => cs[0] && cs[0].i.focus() };
413
+ };
414
+ const ghost = (label, o = {}) => el("button", { type: "button", cls: "gh", title: o.title || null }, o.icon ? icon(o.icon) : null, label ? el("span", {}, label) : null);
415
+ const groups = [["本轮拍板", "需要你拍板", (d) => d.group === "now"], ["早前", "上轮按默认处理(勾「推翻」才回复)与早前尚未决策(默认不回复)", (d) => d.group !== "now"]];
416
+ groups.forEach(([label, hint, f]) => {
417
+ const ds = (spec.decisions || []).filter(f).sort((a, b) => a.n - b.n);
418
+ if (!ds.length)
419
+ return;
420
+ const rs = group(label, hint);
421
+ ds.forEach((d) => {
422
+ const st = { pick: null, text: "" };
423
+ const x = { d, st };
424
+ S.dec.push(x);
425
+ const { q } = qcell(d, d.q);
426
+ const extra = [];
427
+ let ctl, pick, focus, note = null;
428
+ if (d.group === "defaulted") {
429
+ const ed = editor(st, "改成什么");
430
+ const c = check("推翻", false, { title: "推翻上轮的默认处理" });
431
+ c.i.addEventListener("change", () => {
432
+ st.pick = c.i.checked ? "over" : null;
433
+ c.lb.classList.toggle("chg", c.i.checked);
434
+ ed.show(c.i.checked, true);
435
+ });
436
+ ctl = el("div", { cls: "ctl" }, c.lb);
437
+ extra.push(ed.box);
438
+ pick = (i) => {
439
+ if (i === 0)
440
+ c.i.click();
441
+ };
442
+ focus = () => c.i.focus();
443
+ ed.i.__esc = () => c.i.focus();
444
+ x.changed = () => st.pick === "over";
445
+ x.sum = () => "推翻";
446
+ } else if (d.ask) {
447
+ const inp = area(d.ph || "填写;要附文件就留空,到输入框里附", "ask");
448
+ inp.addEventListener("input", () => {
449
+ st.text = inp.value;
450
+ upd();
451
+ });
452
+ ctl = inp;
453
+ x.top = true;
454
+ pick = () => {};
455
+ focus = () => inp.focus();
456
+ x.changed = () => !!(st.text || "").trim();
457
+ x.sum = () => "已填";
458
+ } else if (d.multi) {
459
+ const os = d.opts || [];
460
+ const recs = Array.isArray(d.rec) ? d.rec : d.rec != null ? [d.rec] : [];
461
+ const initOn = new Set(d.group === "now" ? recs : []);
462
+ st.sel = new Set(initOn);
463
+ x.init = initOn;
464
+ const m = multi(os, recs, st, initOn);
465
+ const ed = editor(st, "附一句;不勾选项时即为你的回复");
466
+ note = () => {
467
+ const on = ed.box.hidden;
468
+ ed.show(on, true);
469
+ if (!on)
470
+ m.focus();
471
+ };
472
+ ctl = m.w;
473
+ extra.push(ed.box);
474
+ x.reset = () => m.set(initOn);
475
+ pick = (i) => m.toggle(i);
476
+ focus = m.focus;
477
+ ed.i.__esc = () => {
478
+ ed.show(false);
479
+ m.focus();
480
+ };
481
+ x.changed = () => !sameSet(st.sel, initOn) || !!txt(st);
482
+ x.sum = () => {
483
+ const s = [...st.sel].sort((a, b) => a - b).map((i) => os[i]);
484
+ return (s.length ? s.join("、") : "都不选") + (txt(st) ? "(附言)" : "");
485
+ };
486
+ } else {
487
+ const os = d.opts || [];
488
+ const opts = os.map((l, i) => ({ v: "o" + i, label: l, rec: i === d.rec, title: i === d.rec ? "建议;再点一次即不回复" : "再点一次即不回复" }));
489
+ st.pick = d.group === "now" && os[d.rec] != null ? "o" + d.rec : null;
490
+ x.init = st.pick;
491
+ const sg = seg(opts, st, { label: d.q, init: x.init, toggle: true, cls: "dseg", title: d.def || null });
492
+ const ed = editor(st, "附一句;不选选项时即为你的回复");
493
+ note = () => {
494
+ const on = ed.box.hidden;
495
+ ed.show(on, true);
496
+ if (!on)
497
+ sg.focus();
498
+ };
499
+ ctl = el("div", { cls: "ctl" }, sg.w);
500
+ extra.push(ed.box);
501
+ x.reset = () => sg.set(x.init);
502
+ pick = (i) => sg.choose(i, false);
503
+ focus = sg.focus;
504
+ ed.i.__esc = () => {
505
+ ed.show(false);
506
+ sg.focus();
507
+ };
508
+ x.changed = () => st.pick !== x.init || !!txt(st);
509
+ x.sum = () => (st.pick ? os[+st.pick.slice(1)] : "不回复") + (txt(st) ? "(附言)" : "");
510
+ }
511
+ const ln = el("div", { cls: "ln" + (x.top ? " top" : "") }, q, ctl);
512
+ const it = item(rs, ln, extra);
513
+ if (note) {
514
+ ln.addEventListener("click", (e) => {
515
+ if (e.target.closest("button,input,textarea,label,a,.ctl"))
516
+ return;
517
+ note();
518
+ });
519
+ it.__note = note;
520
+ }
521
+ if (d.core)
522
+ it.classList.add("core");
523
+ it.__pick = pick;
524
+ it.__focus = focus;
525
+ x.it = it;
526
+ });
527
+ });
528
+ if (spec.actions && spec.actions.length) {
529
+ const rs = group("你要做的", "做完后在这里回执");
530
+ spec.actions.forEach((a) => {
531
+ const st = { pick: null, text: "" };
532
+ const ed = editor(st, "贴结果、报错或原因");
533
+ const opts = [["done", "已做"], ["issue", "有问题"], ["no", "没做"], ["you", "你来做"]].map(([v, label]) => ({ v, label }));
534
+ const sg = seg(opts, st, { toggle: true, init: null, label: a.short || a.text, onChange: (kb) => {
535
+ const on = st.pick === "issue" || st.pick === "no";
536
+ ed.box.hidden = !on;
537
+ if (on) {
538
+ grow(ed.i);
539
+ if (!kb)
540
+ ed.i.focus();
541
+ }
542
+ } });
543
+ let cp = null;
544
+ if (a.cmd) {
545
+ cp = ghost("复制命令", { icon: "copy", title: a.cmd });
546
+ const lb = cp.querySelector("span");
547
+ cp.addEventListener("click", () => {
548
+ copyText(a.cmd);
549
+ flash(lb, "已复制");
550
+ });
551
+ }
552
+ const { q } = qcell(null, a.text);
553
+ const it = item(rs, el("div", { cls: "ln" }, q, el("div", { cls: "ctl" }, sg.w, cp)), [ed.box]);
554
+ it.__pick = (i) => sg.choose(i, false);
555
+ it.__focus = sg.focus;
556
+ ed.i.__esc = sg.focus;
557
+ S.act.push({ a, st, it });
558
+ });
559
+ }
560
+ const dl = spec.delivery;
561
+ const optl = spec.optional || [];
562
+ if (dl || optl.length) {
563
+ const rs = group("收尾");
564
+ if (dl) {
565
+ const cs = [];
566
+ (dl.toggles || []).forEach((t) => {
567
+ const x = { t, init: !!t.rec, st: { on: !!t.rec } };
568
+ const c = check(t.label, x.init, { rec: t.rec, title: t.rec ? "建议;取消勾选即不表态" : "勾选才表态" });
569
+ c.i.addEventListener("change", () => {
570
+ x.st.on = c.i.checked;
571
+ c.lb.classList.toggle("chg", x.st.on !== x.init);
572
+ upd();
573
+ });
574
+ S.del.push(x);
575
+ cs.push(c);
576
+ });
577
+ const { q } = qcell(null, dl.info || "");
578
+ q.classList.add("info");
579
+ const it = item(rs, el("div", { cls: "ln" }, q, el("div", { cls: "ctl" }, ...cs.map((c) => c.lb))));
580
+ it.__pick = (i) => {
581
+ if (cs[i])
582
+ cs[i].i.click();
583
+ };
584
+ it.__focus = () => {
585
+ if (cs[0])
586
+ cs[0].i.focus();
587
+ };
588
+ S.delIt = it;
589
+ }
590
+ optl.forEach((o) => {
591
+ const st = { on: false };
592
+ const c = check("也做", false);
593
+ c.i.addEventListener("change", () => {
594
+ st.on = c.i.checked;
595
+ c.lb.classList.toggle("chg", st.on);
596
+ upd();
597
+ });
598
+ const { q } = qcell(null, o.text);
599
+ const it = item(rs, el("div", { cls: "ln" }, q, el("div", { cls: "ctl" }, c.lb)));
600
+ it.__pick = (i) => {
601
+ if (i === 0)
602
+ c.i.click();
603
+ };
604
+ it.__focus = () => c.i.focus();
605
+ S.opt.push({ o, st, it });
606
+ });
607
+ }
608
+ const fmt = (head, t, ind) => {
609
+ let ls = String(t).split(`
610
+ `).map((l) => l.replace(/\s+$/, ""));
611
+ while (ls.length && !ls[0])
612
+ ls.shift();
613
+ while (ls.length && !ls[ls.length - 1])
614
+ ls.pop();
615
+ ls = ls.filter((l, k) => l || ls[k - 1]);
616
+ if (ls.length <= 1)
617
+ return head + (ls[0] || "");
618
+ const pad = " ".repeat(ind);
619
+ return head + ls[0] + `
620
+ ` + ls.slice(1).map((l) => pad + l).join(`
621
+ `);
622
+ };
623
+ const line = (x) => {
624
+ const { d, st } = x, t = txt(st), h = d.n + ". ", w = h.length;
625
+ if (d.ask) {
626
+ const v = (st.text || "").trim();
627
+ return v ? fmt(h, v, w) : null;
628
+ }
629
+ if (d.group === "defaulted")
630
+ return st.pick === "over" ? fmt(h + "推翻:", t || "(待补充)", w) : null;
631
+ if (d.multi) {
632
+ const s = [...st.sel].sort((a, b) => a - b).map((i) => d.opts[i]);
633
+ if (s.length)
634
+ return fmt(h + s.join("、") + (t ? "," : ""), t, w);
635
+ if (x.init.size)
636
+ return fmt(h + "都不选" + (t ? "," : ""), t, w);
637
+ return t ? fmt(h, t, w) : null;
638
+ }
639
+ if (st.pick && st.pick[0] === "o")
640
+ return fmt(h + d.opts[+st.pick.slice(1)] + (t ? "," : ""), t, w);
641
+ return t ? fmt(h, t, w) : null;
642
+ };
643
+ const put = (L, arr) => {
644
+ const sep = arr.some((v) => v.includes(`
645
+ `));
646
+ arr.forEach((v, k) => {
647
+ if (sep && k)
648
+ L.push("");
649
+ L.push(v);
650
+ });
651
+ return sep;
652
+ };
653
+ function build() {
654
+ const L = [];
655
+ const now = S.dec.filter((x) => x.d.group !== "pending").map(line).filter(Boolean);
656
+ const pend = S.dec.filter((x) => x.d.group === "pending").map(line).filter(Boolean);
657
+ if (now.length || pend.length) {
658
+ L.push("决策:");
659
+ const sep = put(L, now);
660
+ if (pend.length) {
661
+ if (sep || pend.some((v) => v.includes(`
662
+ `)))
663
+ L.push("");
664
+ L.push("--早前尚未决策--");
665
+ put(L, pend);
666
+ }
667
+ }
668
+ const act = S.act.filter((x) => x.st.pick);
669
+ if (act.length) {
670
+ if (L.length)
671
+ L.push("");
672
+ L.push("反馈:");
673
+ put(L, act.map((x) => {
674
+ const t = txt(x.st);
675
+ return fmt("- " + x.a.short + ":" + LAB[x.st.pick] + (t ? ":" : ""), t, 2);
676
+ }));
677
+ }
678
+ const del = S.del.filter((x) => x.st.on).map((x) => x.t.label);
679
+ if (del.length) {
680
+ if (L.length)
681
+ L.push("");
682
+ L.push("交付:" + del.join(","));
683
+ }
684
+ const opt = S.opt.filter((x) => x.st.on);
685
+ if (opt.length) {
686
+ if (L.length)
687
+ L.push("");
688
+ opt.forEach((x) => L.push("也做:" + x.o.text));
689
+ }
690
+ return L.join(`
691
+ `);
692
+ }
693
+ const devs = () => {
694
+ const a = [];
695
+ S.dec.forEach((x) => {
696
+ if (x.changed())
697
+ a.push(x.d.n + " " + x.sum());
698
+ });
699
+ S.act.forEach((x) => {
700
+ if (x.st.pick)
701
+ a.push(x.a.short + ":" + LAB[x.st.pick]);
702
+ });
703
+ S.del.forEach((x) => {
704
+ if (x.st.on !== x.init)
705
+ a.push((x.st.on ? "" : "不") + x.t.label);
706
+ });
707
+ S.opt.forEach((x) => {
708
+ if (x.st.on)
709
+ a.push("也做 " + cut(x.o.text, 10));
710
+ });
711
+ return a;
712
+ };
713
+ const wrap = (t) => t ? "<turn-reply" + (TURN ? ' turn="' + TURN + '"' : "") + `>
714
+ ` + t + `
715
+ </turn-reply>` : t;
716
+ const nowDec = S.dec.filter((x) => x.reset && x.d.group === "now");
717
+ let allRec = null;
718
+ if (nowDec.length) {
719
+ allRec = ghost("全部按建议", { icon: "reset", title: "把本轮拍板恢复为建议项" });
720
+ allRec.addEventListener("click", () => nowDec.forEach((x) => x.reset()));
721
+ }
722
+ const cnt = el("span", {});
723
+ const pv = el("button", { type: "button", cls: "lk", "aria-expanded": "false" }, "预览");
724
+ const sum = el("span", { cls: "sum", "aria-live": "polite" }, cnt, pv);
725
+ const pre = el("pre", { cls: "pv" });
726
+ pre.hidden = true;
727
+ const closePre = () => {
728
+ pre.hidden = true;
729
+ pv.textContent = "预览";
730
+ pv.setAttribute("aria-expanded", "false");
731
+ };
732
+ pv.addEventListener("click", () => {
733
+ if (pre.hidden) {
734
+ pre.hidden = false;
735
+ pv.textContent = "收起";
736
+ pv.setAttribute("aria-expanded", "true");
737
+ } else
738
+ closePre();
739
+ });
740
+ const cpLb = el("span", {}, "复制");
741
+ const cp = el("button", { type: "button", cls: "btn" }, cpLb);
742
+ cp.addEventListener("click", () => {
743
+ const t = build();
744
+ if (t) {
745
+ copyText(wrap(t));
746
+ flash(cpLb, "已复制");
747
+ }
748
+ });
749
+ let go = null;
750
+ if (hasSend) {
751
+ go = el("button", { type: "button", cls: "btn pri" }, "填入输入框");
752
+ go.addEventListener("click", (e) => {
753
+ e.stopPropagation();
754
+ fill();
755
+ });
756
+ } else {
757
+ cp.classList.add("pri");
758
+ }
759
+ const foot = el("div", { cls: "foot" }, allRec, sum, cp, go);
760
+ const fsum = el("span", { cls: "fs" });
761
+ const fx = el("button", { type: "button", cls: "lk" }, "展开");
762
+ const fold = el("div", { cls: "fold" }, el("span", { cls: "mk-ok", "aria-hidden": "true" }), fsum, fx);
763
+ const setFold = (on) => {
764
+ root.classList.toggle("folded", on);
765
+ if (on)
766
+ closePre();
767
+ else if (root.classList.contains("kb") && items[0])
768
+ items[0].__focus();
769
+ };
770
+ fold.addEventListener("click", () => setFold(false));
771
+ const ns = el("div", { cls: "ns", role: "status" }, "宿主报告没有填进输入框。若输入框里已经有这段文字,可忽略;否则点「复制」后手动粘贴。");
772
+ let nsObs = null, nsTimer = 0;
773
+ const watchNotSent = () => {
774
+ if (nsObs)
775
+ nsObs.disconnect();
776
+ clearTimeout(nsTimer);
777
+ root.classList.remove("notsent");
778
+ const b = document.body;
779
+ if (!b || typeof MutationObserver !== "function")
780
+ return;
781
+ const hit = () => {
782
+ nsObs.disconnect();
783
+ clearTimeout(nsTimer);
784
+ root.classList.add("notsent");
785
+ setFold(false);
786
+ };
787
+ nsObs = new MutationObserver(() => {
788
+ if (b.hasAttribute("data-not-sent"))
789
+ hit();
790
+ });
791
+ nsObs.observe(b, { attributes: true, attributeFilter: ["data-not-sent"] });
792
+ nsTimer = setTimeout(() => nsObs.disconnect(), 5000);
793
+ };
794
+ function fill() {
795
+ const t = build();
796
+ if (!t)
797
+ return;
798
+ watchNotSent();
799
+ sendPrompt(wrap(t));
800
+ const dv = devs();
801
+ fsum.textContent = "已填入 · " + (dv.length ? dv.join(" · ") : "全部按建议");
802
+ fsum.title = fsum.textContent;
803
+ setFold(true);
804
+ }
805
+ const primary = () => {
806
+ if (hasSend)
807
+ fill();
808
+ else
809
+ cp.click();
810
+ };
811
+ root.addEventListener("mousedown", () => root.classList.remove("kb"));
812
+ root.addEventListener("keydown", (e) => {
813
+ if (e.key === "Tab" || e.key.startsWith("Arrow") || /^[0-9]$/.test(e.key))
814
+ root.classList.add("kb");
815
+ if (root.classList.contains("folded"))
816
+ return;
817
+ const tg = e.target;
818
+ if (tg.tagName === "TEXTAREA") {
819
+ if (e.isComposing || e.keyCode === 229)
820
+ return;
821
+ if (e.key === "Escape" && tg.__esc) {
822
+ e.preventDefault();
823
+ tg.__esc();
824
+ }
825
+ return;
826
+ }
827
+ if (e.metaKey || e.ctrlKey || e.altKey)
828
+ return;
829
+ const it = tg.closest && tg.closest(".it");
830
+ if (!it)
831
+ return;
832
+ if (e.key === "/" && it.__note) {
833
+ e.preventDefault();
834
+ it.__note();
835
+ return;
836
+ }
837
+ if (/^[1-9]$/.test(e.key) && it.__pick) {
838
+ e.preventDefault();
839
+ it.__pick(+e.key - 1);
840
+ return;
841
+ }
842
+ if (e.key === "ArrowDown" || e.key === "ArrowUp") {
843
+ const i = items.indexOf(it);
844
+ const nx = items[i + (e.key === "ArrowDown" ? 1 : -1)];
845
+ if (nx) {
846
+ e.preventDefault();
847
+ nx.__focus();
848
+ }
849
+ }
850
+ });
851
+ root.append(fold, bd, foot, ns, pre);
852
+ function upd() {
853
+ const t = build();
854
+ const n = count(t);
855
+ const dv = devs();
856
+ S.dec.forEach((x) => x.it.classList.toggle("chg", x.changed()));
857
+ S.act.forEach((x) => x.it.classList.toggle("chg", !!x.st.pick));
858
+ if (S.delIt)
859
+ S.delIt.classList.toggle("chg", S.del.some((x) => x.st.on !== x.init));
860
+ S.opt.forEach((x) => x.it.classList.toggle("chg", x.st.on));
861
+ const parts = [];
862
+ parts.push(dv.length ? "改了 " : "全部按建议", ...dv.length ? [el("b", {}, String(dv.length)), " 项"] : []);
863
+ if (n)
864
+ parts.push(" · 将填入 ", el("b", {}, String(n)), " 行");
865
+ else
866
+ parts.push(" · 没有要回复的内容");
867
+ cnt.replaceChildren(...parts);
868
+ pre.textContent = wrap(t);
869
+ pv.hidden = !n;
870
+ if (!n)
871
+ closePre();
872
+ cp.disabled = !n;
873
+ if (go)
874
+ go.disabled = !n;
875
+ if (allRec)
876
+ allRec.disabled = nowDec.every((x) => !x.changed());
877
+ }
878
+ upd();
879
+ const cw = {};
880
+ const dbs = [...root.querySelectorAll(".dseg button.sg")];
881
+ dbs.forEach((b) => {
882
+ const c = b.dataset.col;
883
+ cw[c] = Math.max(cw[c] || 0, b.offsetWidth);
884
+ });
885
+ dbs.forEach((b) => {
886
+ b.style.setProperty("width", Math.ceil(cw[b.dataset.col]) + 12 + "px", "important");
887
+ });
888
+ root.classList.add("measuring");
889
+ let m = 0;
890
+ root.querySelectorAll(".q").forEach((q) => {
891
+ m = Math.max(m, q.offsetWidth);
892
+ });
893
+ root.classList.remove("measuring");
894
+ if (m > 0)
895
+ root.style.setProperty("--qw", Math.min(Math.ceil(m) + 2, 260) + "px");
896
+ }
897
+ return render;
898
+ })();
899
+
900
+ // src/index.js
901
+ var version = "0.1.1";
902
+ var STYLE_ID = "trw-style-" + version;
903
+ function injectCSS(root) {
904
+ const d = root.ownerDocument || document;
905
+ if (d.getElementById(STYLE_ID))
906
+ return;
907
+ const s = d.createElement("style");
908
+ s.id = STYLE_ID;
909
+ s.textContent = css_default;
910
+ (d.head || root.parentNode || d.documentElement).appendChild(s);
911
+ }
912
+ function fail(root, msg) {
913
+ root.replaceChildren();
914
+ root.classList.remove("folded", "kb");
915
+ const p = (root.ownerDocument || document).createElement("div");
916
+ p.className = "err";
917
+ p.setAttribute("role", "alert");
918
+ p.title = msg;
919
+ p.textContent = msg;
920
+ root.append(p);
921
+ }
922
+ var TAIL = ",请直接在输入框回复";
923
+ function render(root, spec) {
924
+ if (!root || typeof root.append !== "function") {
925
+ console.error("[turn-reply] root 不是元素");
926
+ return ["root 不是元素"];
927
+ }
928
+ root.classList.add("trw");
929
+ injectCSS(root);
930
+ let s = spec;
931
+ if (typeof s === "string") {
932
+ try {
933
+ s = JSON.parse(s);
934
+ } catch (x) {
935
+ fail(root, "面板数据不是合法 JSON" + TAIL);
936
+ return ["JSON 解析失败"];
937
+ }
938
+ }
939
+ const errs = validate(s);
940
+ if (errs.length) {
941
+ console.error(`[turn-reply] spec 不合法:
942
+ ` + errs.join(`
943
+ `));
944
+ fail(root, "面板数据不合法(" + errs.length + " 处,首处 " + errs[0] + ")" + TAIL);
945
+ return errs;
946
+ }
947
+ try {
948
+ renderPanel(root, s);
949
+ } catch (x) {
950
+ console.error("[turn-reply] 渲染出错", x);
951
+ const m = "面板渲染出错(" + (x && x.message || x) + ")" + TAIL;
952
+ fail(root, m);
953
+ return [m];
954
+ }
955
+ return [];
956
+ }
957
+
958
+ // src/entry.js
959
+ var g = typeof window !== "undefined" ? window : globalThis;
960
+ if (!g.TR || g.TR.version !== version)
961
+ g.TR = { render, validate, version, css: css_default };
962
+ })();
package/dist/tr.min.js ADDED
@@ -0,0 +1,13 @@
1
+ /*! @npmjsdnt/turn-reply@0.1.1 turn-reply panel */
2
+ (()=>{var rt=".trw{--c-bg:var(--surface-2);--c-sunken:var(--surface-1);--c-hover:var(--fill-ghost-hover,var(--surface-1));--c-soft:var(--fill-ghost-selected,var(--surface-1));--c-solid:var(--fill-primary,var(--text-primary));--c-on-solid:var(--on-primary,var(--surface-2));--c-line:var(--border);--c-line-s:var(--border-strong);--c-line-x:var(--border-stronger,var(--border-strong));--c-ink1:var(--text-primary);--c-ink2:var(--text-secondary);--c-ink3:var(--text-muted);--c-ink4:var(--text-disabled,var(--text-muted));--c-attn:var(--text-warning);--c-ok:var(--text-success);--c-focus:var(--border-accent,var(--text-accent));--c-r:6px;--c-track:color-mix(in srgb,var(--c-ink1,currentColor) 5%,transparent);--c-lift:var(--surface-3,var(--surface-2));--c-hov:color-mix(in srgb,var(--c-ink1,currentColor) 4%,transparent);container-type:inline-size;position:relative;box-sizing:border-box;font-family:var(--font-sans);font-size:13px;line-height:20px;font-weight:400;font-variant-numeric:tabular-nums;-webkit-font-smoothing:antialiased;color:var(--c-ink1);background:transparent;border:0;border-radius:0;padding:0}.trw.dark{--c-lift:color-mix(in srgb,var(--c-ink1,currentColor) 15%,transparent);--c-hov:color-mix(in srgb,var(--c-ink1,currentColor) 8%,transparent)}.trw *,.trw *::before,.trw *::after{box-sizing:border-box}.trw [hidden]{display:none!important}.trw .mono{font-family:var(--font-mono);font-size:12px}.trw .grp{display:flex;align-items:flex-start;padding:6px 0;border-top:0.5px solid var(--c-line)}.trw .bd>.grp:first-child{border-top:0}.trw .gl{flex:0 0 60px;padding-top:6px;font-size:11px;line-height:16px;color:var(--c-ink2);white-space:nowrap;cursor:default}.trw .rs{flex:1 1 auto;min-width:0}.trw .it{margin:0 -6px;padding:0 6px;border-radius:0}.trw .it:hover,.trw.kb .it:focus-within{background:var(--c-hover)}.trw .ln{display:flex;flex-wrap:wrap;align-items:center;gap:2px 8px;min-height:28px}.trw .bd>.grp:first-child .it:first-child .ln{padding-right:40px}.trw .q{flex:0 0 var(--qw,240px);min-width:0;display:flex;align-items:center;gap:6px;white-space:nowrap;overflow:hidden}.trw.measuring .q{flex:none!important;width:max-content!important}.trw .qt{min-width:0;overflow:hidden;text-overflow:ellipsis}.trw .n{flex:none;min-width:14px;color:var(--c-ink2)}.trw .it.core .qt{font-weight:500}.trw .q.info .qt{font-size:12px;color:var(--c-ink2)}.trw a.tk{font-family:var(--font-mono);font-size:12px;color:var(--c-ink1);text-decoration:underline;text-decoration-color:var(--c-line-x);text-underline-offset:2px}.trw .ctl{flex:none;display:flex;flex-wrap:wrap;align-items:center;gap:4px 6px;padding:0 4px;margin:0 -4px}.trw .cb{flex:none;width:9px;height:9px;background:var(--c-attn);clip-path:polygon(50% 0,100% 50%,50% 100%,0 50%)}.trw .seg{display:inline-flex;align-items:center;gap:2px;height:26px;padding:2px;border:0;border-radius:7px;background:var(--c-track)}.trw button.sg{position:relative;font-family:inherit!important;font-size:12px!important;font-weight:400!important;line-height:20px!important;height:22px!important;min-height:0!important;margin:0!important;padding:0 9px!important;border:0!important;border-radius:5px!important;background:transparent!important;color:var(--c-ink2)!important;box-shadow:none!important;cursor:pointer;white-space:nowrap;text-align:center;justify-content:center}.trw button.sg[aria-checked=\"false\"]:hover{background:var(--c-hov)!important;color:var(--c-ink1)!important}.trw .ck.rec>span::before{content:\"\";display:inline-block;width:4px;height:4px;border-radius:50%;background:currentColor;margin-right:5px;vertical-align:2px}.trw button.sg.rec{padding:0 4px 0 14px!important}.trw button.sg.rec::before{content:\"\";position:absolute;left:6px;top:50%;width:4px;height:4px;margin-top:-2px;border-radius:50%;background:currentColor;opacity:.4}.trw button.sg.sk{color:var(--c-ink3)!important}.trw button.sg[aria-checked=\"true\"]{background:var(--c-lift)!important;color:var(--c-ink1)!important;box-shadow:none!important}.trw .dseg button.sg[aria-checked=\"true\"]:hover::before{content:\"×\";position:absolute;left:4px;top:0;width:8px;height:auto;margin:0;border-radius:0;background:none;line-height:22px;text-align:center;opacity:1;color:var(--c-ink3)}.trw .k{display:none;position:absolute;top:-8px;right:-4px;font:11px/14px var(--font-mono);padding:0 3px;border-radius:4px;background:var(--c-bg);color:var(--c-ink3);border:0.5px solid var(--c-line-s);pointer-events:none;z-index:1}.trw.kb .it:focus-within .k{display:block}.trw .ck{display:inline-flex;align-items:center;gap:6px;height:26px;padding:0 6px;border-radius:var(--c-r);font-size:12px;color:var(--c-ink2);cursor:pointer;white-space:nowrap;user-select:none}.trw .ck:hover{background:var(--c-hover);color:var(--c-ink1)}.trw .ck input{width:13px;height:13px;margin:0;accent-color:var(--c-solid);cursor:pointer}.trw .ck:has(input:checked){color:var(--c-ink1)}.trw button.gh{display:inline-flex;align-items:center;gap:5px;font-family:inherit!important;font-size:12px!important;font-weight:500!important;line-height:20px!important;height:26px!important;min-height:0!important;margin:0!important;padding:0 8px!important;border:0.5px solid transparent!important;border-radius:var(--c-r)!important;background:transparent!important;color:var(--c-ink2)!important;box-shadow:none!important;cursor:pointer;white-space:nowrap}.trw button.gh:hover{background:var(--c-hover)!important;color:var(--c-ink1)!important}.trw svg.i{width:14px;height:14px;flex:none;fill:none;stroke:currentColor;stroke-width:1.3;stroke-linecap:round;stroke-linejoin:round}.trw .ed{display:flex;padding:4px 0 8px calc(var(--qw,240px) + 8px)}.trw .it:last-child>.ed{padding-bottom:4px}.trw .ed textarea,.trw textarea.ask{display:block;flex:1;min-width:0;min-height:28px;height:28px;resize:none!important;overflow:hidden;margin:0!important;padding:4px 10px!important;font:12px/18px var(--font-sans,system-ui)!important;white-space:pre-wrap;overflow-wrap:anywhere;border:0.5px solid var(--c-line-s)!important;border-radius:var(--c-r)!important;background:var(--c-bg)!important;color:var(--c-ink1)!important;box-shadow:none!important}.trw .ed textarea::placeholder,.trw textarea.ask::placeholder{color:var(--c-ink3)}.trw textarea.ask{flex:1 1 160px;min-height:26px;height:26px;padding:3px 10px!important}.trw .ln.top{align-items:flex-start}.trw .ln.top .q{min-height:26px}.trw .foot{display:flex;flex-wrap:wrap;align-items:center;gap:6px 8px;padding:8px 0 2px;border-top:0.5px solid var(--c-line)}.trw .sum{flex:1 1 auto;display:inline-flex;align-items:center;gap:8px;font-size:12px;line-height:18px;color:var(--c-ink3);white-space:nowrap}.trw .sum b{font-weight:500;color:var(--c-ink2)}.trw button.lk{font-family:inherit!important;font-size:12px!important;font-weight:400!important;line-height:18px!important;height:auto!important;min-height:0!important;margin:0!important;padding:0 2px!important;border:0!important;border-radius:4px!important;background:transparent!important;color:var(--c-ink2)!important;box-shadow:none!important;cursor:pointer;text-decoration:underline;text-decoration-color:var(--c-line-x);text-underline-offset:3px}.trw button.btn{display:inline-flex;align-items:center;gap:6px;font-family:inherit!important;font-size:12px!important;font-weight:500!important;line-height:20px!important;height:28px!important;min-height:0!important;margin:0!important;padding:0 12px!important;border:0.5px solid transparent!important;border-radius:var(--c-r)!important;background:transparent!important;color:var(--c-ink2)!important;box-shadow:none!important;cursor:pointer;white-space:nowrap}.trw button.btn:hover{background:var(--c-hover)!important;color:var(--c-ink1)!important}.trw button.btn.pri{border-color:var(--c-line-x)!important;color:var(--c-ink1)!important}.trw button.btn:disabled,.trw button.gh:disabled{color:var(--c-ink4)!important;background:transparent!important;cursor:default}.trw pre.pv{font:12px/18px var(--font-mono);white-space:pre-wrap;overflow-wrap:anywhere;background:var(--c-sunken);padding:8px 10px;border-radius:var(--c-r);margin:0 0 8px;color:var(--c-ink2)}.trw .fold{display:none;align-items:center;gap:6px;min-height:34px;font-size:12px;color:var(--c-ink2);cursor:pointer;padding:0 40px 0 6px;margin:0 -6px}.trw .fold .fs{flex:0 1 auto;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.trw .mk-ok{flex:none;width:10px;height:8px;background:var(--c-ok);clip-path:polygon(0 56%,15% 38%,38% 62%,85% 0,100% 19%,38% 100%)}.trw.folded .fold{display:flex}.trw.folded>:not(.fold){display:none!important}.trw.folded:hover{background:var(--c-hover);border-radius:0}.trw button:focus-visible{outline:2px solid var(--c-focus)!important;outline-offset:-2px}.trw .ed textarea:focus,.trw textarea.ask:focus{outline:none!important;border-color:var(--c-focus)!important;box-shadow:inset 0 0 0 1px var(--c-focus)!important}@container (max-width:480px){.trw .grp{display:block}.trw .ln{flex-wrap:wrap;row-gap:2px;padding-bottom:2px}.trw .q{flex:1 1 auto;white-space:normal}.trw .ed{padding-left:0}}.trw .err{padding:6px 0;font-size:12px;line-height:18px;color:var(--c-attn);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.trw.dark{--c-track:color-mix(in srgb,var(--c-ink1,currentColor) 8%,transparent);--c-lift:color-mix(in srgb,var(--c-ink1,currentColor) 26%,transparent);--c-hov:color-mix(in srgb,var(--c-ink1,currentColor) 12%,transparent)}.trw.dark button.sg.rec::before{opacity:.75}.trw.dark button.sg[aria-checked=\"true\"]{font-weight:500!important}.trw .ns{display:none;font-size:12px;line-height:18px;color:var(--c-attn);padding:6px 0 0}.trw.notsent .ns{display:block}";var z=(n,l=1/0,m=1)=>typeof n==="string"&&n.length>=m&&n.length<=l,H=(n,l,m,y)=>{for(let s of Object.keys(n))if(!l.includes(s))y.push(`${m}.${s} 未定义的字段`)};function ot(n){let l=[];if(!n||typeof n!=="object"||Array.isArray(n))return["$ 不是对象"];if(H(n,["v","turn","ticketUrl","decisions","actions","delivery","optional"],"$",l),n.v!==1)l.push("$.v 必须为 1");if(!z(n.turn,40)||!/^[\w.:-]+$/.test(n.turn))l.push("$.turn 缺失或含非法字符");if(n.ticketUrl!==void 0&&!(z(n.ticketUrl)&&n.ticketUrl.startsWith("https://")))l.push("$.ticketUrl 须为 https:// 前缀");let m=new Set;(n.decisions??[]).forEach((s,x)=>{let f=`$.decisions[${x}]`;if(!s||typeof s!=="object")return l.push(`${f} 不是对象`);if(H(s,["n","group","core","q","opts","rec","def","multi","ask","ph"],f,l),!Number.isInteger(s.n)||s.n<1)l.push(`${f}.n 须为正整数`);else if(m.has(s.n))l.push(`${f}.n=${s.n} 重复`);else m.add(s.n);if(!["now","defaulted","pending"].includes(s.group))l.push(`${f}.group 非法`);if(!z(s.q,40))l.push(`${f}.q 须为 1–40 字`);if(s.core!==void 0&&typeof s.core!=="boolean")l.push(`${f}.core 须为布尔`);if(s.def!==void 0&&!z(s.def,60))l.push(`${f}.def 须为 ≤60 字`);if(s.multi!==void 0&&s.multi!==!0)l.push(`${f}.multi 只能为 true`);if(s.ask!==void 0&&s.ask!==!0)l.push(`${f}.ask 只能为 true`);let T=s.opts;if(T!==void 0&&!(Array.isArray(T)&&T.every((D)=>z(D,12))))l.push(`${f}.opts 须为 1–12 字的字符串数组`);let N=Array.isArray(T)?T.length:0,I=s.group==="defaulted"?"defaulted":s.ask?"ask":s.multi?"multi":"one";if(s.ask&&s.multi)l.push(`${f} ask 与 multi 不能同时出现`);if(I==="defaulted"&&(T||s.rec!==void 0||s.ask||s.multi))l.push(`${f} defaulted 条目只有「推翻」,不带 opts/rec/ask/multi`);if(I==="ask"&&(T||s.rec!==void 0))l.push(`${f} ask 条目不带 opts/rec`);if(s.ph!==void 0&&(I!=="ask"||!z(s.ph,40)))l.push(`${f}.ph 只用于 ask,≤40 字`);if(I==="one"&&(N<2||N>4))l.push(`${f} 单选须有 2–4 个 opts(现 ${N})`);if(I==="multi"&&(N<2||N>8))l.push(`${f} 多选须有 2–8 个 opts(现 ${N})`);if(I==="one"&&s.rec!==void 0&&!(Number.isInteger(s.rec)&&s.rec>=0&&s.rec<N))l.push(`${f}.rec 须为 opts 下标`);if(I==="multi"&&s.rec!==void 0&&!(Array.isArray(s.rec)&&s.rec.every((D)=>Number.isInteger(D)&&D>=0&&D<N)&&new Set(s.rec).size===s.rec.length))l.push(`${f}.rec 须为不重复的 opts 下标数组`);if(Array.isArray(T)&&new Set(T).size!==N)l.push(`${f}.opts 有重复`)});let y=[...m].sort((s,x)=>s-x);if(y.length&&y.some((s,x)=>x&&s!==y[x-1]+1))l.push(`$.decisions 编号不连续:${y.join(",")}`);if((n.actions??[]).forEach((s,x)=>{let f=`$.actions[${x}]`;if(!s||typeof s!=="object")return l.push(`${f} 不是对象`);if(H(s,["text","short","cmd"],f,l),!z(s.text,120))l.push(`${f}.text 须为 1–120 字`);if(!z(s.short,24))l.push(`${f}.short 须为 1–24 字`);if(s.cmd!==void 0&&!z(s.cmd))l.push(`${f}.cmd 须为非空字符串`)}),n.delivery!==void 0){let s=n.delivery;if(!s||typeof s!=="object")l.push("$.delivery 不是对象");else{if(H(s,["info","toggles"],"$.delivery",l),s.info!==void 0&&!z(s.info,120))l.push("$.delivery.info 须为 ≤120 字");(s.toggles??[]).forEach((x,f)=>{if(H(x??{},["label","rec"],`$.delivery.toggles[${f}]`,l),!z(x?.label,20))l.push(`$.delivery.toggles[${f}].label 须为 1–20 字`);if(x?.rec!==void 0&&typeof x.rec!=="boolean")l.push(`$.delivery.toggles[${f}].rec 须为布尔`)})}}(n.optional??[]).forEach((s,x)=>{if(H(s??{},["text"],`$.optional[${x}]`,l),!z(s?.text,120))l.push(`$.optional[${x}].text 须为 1–120 字`)});for(let s of["decisions","actions","optional"])if(n[s]!==void 0&&!Array.isArray(n[s]))l.push(`$.${s} 须为数组`);return l}var Nt=(()=>{let n=(p,h={},...E)=>{let w=document.createElement(p);for(let[g,_]of Object.entries(h)){if(_==null||_===!1)continue;if(g==="cls")w.className=_;else w.setAttribute(g,_)}return E.flat().forEach((g)=>{if(g!=null&&g!==!1)w.append(g)}),w},l={copy:'<rect x="5.5" y="5.5" width="7.5" height="7.5" rx="1.2"/><path d="M10.5 3.5V3a.5.5 0 0 0-.5-.5H3a.5.5 0 0 0-.5.5v7a.5.5 0 0 0 .5.5h.5"/>',reset:'<path d="M3.2 8a4.8 4.8 0 1 0 1.4-3.4"/><path d="M3.2 2.6v2.6h2.6"/>'},m=(p)=>{let h=document.createElementNS("http://www.w3.org/2000/svg","svg");return h.setAttribute("viewBox","0 0 16 16"),h.setAttribute("class","i"),h.setAttribute("aria-hidden","true"),h.innerHTML=l[p],h},y=null,s=(p)=>{if(!p)return[];let h=[],E=0;return p.replace(/\b[A-Z]{2,6}-\d+\b|\b[0-9a-f]{7,40}\b/g,(w,g)=>{let _=/^[A-Z]/.test(w);if(!_&&!(/\d/.test(w)&&/[a-f]/.test(w)))return w;if(_&&!y)return w;return h.push(p.slice(E,g),_?n("a",{cls:"tk",href:y+w,target:"_blank",rel:"noopener"},w):n("span",{cls:"mono"},w.slice(0,7))),E=g+w.length,w}),h.push(p.slice(E)),h},x=(p)=>{let h=()=>{let E=n("textarea",{style:"position:absolute;left:-9999px;top:0","aria-hidden":"true"});E.value=p,document.body.append(E),E.select();try{document.execCommand("copy")}catch(w){}E.remove()};try{navigator.clipboard.writeText(p).catch(h)}catch(E){h()}},f=(p,h)=>{if(!p.dataset.l)p.dataset.l=p.textContent;p.textContent=h,clearTimeout(p._t),p._t=setTimeout(()=>{p.textContent=p.dataset.l},1400)},T=(p)=>p?p.split(`
3
+ `).filter(Boolean).length:0,N=(p,h)=>p.length>h?p.slice(0,h)+"…":p,I=(p,h)=>p.size===h.size&&[...p].every((E)=>h.has(E)),D={done:"已做",issue:"有问题",no:"没做",you:"你来做"};function Ot(p,h){p.replaceChildren(),p.classList.remove("folded","kb");{let t=(getComputedStyle(p).color.match(/\d+/g)||[0,0,0]).slice(0,3).map(Number);p.classList.toggle("dark",(t[0]*299+t[1]*587+t[2]*114)/1000>140)}y=h.ticketUrl||null;let E=h.turn?String(h.turn).replace(/[^\w.:-]/g,""):"",w=typeof sendPrompt==="function",g={dec:[],act:[],del:[],opt:[]},_=[],wt=n("div",{cls:"bd"}),st=(t,e)=>{let o=n("div",{cls:"rs"});return wt.append(n("div",{cls:"grp"},n("div",{cls:"gl",title:e||null},t),o)),o},X=(t,e,o)=>{let r=n("div",{cls:"it"},e,...o||[]);return t.append(r),_.push(r),r},Y=(t,e)=>{let o=n("span",{cls:"qt"},...s(e));return{q:n("div",{cls:"q",title:e||null},t&&t.n!=null?n("span",{cls:"n"},t.n+"."):null,t&&t.core?n("span",{cls:"cb",role:"img","aria-label":"核心决策",title:"核心决策"}):null,o),qt:o}},ct=(t)=>{if(!t.value){t.style.removeProperty("height");return}t.style.setProperty("height","auto","important"),t.style.setProperty("height",t.scrollHeight+(t.offsetHeight-t.clientHeight)+"px","important")},kt=(t,e)=>{let o=n("textarea",{rows:"1",cls:e||null,placeholder:t,"aria-label":t});return o.addEventListener("input",()=>ct(o)),o},G=(t,e)=>{let o=n("div",{cls:"ed"}),r=kt(e);return r.addEventListener("input",()=>{t.text=r.value,O()}),o.append(r),o.hidden=!0,t.ed=o,{box:o,i:r,show(a,i){if(o.hidden=!a,a){if(ct(r),i)r.focus()}O()}}},U=(t)=>t.ed&&!t.ed.hidden?(t.text||"").trim():"",yt=(t,e,o={})=>{let r=o.init===void 0?null:o.init,a=n("div",{cls:"seg"+(o.cls?" "+o.cls:""),role:"radiogroup","aria-label":o.label||null,title:o.title||null}),i=t.map((u,b)=>n("button",{type:"button",role:"radio",cls:"sg"+(u.rec?" rec":""),"data-col":String(b),title:u.title||null},u.label,n("span",{cls:"k","aria-hidden":"true"},String(b+1)))),c=()=>{let u=t.findIndex((L)=>L.v===e.pick),b=e.pick!==r;i.forEach((L,M)=>{L.setAttribute("aria-checked",String(M===u)),L.classList.toggle("chg",M===u&&b),L.tabIndex=M===(u<0?0:u)?0:-1})},d=(u,b)=>{if(e.pick=u,c(),o.onChange)o.onChange(b);O()},v=(u,b)=>{if(t[u])d(o.toggle&&e.pick===t[u].v?null:t[u].v,b)};return i.forEach((u,b)=>u.addEventListener("click",()=>v(b,!1))),a.addEventListener("keydown",(u)=>{if(u.key!=="ArrowRight"&&u.key!=="ArrowLeft")return;u.preventDefault();let L=(Math.max(0,i.indexOf(document.activeElement))+(u.key==="ArrowRight"?1:-1)+i.length)%i.length;d(t[L].v,!0),i[L].focus()}),c(),a.append(...i),{w:a,set:d,choose:v,focus:()=>(i.find((u)=>u.tabIndex===0)||i[0]).focus()}},Q=(t,e,o={})=>{let r=n("input",{type:"checkbox"});return r.checked=!!e,{lb:n("label",{cls:"ck"+(o.rec?" rec":""),title:o.title||null},r,n("span",{},t)),i:r}},Mt=(t,e,o,r)=>{let a=n("div",{cls:"ctl",role:"group"}),i=t.map((d,v)=>Q(d,r.has(v),{rec:e.includes(v),title:e.includes(v)?"建议":null})),c=()=>i.forEach((d,v)=>d.lb.classList.toggle("chg",o.sel.has(v)!==r.has(v)));return i.forEach((d,v)=>d.i.addEventListener("change",()=>{d.i.checked?o.sel.add(v):o.sel.delete(v),c(),O()})),a.append(...i.map((d)=>d.lb)),{w:a,set:(d)=>{o.sel=new Set(d),i.forEach((v,u)=>{v.i.checked=o.sel.has(u)}),c(),O()},toggle:(d)=>{if(i[d])i[d].i.click()},focus:()=>i[0]&&i[0].i.focus()}},Et=(t,e={})=>n("button",{type:"button",cls:"gh",title:e.title||null},e.icon?m(e.icon):null,t?n("span",{},t):null);if([["本轮拍板","需要你拍板",(t)=>t.group==="now"],["早前","上轮按默认处理(勾「推翻」才回复)与早前尚未决策(默认不回复)",(t)=>t.group!=="now"]].forEach(([t,e,o])=>{let r=(h.decisions||[]).filter(o).sort((i,c)=>i.n-c.n);if(!r.length)return;let a=st(t,e);r.forEach((i)=>{let c={pick:null,text:""},d={d:i,st:c};g.dec.push(d);let{q:v}=Y(i,i.q),u=[],b,L,M,V=null;if(i.group==="defaulted"){let k=G(c,"改成什么"),A=Q("推翻",!1,{title:"推翻上轮的默认处理"});A.i.addEventListener("change",()=>{c.pick=A.i.checked?"over":null,A.lb.classList.toggle("chg",A.i.checked),k.show(A.i.checked,!0)}),b=n("div",{cls:"ctl"},A.lb),u.push(k.box),L=(S)=>{if(S===0)A.i.click()},M=()=>A.i.focus(),k.i.__esc=()=>A.i.focus(),d.changed=()=>c.pick==="over",d.sum=()=>"推翻"}else if(i.ask){let k=kt(i.ph||"填写;要附文件就留空,到输入框里附","ask");k.addEventListener("input",()=>{c.text=k.value,O()}),b=k,d.top=!0,L=()=>{},M=()=>k.focus(),d.changed=()=>!!(c.text||"").trim(),d.sum=()=>"已填"}else if(i.multi){let k=i.opts||[],A=Array.isArray(i.rec)?i.rec:i.rec!=null?[i.rec]:[],S=new Set(i.group==="now"?A:[]);c.sel=new Set(S),d.init=S;let C=Mt(k,A,c,S),q=G(c,"附一句;不勾选项时即为你的回复");V=()=>{let j=q.box.hidden;if(q.show(j,!0),!j)C.focus()},b=C.w,u.push(q.box),d.reset=()=>C.set(S),L=(j)=>C.toggle(j),M=C.focus,q.i.__esc=()=>{q.show(!1),C.focus()},d.changed=()=>!I(c.sel,S)||!!U(c),d.sum=()=>{let j=[...c.sel].sort((mt,Ft)=>mt-Ft).map((mt)=>k[mt]);return(j.length?j.join("、"):"都不选")+(U(c)?"(附言)":"")}}else{let k=i.opts||[],A=k.map((q,j)=>({v:"o"+j,label:q,rec:j===i.rec,title:j===i.rec?"建议;再点一次即不回复":"再点一次即不回复"}));c.pick=i.group==="now"&&k[i.rec]!=null?"o"+i.rec:null,d.init=c.pick;let S=yt(A,c,{label:i.q,init:d.init,toggle:!0,cls:"dseg",title:i.def||null}),C=G(c,"附一句;不选选项时即为你的回复");V=()=>{let q=C.box.hidden;if(C.show(q,!0),!q)S.focus()},b=n("div",{cls:"ctl"},S.w),u.push(C.box),d.reset=()=>S.set(d.init),L=(q)=>S.choose(q,!1),M=S.focus,C.i.__esc=()=>{C.show(!1),S.focus()},d.changed=()=>c.pick!==d.init||!!U(c),d.sum=()=>(c.pick?k[+c.pick.slice(1)]:"不回复")+(U(c)?"(附言)":"")}let Tt=n("div",{cls:"ln"+(d.top?" top":"")},v,b),Z=X(a,Tt,u);if(V)Tt.addEventListener("click",(k)=>{if(k.target.closest("button,input,textarea,label,a,.ctl"))return;V()}),Z.__note=V;if(i.core)Z.classList.add("core");Z.__pick=L,Z.__focus=M,d.it=Z})}),h.actions&&h.actions.length){let t=st("你要做的","做完后在这里回执");h.actions.forEach((e)=>{let o={pick:null,text:""},r=G(o,"贴结果、报错或原因"),a=[["done","已做"],["issue","有问题"],["no","没做"],["you","你来做"]].map(([u,b])=>({v:u,label:b})),i=yt(a,o,{toggle:!0,init:null,label:e.short||e.text,onChange:(u)=>{let b=o.pick==="issue"||o.pick==="no";if(r.box.hidden=!b,b){if(ct(r.i),!u)r.i.focus()}}}),c=null;if(e.cmd){c=Et("复制命令",{icon:"copy",title:e.cmd});let u=c.querySelector("span");c.addEventListener("click",()=>{x(e.cmd),f(u,"已复制")})}let{q:d}=Y(null,e.text),v=X(t,n("div",{cls:"ln"},d,n("div",{cls:"ctl"},i.w,c)),[r.box]);v.__pick=(u)=>i.choose(u,!1),v.__focus=i.focus,r.i.__esc=i.focus,g.act.push({a:e,st:o,it:v})})}let tt=h.delivery,$t=h.optional||[];if(tt||$t.length){let t=st("收尾");if(tt){let e=[];(tt.toggles||[]).forEach((a)=>{let i={t:a,init:!!a.rec,st:{on:!!a.rec}},c=Q(a.label,i.init,{rec:a.rec,title:a.rec?"建议;取消勾选即不表态":"勾选才表态"});c.i.addEventListener("change",()=>{i.st.on=c.i.checked,c.lb.classList.toggle("chg",i.st.on!==i.init),O()}),g.del.push(i),e.push(c)});let{q:o}=Y(null,tt.info||"");o.classList.add("info");let r=X(t,n("div",{cls:"ln"},o,n("div",{cls:"ctl"},...e.map((a)=>a.lb))));r.__pick=(a)=>{if(e[a])e[a].i.click()},r.__focus=()=>{if(e[0])e[0].i.focus()},g.delIt=r}$t.forEach((e)=>{let o={on:!1},r=Q("也做",!1);r.i.addEventListener("change",()=>{o.on=r.i.checked,r.lb.classList.toggle("chg",o.on),O()});let{q:a}=Y(null,e.text),i=X(t,n("div",{cls:"ln"},a,n("div",{cls:"ctl"},r.lb)));i.__pick=(c)=>{if(c===0)r.i.click()},i.__focus=()=>r.i.focus(),g.opt.push({o:e,st:o,it:i})})}let P=(t,e,o)=>{let r=String(e).split(`
4
+ `).map((i)=>i.replace(/\s+$/,""));while(r.length&&!r[0])r.shift();while(r.length&&!r[r.length-1])r.pop();if(r=r.filter((i,c)=>i||r[c-1]),r.length<=1)return t+(r[0]||"");let a=" ".repeat(o);return t+r[0]+`
5
+ `+r.slice(1).map((i)=>a+i).join(`
6
+ `)},_t=(t)=>{let{d:e,st:o}=t,r=U(o),a=e.n+". ",i=a.length;if(e.ask){let c=(o.text||"").trim();return c?P(a,c,i):null}if(e.group==="defaulted")return o.pick==="over"?P(a+"推翻:",r||"(待补充)",i):null;if(e.multi){let c=[...o.sel].sort((d,v)=>d-v).map((d)=>e.opts[d]);if(c.length)return P(a+c.join("、")+(r?",":""),r,i);if(t.init.size)return P(a+"都不选"+(r?",":""),r,i);return r?P(a,r,i):null}if(o.pick&&o.pick[0]==="o")return P(a+e.opts[+o.pick.slice(1)]+(r?",":""),r,i);return r?P(a,r,i):null},at=(t,e)=>{let o=e.some((r)=>r.includes(`
7
+ `));return e.forEach((r,a)=>{if(o&&a)t.push("");t.push(r)}),o};function lt(){let t=[],e=g.dec.filter((c)=>c.d.group!=="pending").map(_t).filter(Boolean),o=g.dec.filter((c)=>c.d.group==="pending").map(_t).filter(Boolean);if(e.length||o.length){t.push("决策:");let c=at(t,e);if(o.length){if(c||o.some((d)=>d.includes(`
8
+ `)))t.push("");t.push("--早前尚未决策--"),at(t,o)}}let r=g.act.filter((c)=>c.st.pick);if(r.length){if(t.length)t.push("");t.push("反馈:"),at(t,r.map((c)=>{let d=U(c.st);return P("- "+c.a.short+":"+D[c.st.pick]+(d?":":""),d,2)}))}let a=g.del.filter((c)=>c.st.on).map((c)=>c.t.label);if(a.length){if(t.length)t.push("");t.push("交付:"+a.join(","))}let i=g.opt.filter((c)=>c.st.on);if(i.length){if(t.length)t.push("");i.forEach((c)=>t.push("也做:"+c.o.text))}return t.join(`
9
+ `)}let Lt=()=>{let t=[];return g.dec.forEach((e)=>{if(e.changed())t.push(e.d.n+" "+e.sum())}),g.act.forEach((e)=>{if(e.st.pick)t.push(e.a.short+":"+D[e.st.pick])}),g.del.forEach((e)=>{if(e.st.on!==e.init)t.push((e.st.on?"":"不")+e.t.label)}),g.opt.forEach((e)=>{if(e.st.on)t.push("也做 "+N(e.o.text,10))}),t},pt=(t)=>t?"<turn-reply"+(E?' turn="'+E+'"':"")+`>
10
+ `+t+`
11
+ </turn-reply>`:t,dt=g.dec.filter((t)=>t.reset&&t.d.group==="now"),J=null;if(dt.length)J=Et("全部按建议",{icon:"reset",title:"把本轮拍板恢复为建议项"}),J.addEventListener("click",()=>dt.forEach((t)=>t.reset()));let At=n("span",{}),R=n("button",{type:"button",cls:"lk","aria-expanded":"false"},"预览"),Dt=n("span",{cls:"sum","aria-live":"polite"},At,R),B=n("pre",{cls:"pv"});B.hidden=!0;let ut=()=>{B.hidden=!0,R.textContent="预览",R.setAttribute("aria-expanded","false")};R.addEventListener("click",()=>{if(B.hidden)B.hidden=!1,R.textContent="收起",R.setAttribute("aria-expanded","true");else ut()});let St=n("span",{},"复制"),W=n("button",{type:"button",cls:"btn"},St);W.addEventListener("click",()=>{let t=lt();if(t)x(pt(t)),f(St,"已复制")});let K=null;if(w)K=n("button",{type:"button",cls:"btn pri"},"填入输入框"),K.addEventListener("click",(t)=>{t.stopPropagation(),qt()});else W.classList.add("pri");let Pt=n("div",{cls:"foot"},J,Dt,W,K),et=n("span",{cls:"fs"}),Rt=n("button",{type:"button",cls:"lk"},"展开"),Ct=n("div",{cls:"fold"},n("span",{cls:"mk-ok","aria-hidden":"true"}),et,Rt),ft=(t)=>{if(p.classList.toggle("folded",t),t)ut();else if(p.classList.contains("kb")&&_[0])_[0].__focus()};Ct.addEventListener("click",()=>ft(!1));let Ut=n("div",{cls:"ns",role:"status"},"宿主报告没有填进输入框。若输入框里已经有这段文字,可忽略;否则点「复制」后手动粘贴。"),F=null,ht=0,Bt=()=>{if(F)F.disconnect();clearTimeout(ht),p.classList.remove("notsent");let t=document.body;if(!t||typeof MutationObserver!=="function")return;let e=()=>{F.disconnect(),clearTimeout(ht),p.classList.add("notsent"),ft(!1)};F=new MutationObserver(()=>{if(t.hasAttribute("data-not-sent"))e()}),F.observe(t,{attributes:!0,attributeFilter:["data-not-sent"]}),ht=setTimeout(()=>F.disconnect(),5000)};function qt(){let t=lt();if(!t)return;Bt(),sendPrompt(pt(t));let e=Lt();et.textContent="已填入 · "+(e.length?e.join(" · "):"全部按建议"),et.title=et.textContent,ft(!0)}let Wt=()=>{if(w)qt();else W.click()};p.addEventListener("mousedown",()=>p.classList.remove("kb")),p.addEventListener("keydown",(t)=>{if(t.key==="Tab"||t.key.startsWith("Arrow")||/^[0-9]$/.test(t.key))p.classList.add("kb");if(p.classList.contains("folded"))return;let e=t.target;if(e.tagName==="TEXTAREA"){if(t.isComposing||t.keyCode===229)return;if(t.key==="Escape"&&e.__esc)t.preventDefault(),e.__esc();return}if(t.metaKey||t.ctrlKey||t.altKey)return;let o=e.closest&&e.closest(".it");if(!o)return;if(t.key==="/"&&o.__note){t.preventDefault(),o.__note();return}if(/^[1-9]$/.test(t.key)&&o.__pick){t.preventDefault(),o.__pick(+t.key-1);return}if(t.key==="ArrowDown"||t.key==="ArrowUp"){let r=_.indexOf(o),a=_[r+(t.key==="ArrowDown"?1:-1)];if(a)t.preventDefault(),a.__focus()}}),p.append(Ct,wt,Pt,Ut,B);function O(){let t=lt(),e=T(t),o=Lt();if(g.dec.forEach((a)=>a.it.classList.toggle("chg",a.changed())),g.act.forEach((a)=>a.it.classList.toggle("chg",!!a.st.pick)),g.delIt)g.delIt.classList.toggle("chg",g.del.some((a)=>a.st.on!==a.init));g.opt.forEach((a)=>a.it.classList.toggle("chg",a.st.on));let r=[];if(r.push(o.length?"改了 ":"全部按建议",...o.length?[n("b",{},String(o.length))," 项"]:[]),e)r.push(" · 将填入 ",n("b",{},String(e))," 行");else r.push(" · 没有要回复的内容");if(At.replaceChildren(...r),B.textContent=pt(t),R.hidden=!e,!e)ut();if(W.disabled=!e,K)K.disabled=!e;if(J)J.disabled=dt.every((a)=>!a.changed())}O();let gt={},zt=[...p.querySelectorAll(".dseg button.sg")];zt.forEach((t)=>{let e=t.dataset.col;gt[e]=Math.max(gt[e]||0,t.offsetWidth)}),zt.forEach((t)=>{t.style.setProperty("width",Math.ceil(gt[t.dataset.col])+12+"px","important")}),p.classList.add("measuring");let nt=0;if(p.querySelectorAll(".q").forEach((t)=>{nt=Math.max(nt,t.offsetWidth)}),p.classList.remove("measuring"),nt>0)p.style.setProperty("--qw",Math.min(Math.ceil(nt)+2,260)+"px")}return Ot})();var it="0.1.1",jt="trw-style-"+it;function Ht(n){let l=n.ownerDocument||document;if(l.getElementById(jt))return;let m=l.createElement("style");m.id=jt,m.textContent=rt,(l.head||n.parentNode||l.documentElement).appendChild(m)}function xt(n,l){n.replaceChildren(),n.classList.remove("folded","kb");let m=(n.ownerDocument||document).createElement("div");m.className="err",m.setAttribute("role","alert"),m.title=l,m.textContent=l,n.append(m)}var vt=",请直接在输入框回复";function It(n,l){if(!n||typeof n.append!=="function")return console.error("[turn-reply] root 不是元素"),["root 不是元素"];n.classList.add("trw"),Ht(n);let m=l;if(typeof m==="string")try{m=JSON.parse(m)}catch(s){return xt(n,"面板数据不是合法 JSON"+vt),["JSON 解析失败"]}let y=ot(m);if(y.length)return console.error(`[turn-reply] spec 不合法:
12
+ `+y.join(`
13
+ `)),xt(n,"面板数据不合法("+y.length+" 处,首处 "+y[0]+")"+vt),y;try{Nt(n,m)}catch(s){console.error("[turn-reply] 渲染出错",s);let x="面板渲染出错("+(s&&s.message||s)+")"+vt;return xt(n,x),[x]}return[]}var bt=typeof window<"u"?window:globalThis;if(!bt.TR||bt.TR.version!==it)bt.TR={render:It,validate:ot,version:it,css:rt};})();
package/package.json CHANGED
@@ -1,6 +1,21 @@
1
1
  {
2
2
  "name": "@npmjsdnt/turn-reply",
3
- "version": "0.0.0-stage",
4
- "stub": true,
5
- "description": "Temporary package placeholder for staged publishing"
6
- }
3
+ "version": "0.1.1",
4
+ "description": "turn-report 回复面板:TR.render(root, spec),供 show_widget 每轮只贴引导代码+spec",
5
+ "license": "UNLICENSED",
6
+ "main": "dist/tr.js",
7
+ "jsdelivr": "dist/tr.min.js",
8
+ "unpkg": "dist/tr.min.js",
9
+ "files": [
10
+ "dist/tr.js",
11
+ "dist/tr.min.js",
12
+ "dist/tr.css"
13
+ ],
14
+ "scripts": {
15
+ "build": "bun build.ts",
16
+ "test": "bun build.ts && bun test"
17
+ },
18
+ "devDependencies": {
19
+ "happy-dom": "^20"
20
+ }
21
+ }
package/README.md DELETED
@@ -1,3 +0,0 @@
1
- # Temporary Holding Version
2
-
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.