@jayyuen66/dsh-plugin-shared 0.2.6 → 0.2.8

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.
@@ -18,11 +18,11 @@ import{createElement as e,useCallback as t,useEffect as n,useId as r,useLayoutEf
18
18
  .dsu-helpBtn{appearance:none;border:0;background:transparent;padding:0;width:16px;height:16px;display:inline-flex;align-items:center;justify-content:center;color:var(--dsw-alias-label-tertiary);cursor:help;border-radius:50%;flex:none}
19
19
  .dsu-help:hover .dsu-helpBtn,.dsu-helpBtn:focus-visible{color:var(--dsw-alias-label-primary)}
20
20
  .dsu-helpBtn:focus-visible{outline:2px solid var(--dsw-alias-state-business-primary);outline-offset:1px}
21
- .dsu-tip{position:fixed;z-index:60;box-sizing:border-box;max-width:min(340px,calc(100vw - 16px));max-height:calc(100vh - 16px);overflow:auto;overflow-wrap:anywhere;padding:10px 12px;border-radius:10px;background:var(--dsw-alias-bg-layer-2);border:.5px solid var(--dsw-alias-border-l3);box-shadow:0 12px 32px rgb(0 0 0 / 45%);font-size:12px;line-height:1.6;font-weight:400;color:var(--dsw-alias-label-secondary)}
21
+ .dsu-tip{width:max-content;position:fixed;position-area:block-end span-inline-end;justify-self:start;margin-top:8px;z-index:60;box-sizing:border-box;max-width:min(340px,calc(100vw - 16px));max-height:calc(100vh - 16px);overflow:auto;overflow-wrap:anywhere;padding:10px 12px;border-radius:10px;background:var(--dsw-alias-bg-layer-2);border:.5px solid var(--dsw-alias-border-l3);box-shadow:0 12px 32px rgb(0 0 0 / 45%);font-size:12px;line-height:1.6;font-weight:400;color:var(--dsw-alias-label-secondary)}
22
22
  .dsu-input{width:100%;height:34px;padding:0 12px;border:.5px solid var(--dsw-alias-border-l4);border-radius:var(--dsw-radius-md);background:var(--dsw-alias-bg-layer-3);color:var(--dsw-alias-label-primary);font:inherit;font-size:13px}
23
23
  .dsu-input:focus-visible{outline:none;border-color:var(--dsw-alias-state-business-primary)}
24
24
  .dsu-input[aria-invalid="true"]{border-color:var(--dsw-alias-state-error-primary)}
25
- .dsu-input:disabled{color:var(--dsw-alias-label-tertiary);cursor:default}
25
+ .dsu-input:disabled{color:var(--dsw-alias-label-tertiary);cursor:not-allowed}
26
26
  .dsu-input::placeholder{color:var(--dsw-alias-label-tertiary)}
27
27
  .dsu-textarea{height:auto;min-height:96px;padding:8px 12px;line-height:1.6;resize:vertical}
28
28
  .dsu-mono{font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace}
@@ -43,7 +43,7 @@ import{createElement as e,useCallback as t,useEffect as n,useId as r,useLayoutEf
43
43
  .dsu-selectValue{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
44
44
  .dsu-chevron{flex:none;color:var(--dsw-alias-label-tertiary);transition:transform .16s}
45
45
  .dsu-select[aria-expanded="true"] .dsu-chevron{transform:rotate(180deg)}
46
- .dsu-menu{position:fixed;position-area:block-end span-inline-start;justify-self:start;margin-top:6px;z-index:70;padding:4px;background:var(--dsw-alias-bg-layer-2);border:.5px solid var(--dsw-alias-border-l3);border-radius:12px;box-shadow:0 12px 32px rgb(0 0 0 / 50%);max-height:280px;overflow:auto}
46
+ .dsu-menu{position:fixed;position-area:block-end span-inline-end;justify-self:start;margin-top:6px;z-index:70;padding:4px;background:var(--dsw-alias-bg-layer-2);border:.5px solid var(--dsw-alias-border-l3);border-radius:12px;box-shadow:0 12px 32px rgb(0 0 0 / 50%);max-height:280px;overflow:auto}
47
47
  .dsu-option{appearance:none;border:0;background:transparent;color:var(--dsw-alias-label-primary);font:inherit;font-size:13px;line-height:1.4;width:100%;display:flex;align-items:center;justify-content:space-between;gap:12px;padding:8px 10px;border-radius:8px;cursor:pointer;text-align:left}
48
48
  .dsu-option:hover,.dsu-option[data-active="true"]{background:var(--dsw-alias-bg-layer-3)}
49
49
  .dsu-option:disabled{color:var(--dsw-alias-label-tertiary);cursor:not-allowed}
@@ -76,30 +76,30 @@ import{createElement as e,useCallback as t,useEffect as n,useId as r,useLayoutEf
76
76
  @media (prefers-reduced-motion:reduce){
77
77
  .dsu-switch,.dsu-knob,.dsu-chevron,.dsu-btn{transition:none}
78
78
  }
79
- `;function l(e,t=30){return e.length<=t?{hint:e}:{detail:e}}function u(t){return e(`div`,{className:`dsu-form`},t.children)}function d(t){return e(`section`,{className:`dsu-section`},e(`h2`,{className:`dsu-sectionTitle`},t.title),t.hint===void 0?null:e(`p`,{className:`dsu-sectionHint`},t.hint),t.children)}function f(t){return e(`div`,{className:`dsu-grid`},t.children)}function p(t){if(t.items.length===0)return null;let n=t.items.map((t,n)=>e(`span`,{key:n},n===0?t:`· ${t}`));return e(`div`,{className:`dsu-statusbar`},...n)}function m(a){let c=r(),[l,u]=s(!1),[d,f]=s(!1),p=o(!1),m=o(!1),h=o(!1),g=o(null),_=o(null),v=o(null),y=t(()=>{v.current!==null&&(clearTimeout(v.current),v.current=null)},[]),b=t(()=>{let e=g.current,t=_.current;
79
+ `;function l(e,t=30){return e.length<=t?{hint:e}:{detail:e}}function u(t){return e(`div`,{className:`dsu-form`},t.children)}function d(t){return e(`section`,{className:`dsu-section`},e(`h2`,{className:`dsu-sectionTitle`},t.title),t.hint===void 0?null:e(`p`,{className:`dsu-sectionHint`},t.hint),t.children)}function f(t){return e(`div`,{className:`dsu-grid`},t.children)}function p(t){if(t.items.length===0)return null;let n=t.items.map((t,n)=>e(`span`,{key:n},n===0?t:`· ${t}`));return e(`div`,{className:`dsu-statusbar`},...n)}function m(){return`happyDOM`in globalThis?!1:typeof CSS<`u`&&typeof CSS.supports==`function`&&CSS.supports(`position-area: block-end`)}function h(e,t){let n=Math.abs(t.left-e.left)<=2,r=Math.abs(t.right-e.right)<=2;if(!n&&!r)return!0;let i=t.top>=e.bottom-2,a=t.bottom<=e.top+2;return!i&&!a}function g(a){let c=r(),l=`--dsu-tip-${c.replaceAll(/[^a-zA-Z0-9]/gu,``)}`,[u,d]=s(!1),f=o(!1),p=o(!1),g=o(!1),_=o(null),v=o(null),y=o(null),b=o(null),x=t(()=>{b.current!==null&&(clearTimeout(b.current),b.current=null)},[]),S=t(()=>{let e=v.current,t=y.current;
80
80
  /* v8 ignore next 3 -- place 只在 open 的 layout effect 与挂载期监听器里调用;refs 为空只可能是卸载竞态 */
81
- if(e===null||t===null)return;let n=e.getBoundingClientRect(),r=t.offsetWidth,i=t.offsetHeight,{left:a}=n,o=n.bottom+8;o+i>window.innerHeight-8&&(o=n.top-i-8),a+r>window.innerWidth-8&&(a=window.innerWidth-r-8);let s=Math.max(8,window.innerWidth-r-8),c=Math.max(8,window.innerHeight-i-8);t.style.left=`${Math.min(Math.max(8,a),s)}px`,t.style.top=`${Math.min(Math.max(8,o),c)}px`},[]),x=t(()=>{y(),h.current=!1,f(!1),u(!1)},[y]),S=t(()=>{y(),u(!0)},[y]),C=t(()=>{y(),p.current||m.current||h.current||(v.current=setTimeout(()=>{
81
+ if(e===null||t===null)return;let n=m()&&t.style.positionArea!==`none`,r=e.getBoundingClientRect();if(n&&!h(r,t.getBoundingClientRect()))return;n&&(t.style.positionArea=`none`),t.style.marginTop=`0px`;let i=t.offsetWidth,a=t.offsetHeight,{left:o}=r,s=r.bottom+8;s+a>window.innerHeight-8&&(s=r.top-a-8),o+i>window.innerWidth-8&&(o=window.innerWidth-i-8);let c=Math.max(8,window.innerWidth-i-8),l=Math.max(8,window.innerHeight-a-8);t.style.left=`${Math.min(Math.max(8,o),c)}px`,t.style.top=`${Math.min(Math.max(8,s),l)}px`},[]),C=t(()=>{x(),g.current=!1,d(!1)},[x]),w=t(()=>{x(),d(!0)},[x]),T=t(()=>{x(),f.current||p.current||g.current||(b.current=setTimeout(()=>{
82
82
  /* v8 ignore next 3 -- 任何重新进入/钉住都会 cancelHide;这次复查只防未来的异步路径 */
83
- v.current=null,p.current||m.current||h.current||u(!1)},120))},[y]),w=t(e=>{h.current=e,f(e)},[]);i(()=>{if(!l)return()=>{};b();let e=e=>{let{target:t}=e;t instanceof Node&&_.current?.contains(t)===!0||(h.current?b():x())},t=()=>{b()};return window.addEventListener(`scroll`,e,!0),window.addEventListener(`resize`,t),()=>{window.removeEventListener(`scroll`,e,!0),window.removeEventListener(`resize`,t)}},[l,a.detail,b,x]),n(()=>{if(!l)return()=>{};let e=e=>{e.key===`Escape`&&x()};return document.addEventListener(`keydown`,e),()=>{document.removeEventListener(`keydown`,e)}},[l,x]),n(()=>y,[y]);let T=e(`button`,{ref:g,type:`button`,className:`dsu-helpBtn`,"aria-label":`${a.label} 说明`,"aria-describedby":c,"aria-pressed":d,onClick:()=>{h.current?x():(w(!0),S())}},e(`svg`,{width:12,height:12,viewBox:`0 0 14 14`,"aria-hidden":!0},e(`circle`,{cx:7,cy:7,r:6,fill:`none`,stroke:`currentColor`,strokeWidth:1.2}),e(`path`,{d:`M7 6.2v4`,stroke:`currentColor`,strokeWidth:1.3,strokeLinecap:`round`}),e(`circle`,{cx:7,cy:4.3,r:.8,fill:`currentColor`}))),E=e(`div`,{ref:_,id:c,role:`tooltip`,className:`dsu-tip`,hidden:!l},a.detail),D=a.showLabel===!1?null:e(`span`,{className:`dsu-label${a.compact===!0?` dsu-labelMono`:``}`},a.label);return e(`span`,{className:`dsu-help`,onMouseEnter:()=>{p.current=!0,S()},onMouseLeave:()=>{p.current=!1,C()},onFocus:()=>{m.current=!0,S()},onBlur:e=>{let t=e.relatedTarget;t instanceof Node&&e.currentTarget.contains(t)||(m.current=!1,C())}},D,T,E)}function h(t){let n=`dsu-label${t.compact===!0?` dsu-labelMono`:``}`,r=t.controlId===void 0?e(`span`,{className:n},t.label):e(`label`,{className:n,htmlFor:t.controlId},t.label);return e(`div`,{className:`dsu-labelRow`},r,t.detail===void 0?null:e(m,{label:t.label,detail:t.detail,showLabel:!1}))}function g(t){let n=t.controlId===void 0?void 0:`${t.controlId}-hint`;return e(`div`,{className:`dsu-field${t.wide===!0?` dsu-fieldWide`:``}`},e(`div`,{className:`dsu-fieldMeta`},e(h,{label:t.label,detail:t.detail,compact:t.compact,controlId:t.controlId}),t.hint===void 0?null:e(`p`,{className:`dsu-hint`,id:n},t.hint)),e(`div`,{className:`dsu-control`},t.children))}function _(t){let n=r(),i=t.hint===void 0?void 0:`${n}-hint`;return e(g,{...t,controlId:n},e(`button`,{type:`button`,role:`switch`,id:n,className:`dsu-switch`,"aria-checked":t.checked,"aria-describedby":i,"data-field":t.field,disabled:t.disabled===!0,onClick:()=>{t.onChange(!t.checked)}},e(`span`,{className:`dsu-knob`})))}function v(t){let i=typeof t.value==`number`&&Number.isFinite(t.value)?String(t.value):``,[a,c]=s(i),[l,u]=s(!1),d=o(void 0),f=r(),p=r(),m=[t.hint===void 0?void 0:`${f}-hint`,l?p:void 0].filter(e=>e!==void 0),h=m.length===0?void 0:m.join(` `);n(()=>{t.value!==d.current&&(d.current=t.value,c(i),u(!1))},[t.value,i]);let _=e=>{let n=t.min??-1/0,r=t.max??1/0;if(!Number.isFinite(e)||e<n||e>r)return!1;let{step:i}=t;if(i===void 0||i<=0)return!0;let a=(e-(t.min??0))/i;return Math.abs(a-Math.round(a))<1e-9},v=e=>{if(c(e),e===``){u(!1),d.current=void 0,t.onChange(void 0);return}let n=Number(e);_(n)?(u(!1),d.current=n,t.onChange(n)):u(!0)},y=()=>{a===``||l||c(String(Number(a)))};return e(g,{...t,controlId:f},e(`div`,{className:`dsu-numberWrap`},e(`div`,{className:`dsu-number`},e(`input`,{className:`dsu-input`,type:`number`,inputMode:`numeric`,id:f,value:a,min:t.min,max:t.max,step:t.step,placeholder:t.placeholder,"aria-invalid":l||void 0,"aria-describedby":h,"data-field":t.field,disabled:t.disabled===!0,onChange:e=>{v(e.target.value)},onBlur:y}),t.unit===void 0?null:e(`span`,{className:`dsu-unit`},t.unit)),l?e(`p`,{className:`dsu-error`,id:p},t.invalidHint):null))}function y(t){let[i,a]=s(t.value),[o,c]=s(!1),l=r(),u=t.hint===void 0?void 0:`${l}-hint`;n(()=>{o||a(t.value)},[t.value,o]);let d={id:l,className:`dsu-input${t.multiline===!0?` dsu-textarea`:``}${t.monospace===!0?` dsu-mono`:``}`,value:i,placeholder:t.placeholder,"aria-describedby":u,"data-field":t.field,disabled:t.disabled===!0,onFocus:()=>{c(!0)},onBlur:()=>{c(!1)},onChange:e=>{a(e.target.value),t.onChange(e.target.value)}};return e(g,{...t,controlId:l},t.multiline===!0?e(`textarea`,d):e(`input`,d))}function b(t){let i=t.separator??`comma`,a=t.value.join(i===`newline`?`
83
+ b.current=null,f.current||p.current||g.current||d(!1)},120))},[x]),E=t(e=>{g.current=e},[]);i(()=>{if(!u)return()=>{};S();let e=e=>{let{target:t}=e;t instanceof Node&&y.current?.contains(t)===!0||(g.current?S():C())},t=()=>{S()},n=e=>{let t=e.target;_.current?.contains(t)!==!0&&C()};return document.addEventListener(`pointerdown`,n,!0),window.addEventListener(`scroll`,e,!0),window.addEventListener(`resize`,t),()=>{document.removeEventListener(`pointerdown`,n,!0),window.removeEventListener(`scroll`,e,!0),window.removeEventListener(`resize`,t)}},[u,a.detail,S,C]),n(()=>{if(!u)return()=>{};let e=e=>{e.key===`Escape`&&C()};return document.addEventListener(`keydown`,e),()=>{document.removeEventListener(`keydown`,e)}},[u,C]),n(()=>x,[x]);let D=e(`button`,{ref:v,type:`button`,className:`dsu-helpBtn`,style:{anchorName:l},"aria-label":`${a.label} 说明`,"aria-expanded":u,"aria-controls":c,onClick:()=>{g.current?C():(E(!0),w())}},e(`svg`,{width:12,height:12,viewBox:`0 0 14 14`,"aria-hidden":!0},e(`circle`,{cx:7,cy:7,r:6,fill:`none`,stroke:`currentColor`,strokeWidth:1.2}),e(`path`,{d:`M7 6.2v4`,stroke:`currentColor`,strokeWidth:1.3,strokeLinecap:`round`}),e(`circle`,{cx:7,cy:4.3,r:.8,fill:`currentColor`}))),O=e(`div`,{ref:y,id:c,role:`tooltip`,className:`dsu-tip`,style:{positionAnchor:l,positionTryFallbacks:`flip-block, flip-inline`},hidden:!u},a.detail),k=a.showLabel===!1?null:e(`span`,{className:`dsu-label${a.compact===!0?` dsu-labelMono`:``}`},a.label);return e(`span`,{ref:_,className:`dsu-help`,onMouseEnter:()=>{f.current=!0,w()},onMouseLeave:()=>{f.current=!1,T()},onFocus:()=>{p.current=!0,w()},onBlur:e=>{let t=e.relatedTarget;t instanceof Node&&e.currentTarget.contains(t)||(p.current=!1,T())}},k,D,O)}function _(t){let n=`dsu-label${t.compact===!0?` dsu-labelMono`:``}`,r=t.controlId===void 0?e(`span`,{className:n},t.label):e(`label`,{className:n,htmlFor:t.controlId},t.label);return e(`div`,{className:`dsu-labelRow`},r,t.detail===void 0?null:e(g,{label:t.label,detail:t.detail,showLabel:!1}))}function v(t){let n=t.controlId===void 0?void 0:`${t.controlId}-hint`;return e(`div`,{className:`dsu-field${t.wide===!0?` dsu-fieldWide`:``}`},e(`div`,{className:`dsu-fieldMeta`},e(_,{label:t.label,detail:t.detail,compact:t.compact,controlId:t.controlId}),t.hint===void 0?null:e(`p`,{className:`dsu-hint`,id:n},t.hint)),e(`div`,{className:`dsu-control`},t.children))}function y(t){let n=r(),i=t.hint===void 0?void 0:`${n}-hint`;return e(v,{...t,controlId:n},e(`button`,{type:`button`,role:`switch`,id:n,className:`dsu-switch`,"aria-checked":t.checked,"aria-describedby":i,"data-field":t.field,disabled:t.disabled===!0,onClick:()=>{t.onChange(!t.checked)}},e(`span`,{className:`dsu-knob`})))}function b(t){let i=typeof t.value==`number`&&Number.isFinite(t.value)?String(t.value):``,[a,c]=s(i),[l,u]=s(!1),[d,f]=s(!1),p=o(void 0),m=r(),h=r(),g=t.hint===void 0?void 0:`${m}-hint`,_=l&&d,y=[g,_?h:void 0].filter(e=>e!==void 0),b=y.length===0?void 0:y.join(` `);n(()=>{t.value!==p.current&&(p.current=t.value,c(i),u(!1),f(!1))},[t.value,i]);let x=e=>{let n=t.min??-1/0,r=t.max??1/0;if(!Number.isFinite(e)||e<n||e>r)return!1;let{step:i}=t;if(i===void 0||i<=0)return!0;let a=(e-(t.min??0))/i;return Math.abs(a-Math.round(a))<1e-9},S=e=>{if(f(!1),c(e),e===``){u(!1),p.current=void 0,t.onChange(void 0);return}let n=Number(e);x(n)?(u(!1),p.current=n,t.onChange(n)):u(!0)},C=()=>{a===``||l||c(String(Number(a)))},w=()=>{f(l),C()};return e(v,{...t,controlId:m},e(`div`,{className:`dsu-numberWrap`},e(`div`,{className:`dsu-number`},e(`input`,{className:`dsu-input`,type:`number`,inputMode:`numeric`,id:m,value:a,min:t.min,max:t.max,step:t.step,placeholder:t.placeholder,"aria-invalid":_||void 0,"aria-describedby":b,"data-field":t.field,disabled:t.disabled===!0,onChange:e=>{S(e.target.value)},onBlur:w}),t.unit===void 0?null:e(`span`,{className:`dsu-unit`},t.unit)),_?e(`p`,{className:`dsu-error`,id:h},t.invalidHint):null))}function x(t){let[i,a]=s(t.value),[o,c]=s(!1),l=r(),u=t.hint===void 0?void 0:`${l}-hint`;n(()=>{o||a(t.value)},[t.value,o]);let d={id:l,className:`dsu-input${t.multiline===!0?` dsu-textarea`:``}${t.monospace===!0?` dsu-mono`:``}`,value:i,placeholder:t.placeholder,"aria-describedby":u,"data-field":t.field,disabled:t.disabled===!0,onFocus:()=>{c(!0)},onBlur:()=>{c(!1)},onChange:e=>{a(e.target.value),t.onChange(e.target.value)}};return e(v,{...t,controlId:l},t.multiline===!0?e(`textarea`,d):e(`input`,d))}function S(t){let i=t.separator??`comma`,a=t.value.join(i===`newline`?`
84
84
  `:`, `),[o,c]=s(a),[l,u]=s(!1),d=r(),f=t.hint===void 0?void 0:`${d}-hint`;n(()=>{l||c(a)},[a,l]);let p=e=>e.split(i===`newline`?`
85
- `:`,`).map(e=>e.trim()).filter(e=>e.length>0),m={id:d,className:`dsu-input${i===`newline`?` dsu-textarea dsu-mono`:``}`,value:o,placeholder:t.placeholder,"aria-describedby":f,"data-field":t.field,disabled:t.disabled===!0,onFocus:()=>{u(!0)},onBlur:()=>{u(!1)},onChange:e=>{c(e.target.value),t.onChange(p(e.target.value))}};return e(g,{...t,controlId:d},e(i===`newline`?`textarea`:`input`,m))}function x(){return`happyDOM`in globalThis?!1:typeof CSS<`u`&&typeof CSS.supports==`function`&&CSS.supports(`position-area: block-end`)}function S(c){let[l,u]=s(!1),[d,f]=s(0),p=o(null),m=o(null),h=r(),_=r(),v=`--dsu-${_.replaceAll(/[^a-zA-Z0-9]/gu,``)}`,y=c.hint===void 0?void 0:`${_}-hint`,{disabled:b,value:S,options:C,onChange:w}=c,T=a(()=>C.map((e,t)=>({option:e,index:t})).filter(e=>e.option.disabled!==!0),[C]),E=C.find(e=>e.value===S)?.label??S,D=C[d],O=D!==void 0&&D.disabled!==!0,k=t(()=>{let e=p.current,t=m.current;
85
+ `:`,`).map(e=>e.trim()).filter(e=>e.length>0),m={id:d,className:`dsu-input${i===`newline`?` dsu-textarea dsu-mono`:``}`,value:o,placeholder:t.placeholder,"aria-describedby":f,"data-field":t.field,disabled:t.disabled===!0,onFocus:()=>{u(!0)},onBlur:()=>{u(!1)},onChange:e=>{c(e.target.value),t.onChange(p(e.target.value))}};return e(v,{...t,controlId:d},e(i===`newline`?`textarea`:`input`,m))}function C(c){let[l,u]=s(!1),[d,f]=s(0),p=o(null),g=o(null),_=r(),y=r(),b=`--dsu-${y.replaceAll(/[^a-zA-Z0-9]/gu,``)}`,x=c.hint===void 0?void 0:`${y}-hint`,{disabled:S,value:C,options:w,onChange:T}=c,E=a(()=>w.map((e,t)=>({option:e,index:t})).filter(e=>e.option.disabled!==!0),[w]),D=w.find(e=>e.value===C)?.label??C,O=w[d],k=O!==void 0&&O.disabled!==!0,A=t(()=>{let e=p.current,t=g.current;
86
86
  /* v8 ignore next 3 -- place 只在 open 的 layout effect 里调用;refs 为空只可能是卸载竞态 */
87
- if(e===null||t===null)return;let n=e.getBoundingClientRect(),r=Math.min(n.width,window.innerWidth-16);if(t.style.width=`${r}px`,x())return;t.style.marginTop=`0px`;let{left:i}=n;i+r>window.innerWidth-8&&(i=window.innerWidth-r-8);let a=t.offsetHeight,o=n.bottom+6;o+a>window.innerHeight-8&&(o=n.top-a-6);let s=Math.max(8,window.innerWidth-r-8),c=Math.max(8,window.innerHeight-a-8);t.style.left=`${Math.min(Math.max(8,i),s)}px`,t.style.top=`${Math.min(Math.max(8,o),c)}px`},[]),A=t(()=>{u(!1)},[]),j=t(()=>{if(b===!0)return;let e=T.find(e=>e.option.value===S)??T.at(0);e!==void 0&&(f(e.index),u(!0))},[b,S,T]),M=t(e=>{
87
+ if(e===null||t===null)return;let n=e.getBoundingClientRect(),r=Math.min(n.width,window.innerWidth-16);t.style.width=`${r}px`;let i=m()&&t.style.positionArea!==`none`;if(i&&!h(n,t.getBoundingClientRect()))return;i&&(t.style.positionArea=`none`),t.style.marginTop=`0px`;let{left:a}=n;a+r>window.innerWidth-8&&(a=window.innerWidth-r-8);let o=t.offsetHeight,s=n.bottom+6;s+o>window.innerHeight-8&&(s=n.top-o-6);let c=Math.max(8,window.innerWidth-r-8),l=Math.max(8,window.innerHeight-o-8);t.style.left=`${Math.min(Math.max(8,a),c)}px`,t.style.top=`${Math.min(Math.max(8,s),l)}px`},[]),j=t(()=>{u(!1)},[]),M=t(()=>{if(S===!0)return;let e=E.find(e=>e.option.value===C)??E.at(0);e!==void 0&&(f(e.index),u(!0))},[S,C,E]),N=t(e=>{
88
88
  /* v8 ignore next 3 -- 浮层只能经由 openMenu 打开;组件禁用时打不开 */
89
- if(b===!0)return;let t=C[e];
89
+ if(S===!0)return;let t=w[e];
90
90
  /* v8 ignore next 3 -- disabled 选项在浏览器里不派发 click;越界下标由调用方保证 */
91
- t!==void 0&&t.disabled!==!0&&(w(t.value),A(),p.current?.focus())},[b,C,w,A]),N=t(e=>{let t=T.findIndex(e=>e.index===d);
91
+ t!==void 0&&t.disabled!==!0&&(T(t.value),j(),p.current?.focus())},[S,w,T,j]),P=t(e=>{let t=E.findIndex(e=>e.index===d);
92
92
  /* v8 ignore next 5 -- open 时归一 effect 已保证 enabled 非空且 active 落在可用项上 */
93
- if(t===-1||T.length===0)return;let n=(t+e+T.length)%T.length,r=T[n];
93
+ if(t===-1||E.length===0)return;let n=(t+e+E.length)%E.length,r=E[n];
94
94
  /* v8 ignore next 3 -- next 由取模保证在界内 */
95
- r!==void 0&&f(r.index)},[d,T]);i(()=>{if(!l)return()=>{};k();let e=e=>{let t=e.target;m.current?.contains(t)!==!0&&p.current?.contains(t)!==!0&&A()},t=e=>{let{target:t}=e;t instanceof Node&&m.current?.contains(t)===!0||A()},n=()=>{k()};return document.addEventListener(`pointerdown`,e,!0),window.addEventListener(`scroll`,t,!0),window.addEventListener(`resize`,n),()=>{document.removeEventListener(`pointerdown`,e,!0),window.removeEventListener(`scroll`,t,!0),window.removeEventListener(`resize`,n)}},[l,c.options,k,A]),n(()=>{if(!l)return;if(b===!0||T.length===0){A();return}if(T.some(e=>e.index===d))return;let e=T.find(e=>e.option.value===S)??T.at(0);
95
+ r!==void 0&&f(r.index)},[d,E]);i(()=>{if(!l)return()=>{};A();let e=e=>{let t=e.target;g.current?.contains(t)!==!0&&p.current?.contains(t)!==!0&&j()},t=e=>{let{target:t}=e;t instanceof Node&&g.current?.contains(t)===!0||j()},n=()=>{A()};return document.addEventListener(`pointerdown`,e,!0),window.addEventListener(`scroll`,t,!0),window.addEventListener(`resize`,n),()=>{document.removeEventListener(`pointerdown`,e,!0),window.removeEventListener(`scroll`,t,!0),window.removeEventListener(`resize`,n)}},[l,c.options,A,j]),n(()=>{if(!l)return;if(S===!0||E.length===0){j();return}if(E.some(e=>e.index===d))return;let e=E.find(e=>e.option.value===C)??E.at(0);
96
96
  /* v8 ignore next 3 -- enabled 非空在上一分支已保证 */
97
- e!==void 0&&f(e.index)},[l,b,S,C,d,A,T]),i(()=>{if(!l)return;let e=m.current;
97
+ e!==void 0&&f(e.index)},[l,S,C,w,d,j,E]),i(()=>{if(!l)return;let e=g.current;
98
98
  /* v8 ignore next 2 -- 同上,menu 在 open 的 commit 之后必然已挂上 */
99
99
  if(e===null)return;let t=e.querySelector(`[data-active="true"]`);
100
100
  /* v8 ignore next 2 -- active 已由归一 effect 保证落在可用项上 */
101
- t!==null&&(t.offsetTop<e.scrollTop?e.scrollTop=t.offsetTop:t.offsetTop+t.offsetHeight>e.scrollTop+e.clientHeight&&(e.scrollTop=t.offsetTop+t.offsetHeight-e.clientHeight))},[l,d,C]);let P=e=>{if(e.key===`ArrowDown`||e.key===`ArrowUp`){if(e.preventDefault(),!l){j();return}N(e.key===`ArrowDown`?1:-1)}else if(e.key===`Home`||e.key===`End`){if(e.preventDefault(),l||j(),T.length===0)return;let t=e.key===`Home`?T.at(0):T.at(-1);
101
+ t!==null&&(t.offsetTop<e.scrollTop?e.scrollTop=t.offsetTop:t.offsetTop+t.offsetHeight>e.scrollTop+e.clientHeight&&(e.scrollTop=t.offsetTop+t.offsetHeight-e.clientHeight))},[l,d,w]);let F=e=>{if(e.key===`ArrowDown`||e.key===`ArrowUp`){if(e.preventDefault(),!l){M();return}P(e.key===`ArrowDown`?1:-1)}else if(e.key===`Home`||e.key===`End`){if(e.preventDefault(),l||M(),E.length===0)return;let t=e.key===`Home`?E.at(0):E.at(-1);
102
102
  /* v8 ignore next 3 -- enabled 为空已在上一条返回 */
103
- if(t===void 0)return;f(t.index)}else if(e.key===`Enter`||e.key===` `){if(e.preventDefault(),!l){j();return}M(d)}else(e.key===`Tab`||e.key===`Escape`)&&A()},F=[],I;for(let[t,n]of C.entries())n.group!==I&&(n.group!==void 0&&F.push(e(`div`,{key:`group-${t}-${n.group}`,className:`dsu-optionGroup`,role:`presentation`},n.group)),I=n.group),F.push(e(`button`,{key:`option-${n.value}`,type:`button`,role:`option`,id:`${h}-${t}`,className:`dsu-option`,tabIndex:-1,"aria-selected":n.value===c.value,"data-active":t===d,disabled:n.disabled===!0,onMouseDown:e=>{e.preventDefault()},onClick:()=>{M(t)},onMouseEnter:()=>{
103
+ if(t===void 0)return;f(t.index)}else if(e.key===`Enter`||e.key===` `){if(e.preventDefault(),!l){M();return}N(d)}else(e.key===`Tab`||e.key===`Escape`)&&j()},I=[],L;for(let[t,n]of w.entries())n.group!==L&&(n.group!==void 0&&I.push(e(`div`,{key:`group-${t}-${n.group}`,className:`dsu-optionGroup`,role:`presentation`},n.group)),L=n.group),I.push(e(`button`,{key:`option-${n.value}`,type:`button`,role:`option`,id:`${_}-${t}`,className:`dsu-option`,tabIndex:-1,"aria-selected":n.value===c.value,"data-active":t===d,disabled:n.disabled===!0,onMouseDown:e=>{e.preventDefault()},onClick:()=>{N(t)},onMouseEnter:()=>{
104
104
  /* v8 ignore next -- happy-dom 对 disabled 元素不派发 mouse 事件;浏览器实现各有差异,保留禁用检查 */
105
- n.disabled!==!0&&f(t)}},e(`span`,null,n.label),e(`svg`,{className:`dsu-check`,width:14,height:14,viewBox:`0 0 14 14`,"aria-hidden":!0},e(`path`,{d:`M2.5 7.5l3 3 6-7`,fill:`none`,stroke:`currentColor`,strokeWidth:1.5,strokeLinecap:`round`,strokeLinejoin:`round`}))));return e(g,{...c,controlId:_},e(`div`,{className:`dsu-selectWrap`,onBlur:e=>{let t=e.relatedTarget;t instanceof Node&&e.currentTarget.contains(t)||A()}},e(`button`,{ref:p,type:`button`,id:_,style:{anchorName:v},className:`dsu-select dsu-input`,role:`combobox`,"aria-haspopup":`listbox`,"aria-expanded":l,"aria-controls":`${h}-list`,"aria-activedescendant":l&&O?`${h}-${d}`:void 0,"aria-describedby":y,"data-field":c.field,disabled:b===!0||C.length===0,onClick:()=>{l?A():j()},onKeyDown:P},e(`span`,{className:`dsu-selectValue`},E),e(`svg`,{className:`dsu-chevron`,width:14,height:14,viewBox:`0 0 14 14`,"aria-hidden":!0},e(`path`,{d:`M3 5l4 4 4-4`,fill:`none`,stroke:`currentColor`,strokeWidth:1.5,strokeLinecap:`round`,strokeLinejoin:`round`}))),e(`div`,{ref:m,id:`${h}-list`,role:`listbox`,className:`dsu-menu`,style:{positionAnchor:v,positionTryFallbacks:`flip-block, flip-inline`},"aria-label":c.label,hidden:!l},...F)))}function C(t){let n=!t.writable||t.busy||!t.dirty,r;return r=t.error===null?t.writable?t.dirty?t.dirtyLabel:t.cleanLabel:t.readOnlyLabel:t.error,e(`div`,{className:`dsu-savebar`,"data-dirty":t.dirty},e(`button`,{type:`button`,className:`dsu-btn dsu-btnPrimary`,"data-field":`save`,disabled:n,onClick:t.onSave},t.busy?t.savingLabel:t.saveLabel),e(`button`,{type:`button`,className:`dsu-btn`,"data-field":`discard`,disabled:n,onClick:t.onDiscard},t.revertLabel),e(`span`,{className:t.error===null?`dsu-status`:`dsu-status dsu-statusError`},r))}export{y as a,h as c,f as d,d as f,c as h,v as i,m as l,l as m,S as n,_ as o,p,b as r,g as s,C as t,u};
105
+ n.disabled!==!0&&f(t)}},e(`span`,null,n.label),e(`svg`,{className:`dsu-check`,width:14,height:14,viewBox:`0 0 14 14`,"aria-hidden":!0},e(`path`,{d:`M2.5 7.5l3 3 6-7`,fill:`none`,stroke:`currentColor`,strokeWidth:1.5,strokeLinecap:`round`,strokeLinejoin:`round`}))));return e(v,{...c,controlId:y},e(`div`,{className:`dsu-selectWrap`,onBlur:e=>{let t=e.relatedTarget;t instanceof Node&&e.currentTarget.contains(t)||j()}},e(`button`,{ref:p,type:`button`,id:y,style:{anchorName:b},className:`dsu-select dsu-input`,role:`combobox`,"aria-haspopup":`listbox`,"aria-expanded":l,"aria-controls":`${_}-list`,"aria-activedescendant":l&&k?`${_}-${d}`:void 0,"aria-describedby":x,"data-field":c.field,disabled:S===!0||w.length===0,onClick:()=>{l?j():M()},onKeyDown:F},e(`span`,{className:`dsu-selectValue`},D),e(`svg`,{className:`dsu-chevron`,width:14,height:14,viewBox:`0 0 14 14`,"aria-hidden":!0},e(`path`,{d:`M3 5l4 4 4-4`,fill:`none`,stroke:`currentColor`,strokeWidth:1.5,strokeLinecap:`round`,strokeLinejoin:`round`}))),e(`div`,{ref:g,id:`${_}-list`,role:`listbox`,className:`dsu-menu`,style:{positionAnchor:b,positionTryFallbacks:`flip-block, flip-inline`},"aria-label":c.label,hidden:!l},...I)))}function w(t){let n=!t.writable||t.busy||!t.dirty,r;return r=t.error===null?t.writable?t.dirty?t.dirtyLabel:t.cleanLabel:t.readOnlyLabel:t.error,e(`div`,{className:`dsu-savebar`,"data-dirty":t.dirty},e(`button`,{type:`button`,className:`dsu-btn dsu-btnPrimary`,"data-field":`save`,disabled:n,onClick:t.onSave},t.busy?t.savingLabel:t.saveLabel),e(`button`,{type:`button`,className:`dsu-btn`,"data-field":`discard`,disabled:n,onClick:t.onDiscard},t.revertLabel),e(`span`,{role:`status`,className:t.error===null?`dsu-status`:`dsu-status dsu-statusError`},r))}export{x as a,_ as c,f as d,d as f,c as h,b as i,g as l,l as m,C as n,y as o,p,S as r,v as s,w as t,u};
package/dist/card-ui.js CHANGED
@@ -1 +1 @@
1
- export{h as CARD_UI_CSS,u as CardForm,s as Field,d as FieldGrid,c as FieldLabel,l as InfoTip,r as ListField,i as NumberField,t as SaveBar,f as Section,n as SelectField,p as StatusBar,a as TextField,o as ToggleField,m as splitHint}from"./card-ui-D2cuQvLS.js";
1
+ export{h as CARD_UI_CSS,u as CardForm,s as Field,d as FieldGrid,c as FieldLabel,l as InfoTip,r as ListField,i as NumberField,t as SaveBar,f as Section,n as SelectField,p as StatusBar,a as TextField,o as ToggleField,m as splitHint}from"./card-ui-yf56_khz.js";
@@ -1 +1 @@
1
- import{a as e,c as t,d as n,f as r,h as i,i as a,l as o,m as s,n as c,o as l,p as u,r as d,s as f,t as p,u as m}from"./card-ui-D2cuQvLS.js";import{diffTouched as h}from"./card-diff.js";import{claimApply as g}from"./card-apply.js";import{fieldOf as _,isRecord as v}from"./record.js";import{errorText as y}from"./errors.js";const b=`@jayyuen66/dsh-plugin-shared`;function x(){}export{i as CARD_UI_CSS,m as CardForm,f as Field,n as FieldGrid,t as FieldLabel,o as InfoTip,d as ListField,a as NumberField,p as SaveBar,r as Section,c as SelectField,u as StatusBar,e as TextField,l as ToggleField,x as apply,g as claimApply,h as diffTouched,y as errorText,_ as fieldOf,v as isRecord,b as name,s as splitHint};
1
+ import{a as e,c as t,d as n,f as r,h as i,i as a,l as o,m as s,n as c,o as l,p as u,r as d,s as f,t as p,u as m}from"./card-ui-yf56_khz.js";import{diffTouched as h}from"./card-diff.js";import{claimApply as g}from"./card-apply.js";import{fieldOf as _,isRecord as v}from"./record.js";import{errorText as y}from"./errors.js";const b=`@jayyuen66/dsh-plugin-shared`;function x(){}export{i as CARD_UI_CSS,m as CardForm,f as Field,n as FieldGrid,t as FieldLabel,o as InfoTip,d as ListField,a as NumberField,p as SaveBar,r as Section,c as SelectField,u as StatusBar,e as TextField,l as ToggleField,x as apply,g as claimApply,h as diffTouched,y as errorText,_ as fieldOf,v as isRecord,b as name,s as splitHint};
package/dist/client.js CHANGED
@@ -29,11 +29,11 @@ const CARD_UI_CSS = `
29
29
  .dsu-helpBtn{appearance:none;border:0;background:transparent;padding:0;width:16px;height:16px;display:inline-flex;align-items:center;justify-content:center;color:var(--dsw-alias-label-tertiary);cursor:help;border-radius:50%;flex:none}
30
30
  .dsu-help:hover .dsu-helpBtn,.dsu-helpBtn:focus-visible{color:var(--dsw-alias-label-primary)}
31
31
  .dsu-helpBtn:focus-visible{outline:2px solid var(--dsw-alias-state-business-primary);outline-offset:1px}
32
- .dsu-tip{position:fixed;z-index:60;box-sizing:border-box;max-width:min(340px,calc(100vw - 16px));max-height:calc(100vh - 16px);overflow:auto;overflow-wrap:anywhere;padding:10px 12px;border-radius:10px;background:var(--dsw-alias-bg-layer-2);border:.5px solid var(--dsw-alias-border-l3);box-shadow:0 12px 32px rgb(0 0 0 / 45%);font-size:12px;line-height:1.6;font-weight:400;color:var(--dsw-alias-label-secondary)}
32
+ .dsu-tip{width:max-content;position:fixed;position-area:block-end span-inline-end;justify-self:start;margin-top:8px;z-index:60;box-sizing:border-box;max-width:min(340px,calc(100vw - 16px));max-height:calc(100vh - 16px);overflow:auto;overflow-wrap:anywhere;padding:10px 12px;border-radius:10px;background:var(--dsw-alias-bg-layer-2);border:.5px solid var(--dsw-alias-border-l3);box-shadow:0 12px 32px rgb(0 0 0 / 45%);font-size:12px;line-height:1.6;font-weight:400;color:var(--dsw-alias-label-secondary)}
33
33
  .dsu-input{width:100%;height:34px;padding:0 12px;border:.5px solid var(--dsw-alias-border-l4);border-radius:var(--dsw-radius-md);background:var(--dsw-alias-bg-layer-3);color:var(--dsw-alias-label-primary);font:inherit;font-size:13px}
34
34
  .dsu-input:focus-visible{outline:none;border-color:var(--dsw-alias-state-business-primary)}
35
35
  .dsu-input[aria-invalid="true"]{border-color:var(--dsw-alias-state-error-primary)}
36
- .dsu-input:disabled{color:var(--dsw-alias-label-tertiary);cursor:default}
36
+ .dsu-input:disabled{color:var(--dsw-alias-label-tertiary);cursor:not-allowed}
37
37
  .dsu-input::placeholder{color:var(--dsw-alias-label-tertiary)}
38
38
  .dsu-textarea{height:auto;min-height:96px;padding:8px 12px;line-height:1.6;resize:vertical}
39
39
  .dsu-mono{font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace}
@@ -54,7 +54,7 @@ const CARD_UI_CSS = `
54
54
  .dsu-selectValue{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
55
55
  .dsu-chevron{flex:none;color:var(--dsw-alias-label-tertiary);transition:transform .16s}
56
56
  .dsu-select[aria-expanded="true"] .dsu-chevron{transform:rotate(180deg)}
57
- .dsu-menu{position:fixed;position-area:block-end span-inline-start;justify-self:start;margin-top:6px;z-index:70;padding:4px;background:var(--dsw-alias-bg-layer-2);border:.5px solid var(--dsw-alias-border-l3);border-radius:12px;box-shadow:0 12px 32px rgb(0 0 0 / 50%);max-height:280px;overflow:auto}
57
+ .dsu-menu{position:fixed;position-area:block-end span-inline-end;justify-self:start;margin-top:6px;z-index:70;padding:4px;background:var(--dsw-alias-bg-layer-2);border:.5px solid var(--dsw-alias-border-l3);border-radius:12px;box-shadow:0 12px 32px rgb(0 0 0 / 50%);max-height:280px;overflow:auto}
58
58
  .dsu-option{appearance:none;border:0;background:transparent;color:var(--dsw-alias-label-primary);font:inherit;font-size:13px;line-height:1.4;width:100%;display:flex;align-items:center;justify-content:space-between;gap:12px;padding:8px 10px;border-radius:8px;cursor:pointer;text-align:left}
59
59
  .dsu-option:hover,.dsu-option[data-active="true"]{background:var(--dsw-alias-bg-layer-3)}
60
60
  .dsu-option:disabled{color:var(--dsw-alias-label-tertiary);cursor:not-allowed}
@@ -118,15 +118,51 @@ function StatusBar(props) {
118
118
  const children = props.items.map((item, index) => (0, react.createElement)("span", { key: index }, index === 0 ? item : `· ${item}`));
119
119
  return (0, react.createElement)("div", { className: "dsu-statusbar" }, ...children);
120
120
  }
121
+ // lib/card-ui/anchor.ts
122
+ /** 浏览器是否支持 CSS anchor 定位(宿主 webview 支持,与宿主 Menu 同一套平台 API)。
123
+ * 支持时浮层位置由 `position-area` 跟随触发器,缩放/平移不漂;happy-dom 等不支持处回退 JS 矩形。
124
+ * 探测的是本组件实际依赖的 `position-area`,不是更早出现的 `anchor-name`:只支持
125
+ * `anchor-name` 的半档实现里浮层不会被真正定位。happy-dom 的 CSS.supports 对 anchor-name
126
+ * 误返 true,但它并不真做 anchor 布局;happy-dom 在 window 上暴露 happyDOM 属性,据此排除
127
+ * (真实浏览器没有该属性)。 */
128
+ function cssAnchorSupported() {
129
+ if ("happyDOM" in globalThis) return false;
130
+ return typeof CSS !== "undefined" && typeof CSS.supports === "function" && CSS.supports("position-area: block-end");
131
+ }
132
+ /**
133
+ * 锚定之后浮层是否真的落在触发器上。
134
+ *
135
+ * cssAnchorSupported() 只回答「这个引擎认识这套 CSS」,不回答「这条规则最终有没有生效」。
136
+ * 0.2.5–0.2.6 的事故形态就是后者:规则写法(span-inline-start)把浮层钉到视口左边缘,
137
+ * 而引擎完全支持它,于是没有任何一层会报错——只有实测矩形看得见。宿主若用更高优先级的
138
+ * 规则覆盖 position-area,症状相同(元素仍是 position:fixed,没有 left/top 时落到静态
139
+ * 位置即视口左侧)。
140
+ *
141
+ * 判据用「对齐」而不是「坐标相等」:flip-inline 会把浮层改成与触发器右边缘对齐,所以
142
+ * 行内起始边或结束边任一重合即算贴住;块向则要求不重叠(flip-block 翻到上方时浮层的
143
+ * 下边缘贴在触发器上边缘)。两条都不成立时调用方改用 JS 矩形定位。
144
+ * @param trigger - 触发器(下拉按钮 / 说明按钮)的矩形
145
+ * @param floating - 浮层(候选列表 / 说明浮层)的矩形
146
+ * @returns 浮层没有贴住触发器时为 true
147
+ */
148
+ function anchorPlacementOff(trigger, floating) {
149
+ const inlineStart = Math.abs(floating.left - trigger.left) <= 2;
150
+ const inlineEnd = Math.abs(floating.right - trigger.right) <= 2;
151
+ if (!inlineStart && !inlineEnd) return true;
152
+ const below = floating.top >= trigger.bottom - 2;
153
+ const above = floating.bottom <= trigger.top + 2;
154
+ return !below && !above;
155
+ }
121
156
  // lib/card-ui/field.ts
122
- /** 说明按钮与浮层:悬停/聚焦显示,点击钉住,Esc 关闭。 */
157
+ /** 说明按钮与浮层:悬停/聚焦显示,点击钉住,Esc 或点击外部关闭。 */
123
158
  function InfoTip(props) {
124
159
  const id = (0, react.useId)();
160
+ const anchorId = `--dsu-tip-${id.replaceAll(/[^a-zA-Z0-9]/gu, "")}`;
125
161
  const [open, setOpen] = (0, react.useState)(false);
126
- const [pinned, setPinned] = (0, react.useState)(false);
127
162
  const hoveredRef = (0, react.useRef)(false);
128
163
  const focusedRef = (0, react.useRef)(false);
129
164
  const pinnedRef = (0, react.useRef)(false);
165
+ const wrapRef = (0, react.useRef)(null);
130
166
  const anchorRef = (0, react.useRef)(null);
131
167
  const tipRef = (0, react.useRef)(null);
132
168
  const hideTimer = (0, react.useRef)(null);
@@ -141,7 +177,11 @@ function InfoTip(props) {
141
177
  const tip = tipRef.current;
142
178
  /* v8 ignore next 3 -- place 只在 open 的 layout effect 与挂载期监听器里调用;refs 为空只可能是卸载竞态 */
143
179
  if (anchor === null || tip === null) return;
180
+ const anchored = cssAnchorSupported() && tip.style.positionArea !== "none";
144
181
  const rect = anchor.getBoundingClientRect();
182
+ if (anchored && !anchorPlacementOff(rect, tip.getBoundingClientRect())) return;
183
+ if (anchored) tip.style.positionArea = "none";
184
+ tip.style.marginTop = "0px";
145
185
  const width = tip.offsetWidth;
146
186
  const height = tip.offsetHeight;
147
187
  let { left } = rect;
@@ -156,7 +196,6 @@ function InfoTip(props) {
156
196
  const close = (0, react.useCallback)(() => {
157
197
  cancelHide();
158
198
  pinnedRef.current = false;
159
- setPinned(false);
160
199
  setOpen(false);
161
200
  }, [cancelHide]);
162
201
  const show = (0, react.useCallback)(() => {
@@ -174,7 +213,6 @@ function InfoTip(props) {
174
213
  }, [cancelHide]);
175
214
  const updatePinned = (0, react.useCallback)((next) => {
176
215
  pinnedRef.current = next;
177
- setPinned(next);
178
216
  }, []);
179
217
  (0, react.useLayoutEffect)(() => {
180
218
  if (!open) return () => {};
@@ -191,9 +229,16 @@ function InfoTip(props) {
191
229
  const onResize = () => {
192
230
  place();
193
231
  };
232
+ const onPointerDown = (event) => {
233
+ const target = event.target;
234
+ if (wrapRef.current?.contains(target) === true) return;
235
+ close();
236
+ };
237
+ document.addEventListener("pointerdown", onPointerDown, true);
194
238
  window.addEventListener("scroll", onScroll, true);
195
239
  window.addEventListener("resize", onResize);
196
240
  return () => {
241
+ document.removeEventListener("pointerdown", onPointerDown, true);
197
242
  window.removeEventListener("scroll", onScroll, true);
198
243
  window.removeEventListener("resize", onResize);
199
244
  };
@@ -218,9 +263,10 @@ function InfoTip(props) {
218
263
  ref: anchorRef,
219
264
  type: "button",
220
265
  className: "dsu-helpBtn",
266
+ style: { anchorName: anchorId },
221
267
  "aria-label": `${props.label} 说明`,
222
- "aria-describedby": id,
223
- "aria-pressed": pinned,
268
+ "aria-expanded": open,
269
+ "aria-controls": id,
224
270
  onClick: () => {
225
271
  if (pinnedRef.current) {
226
272
  close();
@@ -257,10 +303,15 @@ function InfoTip(props) {
257
303
  id,
258
304
  role: "tooltip",
259
305
  className: "dsu-tip",
306
+ style: {
307
+ positionAnchor: anchorId,
308
+ positionTryFallbacks: "flip-block, flip-inline"
309
+ },
260
310
  hidden: !open
261
311
  }, props.detail);
262
312
  const labelNode = props.showLabel === false ? null : (0, react.createElement)("span", { className: `dsu-label${props.compact === true ? " dsu-labelMono" : ""}` }, props.label);
263
313
  return (0, react.createElement)("span", {
314
+ ref: wrapRef,
264
315
  className: "dsu-help",
265
316
  onMouseEnter: () => {
266
317
  hoveredRef.current = true;
@@ -330,21 +381,25 @@ function ToggleField(props) {
330
381
  }
331
382
  }, (0, react.createElement)("span", { className: "dsu-knob" })));
332
383
  }
333
- /** 数字行:以显示单位读写,越界值不写入。 */
384
+ /** 数字行:以显示单位读写,越界值不写入,失焦后才提示。 */
334
385
  function NumberField(props) {
335
386
  const text = typeof props.value === "number" && Number.isFinite(props.value) ? String(props.value) : "";
336
387
  const [draft, setDraft] = (0, react.useState)(text);
337
388
  const [invalid, setInvalid] = (0, react.useState)(false);
389
+ const [showInvalid, setShowInvalid] = (0, react.useState)(false);
338
390
  const lastEmitted = (0, react.useRef)(void 0);
339
391
  const controlId = (0, react.useId)();
340
392
  const errorId = (0, react.useId)();
341
- const describedByIds = [props.hint === void 0 ? void 0 : `${controlId}-hint`, invalid ? errorId : void 0].filter((entry) => entry !== void 0);
393
+ const hintId = props.hint === void 0 ? void 0 : `${controlId}-hint`;
394
+ const showError = invalid && showInvalid;
395
+ const describedByIds = [hintId, showError ? errorId : void 0].filter((entry) => entry !== void 0);
342
396
  const describedBy = describedByIds.length === 0 ? void 0 : describedByIds.join(" ");
343
397
  (0, react.useEffect)(() => {
344
398
  if (props.value === lastEmitted.current) return;
345
399
  lastEmitted.current = props.value;
346
400
  setDraft(text);
347
401
  setInvalid(false);
402
+ setShowInvalid(false);
348
403
  }, [props.value, text]);
349
404
  const accepts = (value) => {
350
405
  const min = props.min ?? -1e400;
@@ -356,6 +411,7 @@ function NumberField(props) {
356
411
  return Math.abs(offset - Math.round(offset)) < 1e-9;
357
412
  };
358
413
  const change = (next) => {
414
+ setShowInvalid(false);
359
415
  setDraft(next);
360
416
  if (next === "") {
361
417
  setInvalid(false);
@@ -376,6 +432,10 @@ function NumberField(props) {
376
432
  if (draft === "" || invalid) return;
377
433
  setDraft(String(Number(draft)));
378
434
  };
435
+ const blur = () => {
436
+ setShowInvalid(invalid);
437
+ normalize();
438
+ };
379
439
  return (0, react.createElement)(Field, {
380
440
  ...props,
381
441
  controlId
@@ -389,15 +449,15 @@ function NumberField(props) {
389
449
  max: props.max,
390
450
  step: props.step,
391
451
  placeholder: props.placeholder,
392
- "aria-invalid": invalid || void 0,
452
+ "aria-invalid": showError || void 0,
393
453
  "aria-describedby": describedBy,
394
454
  "data-field": props.field,
395
455
  disabled: props.disabled === true,
396
456
  onChange: (event) => {
397
457
  change(event.target.value);
398
458
  },
399
- onBlur: normalize
400
- }), props.unit === void 0 ? null : (0, react.createElement)("span", { className: "dsu-unit" }, props.unit)), invalid ? (0, react.createElement)("p", {
459
+ onBlur: blur
460
+ }), props.unit === void 0 ? null : (0, react.createElement)("span", { className: "dsu-unit" }, props.unit)), showError ? (0, react.createElement)("p", {
401
461
  className: "dsu-error",
402
462
  id: errorId
403
463
  }, props.invalidHint) : null));
@@ -472,16 +532,6 @@ function ListField(props) {
472
532
  }, separator === "newline" ? (0, react.createElement)("textarea", shared) : (0, react.createElement)("input", shared));
473
533
  }
474
534
  // lib/card-ui/select.ts
475
- /** 浏览器是否支持 CSS anchor 定位(宿主 webview 支持,与宿主 Menu 同一套平台 API)。
476
- * 支持时浮层位置由 `position-area` 跟随触发器,缩放/平移不漂;happy-dom 等不支持处回退 JS 矩形。
477
- * 探测的是本组件实际依赖的 `position-area`,不是更早出现的 `anchor-name`:只支持
478
- * `anchor-name` 的半档实现里浮层不会被真正定位。happy-dom 的 CSS.supports 对 anchor-name
479
- * 误返 true,但它并不真做 anchor 布局;happy-dom 在 window 上暴露 happyDOM 属性,据此排除
480
- * (真实浏览器没有该属性)。 */
481
- function cssAnchorSupported() {
482
- if ("happyDOM" in globalThis) return false;
483
- return typeof CSS !== "undefined" && typeof CSS.supports === "function" && CSS.supports("position-area: block-end");
484
- }
485
535
  /** 自定义下拉:浮层固定定位,键盘可选,点击外部关闭。 */
486
536
  function SelectField(props) {
487
537
  const [open, setOpen] = (0, react.useState)(false);
@@ -508,7 +558,9 @@ function SelectField(props) {
508
558
  const rect = trigger.getBoundingClientRect();
509
559
  const width = Math.min(rect.width, window.innerWidth - 16);
510
560
  menu.style.width = `${width}px`;
511
- if (cssAnchorSupported()) return;
561
+ const anchored = cssAnchorSupported() && menu.style.positionArea !== "none";
562
+ if (anchored && !anchorPlacementOff(rect, menu.getBoundingClientRect())) return;
563
+ if (anchored) menu.style.positionArea = "none";
512
564
  menu.style.marginTop = "0px";
513
565
  let { left } = rect;
514
566
  if (left + width > window.innerWidth - 8) left = window.innerWidth - width - 8;
@@ -790,7 +842,10 @@ function SaveBar(props) {
790
842
  "data-field": "discard",
791
843
  disabled,
792
844
  onClick: props.onDiscard
793
- }, props.revertLabel), (0, react.createElement)("span", { className: props.error === null ? "dsu-status" : "dsu-status dsu-statusError" }, status));
845
+ }, props.revertLabel), (0, react.createElement)("span", {
846
+ role: "status",
847
+ className: props.error === null ? "dsu-status" : "dsu-status dsu-statusError"
848
+ }, status));
794
849
  }
795
850
  // lib/card-diff.ts
796
851
  /**
@@ -0,0 +1,26 @@
1
+ /** 浏览器是否支持 CSS anchor 定位(宿主 webview 支持,与宿主 Menu 同一套平台 API)。
2
+ * 支持时浮层位置由 `position-area` 跟随触发器,缩放/平移不漂;happy-dom 等不支持处回退 JS 矩形。
3
+ * 探测的是本组件实际依赖的 `position-area`,不是更早出现的 `anchor-name`:只支持
4
+ * `anchor-name` 的半档实现里浮层不会被真正定位。happy-dom 的 CSS.supports 对 anchor-name
5
+ * 误返 true,但它并不真做 anchor 布局;happy-dom 在 window 上暴露 happyDOM 属性,据此排除
6
+ * (真实浏览器没有该属性)。 */
7
+ export declare function cssAnchorSupported(): boolean;
8
+ /** 几何判据的容差(px):亚像素舍入、1px 边框与缩放都不该触发回退。 */
9
+ export declare const ANCHOR_PLACEMENT_TOLERANCE = 2;
10
+ /**
11
+ * 锚定之后浮层是否真的落在触发器上。
12
+ *
13
+ * cssAnchorSupported() 只回答「这个引擎认识这套 CSS」,不回答「这条规则最终有没有生效」。
14
+ * 0.2.5–0.2.6 的事故形态就是后者:规则写法(span-inline-start)把浮层钉到视口左边缘,
15
+ * 而引擎完全支持它,于是没有任何一层会报错——只有实测矩形看得见。宿主若用更高优先级的
16
+ * 规则覆盖 position-area,症状相同(元素仍是 position:fixed,没有 left/top 时落到静态
17
+ * 位置即视口左侧)。
18
+ *
19
+ * 判据用「对齐」而不是「坐标相等」:flip-inline 会把浮层改成与触发器右边缘对齐,所以
20
+ * 行内起始边或结束边任一重合即算贴住;块向则要求不重叠(flip-block 翻到上方时浮层的
21
+ * 下边缘贴在触发器上边缘)。两条都不成立时调用方改用 JS 矩形定位。
22
+ * @param trigger - 触发器(下拉按钮 / 说明按钮)的矩形
23
+ * @param floating - 浮层(候选列表 / 说明浮层)的矩形
24
+ * @returns 浮层没有贴住触发器时为 true
25
+ */
26
+ export declare function anchorPlacementOff(trigger: DOMRect, floating: DOMRect): boolean;
@@ -12,7 +12,7 @@ export interface FieldBase {
12
12
  /** 控件的 DOM id;字段组件用 `useId` 生成,FieldLabel 用它建立 label↔control 关联。 */
13
13
  controlId?: string;
14
14
  }
15
- /** 说明按钮与浮层:悬停/聚焦显示,点击钉住,Esc 关闭。 */
15
+ /** 说明按钮与浮层:悬停/聚焦显示,点击钉住,Esc 或点击外部关闭。 */
16
16
  export declare function InfoTip(props: {
17
17
  label: string;
18
18
  detail: string;
@@ -5,7 +5,7 @@ export declare function ToggleField(props: FieldBase & {
5
5
  checked: boolean;
6
6
  onChange: (next: boolean) => void;
7
7
  }): ReactElement;
8
- /** 数字行:以显示单位读写,越界值不写入。 */
8
+ /** 数字行:以显示单位读写,越界值不写入,失焦后才提示。 */
9
9
  export declare function NumberField(props: FieldBase & {
10
10
  value: number | undefined;
11
11
  min?: number;
@@ -1,2 +1,2 @@
1
1
  /** 设置卡统一样式。颜色/圆角全部走宿主主题令牌。 */
2
- export declare const CARD_UI_CSS = "\n.dsu-form{display:flex;flex-direction:column}\n.dsu-section{margin-top:24px;padding-top:24px;border-top:.5px solid var(--dsw-alias-border-l1)}\n.dsu-form>.dsu-section:first-child{margin-top:0;padding-top:0;border-top:0}\n.dsu-sectionTitle{margin:0;font-size:15px;font-weight:600;line-height:1.4;color:var(--dsw-alias-label-primary)}\n.dsu-sectionHint{margin:4px 0 0;font-size:12px;line-height:1.5;color:var(--dsw-alias-label-tertiary)}\n.dsu-statusbar{display:flex;flex-wrap:wrap;gap:4px 8px;margin-top:8px;font-size:12px;line-height:1.5;color:var(--dsw-alias-label-tertiary)}\n.dsu-field{display:grid;grid-template-columns:minmax(0,1fr) minmax(240px,360px);column-gap:32px;align-items:center;padding:12px 0;border-top:.5px solid var(--dsw-alias-border-l2)}\n.dsu-fieldMeta{display:flex;flex-direction:column;gap:4px;min-width:0}\n.dsu-labelRow{display:flex;align-items:center;gap:6px;min-width:0}\n.dsu-label{font-size:13px;font-weight:500;line-height:1.5;color:var(--dsw-alias-label-primary)}\n.dsu-labelMono{font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;font-size:12px}\n.dsu-hint{margin:0;font-size:12px;line-height:1.5;color:var(--dsw-alias-label-tertiary)}\n.dsu-control{min-width:0;display:flex;align-items:center;gap:8px}\n.dsu-fieldWide{grid-template-columns:minmax(0,1fr);align-items:start}\n.dsu-fieldWide .dsu-control{width:100%;max-width:720px;margin-top:2px}\n.dsu-help{display:inline-flex;align-items:center;gap:6px;min-width:0}\n.dsu-helpBtn{appearance:none;border:0;background:transparent;padding:0;width:16px;height:16px;display:inline-flex;align-items:center;justify-content:center;color:var(--dsw-alias-label-tertiary);cursor:help;border-radius:50%;flex:none}\n.dsu-help:hover .dsu-helpBtn,.dsu-helpBtn:focus-visible{color:var(--dsw-alias-label-primary)}\n.dsu-helpBtn:focus-visible{outline:2px solid var(--dsw-alias-state-business-primary);outline-offset:1px}\n.dsu-tip{position:fixed;z-index:60;box-sizing:border-box;max-width:min(340px,calc(100vw - 16px));max-height:calc(100vh - 16px);overflow:auto;overflow-wrap:anywhere;padding:10px 12px;border-radius:10px;background:var(--dsw-alias-bg-layer-2);border:.5px solid var(--dsw-alias-border-l3);box-shadow:0 12px 32px rgb(0 0 0 / 45%);font-size:12px;line-height:1.6;font-weight:400;color:var(--dsw-alias-label-secondary)}\n.dsu-input{width:100%;height:34px;padding:0 12px;border:.5px solid var(--dsw-alias-border-l4);border-radius:var(--dsw-radius-md);background:var(--dsw-alias-bg-layer-3);color:var(--dsw-alias-label-primary);font:inherit;font-size:13px}\n.dsu-input:focus-visible{outline:none;border-color:var(--dsw-alias-state-business-primary)}\n.dsu-input[aria-invalid=\"true\"]{border-color:var(--dsw-alias-state-error-primary)}\n.dsu-input:disabled{color:var(--dsw-alias-label-tertiary);cursor:default}\n.dsu-input::placeholder{color:var(--dsw-alias-label-tertiary)}\n.dsu-textarea{height:auto;min-height:96px;padding:8px 12px;line-height:1.6;resize:vertical}\n.dsu-mono{font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace}\n.dsu-numberWrap{display:flex;flex-direction:column;gap:4px;width:100%;min-width:0}\n.dsu-number{display:flex;align-items:center;gap:8px;min-width:0}\n.dsu-number .dsu-input{min-width:0}\n.dsu-unit{flex:none;font-size:12px;color:var(--dsw-alias-label-tertiary)}\n.dsu-error{margin:0;font-size:12px;line-height:1.5;color:var(--dsw-alias-state-error-primary)}\n.dsu-switch{appearance:none;width:36px;height:20px;border-radius:999px;border:0;padding:2px;background:var(--dsw-alias-border-l3);display:flex;align-items:center;cursor:pointer;flex:none;transition:background-color .16s}\n.dsu-knob{width:16px;height:16px;border-radius:50%;background:var(--dsw-alias-label-primary);transition:transform .16s,background-color .16s}\n.dsu-switch[aria-checked=\"true\"]{background:var(--dsw-alias-label-primary)}\n.dsu-switch[aria-checked=\"true\"] .dsu-knob{transform:translateX(16px);background:var(--dsw-alias-label-primary-foreground)}\n.dsu-switch:disabled{opacity:.4;cursor:not-allowed}\n.dsu-switch:focus-visible{outline:2px solid var(--dsw-alias-state-business-primary);outline-offset:2px}\n.dsu-selectWrap{position:relative;width:100%;min-width:0}\n.dsu-select{display:flex;align-items:center;justify-content:space-between;gap:8px;text-align:left;cursor:pointer}\n.dsu-select[aria-expanded=\"true\"]{border-color:var(--dsw-alias-state-business-primary)}\n.dsu-selectValue{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}\n.dsu-chevron{flex:none;color:var(--dsw-alias-label-tertiary);transition:transform .16s}\n.dsu-select[aria-expanded=\"true\"] .dsu-chevron{transform:rotate(180deg)}\n.dsu-menu{position:fixed;position-area:block-end span-inline-start;justify-self:start;margin-top:6px;z-index:70;padding:4px;background:var(--dsw-alias-bg-layer-2);border:.5px solid var(--dsw-alias-border-l3);border-radius:12px;box-shadow:0 12px 32px rgb(0 0 0 / 50%);max-height:280px;overflow:auto}\n.dsu-option{appearance:none;border:0;background:transparent;color:var(--dsw-alias-label-primary);font:inherit;font-size:13px;line-height:1.4;width:100%;display:flex;align-items:center;justify-content:space-between;gap:12px;padding:8px 10px;border-radius:8px;cursor:pointer;text-align:left}\n.dsu-option:hover,.dsu-option[data-active=\"true\"]{background:var(--dsw-alias-bg-layer-3)}\n.dsu-option:disabled{color:var(--dsw-alias-label-tertiary);cursor:not-allowed}\n.dsu-option:focus-visible{outline:2px solid var(--dsw-alias-state-business-primary);outline-offset:-2px}\n.dsu-optionGroup{padding:6px 10px 2px;font-size:11px;font-weight:600;color:var(--dsw-alias-label-tertiary)}\n.dsu-check{opacity:0;flex:none}\n.dsu-option[aria-selected=\"true\"] .dsu-check{opacity:1}\n.dsu-savebar{display:flex;align-items:center;gap:8px;padding:12px 0;margin-top:24px;border-top:.5px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-base)}\n.dsu-savebar[data-dirty=\"true\"]{position:sticky;bottom:0;z-index:2;box-shadow:0 -12px 24px rgb(0 0 0 / 35%)}\n.dsu-btn{appearance:none;border:.5px solid var(--dsw-alias-border-l2);background:transparent;color:var(--dsw-alias-label-primary);font:inherit;font-size:13px;line-height:1.5;border-radius:var(--dsw-radius-md);padding:5px 14px;cursor:pointer;transition:background-color .12s,border-color .12s,color .12s,filter .12s}\n.dsu-btn:hover:not(:disabled){background:var(--dsw-alias-bg-layer-2);border-color:var(--dsw-alias-border-l3)}\n.dsu-btn:active:not(:disabled){background:var(--dsw-alias-bg-layer-1)}\n.dsu-btn:focus-visible{outline:2px solid var(--dsw-alias-state-business-primary);outline-offset:1px}\n.dsu-btn:disabled{opacity:.4;cursor:not-allowed}\n.dsu-btnPrimary{background:var(--dsw-alias-label-primary);border-color:var(--dsw-alias-label-primary);color:var(--dsw-alias-bg-layer-3)}\n.dsu-btnPrimary:hover:not(:disabled){background:var(--dsw-alias-label-primary);border-color:var(--dsw-alias-label-primary);filter:brightness(.9)}\n.dsu-btnPrimary:active:not(:disabled){background:var(--dsw-alias-label-primary);border-color:var(--dsw-alias-label-primary);filter:brightness(.84)}\n.dsu-btnDanger{color:var(--dsw-alias-state-error-primary)}\n.dsu-btnDanger:hover:not(:disabled){color:var(--dsw-alias-state-error-primary);border-color:var(--dsw-alias-state-error-primary);background:var(--dsw-alias-bg-layer-2)}\n.dsu-status{margin-left:auto;font-size:12px;color:var(--dsw-alias-label-tertiary)}\n.dsu-statusError{color:var(--dsw-alias-state-error-primary)}\n.dsu-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(min(200px,100%),1fr));gap:0 24px}\n.dsu-grid>.dsu-field{display:flex;flex-direction:column;align-items:stretch;gap:6px;padding:10px 0;border-top:.5px solid var(--dsw-alias-border-l1)}\n.dsu-grid>.dsu-field .dsu-control{width:100%}\n@media (max-width:640px){\n .dsu-field{grid-template-columns:minmax(0,1fr);align-items:start}\n .dsu-control{width:100%;max-width:720px}\n .dsu-section{margin-top:20px;padding-top:20px}\n}\n@media (prefers-reduced-motion:reduce){\n .dsu-switch,.dsu-knob,.dsu-chevron,.dsu-btn{transition:none}\n}\n";
2
+ export declare const CARD_UI_CSS = "\n.dsu-form{display:flex;flex-direction:column}\n.dsu-section{margin-top:24px;padding-top:24px;border-top:.5px solid var(--dsw-alias-border-l1)}\n.dsu-form>.dsu-section:first-child{margin-top:0;padding-top:0;border-top:0}\n.dsu-sectionTitle{margin:0;font-size:15px;font-weight:600;line-height:1.4;color:var(--dsw-alias-label-primary)}\n.dsu-sectionHint{margin:4px 0 0;font-size:12px;line-height:1.5;color:var(--dsw-alias-label-tertiary)}\n.dsu-statusbar{display:flex;flex-wrap:wrap;gap:4px 8px;margin-top:8px;font-size:12px;line-height:1.5;color:var(--dsw-alias-label-tertiary)}\n.dsu-field{display:grid;grid-template-columns:minmax(0,1fr) minmax(240px,360px);column-gap:32px;align-items:center;padding:12px 0;border-top:.5px solid var(--dsw-alias-border-l2)}\n.dsu-fieldMeta{display:flex;flex-direction:column;gap:4px;min-width:0}\n.dsu-labelRow{display:flex;align-items:center;gap:6px;min-width:0}\n.dsu-label{font-size:13px;font-weight:500;line-height:1.5;color:var(--dsw-alias-label-primary)}\n.dsu-labelMono{font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;font-size:12px}\n.dsu-hint{margin:0;font-size:12px;line-height:1.5;color:var(--dsw-alias-label-tertiary)}\n.dsu-control{min-width:0;display:flex;align-items:center;gap:8px}\n.dsu-fieldWide{grid-template-columns:minmax(0,1fr);align-items:start}\n.dsu-fieldWide .dsu-control{width:100%;max-width:720px;margin-top:2px}\n.dsu-help{display:inline-flex;align-items:center;gap:6px;min-width:0}\n.dsu-helpBtn{appearance:none;border:0;background:transparent;padding:0;width:16px;height:16px;display:inline-flex;align-items:center;justify-content:center;color:var(--dsw-alias-label-tertiary);cursor:help;border-radius:50%;flex:none}\n.dsu-help:hover .dsu-helpBtn,.dsu-helpBtn:focus-visible{color:var(--dsw-alias-label-primary)}\n.dsu-helpBtn:focus-visible{outline:2px solid var(--dsw-alias-state-business-primary);outline-offset:1px}\n.dsu-tip{width:max-content;position:fixed;position-area:block-end span-inline-end;justify-self:start;margin-top:8px;z-index:60;box-sizing:border-box;max-width:min(340px,calc(100vw - 16px));max-height:calc(100vh - 16px);overflow:auto;overflow-wrap:anywhere;padding:10px 12px;border-radius:10px;background:var(--dsw-alias-bg-layer-2);border:.5px solid var(--dsw-alias-border-l3);box-shadow:0 12px 32px rgb(0 0 0 / 45%);font-size:12px;line-height:1.6;font-weight:400;color:var(--dsw-alias-label-secondary)}\n.dsu-input{width:100%;height:34px;padding:0 12px;border:.5px solid var(--dsw-alias-border-l4);border-radius:var(--dsw-radius-md);background:var(--dsw-alias-bg-layer-3);color:var(--dsw-alias-label-primary);font:inherit;font-size:13px}\n.dsu-input:focus-visible{outline:none;border-color:var(--dsw-alias-state-business-primary)}\n.dsu-input[aria-invalid=\"true\"]{border-color:var(--dsw-alias-state-error-primary)}\n.dsu-input:disabled{color:var(--dsw-alias-label-tertiary);cursor:not-allowed}\n.dsu-input::placeholder{color:var(--dsw-alias-label-tertiary)}\n.dsu-textarea{height:auto;min-height:96px;padding:8px 12px;line-height:1.6;resize:vertical}\n.dsu-mono{font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace}\n.dsu-numberWrap{display:flex;flex-direction:column;gap:4px;width:100%;min-width:0}\n.dsu-number{display:flex;align-items:center;gap:8px;min-width:0}\n.dsu-number .dsu-input{min-width:0}\n.dsu-unit{flex:none;font-size:12px;color:var(--dsw-alias-label-tertiary)}\n.dsu-error{margin:0;font-size:12px;line-height:1.5;color:var(--dsw-alias-state-error-primary)}\n.dsu-switch{appearance:none;width:36px;height:20px;border-radius:999px;border:0;padding:2px;background:var(--dsw-alias-border-l3);display:flex;align-items:center;cursor:pointer;flex:none;transition:background-color .16s}\n.dsu-knob{width:16px;height:16px;border-radius:50%;background:var(--dsw-alias-label-primary);transition:transform .16s,background-color .16s}\n.dsu-switch[aria-checked=\"true\"]{background:var(--dsw-alias-label-primary)}\n.dsu-switch[aria-checked=\"true\"] .dsu-knob{transform:translateX(16px);background:var(--dsw-alias-label-primary-foreground)}\n.dsu-switch:disabled{opacity:.4;cursor:not-allowed}\n.dsu-switch:focus-visible{outline:2px solid var(--dsw-alias-state-business-primary);outline-offset:2px}\n.dsu-selectWrap{position:relative;width:100%;min-width:0}\n.dsu-select{display:flex;align-items:center;justify-content:space-between;gap:8px;text-align:left;cursor:pointer}\n.dsu-select[aria-expanded=\"true\"]{border-color:var(--dsw-alias-state-business-primary)}\n.dsu-selectValue{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}\n.dsu-chevron{flex:none;color:var(--dsw-alias-label-tertiary);transition:transform .16s}\n.dsu-select[aria-expanded=\"true\"] .dsu-chevron{transform:rotate(180deg)}\n.dsu-menu{position:fixed;position-area:block-end span-inline-end;justify-self:start;margin-top:6px;z-index:70;padding:4px;background:var(--dsw-alias-bg-layer-2);border:.5px solid var(--dsw-alias-border-l3);border-radius:12px;box-shadow:0 12px 32px rgb(0 0 0 / 50%);max-height:280px;overflow:auto}\n.dsu-option{appearance:none;border:0;background:transparent;color:var(--dsw-alias-label-primary);font:inherit;font-size:13px;line-height:1.4;width:100%;display:flex;align-items:center;justify-content:space-between;gap:12px;padding:8px 10px;border-radius:8px;cursor:pointer;text-align:left}\n.dsu-option:hover,.dsu-option[data-active=\"true\"]{background:var(--dsw-alias-bg-layer-3)}\n.dsu-option:disabled{color:var(--dsw-alias-label-tertiary);cursor:not-allowed}\n.dsu-option:focus-visible{outline:2px solid var(--dsw-alias-state-business-primary);outline-offset:-2px}\n.dsu-optionGroup{padding:6px 10px 2px;font-size:11px;font-weight:600;color:var(--dsw-alias-label-tertiary)}\n.dsu-check{opacity:0;flex:none}\n.dsu-option[aria-selected=\"true\"] .dsu-check{opacity:1}\n.dsu-savebar{display:flex;align-items:center;gap:8px;padding:12px 0;margin-top:24px;border-top:.5px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-base)}\n.dsu-savebar[data-dirty=\"true\"]{position:sticky;bottom:0;z-index:2;box-shadow:0 -12px 24px rgb(0 0 0 / 35%)}\n.dsu-btn{appearance:none;border:.5px solid var(--dsw-alias-border-l2);background:transparent;color:var(--dsw-alias-label-primary);font:inherit;font-size:13px;line-height:1.5;border-radius:var(--dsw-radius-md);padding:5px 14px;cursor:pointer;transition:background-color .12s,border-color .12s,color .12s,filter .12s}\n.dsu-btn:hover:not(:disabled){background:var(--dsw-alias-bg-layer-2);border-color:var(--dsw-alias-border-l3)}\n.dsu-btn:active:not(:disabled){background:var(--dsw-alias-bg-layer-1)}\n.dsu-btn:focus-visible{outline:2px solid var(--dsw-alias-state-business-primary);outline-offset:1px}\n.dsu-btn:disabled{opacity:.4;cursor:not-allowed}\n.dsu-btnPrimary{background:var(--dsw-alias-label-primary);border-color:var(--dsw-alias-label-primary);color:var(--dsw-alias-bg-layer-3)}\n.dsu-btnPrimary:hover:not(:disabled){background:var(--dsw-alias-label-primary);border-color:var(--dsw-alias-label-primary);filter:brightness(.9)}\n.dsu-btnPrimary:active:not(:disabled){background:var(--dsw-alias-label-primary);border-color:var(--dsw-alias-label-primary);filter:brightness(.84)}\n.dsu-btnDanger{color:var(--dsw-alias-state-error-primary)}\n.dsu-btnDanger:hover:not(:disabled){color:var(--dsw-alias-state-error-primary);border-color:var(--dsw-alias-state-error-primary);background:var(--dsw-alias-bg-layer-2)}\n.dsu-status{margin-left:auto;font-size:12px;color:var(--dsw-alias-label-tertiary)}\n.dsu-statusError{color:var(--dsw-alias-state-error-primary)}\n.dsu-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(min(200px,100%),1fr));gap:0 24px}\n.dsu-grid>.dsu-field{display:flex;flex-direction:column;align-items:stretch;gap:6px;padding:10px 0;border-top:.5px solid var(--dsw-alias-border-l1)}\n.dsu-grid>.dsu-field .dsu-control{width:100%}\n@media (max-width:640px){\n .dsu-field{grid-template-columns:minmax(0,1fr);align-items:start}\n .dsu-control{width:100%;max-width:720px}\n .dsu-section{margin-top:20px;padding-top:20px}\n}\n@media (prefers-reduced-motion:reduce){\n .dsu-switch,.dsu-knob,.dsu-chevron,.dsu-btn{transition:none}\n}\n";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jayyuen66/dsh-plugin-shared",
3
- "version": "0.2.6",
3
+ "version": "0.2.8",
4
4
  "description": "dsh 自研插件的共享工具库:tool 事件流记账扫描 + 卡片 apply/差异骨架 + 统一设置卡 UI 组件 + 官方作业结局映射 + 项目键派生 + 代理对安全截断。宿主半由各插件 import;客户端半以 ./client 共享行由插件 patch 启用,不由用户单独停用",
5
5
  "keywords": [
6
6
  "cordis",