@aiquants/spreadsheet 0.13.0 → 0.14.0

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.
@@ -1,3 +1,3 @@
1
1
  /*! tailwindcss v4.3.0 | MIT License | https://tailwindcss.com */
2
2
  /*! @aiquants/spreadsheet standalone CSS — 非 Tailwind ホスト専用。ホストの Tailwind ビルドと混在させないこと */
3
- @layer theme,base;@layer components{@layer components{.aqvs-scroll-pane{display:flex;position:relative}.aqvs-scroll-pane[data-self-measured=true]{height:100%}.aqvs-scroll-pane-content{box-sizing:border-box;flex:1;height:100%;position:relative;overflow:hidden}.aqvs-tap-scroll-circle{touch-action:none;-webkit-user-select:none;user-select:none;justify-content:center;align-items:center;transition-property:transform;transition-duration:.1s;transition-timing-function:cubic-bezier(0,0,.2,1);display:flex;position:relative}.aqvs-tap-scroll-circle-visual-outer{border-radius:9999px;position:absolute;inset:0}.aqvs-tap-scroll-circle-gradient{background:linear-gradient(to bottom right,#1d4ed899,#60a5fa8c,#bfdbfe66);border:1px solid #fff6;border-radius:9999px;position:absolute;inset:0;box-shadow:0 4px 6px -1px #0000001a,0 2px 4px -1px #0000000f}.aqvs-tap-scroll-circle-inner{border-radius:9999px;position:absolute;inset:18%}.aqvs-sample-visual-pupil{box-sizing:border-box;background-color:#ffffffd9;border:1px solid #ffffff80;border-radius:9999px;position:absolute;top:50%;left:50%}.aqvs-sample-visual-highlight{background-color:#fffc;border-radius:9999px;position:absolute;top:50%;left:50%}.aqvs-sample-visual-rod{background-color:#ffffff80;border-radius:9999px;position:absolute;top:50%;left:50%}.aqvs-scrollbar{z-index:50;cursor:default;-webkit-user-select:none;user-select:none;-webkit-tap-highlight-color:transparent;touch-action:none;background-color:#fff;position:relative}.aqvs-scrollbar-horizontal{flex-direction:row;align-items:stretch;display:flex}.aqvs-scrollbar-vertical{flex-direction:column;align-items:stretch;display:flex}.aqvs-scrollbar[data-visible=false],.aqvs-scrollbar-thumb-wrapper[data-visible=false]{opacity:0;pointer-events:none}.aqvs-scrollbar-tap-circle-wrapper{pointer-events:auto;transition-property:opacity;transition-duration:.15s;transition-timing-function:cubic-bezier(.4,0,.2,1);position:absolute}.aqvs-scrollbar-arrow-button{color:#313131;letter-spacing:normal;background-color:#e0e0e0;border:0 solid;justify-content:center;align-items:center;padding:0;font-family:system-ui,sans-serif;font-size:.75rem;font-weight:400;line-height:1rem;transition-property:color,background-color,border-color,text-decoration-color,fill,stroke;transition-duration:.15s;transition-timing-function:cubic-bezier(.4,0,.2,1);display:flex}.aqvs-scrollbar-arrow-button:focus{outline-offset:2px;outline:2px solid #0000}.aqvs-scrollbar-arrow-button:focus-visible{outline-offset:1px;outline:2px solid #60a5fa}.aqvs-scrollbar-arrow-button:disabled{cursor:not-allowed;opacity:.5}.aqvs-scrollbar-arrow-button:enabled:hover{background-color:#d4d4d4}.aqvs-scrollbar-track{background-color:#f5f5f5;flex:1;position:relative}.aqvs-scrollbar-overlay{pointer-events:none;position:absolute;inset:0}.aqvs-scrollbar-thumb-wrapper{touch-action:none;position:absolute}.aqvs-scrollbar-thumb{transform-origin:50%;background-color:#7f7f7f;transition:transform 80ms ease-out;position:absolute}.aqvs-scrollbar-thumb[data-thumb-state=disabled]{transition:none;transform:none}.aqvs-scrollbar-thumb[data-thumb-state=hover]{background-color:#5f5f5f}.aqvs-scrollbar-thumb[data-thumb-state=dragging]{background-color:#4f4f4f;transition:transform 60ms ease-out}.aqvs-scrollbar-thumb-horizontal{inset:1.5px 0}.aqvs-scrollbar-thumb-horizontal[data-thumb-state=hover]{top:-.5px;bottom:-.5px;transform:scaleY(1.06)}.aqvs-scrollbar-thumb-horizontal[data-thumb-state=dragging]{top:-.5px;bottom:-.5px;transform:scaleY(1.12)}.aqvs-scrollbar-thumb-vertical{inset:0 1.5px}.aqvs-scrollbar-thumb-vertical[data-thumb-state=hover]{left:-.5px;right:-.5px;transform:scaleX(1.06)}.aqvs-scrollbar-thumb-vertical[data-thumb-state=dragging]{left:-.5px;right:-.5px;transform:scaleX(1.12)}.aqvs-scroll-to-edge-button{pointer-events:auto;cursor:pointer;-webkit-user-select:none;user-select:none;-webkit-tap-highlight-color:transparent;color:#fff;text-transform:uppercase;letter-spacing:.05em;-webkit-backdrop-filter:blur(4px);backdrop-filter:blur(4px);background-color:#1f2937cc;border:0 solid;border-radius:9999px;padding:.25rem 3rem;font-family:inherit;font-size:10px;font-weight:500;line-height:1.5;transition-property:transform,background-color;transition-duration:.15s;transform:none;box-shadow:0 4px 6px -1px #0000001a,0 2px 4px -1px #0000000f}.aqvs-scroll-to-edge-button:focus{outline-offset:2px;outline:2px solid #0000}.aqvs-scroll-to-edge-button:focus-visible{outline-offset:1px;outline:2px solid #60a5fa}.aqvs-scroll-to-edge-button:hover{background-color:#374151}.aqvs-scroll-to-edge-button:active{transform:scale(.95)}.aqvs-scroll-to-edge-overlay{pointer-events:none;z-index:10;transition-property:opacity;transition-duration:.5s;position:absolute;inset:0}.aqvs-scroll-to-edge-overlay[data-visible=true]{opacity:1}.aqvs-scroll-to-edge-overlay[data-visible=false]{opacity:0}.aqvs-scroll-to-edge-overlay[data-visible=false] .aqvs-scroll-to-edge-button{pointer-events:none}.aqvs-scroll-to-edge-button-container{justify-content:center;display:flex;position:absolute;left:0;right:0}.aqvs-scroll-to-edge-button-container-top{top:.5rem}.aqvs-scroll-to-edge-button-container-bottom{bottom:.5rem}.aqvs-no-items-container{width:100%;position:absolute;top:0}.aqvs-no-items-text{text-align:center;color:#6b7280}.aqvs-item-container,.aqvs-bottom-inset,.aqvs-items-wrapper{width:100%;position:absolute}.aqvs-live-region{clip-path:inset(50%);white-space:nowrap;border:0;width:1px;height:1px;margin:-1px;padding:0;position:absolute;overflow:hidden}.aqvs-grid{grid-template-rows:minmax(0,1fr) auto;width:100%;height:100%;display:grid;position:relative;overflow:hidden}.aqvs-grid-has-frozen-rows{grid-template-rows:auto minmax(0,1fr) auto}.aqvs-grid-has-trailing-rows{grid-template-rows:minmax(0,1fr) auto auto}.aqvs-grid-has-frozen-rows.aqvs-grid-has-trailing-rows{grid-template-rows:auto minmax(0,1fr) auto auto}.aqvs-grid-frozen-rows{min-width:0;position:relative;overflow:hidden}.aqvs-grid-frozen-band-row{position:absolute;left:0;overflow:hidden}.aqvs-grid-trailing-rows{min-width:0;position:relative;overflow:hidden}.aqvs-grid-trailing-rows-inner{position:absolute;bottom:0;left:0;right:0}.aqvs-grid-trailing-band-row{position:absolute;left:0;overflow:hidden}.aqvs-grid-main{min-width:0;min-height:0;position:relative}.aqvs-grid-row{width:100%;height:100%;transform:translateX(var(--aqvs-grid-hx-residual,0px));position:relative;overflow:visible}.aqvs-grid-cell{height:100%;position:absolute;top:0;overflow:hidden}.aqvs-grid-row.aqvs-grid-row-frozen-host{transform:none}.aqvs-grid-row-scroll{height:100%;top:0;left:var(--aqvs-grid-frozen-width,0px);right:var(--aqvs-grid-trailing-width,0px);position:absolute;overflow:hidden}.aqvs-grid-row-scroll-inner{width:100%;height:100%;transform:translateX(calc(var(--aqvs-grid-hx-residual,0px) - var(--aqvs-grid-frozen-width,0px)));position:absolute;top:0;left:0}.aqvs-grid-row-trailing{height:100%;top:0;left:max(var(--aqvs-grid-frozen-width,0px), calc(100% - var(--aqvs-grid-trailing-width,0px)));position:absolute;right:0;overflow:hidden}.aqvs-grid-row-trailing-inner{height:100%;width:var(--aqvs-grid-trailing-width,0px);position:absolute;top:0;right:0}.aqvs-grid-hbar-strip{min-width:0;padding-left:var(--aqvs-grid-frozen-width,0px);position:relative}.aqvs-grid-live-region{clip:rect(0 0 0 0);white-space:nowrap;border:0;width:1px;height:1px;margin:-1px;padding:0;position:absolute;overflow:hidden}.aqvs-grid-tap-circle-wrapper{z-index:50;pointer-events:auto;position:absolute}.aqvs-grid-tap-circle{transition-property:opacity;transition-duration:.15s;transition-timing-function:cubic-bezier(.4,0,.2,1)}@media (forced-colors:active){.aqvs-tap-scroll-circle{outline-offset:-1px;border-radius:50%;outline:1px solid canvastext}}}.aqsp-root,.aqsp-root *,.aqsp-root :before,.aqsp-root :after{box-sizing:border-box}.aqsp-root{--aqsp-row-header-width:64px;--aqsp-col-header-height:24px;--aqsp-band-row:#0084ff;--aqsp-band-column:#42ff4f;--aqsp-band-intersection:#e1ff00;--aqsp-band-opacity:.2;color:#1f2937;background:#fff;width:100%;height:100%;font-size:13px;line-height:1;position:relative;overflow:hidden}.aqsp-zoom{grid-template-columns:var(--aqsp-row-header-width) minmax(0, 1fr);grid-template-rows:var(--aqsp-col-header-height) minmax(0, 1fr);transform-origin:0 0;width:100%;height:100%;display:grid}.aqsp-corner{background:#f3f4f6;border-bottom:1px solid #d1d5db;border-right:1px solid #d1d5db;grid-area:1/1}.aqsp-col-header{-webkit-user-select:none;user-select:none;background:#f3f4f6;border-bottom:1px solid #d1d5db;grid-area:1/2;position:relative;overflow:hidden}.aqsp-col-header-scroll{height:100%;position:absolute;top:0;right:0;overflow:hidden}.aqsp-row-header-scroll{width:100%;position:absolute;bottom:0;left:0;overflow:hidden}.aqsp-col-header-track{will-change:transform;position:absolute;inset:0}.aqsp-col-header-cell{white-space:nowrap;color:#4b5563;border-right:1px solid #e5e7eb;justify-content:center;align-items:center;height:100%;display:flex;position:absolute;top:0;overflow:hidden}.aqsp-row-header{-webkit-user-select:none;user-select:none;background:#f3f4f6;border-right:1px solid #d1d5db;grid-area:2/1;position:relative;overflow:hidden}.aqsp-row-header-track{will-change:transform;position:absolute;top:0;left:0;right:0}.aqsp-row-header-cell{white-space:nowrap;color:#4b5563;font-variant-numeric:tabular-nums;border-bottom:1px solid #e5e7eb;justify-content:flex-end;align-items:center;padding-right:6px;display:flex;position:absolute;left:0;right:0;overflow:hidden}.aqsp-body{position:absolute;inset:0}.aqsp-row{cursor:default}.aqsp-cell{white-space:nowrap;background:#fff;border-bottom:1px solid #e5e7eb;border-right:1px solid #e5e7eb;align-items:center;padding:0 4px;display:flex}.aqsp-cell[data-aqsp-valign=top]{align-items:flex-start}.aqsp-cell[data-aqsp-valign=bottom]{align-items:flex-end}.aqsp-cell[data-aqsp-wrap]{white-space:pre-wrap;overflow-wrap:anywhere}.aqsp-cell[data-aqsp-note]:after,.aqsp-cell[data-aqsp-comment]:after{content:"";pointer-events:none;border:5px solid #4b5563;border-color:#4b5563 #4b5563 #0000 #0000;width:0;height:0;position:absolute;top:0;right:0}.aqsp-cell[data-aqsp-comment]:after{border-top-color:#f97316;border-right-color:#f97316}.aqsp-cell[data-aqsp-invalid]:before{content:"";pointer-events:none;border:5px solid #0000;border-color:#0000 #0000 #dc2626 #dc2626;width:0;height:0;position:absolute;bottom:0;left:0}.aqsp-cell[data-aqsp-link]{color:#1d4ed8;text-decoration:underline}.aqsp-body-stack{grid-area:2/2;position:relative}.aqsp-overlay{pointer-events:none;position:absolute;inset:0;overflow:hidden}.aqsp-overlay-quad{pointer-events:none;position:absolute;overflow:hidden}.aqsp-selection-fill{mix-blend-mode:multiply;background:#3b82f62e;border:1px solid #2563ebd9;position:absolute;top:0;left:0}.aqsp-active-frame{box-sizing:border-box;border:2px solid #2563eb;position:absolute;top:0;left:0}.aqsp-drag-rect{background:#3b82f61a;border:1px solid #2563eb;position:absolute;top:0;left:0}.aqsp-drag-rect[data-aqsp-drag-mode=subtract]{background:#dc262614;border:1px dashed #dc2626}.aqsp-drag-rect[data-aqsp-drag-mode=point]{background:#16a34a14;border:1px dashed #16a34a}.aqsp-band{opacity:var(--aqsp-band-opacity);pointer-events:none;position:absolute;top:0;left:0}.aqsp-band[data-aqsp-band=row]{background:var(--aqsp-band-row)}.aqsp-band[data-aqsp-band=column]{background:var(--aqsp-band-column)}.aqsp-band[data-aqsp-band=intersection]{background:var(--aqsp-band-intersection)}.aqsp-clip-marquee{position:absolute;top:0;left:0}.aqsp-clip-marquee:after{content:"";top:var(--aqsp-clip-outset-top,-3px);right:var(--aqsp-clip-outset-right,-3px);bottom:var(--aqsp-clip-outset-bottom,-3px);left:var(--aqsp-clip-outset-left,-3px);background-image:linear-gradient(90deg,#2563eb 50%,#fff 50%),linear-gradient(90deg,#2563eb 50%,#fff 50%),linear-gradient(#fff 50%,#2563eb 50%),linear-gradient(#fff 50%,#2563eb 50%);background-position:0 0,8px 100%,0 8px,100% 0;background-repeat:repeat-x,repeat-x,repeat-y,repeat-y;background-size:8px 2px,8px 2px,2px 8px,2px 8px;animation:.4s linear infinite aqsp-marching-ants;position:absolute}@keyframes aqsp-marching-ants{to{background-position:8px 0,0 100%,0 0,100% 8px}}@media (prefers-reduced-motion:reduce){.aqsp-clip-marquee:after{animation:none}}.aqsp-col-resize-strip{cursor:col-resize;height:100%;position:absolute;top:0}.aqsp-row-resize-strip{cursor:row-resize;position:absolute;left:0;right:0}.aqsp-col-header .aqsp-unhide-marker{cursor:col-resize;opacity:.7;background:repeating-linear-gradient(90deg,#2563eb 0 1px,#0000 1px 3px);height:100%;position:absolute;top:0}.aqsp-row-header .aqsp-unhide-marker{cursor:row-resize;opacity:.7;background:repeating-linear-gradient(#2563eb 0 1px,#0000 1px 3px);position:absolute;left:0;right:0}.aqsp-resize-guide{pointer-events:none;background:#2563eb;position:absolute;top:0;left:0}.aqsp-autofill-handle{box-sizing:content-box;pointer-events:auto;cursor:crosshair;background:#2563eb;border:1px solid #fff;width:6px;height:6px;position:absolute;top:0;left:0}.aqsp-autofill-preview{border:1px dashed #16a34a;position:absolute;top:0;left:0}@media (forced-colors:active){.aqsp-band{outline-offset:-2px;background:0 0;outline:2px solid highlight}.aqsp-cell[data-aqsp-note]:after,.aqsp-cell[data-aqsp-comment]:after,.aqsp-cell[data-aqsp-invalid]:before{border:1px solid canvastext;width:6px;height:6px}.aqsp-drag-rect[data-aqsp-drag-mode=point]{background:0 0;border-color:highlight}.aqsp-selection-fill{outline-offset:-2px;background:0 0;border:none;outline:2px solid highlight}.aqsp-clip-marquee:after{background-image:none;border:2px dashed highlight;animation:none}}.aqsp-col-header-cell[data-aqsp-in-selection],.aqsp-row-header-cell[data-aqsp-in-selection]{color:#1d4ed8;background:#dbeafe;font-weight:600}.aqsp-live-region{clip-path:inset(50%);white-space:nowrap;width:1px;height:1px;margin:-1px;padding:0;position:absolute;overflow:hidden}.aqsp-sink{opacity:0;resize:none;pointer-events:auto;cursor:default;border:0;width:1px;height:1px;padding:0;position:absolute}.aqsp-sink[data-aqsp-editing]{opacity:1;z-index:1;box-sizing:border-box;color:#1f2937;caret-color:#1f2937;white-space:pre;outline-offset:-2px;cursor:text;background:#fff;outline:2px solid #2563eb;padding:0 4px;font-family:inherit;font-size:13px;line-height:1;overflow:hidden}.aqsp-sink[data-aqsp-pointing]{caret-color:#16a34a}.aqsp-popover-layer{pointer-events:none;position:absolute;inset:0;overflow:visible}.aqsp-popover-anchor{pointer-events:none;position:absolute;top:0;left:0}.aqsp-popover-anchor[inert]{visibility:hidden}.aqsp-popover{color:#1f2937;text-align:start;white-space:normal;cursor:default;pointer-events:auto;background:#fff;border:1px solid #d1d5db;border-radius:8px;flex-direction:column;width:320px;max-width:320px;font-family:system-ui,-apple-system,Segoe UI,Roboto,Helvetica Neue,Noto Sans JP,sans-serif;font-size:13px;line-height:1.4;display:flex;position:absolute;overflow:hidden;box-shadow:0 1px 2px #00000014,0 8px 24px #00000024}.aqsp-popover:focus-visible{outline-offset:-2px;outline:2px solid #2563eb}.aqsp-popover[data-aqsp-popover-frame=note-tip]{background:#fffbeb;border-color:#f59e0b;box-shadow:0 2px 8px #0000001f}.aqsp-popover-note,.aqsp-popover-comment,.aqsp-popover-link,.aqsp-popover-message{flex-direction:column;min-height:0;padding:10px 12px;display:flex}.aqsp-popover-list{flex-direction:column;min-height:0;padding:6px;display:flex}.aqsp-popover-note-tip{overscroll-behavior:contain;white-space:pre-wrap;overflow-wrap:anywhere;min-height:0;padding:8px 10px;overflow-y:auto}[data-aqsp-popover][data-aqsp-popover-rejected]{border-inline-start:3px solid #dc2626;padding-inline-start:9px}.aqsp-popover-title{color:#374151;align-items:baseline;gap:6px;margin:0 0 6px;font-size:12px;font-weight:600;display:flex}.aqsp-popover-count{color:#6b7280;font-weight:400}.aqsp-popover-textarea,.aqsp-popover-input{width:100%;color:inherit;font:inherit;background:#fff;border:1px solid #d1d5db;border-radius:6px;margin:0;padding:5px 8px;line-height:1.4;display:block}.aqsp-popover-textarea{resize:none;white-space:pre-wrap;flex:auto;height:104px;min-height:56px;overflow:auto}.aqsp-popover-comment .aqsp-popover-textarea{flex:none;height:64px}.aqsp-popover-input{flex:none;height:28px}.aqsp-popover-textarea:focus-visible,.aqsp-popover-input:focus-visible{outline-offset:-1px;border-color:#2563eb;outline:2px solid #2563eb}.aqsp-popover-textarea[aria-invalid=true],.aqsp-popover-input[aria-invalid=true]{border-color:#dc2626}.aqsp-popover-textarea[aria-invalid=true]:focus-visible,.aqsp-popover-input[aria-invalid=true]:focus-visible{border-color:#dc2626;outline-color:#dc2626}.aqsp-popover-hint{color:#6b7280;margin:4px 0 0;font-size:12px}[data-aqsp-popover-rejected] .aqsp-popover-hint{color:#b91c1c}.aqsp-popover-field{flex-direction:column;flex:none;gap:3px;margin:0 0 8px;display:flex}.aqsp-popover-field-label{color:#6b7280;font-size:12px}.aqsp-popover-actions{flex:none;align-items:center;gap:6px;margin-top:8px;display:flex}.aqsp-popover-button{color:#1f2937;min-width:56px;height:26px;font:inherit;cursor:pointer;background:#f9fafb;border:1px solid #d1d5db;border-radius:6px;justify-content:center;align-items:center;margin:0;padding:0 10px;font-size:12px;font-weight:500;line-height:1;display:inline-flex}.aqsp-popover-button:not(:disabled):hover{background:#f3f4f6;border-color:#9ca3af}.aqsp-popover-button:focus-visible{outline-offset:1px;outline:2px solid #2563eb}.aqsp-popover-button:disabled{opacity:.5;cursor:not-allowed}.aqsp-popover-button[data-aqsp-popover-save],.aqsp-popover-button[data-aqsp-popover-post]{color:#fff;background:#2563eb;border-color:#2563eb}.aqsp-popover-button[data-aqsp-popover-save]:not(:disabled):hover,.aqsp-popover-button[data-aqsp-popover-post]:not(:disabled):hover{background:#1d4ed8;border-color:#1d4ed8}.aqsp-popover-button[data-aqsp-popover-close]{color:#6b7280;background:0 0;border-color:#0000;width:26px;min-width:0;margin-inline-start:auto;padding:0;font-size:16px;font-weight:400}.aqsp-popover-button[data-aqsp-popover-close]:not(:disabled):hover{color:#1f2937;background:#f3f4f6;border-color:#0000}.aqsp-popover-thread{overscroll-behavior:contain;flex:auto;min-height:48px;max-height:220px;margin:0 0 8px;padding:0;list-style:none;overflow-y:auto}.aqsp-popover-comment-item{border-top:1px solid #f3f4f6;padding:6px 0}.aqsp-popover-comment-item:first-child{border-top:0;padding-top:0}.aqsp-popover-comment-author{color:#111827;font-size:12px;font-weight:600}.aqsp-popover-comment-time{color:#6b7280;font-variant-numeric:tabular-nums;margin-inline-start:6px;font-size:11px}.aqsp-popover-comment-text{white-space:pre-wrap;overflow-wrap:anywhere;margin:2px 0 0}.aqsp-popover-list .aqsp-popover-input{margin-bottom:4px}.aqsp-popover-options{overscroll-behavior:contain;flex:auto;min-height:0;max-height:240px;overflow-y:auto}.aqsp-popover-option{white-space:nowrap;text-overflow:ellipsis;cursor:pointer;border-radius:4px;padding:5px 8px;overflow:hidden}.aqsp-popover-option:hover{background:#f3f4f6}.aqsp-popover-option[aria-selected=true]{color:#1e3a8a;background:#dbeafe}.aqsp-popover-option:focus-visible{outline-offset:-2px;outline:2px solid #2563eb}.aqsp-popover-empty{color:#6b7280;padding:6px 8px;font-size:12px}.aqsp-popover-message{padding-inline-end:40px;position:relative}.aqsp-popover-message .aqsp-popover-title{margin-bottom:2px}.aqsp-popover-message-text{white-space:pre-wrap;overflow-wrap:anywhere;margin:0}.aqsp-popover-message .aqsp-popover-button[data-aqsp-popover-close]{position:absolute;inset-block-start:6px;inset-inline-end:6px}.aqsp-popover-message[data-aqsp-popover-rejected]{background:#fef2f2}.aqsp-popover-message[data-aqsp-popover-rejected] .aqsp-popover-title{color:#b91c1c}@media (forced-colors:active){.aqsp-popover-option:hover,.aqsp-popover-option[aria-selected=true]{outline-offset:-2px;outline:2px solid highlight}.aqsp-popover-textarea[aria-invalid=true],.aqsp-popover-input[aria-invalid=true]{border-style:dashed}.aqsp-popover-button[data-aqsp-popover-close]{border-color:buttontext}}[data-aqsp-empty]{width:100%;height:100%;display:block}.aqsp-freeze-divider{background:var(--aqsp-divider-color,#9ca3af);pointer-events:none;position:absolute}.aqsp-freeze-divider-v{width:var(--aqsp-divider-width,2px)}.aqsp-freeze-divider-h{height:var(--aqsp-divider-width,2px)}@media (forced-colors:active){.aqsp-freeze-divider{background:canvastext}}}@layer utilities;
3
+ @layer theme,base;@layer components{@layer components{.aqvs-scroll-pane{display:flex;position:relative}.aqvs-scroll-pane[data-self-measured=true],.aqvs-scroll-pane[data-aqvs-stretched-viewport=true]{height:100%}.aqvs-scroll-pane-content{box-sizing:border-box;flex:1;height:100%;position:relative;overflow:hidden}.aqvs-scroll-pane-content-overlay{box-sizing:border-box;padding:inherit;pointer-events:none;position:absolute;inset:0}.aqvs-scroll-pane-content-overlay-box{height:100%;position:relative;overflow:hidden}.aqvs-tap-scroll-circle{touch-action:none;-webkit-user-select:none;user-select:none;justify-content:center;align-items:center;transition-property:transform;transition-duration:.1s;transition-timing-function:cubic-bezier(0,0,.2,1);display:flex;position:relative}.aqvs-tap-scroll-circle-visual-outer{border-radius:9999px;position:absolute;inset:0}.aqvs-tap-scroll-circle-gradient{background:linear-gradient(to bottom right,#1d4ed899,#60a5fa8c,#bfdbfe66);border:1px solid #fff6;border-radius:9999px;position:absolute;inset:0;box-shadow:0 4px 6px -1px #0000001a,0 2px 4px -1px #0000000f}.aqvs-tap-scroll-circle-inner{border-radius:9999px;position:absolute;inset:18%}.aqvs-sample-visual-pupil{box-sizing:border-box;background-color:#ffffffd9;border:1px solid #ffffff80;border-radius:9999px;position:absolute;top:50%;left:50%}.aqvs-sample-visual-highlight{background-color:#fffc;border-radius:9999px;position:absolute;top:50%;left:50%}.aqvs-sample-visual-rod{background-color:#ffffff80;border-radius:9999px;position:absolute;top:50%;left:50%}.aqvs-scrollbar{z-index:50;cursor:default;-webkit-user-select:none;user-select:none;-webkit-tap-highlight-color:transparent;touch-action:none;background-color:#fff;position:relative}.aqvs-scrollbar-horizontal{flex-direction:row;align-items:stretch;display:flex}.aqvs-scrollbar-vertical{flex-direction:column;align-items:stretch;display:flex}.aqvs-scrollbar[data-visible=false],.aqvs-scrollbar-thumb-wrapper[data-visible=false]{opacity:0;pointer-events:none}.aqvs-scrollbar-track:focus-visible,.aqvs-scroll-pane-content:focus-visible{outline:none}.aqvs-scrollbar-track:focus-visible:after,.aqvs-scroll-pane-content:focus-visible:not([data-aqvs-active-item=visible]):after{content:"";outline:2px solid var(--aqvs-focus-ring-color,#2563eb);outline-offset:-2px;pointer-events:none;position:absolute;inset:0}.aqvs-scrollbar-tap-circle-wrapper{pointer-events:auto;transition-property:opacity;transition-duration:.15s;transition-timing-function:cubic-bezier(.4,0,.2,1);position:absolute}.aqvs-scrollbar-arrow-button{color:#313131;background-color:#e0e0e0;border:0 solid;justify-content:center;align-items:center;padding:0;transition-property:color,background-color,border-color,text-decoration-color,fill,stroke;transition-duration:.15s;transition-timing-function:cubic-bezier(.4,0,.2,1);display:flex}.aqvs-scrollbar-arrow-button:focus{outline-offset:2px;outline:2px solid #0000}.aqvs-scrollbar-arrow-button:disabled{cursor:not-allowed;opacity:.5}.aqvs-scrollbar-arrow-button:enabled:hover{background-color:#d4d4d4}.aqvs-scrollbar-arrow-button:enabled:focus-visible{color:#fff;background-color:#2563eb;outline:none}.aqvs-scrollbar-track{background-color:#f5f5f5;flex:1;position:relative}.aqvs-scrollbar-overlay{pointer-events:none;position:absolute;inset:0}.aqvs-scrollbar-thumb-wrapper{touch-action:none;position:absolute}.aqvs-scrollbar-thumb{transform-origin:50%;background-color:#7f7f7f;transition:transform 80ms ease-out;position:absolute}.aqvs-scrollbar-thumb[data-thumb-state=disabled]{transition:none;transform:none}.aqvs-scrollbar-thumb[data-thumb-state=hover]{background-color:#5f5f5f}.aqvs-scrollbar-thumb[data-thumb-state=dragging]{background-color:#4f4f4f;transition:transform 60ms ease-out}.aqvs-scrollbar-thumb-horizontal{inset:1.5px 0}.aqvs-scrollbar-thumb-horizontal[data-thumb-state=hover]{top:-.5px;bottom:-.5px;transform:scaleY(1.06)}.aqvs-scrollbar-thumb-horizontal[data-thumb-state=dragging]{top:-.5px;bottom:-.5px;transform:scaleY(1.12)}.aqvs-scrollbar-thumb-vertical{inset:0 1.5px}.aqvs-scrollbar-thumb-vertical[data-thumb-state=hover]{left:-.5px;right:-.5px;transform:scaleX(1.06)}.aqvs-scrollbar-thumb-vertical[data-thumb-state=dragging]{left:-.5px;right:-.5px;transform:scaleX(1.12)}.aqvs-scroll-to-edge-button{isolation:isolate;pointer-events:auto;cursor:pointer;-webkit-user-select:none;user-select:none;-webkit-tap-highlight-color:transparent;box-sizing:border-box;min-width:44px;min-height:44px;font-family:inherit;font-weight:500;font-size:var(--aqvs-font-size-body,.8125rem);line-height:var(--aqvs-line-height-body,1.25rem);color:#fff;text-transform:uppercase;letter-spacing:.05em;background-color:#0000;border:0 solid;justify-content:center;align-items:center;padding:12px 3rem;display:inline-flex;position:relative;transform:none}.aqvs-scroll-to-edge-button:before{content:"";z-index:-1;-webkit-backdrop-filter:blur(4px);backdrop-filter:blur(4px);background-color:#1f2937cc;border-radius:9999px;transition-property:transform,background-color;transition-duration:.15s;position:absolute;inset:8px 0;box-shadow:0 4px 6px -1px #0000001a,0 2px 4px -1px #0000000f}.aqvs-scroll-to-edge-button:focus{outline-offset:2px;outline:2px solid #0000}.aqvs-scroll-to-edge-button:focus-visible{outline:none}.aqvs-scroll-to-edge-button:focus-visible:before{outline:2px solid var(--aqvs-focus-ring-color,#2563eb);outline-offset:1px}.aqvs-scroll-to-edge-button:hover:before{background-color:#374151}.aqvs-scroll-to-edge-button:active:before{transform:scale(.95)}.aqvs-scroll-to-edge-overlay{pointer-events:none;z-index:10;transition-property:opacity;transition-duration:.5s;position:absolute;inset:0}.aqvs-scroll-to-edge-overlay[data-visible=true]{opacity:1}.aqvs-scroll-to-edge-overlay[data-visible=false]{opacity:0}.aqvs-scroll-to-edge-overlay[data-visible=false] .aqvs-scroll-to-edge-button{pointer-events:none}.aqvs-scroll-to-edge-button-container{justify-content:center;display:flex;position:absolute;left:0;right:0}.aqvs-scroll-to-edge-button-container-top{top:0}.aqvs-scroll-to-edge-button-container-bottom{bottom:0}.aqvs-no-items-container{width:100%;position:absolute;top:0}.aqvs-no-items-text{text-align:center;color:#6b7280}.aqvs-item-container,.aqvs-bottom-inset{width:100%;position:absolute}.aqvs-items-boundary{contain:size layout style;height:0;position:absolute;top:0;left:0;right:0}.aqvs-items-wrapper{width:100%;position:absolute}.aqvs-live-region{clip-path:inset(50%);white-space:nowrap;border:0;width:1px;height:1px;margin:-1px;padding:0;position:absolute;overflow:hidden}.aqvs-grid{grid-template-rows:minmax(0,1fr) auto;width:100%;height:100%;display:grid;position:relative;overflow:hidden}.aqvs-grid-has-frozen-rows{grid-template-rows:auto minmax(0,1fr) auto}.aqvs-grid-has-trailing-rows{grid-template-rows:minmax(0,1fr) auto auto}.aqvs-grid-has-frozen-rows.aqvs-grid-has-trailing-rows{grid-template-rows:auto minmax(0,1fr) auto auto}.aqvs-grid-frozen-rows{min-width:0;position:relative;overflow:hidden}.aqvs-grid-frozen-band-row{position:absolute;left:0;overflow:hidden}.aqvs-grid-trailing-rows{min-width:0;position:relative;overflow:hidden}.aqvs-grid-trailing-rows-inner{position:absolute;bottom:0;left:0;right:0}.aqvs-grid-trailing-band-row{position:absolute;left:0;overflow:hidden}.aqvs-grid-main{min-width:0;min-height:0;position:relative}.aqvs-grid-row{width:100%;height:100%;transform:translateX(var(--aqvs-grid-hx-residual,0px));position:relative;overflow:visible}.aqvs-grid-cell{height:100%;position:absolute;top:0;overflow:hidden}.aqvs-grid-row.aqvs-grid-row-frozen-host{transform:none}.aqvs-grid-row-scroll{height:100%;top:0;left:var(--aqvs-grid-frozen-width,0px);right:var(--aqvs-grid-trailing-width,0px);position:absolute;overflow:hidden}.aqvs-grid-row-scroll-inner{width:100%;height:100%;transform:translateX(calc(var(--aqvs-grid-hx-residual,0px) - var(--aqvs-grid-frozen-width,0px)));position:absolute;top:0;left:0}.aqvs-grid-row-trailing{height:100%;top:0;left:max(var(--aqvs-grid-frozen-width,0px), calc(100% - var(--aqvs-grid-trailing-width,0px)));position:absolute;right:0;overflow:hidden}.aqvs-grid-row-trailing-inner{height:100%;width:var(--aqvs-grid-trailing-width,0px);position:absolute;top:0;right:0}.aqvs-grid-hbar-strip{min-width:0;padding-left:var(--aqvs-grid-frozen-width,0px);position:relative}.aqvs-grid-live-region{clip:rect(0 0 0 0);white-space:nowrap;border:0;width:1px;height:1px;margin:-1px;padding:0;position:absolute;overflow:hidden}.aqvs-grid-tap-circle-wrapper{z-index:50;pointer-events:auto;position:absolute}.aqvs-grid-tap-circle{transition-property:opacity;transition-duration:.15s;transition-timing-function:cubic-bezier(.4,0,.2,1)}@media (forced-colors:active){.aqvs-tap-scroll-circle{outline-offset:-1px;border-radius:50%;outline:1px solid canvastext}.aqvs-scrollbar,.aqvs-scrollbar-track{outline-offset:-1px;outline:1px solid graytext}.aqvs-scrollbar-thumb{forced-color-adjust:none;background-color:canvastext}.aqvs-scrollbar-thumb[data-thumb-state=hover],.aqvs-scrollbar-thumb[data-thumb-state=dragging]{background-color:highlight}.aqvs-scrollbar-thumb[data-thumb-state=disabled]{background-color:graytext}.aqvs-scrollbar-arrow-button:enabled:focus-visible{forced-color-adjust:none;color:highlighttext;background-color:highlight}.aqvs-sample-visual-highlight,.aqvs-sample-visual-rod{forced-color-adjust:none;background-color:canvastext}.aqvs-scroll-to-edge-button:before{border:1px solid buttontext}}@media (prefers-reduced-motion:reduce){.aqvs-tap-scroll-circle,.aqvs-tap-scroll-circle *,.aqvs-grid-tap-circle,.aqvs-scrollbar-tap-circle-wrapper,.aqvs-scrollbar-arrow-button,.aqvs-scrollbar-thumb,.aqvs-scroll-to-edge-button:before,.aqvs-scroll-to-edge-overlay{transition:none!important;animation:none!important}}}.aqsp-root,.aqsp-root *,.aqsp-root :before,.aqsp-root :after{box-sizing:border-box}.aqsp-root{--aqsp-row-header-width:64px;--aqsp-col-header-height:24px;--aqsp-band-row:#0084ff;--aqsp-band-column:#42ff4f;--aqsp-band-intersection:#e1ff00;--aqsp-band-opacity:.2;color:#1f2937;background:#fff;width:100%;height:100%;font-size:13px;line-height:1;position:relative;overflow:hidden}.aqsp-zoom{grid-template-columns:var(--aqsp-row-header-width) minmax(0, 1fr);grid-template-rows:var(--aqsp-col-header-height) minmax(0, 1fr);transform-origin:0 0;width:100%;height:100%;display:grid}.aqsp-corner{background:#f3f4f6;border-bottom:1px solid #d1d5db;border-right:1px solid #d1d5db;grid-area:1/1}.aqsp-col-header{-webkit-user-select:none;user-select:none;background:#f3f4f6;border-bottom:1px solid #d1d5db;grid-area:1/2;position:relative;overflow:hidden}.aqsp-col-header-scroll{height:100%;position:absolute;top:0;right:0;overflow:hidden}.aqsp-row-header-scroll{width:100%;position:absolute;bottom:0;left:0;overflow:hidden}.aqsp-col-header-track{will-change:transform;position:absolute;inset:0}.aqsp-col-header-cell{white-space:nowrap;color:#4b5563;border-right:1px solid #e5e7eb;justify-content:center;align-items:center;height:100%;display:flex;position:absolute;top:0;overflow:hidden}.aqsp-row-header{-webkit-user-select:none;user-select:none;background:#f3f4f6;border-right:1px solid #d1d5db;grid-area:2/1;position:relative;overflow:hidden}.aqsp-row-header-track{will-change:transform;position:absolute;top:0;left:0;right:0}.aqsp-row-header-cell{white-space:nowrap;color:#4b5563;font-variant-numeric:tabular-nums;border-bottom:1px solid #e5e7eb;justify-content:flex-end;align-items:center;padding-right:6px;display:flex;position:absolute;left:0;right:0;overflow:hidden}.aqsp-body{position:absolute;inset:0}.aqsp-row{cursor:default}.aqsp-cell{white-space:nowrap;background:#fff;border-bottom:1px solid #e5e7eb;border-right:1px solid #e5e7eb;align-items:center;padding:0 4px;display:flex}.aqsp-cell[data-aqsp-valign=top]{align-items:flex-start}.aqsp-cell[data-aqsp-valign=bottom]{align-items:flex-end}.aqsp-cell[data-aqsp-wrap]{white-space:pre-wrap;overflow-wrap:anywhere}.aqsp-cell[data-aqsp-note]:after,.aqsp-cell[data-aqsp-comment]:after{content:"";pointer-events:none;border:5px solid #4b5563;border-color:#4b5563 #4b5563 #0000 #0000;width:0;height:0;position:absolute;top:0;right:0}.aqsp-cell[data-aqsp-comment]:after{border-top-color:#f97316;border-right-color:#f97316}.aqsp-cell[data-aqsp-invalid]:before{content:"";pointer-events:none;border:5px solid #0000;border-color:#0000 #0000 #dc2626 #dc2626;width:0;height:0;position:absolute;bottom:0;left:0}.aqsp-cell[data-aqsp-link]{color:#1d4ed8;text-decoration:underline}.aqsp-body-stack{grid-area:2/2;position:relative}.aqsp-overlay{pointer-events:none;position:absolute;inset:0;overflow:hidden}.aqsp-overlay-quad{pointer-events:none;position:absolute;overflow:hidden}.aqsp-selection-fill{mix-blend-mode:multiply;background:#3b82f62e;border:1px solid #2563ebd9;position:absolute;top:0;left:0}.aqsp-active-frame{box-sizing:border-box;border:2px solid #2563eb;position:absolute;top:0;left:0}.aqsp-drag-rect{background:#3b82f61a;border:1px solid #2563eb;position:absolute;top:0;left:0}.aqsp-drag-rect[data-aqsp-drag-mode=subtract]{background:#dc262614;border:1px dashed #dc2626}.aqsp-drag-rect[data-aqsp-drag-mode=point]{background:#16a34a14;border:1px dashed #16a34a}.aqsp-band{opacity:var(--aqsp-band-opacity);pointer-events:none;position:absolute;top:0;left:0}.aqsp-band[data-aqsp-band=row]{background:var(--aqsp-band-row)}.aqsp-band[data-aqsp-band=column]{background:var(--aqsp-band-column)}.aqsp-band[data-aqsp-band=intersection]{background:var(--aqsp-band-intersection)}.aqsp-clip-marquee{position:absolute;top:0;left:0}.aqsp-clip-marquee:after{content:"";top:var(--aqsp-clip-outset-top,-3px);right:var(--aqsp-clip-outset-right,-3px);bottom:var(--aqsp-clip-outset-bottom,-3px);left:var(--aqsp-clip-outset-left,-3px);background-image:linear-gradient(90deg,#2563eb 50%,#fff 50%),linear-gradient(90deg,#2563eb 50%,#fff 50%),linear-gradient(#fff 50%,#2563eb 50%),linear-gradient(#fff 50%,#2563eb 50%);background-position:0 0,8px 100%,0 8px,100% 0;background-repeat:repeat-x,repeat-x,repeat-y,repeat-y;background-size:8px 2px,8px 2px,2px 8px,2px 8px;animation:.4s linear infinite aqsp-marching-ants;position:absolute}@keyframes aqsp-marching-ants{to{background-position:8px 0,0 100%,0 0,100% 8px}}@media (prefers-reduced-motion:reduce){.aqsp-clip-marquee:after{animation:none}}.aqsp-col-resize-strip{cursor:col-resize;height:100%;position:absolute;top:0}.aqsp-row-resize-strip{cursor:row-resize;position:absolute;left:0;right:0}.aqsp-col-header .aqsp-unhide-marker{cursor:col-resize;opacity:.7;background:repeating-linear-gradient(90deg,#2563eb 0 1px,#0000 1px 3px);height:100%;position:absolute;top:0}.aqsp-row-header .aqsp-unhide-marker{cursor:row-resize;opacity:.7;background:repeating-linear-gradient(#2563eb 0 1px,#0000 1px 3px);position:absolute;left:0;right:0}.aqsp-resize-guide{pointer-events:none;background:#2563eb;position:absolute;top:0;left:0}.aqsp-autofill-handle{box-sizing:content-box;pointer-events:auto;cursor:crosshair;background:#2563eb;border:1px solid #fff;width:6px;height:6px;position:absolute;top:0;left:0}.aqsp-autofill-preview{border:1px dashed #16a34a;position:absolute;top:0;left:0}@media (forced-colors:active){.aqsp-band{outline-offset:-2px;background:0 0;outline:2px solid highlight}.aqsp-cell[data-aqsp-note]:after,.aqsp-cell[data-aqsp-comment]:after,.aqsp-cell[data-aqsp-invalid]:before{border:1px solid canvastext;width:6px;height:6px}.aqsp-drag-rect[data-aqsp-drag-mode=point]{background:0 0;border-color:highlight}.aqsp-selection-fill{outline-offset:-2px;background:0 0;border:none;outline:2px solid highlight}.aqsp-clip-marquee:after{background-image:none;border:2px dashed highlight;animation:none}}.aqsp-col-header-cell[data-aqsp-in-selection],.aqsp-row-header-cell[data-aqsp-in-selection]{color:#1d4ed8;background:#dbeafe;font-weight:600}.aqsp-live-region{clip-path:inset(50%);white-space:nowrap;width:1px;height:1px;margin:-1px;padding:0;position:absolute;overflow:hidden}.aqsp-sink{opacity:0;resize:none;pointer-events:auto;cursor:default;border:0;width:1px;height:1px;padding:0;position:absolute}.aqsp-sink[data-aqsp-editing]{opacity:1;z-index:1;box-sizing:border-box;color:#1f2937;caret-color:#1f2937;white-space:pre;outline-offset:-2px;cursor:text;background:#fff;outline:2px solid #2563eb;padding:0 4px;font-family:inherit;font-size:13px;line-height:1;overflow:hidden}.aqsp-sink[data-aqsp-pointing]{caret-color:#16a34a}.aqsp-popover-layer{pointer-events:none;position:absolute;inset:0;overflow:visible}.aqsp-popover-anchor{pointer-events:none;position:absolute;top:0;left:0}.aqsp-popover-anchor[inert]{visibility:hidden}.aqsp-popover{color:#1f2937;text-align:start;white-space:normal;cursor:default;pointer-events:auto;background:#fff;border:1px solid #d1d5db;border-radius:8px;flex-direction:column;width:320px;max-width:320px;font-family:system-ui,-apple-system,Segoe UI,Roboto,Helvetica Neue,Noto Sans JP,sans-serif;font-size:13px;line-height:1.4;display:flex;position:absolute;overflow:hidden;box-shadow:0 1px 2px #00000014,0 8px 24px #00000024}.aqsp-popover:focus-visible{outline-offset:-2px;outline:2px solid #2563eb}.aqsp-popover[data-aqsp-popover-frame=note-tip]{background:#fffbeb;border-color:#f59e0b;box-shadow:0 2px 8px #0000001f}.aqsp-popover-note,.aqsp-popover-comment,.aqsp-popover-link,.aqsp-popover-message{flex-direction:column;min-height:0;padding:10px 12px;display:flex}.aqsp-popover-list{flex-direction:column;min-height:0;padding:6px;display:flex}.aqsp-popover-note-tip{overscroll-behavior:contain;white-space:pre-wrap;overflow-wrap:anywhere;min-height:0;padding:8px 10px;overflow-y:auto}[data-aqsp-popover][data-aqsp-popover-rejected]{border-inline-start:3px solid #dc2626;padding-inline-start:9px}.aqsp-popover-title{color:#374151;align-items:baseline;gap:6px;margin:0 0 6px;font-size:12px;font-weight:600;display:flex}.aqsp-popover-count{color:#6b7280;font-weight:400}.aqsp-popover-textarea,.aqsp-popover-input{width:100%;color:inherit;font:inherit;background:#fff;border:1px solid #d1d5db;border-radius:6px;margin:0;padding:5px 8px;line-height:1.4;display:block}.aqsp-popover-textarea{resize:none;white-space:pre-wrap;flex:auto;height:104px;min-height:56px;overflow:auto}.aqsp-popover-comment .aqsp-popover-textarea{flex:none;height:64px}.aqsp-popover-input{flex:none;height:28px}.aqsp-popover-textarea:focus-visible,.aqsp-popover-input:focus-visible{outline-offset:-1px;border-color:#2563eb;outline:2px solid #2563eb}.aqsp-popover-textarea[aria-invalid=true],.aqsp-popover-input[aria-invalid=true]{border-color:#dc2626}.aqsp-popover-textarea[aria-invalid=true]:focus-visible,.aqsp-popover-input[aria-invalid=true]:focus-visible{border-color:#dc2626;outline-color:#dc2626}.aqsp-popover-hint{color:#6b7280;margin:4px 0 0;font-size:12px}[data-aqsp-popover-rejected] .aqsp-popover-hint{color:#b91c1c}.aqsp-popover-field{flex-direction:column;flex:none;gap:3px;margin:0 0 8px;display:flex}.aqsp-popover-field-label{color:#6b7280;font-size:12px}.aqsp-popover-actions{flex:none;align-items:center;gap:6px;margin-top:8px;display:flex}.aqsp-popover-button{color:#1f2937;min-width:56px;height:26px;font:inherit;cursor:pointer;background:#f9fafb;border:1px solid #d1d5db;border-radius:6px;justify-content:center;align-items:center;margin:0;padding:0 10px;font-size:12px;font-weight:500;line-height:1;display:inline-flex}.aqsp-popover-button:not(:disabled):hover{background:#f3f4f6;border-color:#9ca3af}.aqsp-popover-button:focus-visible{outline-offset:1px;outline:2px solid #2563eb}.aqsp-popover-button:disabled{opacity:.5;cursor:not-allowed}.aqsp-popover-button[data-aqsp-popover-save],.aqsp-popover-button[data-aqsp-popover-post]{color:#fff;background:#2563eb;border-color:#2563eb}.aqsp-popover-button[data-aqsp-popover-save]:not(:disabled):hover,.aqsp-popover-button[data-aqsp-popover-post]:not(:disabled):hover{background:#1d4ed8;border-color:#1d4ed8}.aqsp-popover-button[data-aqsp-popover-close]{color:#6b7280;background:0 0;border-color:#0000;width:26px;min-width:0;margin-inline-start:auto;padding:0;font-size:16px;font-weight:400}.aqsp-popover-button[data-aqsp-popover-close]:not(:disabled):hover{color:#1f2937;background:#f3f4f6;border-color:#0000}.aqsp-popover-thread{overscroll-behavior:contain;flex:auto;min-height:48px;max-height:220px;margin:0 0 8px;padding:0;list-style:none;overflow-y:auto}.aqsp-popover-comment-item{border-top:1px solid #f3f4f6;padding:6px 0}.aqsp-popover-comment-item:first-child{border-top:0;padding-top:0}.aqsp-popover-comment-author{color:#111827;font-size:12px;font-weight:600}.aqsp-popover-comment-time{color:#6b7280;font-variant-numeric:tabular-nums;margin-inline-start:6px;font-size:11px}.aqsp-popover-comment-text{white-space:pre-wrap;overflow-wrap:anywhere;margin:2px 0 0}.aqsp-popover-list .aqsp-popover-input{margin-bottom:4px}.aqsp-popover-options{overscroll-behavior:contain;flex:auto;min-height:0;max-height:240px;overflow-y:auto}.aqsp-popover-option{white-space:nowrap;text-overflow:ellipsis;cursor:pointer;border-radius:4px;padding:5px 8px;overflow:hidden}.aqsp-popover-option:hover{background:#f3f4f6}.aqsp-popover-option[aria-selected=true]{color:#1e3a8a;background:#dbeafe}.aqsp-popover-option:focus-visible{outline-offset:-2px;outline:2px solid #2563eb}.aqsp-popover-empty{color:#6b7280;padding:6px 8px;font-size:12px}.aqsp-popover-message{padding-inline-end:40px;position:relative}.aqsp-popover-message .aqsp-popover-title{margin-bottom:2px}.aqsp-popover-message-text{white-space:pre-wrap;overflow-wrap:anywhere;margin:0}.aqsp-popover-message .aqsp-popover-button[data-aqsp-popover-close]{position:absolute;inset-block-start:6px;inset-inline-end:6px}.aqsp-popover-message[data-aqsp-popover-rejected]{background:#fef2f2}.aqsp-popover-message[data-aqsp-popover-rejected] .aqsp-popover-title{color:#b91c1c}@media (forced-colors:active){.aqsp-popover-option:hover,.aqsp-popover-option[aria-selected=true]{outline-offset:-2px;outline:2px solid highlight}.aqsp-popover-textarea[aria-invalid=true],.aqsp-popover-input[aria-invalid=true]{border-style:dashed}.aqsp-popover-button[data-aqsp-popover-close]{border-color:buttontext}}[data-aqsp-empty]{width:100%;height:100%;display:block}.aqsp-freeze-divider{background:var(--aqsp-divider-color,#9ca3af);pointer-events:none;position:absolute}.aqsp-freeze-divider-v{width:var(--aqsp-divider-width,2px)}.aqsp-freeze-divider-h{height:var(--aqsp-divider-width,2px)}@media (forced-colors:active){.aqsp-freeze-divider{background:canvastext}}}@layer utilities;
package/dist/view.cjs ADDED
@@ -0,0 +1 @@
1
+ "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const _=24,o=64,R=12,e=.25,t=4,H=E=>{if(!Number.isFinite(E))throw new RangeError(`[spreadsheet] zoom must be a finite number (got ${E})`);return Math.min(t,Math.max(e,E))},s=(E,S)=>S>0?(Math.floor(E*10+1e-6)+1)/10:(Math.ceil(E*10-1e-6)-1)/10;exports.SPREADSHEET_COLUMN_HEADER_HEIGHT_PX=_;exports.SPREADSHEET_ROW_HEADER_WIDTH_PX=o;exports.SPREADSHEET_SCROLLBAR_SIZE_PX=R;exports.SPREADSHEET_ZOOM_MAX=t;exports.SPREADSHEET_ZOOM_MIN=e;exports.clampSpreadsheetZoom=H;exports.stepSpreadsheetZoom=s;
@@ -0,0 +1,49 @@
1
+ /**
2
+ * Clamps a zoom into [SPREADSHEET_ZOOM_MIN, SPREADSHEET_ZOOM_MAX] without quantizing it, so a host may set any value
3
+ * such as 1.25; the gestures quantize their own arithmetic before they request a zoom. A non-finite value (NaN or
4
+ * ±Infinity) fails fast: Math.min and Math.max would pass NaN through every division by the zoom and defeat the grid's
5
+ * same-value bail.
6
+ * 拡大率を [下限, 上限] へ切る処理。量子化しないため、ホストは 1.25 などどの値でも置ける (操作は求める前に自分の計算で刻む)。
7
+ * 有限でない値 (NaN・±Infinity) はすぐに投げる (Math.min と Math.max は NaN を素通しし、拡大率で割る所をすべて汚し、同じ値なら
8
+ * 何もしないグリッドの判定も効かなくなるため)。
9
+ *
10
+ * @param value - The requested zoom. 求める拡大率。
11
+ * @returns The clamped zoom. 切った拡大率。
12
+ * @throws {RangeError} When the value is not finite. 有限でない場合。
13
+ */
14
+ export declare const clampSpreadsheetZoom: (value: number) => number;
15
+
16
+ /** The height of the column-header band in CSS px (`--aqsp-col-header-height` in the stylesheet). 列見出しの帯の高さ (CSS px。スタイルシートの `--aqsp-col-header-height`)。 */
17
+ export declare const SPREADSHEET_COLUMN_HEADER_HEIGHT_PX = 24;
18
+
19
+ /** The width of the row-header band in CSS px (`--aqsp-row-header-width` in the stylesheet). 行見出しの帯の幅 (CSS px。スタイルシートの `--aqsp-row-header-width`)。 */
20
+ export declare const SPREADSHEET_ROW_HEADER_WIDTH_PX = 64;
21
+
22
+ /**
23
+ * The thickness of each scroll bar the grid always reserves, in CSS px: the vertical bar's width and the horizontal
24
+ * bar's height, both reserved whether or not the grid scrolls.
25
+ * グリッドが常に取っておくスクロールバーの太さ (CSS px)。縦のバーの幅と横のバーの高さで、スクロールしなくても両方を取る。
26
+ */
27
+ export declare const SPREADSHEET_SCROLLBAR_SIZE_PX = 12;
28
+
29
+ /** The largest package zoom. パッケージの拡大率の上限。 */
30
+ export declare const SPREADSHEET_ZOOM_MAX = 4;
31
+
32
+ /** The smallest package zoom. パッケージの拡大率の下限。 */
33
+ export declare const SPREADSHEET_ZOOM_MIN = 0.25;
34
+
35
+ /**
36
+ * The 0.1-grid step of the zoom gestures (Alt+Wheel and Ctrl+Alt+= / -), unclamped and free of float drift. From an
37
+ * off-grid value (the 0.25 bound or a host's 1.25) the step lands on the nearest detent in the travel direction (0.25
38
+ * goes to 0.3 up and 0.2 down); rounding would skip a detent (0.25 to 0.4). Clamp the result with clampSpreadsheetZoom.
39
+ * 拡大縮小の操作 (Alt+ホイールと Ctrl+Alt+= / -) の 0.1 刻み (範囲で切らず、浮動小数のずれを持ち込まない)。刻みの外の値
40
+ * (下限の 0.25 やホストの 1.25) からは、進む向きの最寄りの刻みへ着く (0.25 から上は 0.3、下は 0.2)。丸めると刻みを飛ばす
41
+ * (0.25 から 0.4) ため使わない。結果は clampSpreadsheetZoom で切る。
42
+ *
43
+ * @param value - The current zoom. 今の拡大率。
44
+ * @param direction - 1 to zoom in, -1 to zoom out. 拡大は 1、縮小は -1。
45
+ * @returns The next detent in that direction. その向きの次の刻み。
46
+ */
47
+ export declare const stepSpreadsheetZoom: (value: number, direction: 1 | -1) => number;
48
+
49
+ export { }
package/dist/view.d.ts ADDED
@@ -0,0 +1,49 @@
1
+ /**
2
+ * Clamps a zoom into [SPREADSHEET_ZOOM_MIN, SPREADSHEET_ZOOM_MAX] without quantizing it, so a host may set any value
3
+ * such as 1.25; the gestures quantize their own arithmetic before they request a zoom. A non-finite value (NaN or
4
+ * ±Infinity) fails fast: Math.min and Math.max would pass NaN through every division by the zoom and defeat the grid's
5
+ * same-value bail.
6
+ * 拡大率を [下限, 上限] へ切る処理。量子化しないため、ホストは 1.25 などどの値でも置ける (操作は求める前に自分の計算で刻む)。
7
+ * 有限でない値 (NaN・±Infinity) はすぐに投げる (Math.min と Math.max は NaN を素通しし、拡大率で割る所をすべて汚し、同じ値なら
8
+ * 何もしないグリッドの判定も効かなくなるため)。
9
+ *
10
+ * @param value - The requested zoom. 求める拡大率。
11
+ * @returns The clamped zoom. 切った拡大率。
12
+ * @throws {RangeError} When the value is not finite. 有限でない場合。
13
+ */
14
+ export declare const clampSpreadsheetZoom: (value: number) => number;
15
+
16
+ /** The height of the column-header band in CSS px (`--aqsp-col-header-height` in the stylesheet). 列見出しの帯の高さ (CSS px。スタイルシートの `--aqsp-col-header-height`)。 */
17
+ export declare const SPREADSHEET_COLUMN_HEADER_HEIGHT_PX = 24;
18
+
19
+ /** The width of the row-header band in CSS px (`--aqsp-row-header-width` in the stylesheet). 行見出しの帯の幅 (CSS px。スタイルシートの `--aqsp-row-header-width`)。 */
20
+ export declare const SPREADSHEET_ROW_HEADER_WIDTH_PX = 64;
21
+
22
+ /**
23
+ * The thickness of each scroll bar the grid always reserves, in CSS px: the vertical bar's width and the horizontal
24
+ * bar's height, both reserved whether or not the grid scrolls.
25
+ * グリッドが常に取っておくスクロールバーの太さ (CSS px)。縦のバーの幅と横のバーの高さで、スクロールしなくても両方を取る。
26
+ */
27
+ export declare const SPREADSHEET_SCROLLBAR_SIZE_PX = 12;
28
+
29
+ /** The largest package zoom. パッケージの拡大率の上限。 */
30
+ export declare const SPREADSHEET_ZOOM_MAX = 4;
31
+
32
+ /** The smallest package zoom. パッケージの拡大率の下限。 */
33
+ export declare const SPREADSHEET_ZOOM_MIN = 0.25;
34
+
35
+ /**
36
+ * The 0.1-grid step of the zoom gestures (Alt+Wheel and Ctrl+Alt+= / -), unclamped and free of float drift. From an
37
+ * off-grid value (the 0.25 bound or a host's 1.25) the step lands on the nearest detent in the travel direction (0.25
38
+ * goes to 0.3 up and 0.2 down); rounding would skip a detent (0.25 to 0.4). Clamp the result with clampSpreadsheetZoom.
39
+ * 拡大縮小の操作 (Alt+ホイールと Ctrl+Alt+= / -) の 0.1 刻み (範囲で切らず、浮動小数のずれを持ち込まない)。刻みの外の値
40
+ * (下限の 0.25 やホストの 1.25) からは、進む向きの最寄りの刻みへ着く (0.25 から上は 0.3、下は 0.2)。丸めると刻みを飛ばす
41
+ * (0.25 から 0.4) ため使わない。結果は clampSpreadsheetZoom で切る。
42
+ *
43
+ * @param value - The current zoom. 今の拡大率。
44
+ * @param direction - 1 to zoom in, -1 to zoom out. 拡大は 1、縮小は -1。
45
+ * @returns The next detent in that direction. その向きの次の刻み。
46
+ */
47
+ export declare const stepSpreadsheetZoom: (value: number, direction: 1 | -1) => number;
48
+
49
+ export { }
package/dist/view.js ADDED
@@ -0,0 +1,14 @@
1
+ const e = 24, o = 64, _ = 12, S = 0.25, n = 4, s = (E) => {
2
+ if (!Number.isFinite(E))
3
+ throw new RangeError(`[spreadsheet] zoom must be a finite number (got ${E})`);
4
+ return Math.min(4, Math.max(0.25, E));
5
+ }, r = (E, t) => t > 0 ? (Math.floor(E * 10 + 1e-6) + 1) / 10 : (Math.ceil(E * 10 - 1e-6) - 1) / 10;
6
+ export {
7
+ e as SPREADSHEET_COLUMN_HEADER_HEIGHT_PX,
8
+ o as SPREADSHEET_ROW_HEADER_WIDTH_PX,
9
+ _ as SPREADSHEET_SCROLLBAR_SIZE_PX,
10
+ n as SPREADSHEET_ZOOM_MAX,
11
+ S as SPREADSHEET_ZOOM_MIN,
12
+ s as clampSpreadsheetZoom,
13
+ r as stepSpreadsheetZoom
14
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aiquants/spreadsheet",
3
- "version": "0.13.0",
3
+ "version": "0.14.0",
4
4
  "description": "Excel-grade spreadsheet grid for React: multi-cell selection, TSV/HTML clipboard, in-place editing on top of @aiquants/virtualscroll",
5
5
  "sideEffects": [
6
6
  "**/*.css"
@@ -21,6 +21,17 @@
21
21
  },
22
22
  "default": "./dist/index.js"
23
23
  },
24
+ "./view": {
25
+ "import": {
26
+ "types": "./dist/view.d.ts",
27
+ "default": "./dist/view.js"
28
+ },
29
+ "require": {
30
+ "types": "./dist/view.d.cts",
31
+ "default": "./dist/view.cjs"
32
+ },
33
+ "default": "./dist/view.js"
34
+ },
24
35
  "./styles/spreadsheet.css": "./dist/styles/spreadsheet.css",
25
36
  "./styles/spreadsheet.standalone.css": "./dist/styles/spreadsheet.standalone.css"
26
37
  },
@@ -34,12 +45,12 @@
34
45
  "LICENSE.md"
35
46
  ],
36
47
  "peerDependencies": {
37
- "@aiquants/virtualscroll": "^3.7.0",
48
+ "@aiquants/virtualscroll": "^3.22.0",
38
49
  "react": "^19.2.7",
39
50
  "react-dom": "^19.2.7"
40
51
  },
41
52
  "devDependencies": {
42
- "@aiquants/virtualscroll": "3.7.0",
53
+ "@aiquants/virtualscroll": "3.22.0",
43
54
  "@playwright/test": "^1.59.1",
44
55
  "@tailwindcss/cli": "^4.1.18",
45
56
  "@testing-library/jest-dom": "^6.9.1",
@@ -76,7 +87,9 @@
76
87
  "access": "public"
77
88
  },
78
89
  "scripts": {
79
- "build": "rimraf dist && vite build && pnpm build:css && pnpm build:cts",
90
+ "build": "pnpm -w run workspace:build \"$PNPM_SCRIPT_SRC_DIR\"",
91
+ "prebuild:self": "pnpm -w run workspace:sync \"$PNPM_SCRIPT_SRC_DIR\"",
92
+ "build:self": "rimraf dist && vite build && pnpm build:css && pnpm build:cts",
80
93
  "build:css": "tailwindcss -i src/styles/components.entry.css -o dist/styles/spreadsheet.css --minify && tailwindcss -i src/styles/standalone.entry.css -o dist/styles/spreadsheet.standalone.css --minify",
81
94
  "build:cts": "node -e \"const fs=require('node:fs');const re=/(from\\s+')(\\.{1,2}\\/[^']+)\\.(?:tsx|ts)(')/g;for(const f of fs.readdirSync('dist')){if(!f.endsWith('.d.ts'))continue;const s=fs.readFileSync('dist/'+f,'utf8').replace(re,(_m,p,spec,q)=>p+spec+'.cjs'+q).replace(/^\\/\\/# sourceMappingURL=.*(\\r?\\n)?/gm,'');fs.writeFileSync('dist/'+f.slice(0,-5)+'.d.cts',s)}\"",
82
95
  "typecheck": "tsc --noEmit",
@@ -87,8 +100,8 @@
87
100
  "test:e2e": "playwright test",
88
101
  "lint": "biome check src tests demo/src",
89
102
  "clean": "rimraf dist",
90
- "publish:patch": "pnpm run typecheck && pnpm run --if-present test && pnpm version patch --no-git-tag-version --no-git-checks && pnpm publish --no-git-checks",
91
- "publish:minor": "pnpm run typecheck && pnpm run --if-present test && pnpm version minor --no-git-tag-version --no-git-checks && pnpm publish --no-git-checks",
92
- "publish:major": "pnpm run typecheck && pnpm run --if-present test && pnpm version major --no-git-tag-version --no-git-checks && pnpm publish --no-git-checks"
103
+ "publish:patch": "pnpm run typecheck && pnpm run --if-present test && pnpm run build && node ../../.config/scripts/check-publish-leaks.mjs && pnpm version patch --no-git-tag-version --no-git-checks && pnpm publish --no-git-checks",
104
+ "publish:minor": "pnpm run typecheck && pnpm run --if-present test && pnpm run build && node ../../.config/scripts/check-publish-leaks.mjs && pnpm version minor --no-git-tag-version --no-git-checks && pnpm publish --no-git-checks",
105
+ "publish:major": "pnpm run typecheck && pnpm run --if-present test && pnpm run build && node ../../.config/scripts/check-publish-leaks.mjs && pnpm version major --no-git-tag-version --no-git-checks && pnpm publish --no-git-checks"
93
106
  }
94
107
  }
@@ -85,6 +85,7 @@ import { clampSelectionToGrid, reduceActiveCycle, reduceSelectionExtend, reduceS
85
85
  import { useAutoScroller } from "./selection/useAutoScroller.ts"
86
86
  import { type PointDragOwner, usePointDrag } from "./selection/usePointDrag.ts"
87
87
  import { useSelectionEngine } from "./selection/useSelectionEngine.ts"
88
+ import { clampSpreadsheetZoom, stepSpreadsheetZoom } from "./view.ts"
88
89
 
89
90
  export type { SelectionState } from "./selection/selectionState.ts"
90
91
 
@@ -460,14 +461,14 @@ export type SpreadsheetProps = {
460
461
  locale?: SpreadsheetLocale
461
462
  /**
462
463
  * UI label vocabulary (v0.8 §1.6) — folds the former `sinkAriaLabel` / `rootAriaLabel` props
463
- * (clean cut-over). 28 keys = the 7 engine chrome keys (scrollUp / scrollDown / scrollLeft /
464
- * scrollRight / scrollToTop / scrollToBottom / noItems) + 21 own keys. An omitted prop or an
465
- * explicitly `undefined` key keeps the value of the `locale` catalog. An unknown key or an
466
- * empty / blank value throws a RangeError during render, and the resolved `sinkAriaLabel` MUST
467
- * mention "Escape" (WCAG 2.1.2 escape advisement, §10-4).
464
+ * (clean cut-over). Keys = every engine chrome key of `@aiquants/virtualscroll`
465
+ * (`VIRTUAL_SCROLL_LABEL_KEYS`, e.g. scrollUp / scrollToTop / noItems) + 21 own keys. An omitted
466
+ * prop or an explicitly `undefined` key keeps the value of the `locale` catalog. An unknown key
467
+ * or an empty / blank value throws a RangeError during render, and the resolved `sinkAriaLabel`
468
+ * MUST mention "Escape" (WCAG 2.1.2 escape advisement, §10-4).
468
469
  * UI ラベル語彙 (v0.8 §1.6) — 旧 sinkAriaLabel / rootAriaLabel prop を畳込み (クリーンカットオーバー)。
469
- * 28 キー = エンジンクローム 7 キー (scrollUp / scrollDown / scrollLeft / scrollRight / scrollToTop /
470
- * scrollToBottom / noItems) + 固有 21 キー。prop 省略 / 明示 undefined のキーは `locale` のカタログ値。
470
+ * キー = `@aiquants/virtualscroll` のエンジンクロームキー全件 (`VIRTUAL_SCROLL_LABEL_KEYS` — scrollUp /
471
+ * scrollToTop / noItems など) + 固有 21 キー。prop 省略 / 明示 undefined のキーは `locale` のカタログ値。
471
472
  * 未知キー・空 / 空白値は render 中 RangeError、解決後の sinkAriaLabel は "Escape" を含むこと (§10-4)。
472
473
  */
473
474
  labels?: SpreadsheetLabelOverrides
@@ -476,7 +477,7 @@ export type SpreadsheetProps = {
476
477
  * list, `null` unbinds it. Validated at prop time — a non-canonical chord, a modifier-less
477
478
  * chord, a single string, an override of a non-rebindable row (`pasteSpecial`), a clash with
478
479
  * a non-rebindable built-in row in the command's column, or one chord bound to two commands
479
- * throws a RangeError during render (`clampZoom` precedent). Consulted through a ref.
480
+ * throws a RangeError during render (`clampSpreadsheetZoom` precedent). Consulted through a ref.
480
481
  * 再バインド可能なコマンドチョード (v0.8 §1.9 / ADR-17)。配列は既定一覧の置換、null は未束縛。
481
482
  * prop 時検証 (非正準 / 修飾なし / 単一 string / 非再バインド行の上書き / 列内予約行との一致 /
482
483
  * 二重束縛は render 中 RangeError)。ref 経由で参照。
@@ -572,37 +573,6 @@ export type SpreadsheetProps = {
572
573
  className?: string
573
574
  }
574
575
 
575
- /** Zoom clamp bounds (v0.3) — the 0.1 gesture grid lives in stepZoom's ×10 integer arithmetic. / ズームの clamp 境界 (v0.3) — ジェスチャの 0.1 グリッドは stepZoom の ×10 整数算術側。 */
576
- const ZOOM_MIN = 0.25
577
- const ZOOM_MAX = 4
578
-
579
- /**
580
- * Pure clamp — NO quantization (a 0.25 bound is not 0.1-quantizable; consumers may set any
581
- * value like 1.25). Gestures quantize their own arithmetic before requesting. Non-finite
582
- * input (NaN / ±Infinity) fail-fasts: Math.min/max would propagate NaN through every ÷z
583
- * boundary and defeat the same-value gesture bail (unsuppressed onZoomChange(NaN) spam).
584
- * 純 clamp — 量子化しない (境界 0.25 は 0.1 量子化不能。consumer は 1.25 等の任意値を設定
585
- * できる)。量子化はジェスチャ側が要求前に自分の加算へ適用する。非有限値 (NaN / ±Infinity) は
586
- * fail-fast — Math.min/max は NaN を素通しし、全 ÷z 境界の汚染と同値バウンド無効化 (NaN 同士は
587
- * 不一致) による onZoomChange(NaN) 連射を招くため。
588
- */
589
- const clampZoom = (value: number): number => {
590
- if (!Number.isFinite(value)) {
591
- throw new RangeError(`[spreadsheet] zoom must be a finite number (got ${value})`)
592
- }
593
- return Math.min(ZOOM_MAX, Math.max(ZOOM_MIN, value))
594
- }
595
-
596
- /**
597
- * 0.1-grid gesture step (float-drift-free). From an off-grid value (the 0.25 clamp bound or
598
- * a controlled 1.25) the step lands on the NEAREST detent in the travel direction (0.25 →
599
- * 0.3 / 0.2) — round-based arithmetic skipped a detent (0.25 → 0.4).
600
- * ジェスチャの 0.1 グリッド刻み (float ドリフト遮断)。グリッド外の値 (clamp 境界 0.25 や制御
601
- * 1.25) からは進行方向の最寄りデテントへ着地 (0.25 → 0.3 / 0.2) — 丸め方式はデテントを飛ばす
602
- * (0.25 → 0.4) ため採らない。
603
- */
604
- const stepZoom = (value: number, direction: 1 | -1): number => (direction > 0 ? (Math.floor(value * 10 + 1e-6) + 1) / 10 : (Math.ceil(value * 10 - 1e-6) - 1) / 10)
605
-
606
576
  /**
607
577
  * Validates one overscan prop and returns it unchanged (fail-fast — the engine does NOT
608
578
  * validate overscan: a negative value silently shrinks the rendering window past the visible
@@ -740,10 +710,10 @@ const requirePasteSheet = (sheet: PasteSheet | undefined): PasteSheet => {
740
710
  }
741
711
 
742
712
  /**
743
- * Keeps the previous engine label object while all 7 strings are value-equal, so the object handed
713
+ * Keeps the previous engine label object while every engine string is value-equal, so the object handed
744
714
  * to the memoized GridBody changes identity only when a string changes (a host passing an inline
745
715
  * `labels={{…}}` must not re-render the grid body on every shell render).
746
- * 7 文字列がすべて値等価の間は前回のエンジンラベル object を保持 — memo 化された GridBody へ渡す
716
+ * エンジン文字列がすべて値等価の間は前回のエンジンラベル object を保持 — memo 化された GridBody へ渡す
747
717
  * object の identity は文字列が変わった時だけ変わる (インライン `labels={{…}}` のホストでも shell
748
718
  * 再レンダー毎に本体を再描画させない)。
749
719
  *
@@ -843,12 +813,12 @@ export const Spreadsheet = forwardRef<SpreadsheetHandle, SpreadsheetProps & Spre
843
813
  }
844
814
  const viewStore = viewStoreRef.current
845
815
 
846
- // ---- prop 時検証 (v0.8 §4.2.13 — clampZoom と同じく render 中に RangeError を投げる) ----
816
+ // ---- prop 時検証 (v0.8 §4.2.13 — clampSpreadsheetZoom と同じく render 中に RangeError を投げる) ----
847
817
  // 非対応ロケールはここで render 中 RangeError — 以降の検証メッセージ / GridBody は解決済み値だけを受ける
848
818
  const uiLocale = resolveVirtualScrollLocale(locale)
849
819
  // ラベルの畳込み: resolveLabels が Escape 告知 (§10-4) を検証する (RC22)
850
820
  const resolvedLabels = useMemo(() => resolveLabels(locale, labels), [locale, labels])
851
- // GridBody は memo 境界 — インライン labels で毎回新 object になっても 7 文字列が同じなら identity を保つ
821
+ // GridBody は memo 境界 — インライン labels で毎回新 object になってもエンジン文字列が同じなら identity を保つ
852
822
  const scrollLabels = useValueStableScrollLabels(pickEngineLabels(resolvedLabels))
853
823
  // コマンド表: validateShortcuts の 5 条件 (+ 未知キー) は consumer の設定誤り — render 中に表面化
854
824
  const commandTable = useMemo(() => validateShortcuts(shortcuts), [shortcuts])
@@ -887,8 +857,8 @@ export const Spreadsheet = forwardRef<SpreadsheetHandle, SpreadsheetProps & Spre
887
857
 
888
858
  const rootRef = useRef<HTMLDivElement | null>(null)
889
859
  // ---- ズーム (v0.3): 制御 (zoom prop) / 非制御 (内部 state) の標準二相。実効値は常に clamp ----
890
- const [internalZoom, setInternalZoom] = useState(() => clampZoom(defaultZoom ?? 1))
891
- const zoomValue = clampZoom(zoom ?? internalZoom)
860
+ const [internalZoom, setInternalZoom] = useState(() => clampSpreadsheetZoom(defaultZoom ?? 1))
861
+ const zoomValue = clampSpreadsheetZoom(zoom ?? internalZoom)
892
862
  const zoomRef = useRef(zoomValue)
893
863
  zoomRef.current = zoomValue
894
864
  // ジェスチャ連打はレンダーフラッシュ前に複数イベントが届く — zoomRef (レンダー同期 = 実効値)
@@ -905,7 +875,7 @@ export const Spreadsheet = forwardRef<SpreadsheetHandle, SpreadsheetProps & Spre
905
875
  zoomControlledRef.current = zoom !== undefined
906
876
  /** Applies a gesture's zoom request (controlled mode only notifies). / ジェスチャのズーム要求適用 (制御モードは通知のみ)。 */
907
877
  const requestZoom = useCallback((next: number) => {
908
- const clamped = clampZoom(next)
878
+ const clamped = clampSpreadsheetZoom(next)
909
879
  if (clamped === requestedZoomRef.current) {
910
880
  return
911
881
  }
@@ -954,7 +924,7 @@ export const Spreadsheet = forwardRef<SpreadsheetHandle, SpreadsheetProps & Spre
954
924
  if (isDraggingAnyRef.current?.()) {
955
925
  return
956
926
  }
957
- requestZoom(stepZoom(requestedZoomRef.current, event.deltaY < 0 ? 1 : -1))
927
+ requestZoom(stepSpreadsheetZoom(requestedZoomRef.current, event.deltaY < 0 ? 1 : -1))
958
928
  }
959
929
  const onKeyDown = (event: KeyboardEvent) => {
960
930
  // 外側請求済みは素通し (wheel 側と同じ規律 — ホストの capture ショートカットと二重発火しない)
@@ -984,7 +954,7 @@ export const Spreadsheet = forwardRef<SpreadsheetHandle, SpreadsheetProps & Spre
984
954
  // ズームイン) — 配列非依存の和音が必要なホストは event.code で先に請求すること。
985
955
  // 素通しした和音は ctrl+alt 印字形状の遅延開始 (useGridKeyboard §6.6.2-4) により実文字が到着
986
956
  // しない限り編集セッションを開かない
987
- const next = event.key === "=" || event.key === "+" ? stepZoom(requestedZoomRef.current, 1) : event.key === "-" ? stepZoom(requestedZoomRef.current, -1) : event.key === "0" ? 1 : null
957
+ const next = event.key === "=" || event.key === "+" ? stepSpreadsheetZoom(requestedZoomRef.current, 1) : event.key === "-" ? stepSpreadsheetZoom(requestedZoomRef.current, -1) : event.key === "0" ? 1 : null
988
958
  if (next === null) {
989
959
  return
990
960
  }
@@ -1695,7 +1665,7 @@ export const Spreadsheet = forwardRef<SpreadsheetHandle, SpreadsheetProps & Spre
1695
1665
  colAxis.resize(entry.index, size)
1696
1666
  handle?.updateColSize(entry.index, size)
1697
1667
  }
1698
- // hx 再クランプと可視セルの再配置はグリッド内部 (総幅同期 + 幅エポック) が担う —
1668
+ // hx 再クランプと可視セルの再配置はグリッド内部 (総幅同期 + 列幅木の版数) が担う —
1699
1669
  // ここでの明示 reclamp は退役。ヘッダーの再レンダーは colVersion、残差は末尾 repaint
1700
1670
  viewStore.bumpColVersion()
1701
1671
  repaintColHeaders()
@@ -2676,7 +2646,7 @@ export const Spreadsheet = forwardRef<SpreadsheetHandle, SpreadsheetProps & Spre
2676
2646
  colAxis.resize(col, size)
2677
2647
  handleRef.current?.updateColSize(col, size)
2678
2648
  // ヘッダー再レンダーは colVersion (購読 2)、セル再配置と hx 再クランプはグリッドの
2679
- // 幅エポック + 総幅同期が担う。残差 transform は同期 repaint
2649
+ // 列幅木の版数 + 総幅同期が担う。残差 transform は同期 repaint
2680
2650
  viewStore.bumpColVersion()
2681
2651
  repaintColHeaders()
2682
2652
  repaintOverlay()
@@ -69,7 +69,8 @@ import { type CfIndex, type CfMemo, createCfMemo, resolvePaintedFormat } from ".
69
69
  import { isReadOnlyCell, lazyCellText, resolveCellAlign, resolveCellAttributes, type SpreadsheetDataAdapter } from "../model/dataAdapter.ts"
70
70
  import { isVisiblyInvalid } from "../model/dataValidation.ts"
71
71
  import type { SpreadsheetLocale } from "../model/labels.ts"
72
- import { SCROLLBAR_WIDTH, type ViewStore } from "../model/viewStore.ts"
72
+ import type { ViewStore } from "../model/viewStore.ts"
73
+ import { SPREADSHEET_SCROLLBAR_SIZE_PX } from "../view.ts"
73
74
  import { CellView, type RenderCellContext } from "./CellView.tsx"
74
75
 
75
76
  /** Inline style of a cell (React camelCase keys). / セルのインライン style (React の camelCase キー)。 */
@@ -354,12 +355,12 @@ type GridBodyProps = {
354
355
  */
355
356
  locale: SpreadsheetLocale
356
357
  /**
357
- * The resolved engine chrome strings (the 7 VirtualScrollLabels keys: scroll arrows,
358
+ * The resolved engine chrome strings (every VirtualScrollLabels key, e.g. scroll arrows,
358
359
  * scroll-to-edge pills, "No items"), forwarded to VirtualGrid's `labels`. MUST be value-stable:
359
- * its identity may change only when one of the 7 strings changes, otherwise every shell render
360
+ * its identity may change only when one of the strings changes, otherwise every shell render
360
361
  * pierces the memo boundary.
361
- * 解決済みエンジンクローム文言 (VirtualScrollLabels の 7 キー: スクロール矢印・端スクロールピル・
362
- * "No items")。VirtualGrid の `labels` へ素通し。値安定であること (7 文字列のどれかが変わった時だけ
362
+ * 解決済みエンジンクローム文言 (VirtualScrollLabels の全キー: スクロール矢印・端スクロールピル・
363
+ * "No items" など)。VirtualGrid の `labels` へ素通し。値安定であること (文字列のどれかが変わった時だけ
363
364
  * identity が変わる — さもなくば shell 再レンダー毎に memo 境界を貫通)。
364
365
  */
365
366
  scrollLabels: VirtualScrollLabels
@@ -430,7 +431,7 @@ const GridBodyInner = ({
430
431
  // (マウスドラッグは選択エンジンの所有)
431
432
  const behaviorOptions = useMemo(() => ({ enableKeyboardNavigation: false, pointerDragInputs: ["pen", "touch"] as const, resetOnGetItemHeightChange: true, resetOnGetColWidthChange: true, defaultColWidth: defaultColumnWidth }), [defaultColumnWidth])
432
433
  // タップサークル素通し (v0.10 §2.1): 未指定は undefined キー同乗 = エンジン宣言の不在信号
433
- const scrollBarOptions = useMemo(() => ({ width: SCROLLBAR_WIDTH, tapScrollCircleOptions }), [tapScrollCircleOptions])
434
+ const scrollBarOptions = useMemo(() => ({ width: SPREADSHEET_SCROLLBAR_SIZE_PX, tapScrollCircleOptions }), [tapScrollCircleOptions])
434
435
  // 表示値書式の掛け金 (getCellProps が書き、同じセルの children が直後に消費 — 番兵は届かない座標)
435
436
  const displayLatchRef = useRef<DisplayLatch>({ row: -1, col: -1, value: undefined })
436
437
  /**
@@ -40,7 +40,8 @@ import { type ReactNode, type RefObject, useCallback, useLayoutEffect, useSyncEx
40
40
  import { type AxisModel, visibleIndicesInRange } from "../model/axisModel.ts"
41
41
  import type { CellRange } from "../model/cellCoord.ts"
42
42
  import { frozenWidthOf, trailingWidthOf } from "../model/frozenPartition.ts"
43
- import { SCROLLBAR_WIDTH, type ViewStore } from "../model/viewStore.ts"
43
+ import type { ViewStore } from "../model/viewStore.ts"
44
+ import { SPREADSHEET_SCROLLBAR_SIZE_PX } from "../view.ts"
44
45
  import { columnIndexToName } from "./columnName.ts"
45
46
  import { buildResizeStrips, buildTrailingResizeStrips } from "./resizeStrips.ts"
46
47
 
@@ -195,10 +196,13 @@ export const ColumnHeader = ({ viewStore, colAxis, frozenCols, frozenTrailingCol
195
196
  ),
196
197
  )}
197
198
  {/* T_eff > 0 の inline right = 登記 calc() 形 #4 (ADR-19 例外レジスタ — 等価:
198
- SCROLLBAR_WIDTH + W_T_vis の CSS 衣装。W_T_vis = min(W_T, max(0, 100% −
199
- SCROLLBAR_WIDTH − W_F)) — 100% の再解決がブラウザ自身の heal チャネル。
199
+ SPREADSHEET_SCROLLBAR_SIZE_PX + W_T_vis の CSS 衣装。W_T_vis = min(W_T, max(0, 100% −
200
+ SPREADSHEET_SCROLLBAR_SIZE_PX − W_F)) — 100% の再解決がブラウザ自身の heal チャネル。
200
201
  軸モデル値のみ補間しハンドルは読まない。T = 0 は inline right 不在 = v0.8 恒等) */}
201
- <div className="aqsp-col-header-scroll" data-aqsp-col-header-scroll="" style={{ left: frozenWidth, right: effectiveTrailingCols > 0 ? `calc(${SCROLLBAR_WIDTH}px + min(${trailingWidth}px, max(0px, 100% - ${SCROLLBAR_WIDTH + frozenWidth}px)))` : undefined }}>
202
+ <div
203
+ className="aqsp-col-header-scroll"
204
+ data-aqsp-col-header-scroll=""
205
+ style={{ left: frozenWidth, right: effectiveTrailingCols > 0 ? `calc(${SPREADSHEET_SCROLLBAR_SIZE_PX}px + min(${trailingWidth}px, max(0px, 100% - ${SPREADSHEET_SCROLLBAR_SIZE_PX + frozenWidth}px)))` : undefined }}>
202
206
  {track}
203
207
  {/* ヘッダー分割線セグメント (§2.4 — 存在 = 実効件数駆動の render 双子、可視 =
204
208
  repaintColHeaders の等値抑制 display heal、幾何 = クリップ任せの静的値。
@@ -210,10 +214,10 @@ export const ColumnHeader = ({ viewStore, colAxis, frozenCols, frozenTrailingCol
210
214
  {effectiveTrailingCols > 0 ? (
211
215
  /* 末尾クリップ (§4.12): inline left = 登記 calc() 形 #3 (ADR-19 例外レジスタ —
212
216
  等価: クリップ left = extent − W_T_vis の CSS 衣装。max() は leading 被覆
213
- 画素を隠すだけでアンカーを動かさない)。right = SCROLLBAR_WIDTH (帯右端の
217
+ 画素を隠すだけでアンカーを動かさない)。right = SPREADSHEET_SCROLLBAR_SIZE_PX (帯右端の
214
218
  縦バー帯ぶん)。クリップ箱の描画特性は scroll クリップと同一のため同クラスを
215
219
  再利用 (フックは data-aqsp-col-header-trailing) */
216
- <div className="aqsp-col-header-scroll" data-aqsp-col-header-trailing="" style={{ left: `max(${frozenWidth}px, calc(100% - ${trailingWidth + SCROLLBAR_WIDTH}px))`, right: SCROLLBAR_WIDTH }}>
220
+ <div className="aqsp-col-header-scroll" data-aqsp-col-header-trailing="" style={{ left: `max(${frozenWidth}px, calc(100% - ${trailingWidth + SPREADSHEET_SCROLLBAR_SIZE_PX}px))`, right: SPREADSHEET_SCROLLBAR_SIZE_PX }}>
217
221
  {/* 右詰めインナー (width = W_T の木寸法箱): overlap ではクリップが左縁を隠し、
218
222
  右アンカーが帯の遠端整列を保つ (エンジン末尾クリップの右詰めインナー同文) */}
219
223
  <div style={{ position: "absolute", top: 0, height: "100%", right: 0, width: trailingWidth }}>
@@ -26,7 +26,8 @@ import { type ReactNode, type RefObject, useCallback, useLayoutEffect, useSyncEx
26
26
  import { type AxisModel, visibleIndicesInRange } from "../model/axisModel.ts"
27
27
  import type { CellRange } from "../model/cellCoord.ts"
28
28
  import { frozenHeightOf, trailingHeightOf } from "../model/frozenPartition.ts"
29
- import { SCROLLBAR_WIDTH, type ViewStore } from "../model/viewStore.ts"
29
+ import type { ViewStore } from "../model/viewStore.ts"
30
+ import { SPREADSHEET_SCROLLBAR_SIZE_PX } from "../view.ts"
30
31
  import { buildResizeStrips, buildTrailingResizeStrips } from "./resizeStrips.ts"
31
32
 
32
33
  type RowHeaderProps = {
@@ -145,9 +146,9 @@ export const RowHeader = ({ viewStore, rowAxis, handleRef, bandRef, selectionRan
145
146
  )
146
147
 
147
148
  // margin-bottom はグリッド内在の横バー帯ぶんの切り上げ — CSS は TS 定数を読めないため
148
- // インライン指定 (SCROLLBAR_WIDTH の単一 SSOT — SelectionOverlay の right / bottom と同方式)
149
+ // インライン指定 (SPREADSHEET_SCROLLBAR_SIZE_PX の単一 SSOT — SelectionOverlay の right / bottom と同方式)
149
150
  return (
150
- <div ref={mergedBandRef} className="aqsp-row-header" aria-hidden="true" data-aqsp-row-header="" style={{ marginBottom: SCROLLBAR_WIDTH }}>
151
+ <div ref={mergedBandRef} className="aqsp-row-header" aria-hidden="true" data-aqsp-row-header="" style={{ marginBottom: SPREADSHEET_SCROLLBAR_SIZE_PX }}>
151
152
  {/* track transform は repaintHeaders (命令パス) の専有物 — React は書かない (§6.8-2 (b))。
152
153
  v0.6: R > 0 はスクロール track を静的クリップ (top = H_F) で包み、凍結ラベルを帯直下の
153
154
  静的 subtree に置く (ColumnHeader の 2 帯を転置)。v0.9: T > 0 は末尾静的サブツリー