@aiquants/spreadsheet 0.8.0 → 0.9.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.
- package/CHANGELOG.md +50 -0
- package/README.md +86 -8
- package/dist/index.cjs +14 -14
- package/dist/index.d.cts +27 -0
- package/dist/index.d.ts +27 -0
- package/dist/index.js +4159 -3886
- package/dist/styles/spreadsheet.css +1 -1
- package/dist/styles/spreadsheet.standalone.css +1 -1
- package/package.json +3 -3
- package/src/Spreadsheet.tsx +198 -22
- package/src/grid/GridBody.tsx +16 -0
- package/src/header/ColumnHeader.tsx +84 -12
- package/src/header/RowHeader.tsx +79 -11
- package/src/header/resizeStrips.ts +86 -1
- package/src/header/useHeaderResize.ts +88 -20
- package/src/header/useHeaderSelection.ts +28 -9
- package/src/keyboard/ensureCellVisible.ts +40 -17
- package/src/keyboard/useGridKeyboard.ts +10 -4
- package/src/model/frozenPartition.ts +183 -59
- package/src/overlay/SelectionOverlay.tsx +599 -116
- package/src/overlay/useFillHandle.ts +65 -11
- package/src/popover/usePopovers.ts +39 -7
- package/src/selection/useAutoScroller.ts +58 -15
- package/src/selection/useSelectionEngine.ts +27 -10
- package/src/styles/spreadsheet.css +32 -0
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
/*! tailwindcss v4.3.0 | MIT License | https://tailwindcss.com */
|
|
2
|
-
@layer components{.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}}
|
|
2
|
+
@layer components{.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}}}
|
|
@@ -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-frozen-rows{min-width:0;position:relative;overflow:hidden}.aqvs-grid-frozen-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);position:absolute;right:0;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-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}}.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}}@layer utilities;
|
|
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}}.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/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@aiquants/spreadsheet",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.9.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"
|
|
@@ -36,7 +36,7 @@
|
|
|
36
36
|
"peerDependencies": {
|
|
37
37
|
"react": "^19.2.7",
|
|
38
38
|
"react-dom": "^19.2.7",
|
|
39
|
-
"@aiquants/virtualscroll": "^3.
|
|
39
|
+
"@aiquants/virtualscroll": "^3.5.0"
|
|
40
40
|
},
|
|
41
41
|
"devDependencies": {
|
|
42
42
|
"@playwright/test": "^1.59.1",
|
|
@@ -56,7 +56,7 @@
|
|
|
56
56
|
"vite": "^7.2.7",
|
|
57
57
|
"vite-plugin-dts": "^4.5.4",
|
|
58
58
|
"vitest": "^3.2.4",
|
|
59
|
-
"@aiquants/virtualscroll": "3.
|
|
59
|
+
"@aiquants/virtualscroll": "3.5.0"
|
|
60
60
|
},
|
|
61
61
|
"keywords": [
|
|
62
62
|
"react",
|
package/src/Spreadsheet.tsx
CHANGED
|
@@ -177,6 +177,33 @@ export type SpreadsheetProps = {
|
|
|
177
177
|
* 位置に依らず常時可視で、可視化の縦成分は no-op。飛行中の変更は全ドラッグを取り消す。
|
|
178
178
|
*/
|
|
179
179
|
frozenRows?: number
|
|
180
|
+
/**
|
|
181
|
+
* Freezes the LAST N columns at the right edge (v0.9 — the VirtualGrid frozenTrailingCols
|
|
182
|
+
* pass-through; LIVE prop, default 0). Validation SSOT is the engine's fail-fast contract
|
|
183
|
+
* (integer in [0, 128] — RangeError otherwise; the count clamp is leading-wins:
|
|
184
|
+
* effectiveTrailing = min(T, colCount − effectiveLeading)). Trailing columns stay visible at
|
|
185
|
+
* any horizontal scroll — with ONE registered exception: when the leading + trailing extent
|
|
186
|
+
* exceeds the viewport, occluded trailing cells cannot be scrolled into view and keyboard
|
|
187
|
+
* focus paints no visible frame (ADR-19-1). scrollToCell / ensure-visible treat a trailing
|
|
188
|
+
* target as a horizontal no-op. A mid-flight change cancels every in-flight drag without
|
|
189
|
+
* restore (the frozenColumns cancel seam).
|
|
190
|
+
* 末尾 N 列の右端凍結 (v0.9 — VirtualGrid frozenTrailingCols の素通し。ライブ prop、既定 0)。
|
|
191
|
+
* 検証 SSOT はエンジンの fail-fast 契約 ([0, 128] 整数、それ以外 RangeError。件数クランプは
|
|
192
|
+
* leading 勝ち: min(T, colCount − effectiveLeading))。末尾列は任意の横スクロールで可視 —
|
|
193
|
+
* ただし leading + trailing の extent が viewport を超える overlap では遮蔽された末尾セルを
|
|
194
|
+
* スクロールで可視化できず、キーボードフォーカスは可視フレームを描かない (ADR-19-1 の登記済み
|
|
195
|
+
* 帰結)。scrollToCell / ensure-visible は末尾ターゲットを横 no-op として扱う。飛行中の変更は
|
|
196
|
+
* 全ドラッグを復元なしで取り消す (frozenColumns と同じシーム)。
|
|
197
|
+
*/
|
|
198
|
+
frozenTrailingColumns?: number
|
|
199
|
+
/**
|
|
200
|
+
* Freezes the LAST N rows at the bottom (v0.9 — the VirtualGrid frozenTrailingRows
|
|
201
|
+
* pass-through; LIVE prop, default 0 — the row twin of frozenTrailingColumns, same engine
|
|
202
|
+
* fail-fast contract and cancel seam). The typical use is a pinned totals row.
|
|
203
|
+
* 末尾 N 行の下端凍結 (v0.9 — frozenTrailingRows の素通し。ライブ prop、既定 0 —
|
|
204
|
+
* frozenTrailingColumns の行双子。エンジン契約・取消シームは同文)。典型は固定合計行。
|
|
205
|
+
*/
|
|
206
|
+
frozenTrailingRows?: number
|
|
180
207
|
/**
|
|
181
208
|
* Identity-stable contract (same as adapter): an inline arrow here defeats the CellView memo
|
|
182
209
|
* and turns every host re-render into a full visible re-slice (~800 cells at 16k columns).
|
|
@@ -525,6 +552,8 @@ export const Spreadsheet = forwardRef<SpreadsheetHandle, SpreadsheetProps & Spre
|
|
|
525
552
|
defaultColumnWidth = DEFAULT_COLUMN_WIDTH,
|
|
526
553
|
frozenColumns = 0,
|
|
527
554
|
frozenRows = 0,
|
|
555
|
+
frozenTrailingColumns = 0,
|
|
556
|
+
frozenTrailingRows = 0,
|
|
528
557
|
renderCell,
|
|
529
558
|
onSelectionChange,
|
|
530
559
|
onCellContextMenu,
|
|
@@ -747,6 +776,16 @@ export const Spreadsheet = forwardRef<SpreadsheetHandle, SpreadsheetProps & Spre
|
|
|
747
776
|
const windowOriginYRef = useRef(0)
|
|
748
777
|
const colTrackRef = useRef<HTMLDivElement | null>(null)
|
|
749
778
|
const windowOriginXRef = useRef(0)
|
|
779
|
+
// ヘッダー帯要素 (選択機械 / オートスクローラーの結線先 — 従来はオートスクローラー節で宣言)
|
|
780
|
+
const colHeaderRef = useRef<HTMLDivElement | null>(null)
|
|
781
|
+
const rowHeaderRef = useRef<HTMLDivElement | null>(null)
|
|
782
|
+
// ヘッダー分割線セグメントのマウント時キャッシュ (v0.9 §2.4 / §4.9 census #12/#13):
|
|
783
|
+
// ヘッダー再描画は同期横パス上の毎通知呼びのため、querySelector 走査ではなく JSX ref で
|
|
784
|
+
// 装着済みノードを直読みする (存在は件数駆動 render 双子 — アンマウントで React が null へ戻す)
|
|
785
|
+
const dividerXLeadingRef = useRef<HTMLDivElement | null>(null)
|
|
786
|
+
const dividerXTrailingRef = useRef<HTMLDivElement | null>(null)
|
|
787
|
+
const dividerYLeadingRef = useRef<HTMLDivElement | null>(null)
|
|
788
|
+
const dividerYTrailingRef = useRef<HTMLDivElement | null>(null)
|
|
750
789
|
const liveRegionRef = useRef<HTMLDivElement | null>(null)
|
|
751
790
|
|
|
752
791
|
// ---- 選択状態 (React state + 命令読み ref — §6.9-1) ----
|
|
@@ -873,11 +912,42 @@ export const Spreadsheet = forwardRef<SpreadsheetHandle, SpreadsheetProps & Spre
|
|
|
873
912
|
}, [])
|
|
874
913
|
|
|
875
914
|
/**
|
|
876
|
-
*
|
|
915
|
+
* Equality-suppressed display heal of one header divider segment (v0.9 §4.9 census #12/#13):
|
|
916
|
+
* visibility = band TREE px > 0; existence is the header's count-driven render twin and the
|
|
917
|
+
* geometry stays clip-owned, so this display flip is the ONLY divider write the header
|
|
918
|
+
* repaint path ever makes. The segment arrives through the mount-cached JSX ref (never a
|
|
919
|
+
* per-notification querySelector traversal — the synchronous horizontal pass must not pay
|
|
920
|
+
* a selector scan, least of all a guaranteed miss at F = T = 0). A same-value pass writes
|
|
921
|
+
* nothing — the §5.7 zero-write invariant observes both header repaint writers.
|
|
922
|
+
* ヘッダー分割線セグメント 1 つの等値抑制 display heal (v0.9 §4.9 census #12/#13)。可視 =
|
|
923
|
+
* 帯 TREE px > 0。存在はヘッダーの件数駆動 render 双子、幾何はクリップ所有のままで、ヘッダー
|
|
924
|
+
* 再描画が分割線へ行う書込はこの display フリップだけ。セグメントはマウント時キャッシュの
|
|
925
|
+
* JSX ref 経由 (毎通知の querySelector 走査は同期横パスに載せない — F = T = 0 では全走査
|
|
926
|
+
* ミスが保証される)。同値パスは無書込 — §5.7 のゼロ書込不変量が両書き手を観測する。
|
|
927
|
+
*/
|
|
928
|
+
const healHeaderDivider = useCallback((segment: HTMLElement | null, shown: boolean) => {
|
|
929
|
+
// 件数 0 の家族はセグメント未マウント (ref は null) — 無仕事で戻る
|
|
930
|
+
if (segment === null) {
|
|
931
|
+
return
|
|
932
|
+
}
|
|
933
|
+
const next = shown ? "" : "none"
|
|
934
|
+
// 等値抑制 — 定常スクロール wheel 窓中の分割線 style 書込 = 0 の不変量 (§2.4 / §5.7)
|
|
935
|
+
if (segment.style.display !== next) {
|
|
936
|
+
segment.style.display = next
|
|
937
|
+
}
|
|
938
|
+
}, [])
|
|
939
|
+
|
|
940
|
+
/**
|
|
941
|
+
* Repaints the row-header track residual transform. Callers: onScroll, resizeRow, and
|
|
877
942
|
* RowHeader's layout effect. vy comes from the grid handle (the truth — §7-4; the v0.6 −H_F
|
|
878
|
-
* frozen-band term makes this the exact twin of repaintColHeaders).
|
|
879
|
-
*
|
|
880
|
-
*
|
|
943
|
+
* frozen-band term makes this the exact twin of repaintColHeaders). v0.9 adds the
|
|
944
|
+
* equality-suppressed display heal of the two y header divider segments (§4.9 census #12 —
|
|
945
|
+
* NO geometry write: the scroll-clip insets are the registered calc() forms that re-resolve
|
|
946
|
+
* through 100% by themselves).
|
|
947
|
+
* 行 track の残差 transform を書く命令再描画。vy はグリッドハンドル (§7-4 の真実) から読む
|
|
948
|
+
* (v0.6 の −H_F 凍結帯項で repaintColHeaders の完全双子)。v0.9 で y ヘッダー分割線 2 セグメント
|
|
949
|
+
* の等値抑制 display heal を追加 (§4.9 census #12 — 幾何書込なし: scroll クリップのインセットは
|
|
950
|
+
* 登記 calc() 形が 100% 再解決で自癒する)。
|
|
881
951
|
*/
|
|
882
952
|
const repaintHeaders = useCallback(() => {
|
|
883
953
|
const track = rowTrackRef.current
|
|
@@ -888,14 +958,27 @@ export const Spreadsheet = forwardRef<SpreadsheetHandle, SpreadsheetProps & Spre
|
|
|
888
958
|
const frozenHeight = handleRef.current?.getFrozenSize().height ?? 0
|
|
889
959
|
track.style.transform = `translateY(${windowOriginYRef.current - vy - frozenHeight}px)`
|
|
890
960
|
}
|
|
891
|
-
|
|
961
|
+
// v0.9 (§4.9 census #12): y ヘッダー分割線の可視 heal — 可視 = 帯 TREE px > 0 (H_F / H_T の
|
|
962
|
+
// ハンドルフィールド)。ハンドル未装着は無書込 (JSX 初期状態のまま = 件数 render が真実)。
|
|
963
|
+
// 両セグメント未マウント (R = T = 0) は getFrozenSize 読みごと省く — 同期横パスの無仕事保証
|
|
964
|
+
const handle = handleRef.current
|
|
965
|
+
if (handle !== null && (dividerYLeadingRef.current !== null || dividerYTrailingRef.current !== null)) {
|
|
966
|
+
const frozen = handle.getFrozenSize()
|
|
967
|
+
healHeaderDivider(dividerYLeadingRef.current, frozen.height > 0)
|
|
968
|
+
healHeaderDivider(dividerYTrailingRef.current, frozen.trailingHeight > 0)
|
|
969
|
+
}
|
|
970
|
+
}, [healHeaderDivider])
|
|
892
971
|
|
|
893
972
|
/**
|
|
894
|
-
* Repaints
|
|
973
|
+
* Repaints the column-header track residual transform (§7-5 — the row repaintHeaders
|
|
895
974
|
* twin; the v0.3 --aqsp-hx CSS variable is retired). hx comes from the grid handle (the
|
|
896
|
-
* truth — §7-4). Callers: onScroll, resize tails, and ColumnHeader's layout effect.
|
|
897
|
-
*
|
|
898
|
-
*
|
|
975
|
+
* truth — §7-4). Callers: onScroll, resize tails, and ColumnHeader's layout effect. v0.9
|
|
976
|
+
* adds the equality-suppressed display heal of the two x header divider segments (§4.9
|
|
977
|
+
* census #13 — NO geometry write, the exact twin of repaintHeaders).
|
|
978
|
+
* 列 track の残差 transform を書く命令再描画 (§7-5 — 行 repaintHeaders の双子。v0.3 の
|
|
979
|
+
* --aqsp-hx CSS 変数は退役)。hx はグリッドハンドル (§7-4 の真実) から読む。v0.9 で x ヘッダー
|
|
980
|
+
* 分割線 2 セグメントの等値抑制 display heal を追加 (§4.9 census #13 — 幾何書込なし、
|
|
981
|
+
* repaintHeaders の完全双子)。
|
|
899
982
|
*/
|
|
900
983
|
const repaintColHeaders = useCallback(() => {
|
|
901
984
|
const track = colTrackRef.current
|
|
@@ -906,7 +989,61 @@ export const Spreadsheet = forwardRef<SpreadsheetHandle, SpreadsheetProps & Spre
|
|
|
906
989
|
const frozenWidth = handleRef.current?.getFrozenSize().width ?? 0
|
|
907
990
|
track.style.transform = `translateX(${windowOriginXRef.current - hx - frozenWidth}px)`
|
|
908
991
|
}
|
|
909
|
-
|
|
992
|
+
// v0.9 (§4.9 census #13): x ヘッダー分割線の可視 heal (W_F / W_T の TREE px 駆動 — 行と同文。
|
|
993
|
+
// 両セグメント未マウント (F = T = 0) は getFrozenSize 読みごと省く)
|
|
994
|
+
const handle = handleRef.current
|
|
995
|
+
if (handle !== null && (dividerXLeadingRef.current !== null || dividerXTrailingRef.current !== null)) {
|
|
996
|
+
const frozen = handle.getFrozenSize()
|
|
997
|
+
healHeaderDivider(dividerXLeadingRef.current, frozen.width > 0)
|
|
998
|
+
healHeaderDivider(dividerXTrailingRef.current, frozen.trailingWidth > 0)
|
|
999
|
+
}
|
|
1000
|
+
}, [healHeaderDivider])
|
|
1001
|
+
|
|
1002
|
+
// ---- 分割線可視の post-commit heal (v0.9 §2.4 / §2.7) ----
|
|
1003
|
+
const dividerHealRafRef = useRef<number | null>(null)
|
|
1004
|
+
/**
|
|
1005
|
+
* Schedules ONE post-commit divider-visibility heal after a track-resize seam (v0.9 §2.7 —
|
|
1006
|
+
* "T_px = 0 ⇒ no divider" must hold without an interposed scroll). The seam's synchronous
|
|
1007
|
+
* repaint reads the engine's render-captured getFrozenSize (a registered per-render mapping)
|
|
1008
|
+
* BEFORE the engine has re-rendered the new track size, so the divider display would
|
|
1009
|
+
* otherwise lag one geometry transition until the next write pass. One coalesced rAF
|
|
1010
|
+
* re-runs the three imperative writers from the committed getFrozenSize; the equality
|
|
1011
|
+
* suppression keeps this a zero-write pass unless a visibility flip is actually due, and
|
|
1012
|
+
* the F = T = 0 configuration schedules nothing (v0.8 identity — no reservation either).
|
|
1013
|
+
* トラックリサイズシーム後の分割線可視 post-commit heal を 1 回予約 (v0.9 §2.7 —
|
|
1014
|
+
* 「T_px = 0 ⇒ 分割線なし」はスクロール介在なしで成立が要件)。シームの同期 repaint は
|
|
1015
|
+
* エンジンの render 捕捉 getFrozenSize (登記済み毎レンダー写像) をエンジン再レンダー**前**に
|
|
1016
|
+
* 読むため、放置すると分割線 display が次の書込パスまで 1 遷移遅れる。合流 rAF 1 回で
|
|
1017
|
+
* commit 済み getFrozenSize から命令書き手 3 つを再実行 — 等値抑制によりフリップ不要なら
|
|
1018
|
+
* 無書込パス、F = T = 0 構成は予約ごと省く (v0.8 恒等)。
|
|
1019
|
+
*/
|
|
1020
|
+
const scheduleDividerHeal = useCallback(() => {
|
|
1021
|
+
// 分割線セグメントが 1 本も存在しない構成 (F = T = 0) は heal 対象なし — 予約も残さない
|
|
1022
|
+
if (dividerXLeadingRef.current === null && dividerXTrailingRef.current === null && dividerYLeadingRef.current === null && dividerYTrailingRef.current === null) {
|
|
1023
|
+
return
|
|
1024
|
+
}
|
|
1025
|
+
// 合流 (バッチリサイズの多発呼びでも 1 フレーム 1 heal)
|
|
1026
|
+
if (dividerHealRafRef.current !== null) {
|
|
1027
|
+
return
|
|
1028
|
+
}
|
|
1029
|
+
dividerHealRafRef.current = requestAnimationFrame(() => {
|
|
1030
|
+
dividerHealRafRef.current = null
|
|
1031
|
+
// ヘッダー 2 面 + overlay (胴体セグメントは layersFor が同パスで heal する) — commit 済み
|
|
1032
|
+
// getFrozenSize からの再実行。残差 transform / 幾何は同値再書込 (エンジンが既に確定済み)
|
|
1033
|
+
repaintHeaders()
|
|
1034
|
+
repaintColHeaders()
|
|
1035
|
+
repaintOverlay()
|
|
1036
|
+
})
|
|
1037
|
+
}, [repaintHeaders, repaintColHeaders, repaintOverlay])
|
|
1038
|
+
// アンマウント時に予約中の heal rAF を回収 (本パッケージの全タイマ / rAF 回収規律)
|
|
1039
|
+
useEffect(
|
|
1040
|
+
() => () => {
|
|
1041
|
+
if (dividerHealRafRef.current !== null) {
|
|
1042
|
+
cancelAnimationFrame(dividerHealRafRef.current)
|
|
1043
|
+
}
|
|
1044
|
+
},
|
|
1045
|
+
[],
|
|
1046
|
+
)
|
|
910
1047
|
|
|
911
1048
|
// ensureCellVisible: §6.6.3 の自前 nearest (1 回構築して keyboard / Shift+F10 へ配布 — §6.9-7)。
|
|
912
1049
|
// 軸 identity が変わったら作り直す (クロージャが旧軸を掴む stale を防ぐ)
|
|
@@ -1265,6 +1402,9 @@ export const Spreadsheet = forwardRef<SpreadsheetHandle, SpreadsheetProps & Spre
|
|
|
1265
1402
|
viewStore.bumpColVersion()
|
|
1266
1403
|
repaintColHeaders()
|
|
1267
1404
|
repaintOverlay()
|
|
1405
|
+
// 同期 repaint はエンジン再レンダー前の stale getFrozenSize — 分割線可視は
|
|
1406
|
+
// post-commit heal が commit 済み値で整合させる (§2.7 — スクロール介在なし)
|
|
1407
|
+
scheduleDividerHeal()
|
|
1268
1408
|
return
|
|
1269
1409
|
}
|
|
1270
1410
|
for (const entry of entries) {
|
|
@@ -1276,8 +1416,10 @@ export const Spreadsheet = forwardRef<SpreadsheetHandle, SpreadsheetProps & Spre
|
|
|
1276
1416
|
viewStore.bumpRowGeometry()
|
|
1277
1417
|
repaintHeaders()
|
|
1278
1418
|
repaintOverlay()
|
|
1419
|
+
// 行側も同文 (H_F / H_T の分割線可視は commit 済み値で heal — §2.7)
|
|
1420
|
+
scheduleDividerHeal()
|
|
1279
1421
|
},
|
|
1280
|
-
[rowAxis, colAxis, viewStore, repaintColHeaders, repaintHeaders, repaintOverlay],
|
|
1422
|
+
[rowAxis, colAxis, viewStore, repaintColHeaders, repaintHeaders, repaintOverlay, scheduleDividerHeal],
|
|
1281
1423
|
)
|
|
1282
1424
|
|
|
1283
1425
|
/** Pointer contextmenu relay to onCellContextMenu (§6.4.3-4 sole channel). / pointer 起点の横流し。 */
|
|
@@ -1290,8 +1432,6 @@ export const Spreadsheet = forwardRef<SpreadsheetHandle, SpreadsheetProps & Spre
|
|
|
1290
1432
|
|
|
1291
1433
|
// ---- オートスクローラー 3 種 (セル both / 列ヘッダー x / 行ヘッダー y — §6.4.4 / §6.8) ----
|
|
1292
1434
|
const cellAutoScroller = useAutoScroller({ handleRef, rowAxis, colAxis, bodyRef, onDragFrame, axis: "both", zoomRef })
|
|
1293
|
-
const colHeaderRef = useRef<HTMLDivElement | null>(null)
|
|
1294
|
-
const rowHeaderRef = useRef<HTMLDivElement | null>(null)
|
|
1295
1435
|
const colAutoScroller = useAutoScroller({ handleRef, rowAxis, colAxis, bodyRef, onDragFrame, axis: "x", zoomRef })
|
|
1296
1436
|
const rowAutoScroller = useAutoScroller({ handleRef, rowAxis, colAxis, bodyRef, onDragFrame, axis: "y", zoomRef })
|
|
1297
1437
|
// fill 専用の軸別 2 インスタンス (§8.2 — writer も axis も構築時固定。v0.3 のボックス方式では
|
|
@@ -1641,19 +1781,23 @@ export const Spreadsheet = forwardRef<SpreadsheetHandle, SpreadsheetProps & Spre
|
|
|
1641
1781
|
hideNoteTipRef.current = popovers.hideTip
|
|
1642
1782
|
|
|
1643
1783
|
// ---- コマンド実行 (v0.8 §4.1.13 / ADR-17) ----
|
|
1644
|
-
/** The active cell's viewport rect in visual px — the keyboard-origin cellRect recipe
|
|
1784
|
+
/** The active cell's viewport rect in visual px via the three-way forward map (v0.9 §4.9 census #11 — the keyboard-origin cellRect recipe, onCellContextMenu twin) for onPasteSpecialRequest. / active セルの視覚 px 矩形 — 3 分岐順写像 (v0.9 §4.9 census #11。keyboard 起点 cellRect のレシピ、onCellContextMenu と同式)。 */
|
|
1645
1785
|
const keyboardCellRect = useCallback(() => {
|
|
1646
1786
|
const active = selectionRef.current.active
|
|
1647
1787
|
// 画面外座標へメニューを出さない (§6.6.1) — 可視化してからハンドルの同期読み (§7-4)
|
|
1648
1788
|
ensureCellVisible(active)
|
|
1649
1789
|
const handle = handleRef.current
|
|
1650
1790
|
const position = handle === null ? { x: 0, y: 0 } : handle.getScrollPosition()
|
|
1651
|
-
|
|
1791
|
+
// 帯件数と extent も同じ判断で読む (v0.9 計画 §4.9、census #11 — AxisForwardCtx はこの場で
|
|
1792
|
+
// インライン構築、§2.1 規則 1)。detached ハンドルは件数 0 / extent 0 の縮退 (末尾分岐不活性 = v0.8 恒等)
|
|
1793
|
+
const frozen = handle === null ? { rows: 0, cols: 0, trailingRows: 0, trailingCols: 0 } : handle.getFrozenSize()
|
|
1794
|
+
const viewport = handle === null ? { width: 0, height: 0 } : handle.getViewportSize()
|
|
1652
1795
|
// 両軸とも番兵クランプ (detached の {-1, -1} を座標へ流さない)、ズーム境界で視覚 px へ
|
|
1653
1796
|
const z = zoomRef.current
|
|
1654
1797
|
return {
|
|
1655
|
-
|
|
1656
|
-
|
|
1798
|
+
// 行 / 列とも凍結パーティション 3 分岐順写像 (末尾は extent アンカー — v0.9 §2.1)。×zoom は写像後 (契約不変)
|
|
1799
|
+
top: rowToViewportY(rowAxis, active.row, { scroll: Math.max(0, position.y), frozenCount: frozen.rows, trailingCount: frozen.trailingRows, extent: viewport.height }) * z,
|
|
1800
|
+
left: colToViewportX(colAxis, active.col, { scroll: Math.max(0, position.x), frozenCount: frozen.cols, trailingCount: frozen.trailingCols, extent: viewport.width }) * z,
|
|
1657
1801
|
width: colAxis.sizeOf(active.col) * z,
|
|
1658
1802
|
height: rowAxis.sizeOf(active.row) * z,
|
|
1659
1803
|
}
|
|
@@ -2072,12 +2216,18 @@ export const Spreadsheet = forwardRef<SpreadsheetHandle, SpreadsheetProps & Spre
|
|
|
2072
2216
|
// 同じ stale 座標遮断だが、座標系は同一グリッドのため選択と編集セッションは保持する
|
|
2073
2217
|
const prevFrozenColsRef = useRef(frozenColumns)
|
|
2074
2218
|
const prevFrozenRowsRef = useRef(frozenRows)
|
|
2219
|
+
// v0.9 (§4.9 census #21 — FZ46 教訓): 末尾 2 props も同じ取消 OR に参加する (4 props の
|
|
2220
|
+
// どれかの変化 = 旧 3 分岐パーティションの押下時アンカーが全て陳腐化する)
|
|
2221
|
+
const prevTrailingColsRef = useRef(frozenTrailingColumns)
|
|
2222
|
+
const prevTrailingRowsRef = useRef(frozenTrailingRows)
|
|
2075
2223
|
useLayoutEffect(() => {
|
|
2076
|
-
// 列 /
|
|
2077
|
-
// 押下時アンカーは旧パーティション座標系。混成ヒットで誤 fill 確定を防ぐ)
|
|
2078
|
-
if (prevFrozenColsRef.current !== frozenColumns || prevFrozenRowsRef.current !== frozenRows) {
|
|
2224
|
+
// 列 / 行・先頭 / 末尾いずれの凍結変更も飛行中ドラッグを復元なしで取り消す (R2 是正の縦拡張 +
|
|
2225
|
+
// v0.9 の末尾拡張 — 押下時アンカーは旧パーティション座標系。混成ヒットで誤 fill 確定を防ぐ)
|
|
2226
|
+
if (prevFrozenColsRef.current !== frozenColumns || prevFrozenRowsRef.current !== frozenRows || prevTrailingColsRef.current !== frozenTrailingColumns || prevTrailingRowsRef.current !== frozenTrailingRows) {
|
|
2079
2227
|
prevFrozenColsRef.current = frozenColumns
|
|
2080
2228
|
prevFrozenRowsRef.current = frozenRows
|
|
2229
|
+
prevTrailingColsRef.current = frozenTrailingColumns
|
|
2230
|
+
prevTrailingRowsRef.current = frozenTrailingRows
|
|
2081
2231
|
engine.cancelDrag()
|
|
2082
2232
|
colHeaderMachine.cancelDrag()
|
|
2083
2233
|
rowHeaderMachine.cancelDrag()
|
|
@@ -2088,7 +2238,19 @@ export const Spreadsheet = forwardRef<SpreadsheetHandle, SpreadsheetProps & Spre
|
|
|
2088
2238
|
// (cancelDrag は abortDrag と違いシンク断面を復元しない)
|
|
2089
2239
|
pointDrag.cancelDrag()
|
|
2090
2240
|
}
|
|
2091
|
-
}, [frozenColumns, frozenRows, engine, colHeaderMachine, rowHeaderMachine, headerResizeMachine, fillMachine, pointDrag])
|
|
2241
|
+
}, [frozenColumns, frozenRows, frozenTrailingColumns, frozenTrailingRows, engine, colHeaderMachine, rowHeaderMachine, headerResizeMachine, fillMachine, pointDrag])
|
|
2242
|
+
|
|
2243
|
+
// ---- 凍結 props フリップの分割線可視整合 (v0.9 §2.4 / §2.7) ----
|
|
2244
|
+
// フリップの同一 commit 内でエンジンは新 props で render 済み (毎レンダー写像の getFrozenSize は
|
|
2245
|
+
// layout effect 時点で確定値)。非表示トラックを含む帯へのフリップ (例: 全 track 幅 0 の列を F = 1 で
|
|
2246
|
+
// 凍結) では新規マウントの分割線セグメントが JSX 初期 display "" のまま px = 0 になるため、
|
|
2247
|
+
// paint 前にここで heal する — スクロール介在なしで「px = 0 ⇒ 分割線なし」を成立させる (§2.7)。
|
|
2248
|
+
// F = T = 0 では両ヘッダー書き手が getFrozenSize 読みごと省き、残差 transform の同値再書込のみ
|
|
2249
|
+
useLayoutEffect(() => {
|
|
2250
|
+
repaintHeaders()
|
|
2251
|
+
repaintColHeaders()
|
|
2252
|
+
repaintOverlay()
|
|
2253
|
+
}, [frozenColumns, frozenRows, frozenTrailingColumns, frozenTrailingRows, repaintHeaders, repaintColHeaders, repaintOverlay])
|
|
2092
2254
|
|
|
2093
2255
|
// ---- dataVersion (外部書込通知 §6.9-2 (b) — Undo / 協調編集) もクリップの破棄条件 ----
|
|
2094
2256
|
// adapter 外で値が書き戻ると cut 時行列のまま照合が通り、古い指紋の move が外部値を "" で
|
|
@@ -2129,6 +2291,8 @@ export const Spreadsheet = forwardRef<SpreadsheetHandle, SpreadsheetProps & Spre
|
|
|
2129
2291
|
// §6.8-2 の順序契約の設計内猶予。自己修復するため実害なし)
|
|
2130
2292
|
repaintHeaders()
|
|
2131
2293
|
repaintOverlay()
|
|
2294
|
+
// 分割線可視は commit 済み getFrozenSize の post-commit heal で整合 (§2.7)
|
|
2295
|
+
scheduleDividerHeal()
|
|
2132
2296
|
},
|
|
2133
2297
|
resizeColumn: (col: number, widthPx: number) => {
|
|
2134
2298
|
// 対呼び出し (§3.8): colAxis (SSOT) を先に更新し、グリッドの幅木へ通知する。
|
|
@@ -2141,6 +2305,8 @@ export const Spreadsheet = forwardRef<SpreadsheetHandle, SpreadsheetProps & Spre
|
|
|
2141
2305
|
viewStore.bumpColVersion()
|
|
2142
2306
|
repaintColHeaders()
|
|
2143
2307
|
repaintOverlay()
|
|
2308
|
+
// 分割線可視は commit 済み getFrozenSize の post-commit heal で整合 (§2.7)
|
|
2309
|
+
scheduleDividerHeal()
|
|
2144
2310
|
},
|
|
2145
2311
|
scrollToCell: (cell: CellCoord, options?: ScrollToCellOptions) => {
|
|
2146
2312
|
// エンジンのセル狙いジャンプへ素通し (§7-4 の真実。選択は変えない — 純 viewport 移動)。
|
|
@@ -2175,7 +2341,7 @@ export const Spreadsheet = forwardRef<SpreadsheetHandle, SpreadsheetProps & Spre
|
|
|
2175
2341
|
openPopoverRef.current(kind)
|
|
2176
2342
|
},
|
|
2177
2343
|
}),
|
|
2178
|
-
[rowAxis, colAxis, viewStore, repaintColHeaders, repaintHeaders, repaintOverlay, focusSink, isEditing, rearmSink, adapter, paintedFormatOf, startEdit, requireCommands],
|
|
2344
|
+
[rowAxis, colAxis, viewStore, repaintColHeaders, repaintHeaders, repaintOverlay, scheduleDividerHeal, focusSink, isEditing, rearmSink, adapter, paintedFormatOf, startEdit, requireCommands],
|
|
2179
2345
|
)
|
|
2180
2346
|
|
|
2181
2347
|
// ---- 空グリッド分岐 (§6.9-1: フックの後・結線の前) ----
|
|
@@ -2231,6 +2397,7 @@ export const Spreadsheet = forwardRef<SpreadsheetHandle, SpreadsheetProps & Spre
|
|
|
2231
2397
|
viewStore={viewStore}
|
|
2232
2398
|
colAxis={colAxis}
|
|
2233
2399
|
frozenCols={frozenColumns}
|
|
2400
|
+
frozenTrailingCols={frozenTrailingColumns}
|
|
2234
2401
|
handleRef={handleRef}
|
|
2235
2402
|
bandRef={colHeaderRef}
|
|
2236
2403
|
colTrackRef={colTrackRef}
|
|
@@ -2238,6 +2405,8 @@ export const Spreadsheet = forwardRef<SpreadsheetHandle, SpreadsheetProps & Spre
|
|
|
2238
2405
|
repaintColHeaders={repaintColHeaders}
|
|
2239
2406
|
selectionRanges={selection.ranges}
|
|
2240
2407
|
enableResizeUI={enableResizeUI}
|
|
2408
|
+
dividerLeadingRef={dividerXLeadingRef}
|
|
2409
|
+
dividerTrailingRef={dividerXTrailingRef}
|
|
2241
2410
|
/>
|
|
2242
2411
|
<RowHeader
|
|
2243
2412
|
viewStore={viewStore}
|
|
@@ -2250,6 +2419,9 @@ export const Spreadsheet = forwardRef<SpreadsheetHandle, SpreadsheetProps & Spre
|
|
|
2250
2419
|
repaintHeaders={repaintHeaders}
|
|
2251
2420
|
enableResizeUI={enableResizeUI}
|
|
2252
2421
|
frozenRows={frozenRows}
|
|
2422
|
+
frozenTrailingRows={frozenTrailingRows}
|
|
2423
|
+
dividerLeadingRef={dividerYLeadingRef}
|
|
2424
|
+
dividerTrailingRef={dividerYTrailingRef}
|
|
2253
2425
|
/>
|
|
2254
2426
|
<div className="aqsp-body-stack" data-aqsp-body-stack="">
|
|
2255
2427
|
<GridBody
|
|
@@ -2263,6 +2435,8 @@ export const Spreadsheet = forwardRef<SpreadsheetHandle, SpreadsheetProps & Spre
|
|
|
2263
2435
|
defaultColumnWidth={defaultColumnWidth}
|
|
2264
2436
|
frozenColumns={frozenColumns}
|
|
2265
2437
|
frozenRows={frozenRows}
|
|
2438
|
+
frozenTrailingColumns={frozenTrailingColumns}
|
|
2439
|
+
frozenTrailingRows={frozenTrailingRows}
|
|
2266
2440
|
renderCell={renderCell}
|
|
2267
2441
|
onScroll={onScroll}
|
|
2268
2442
|
onRangeChange={onRangeChange}
|
|
@@ -2294,6 +2468,8 @@ export const Spreadsheet = forwardRef<SpreadsheetHandle, SpreadsheetProps & Spre
|
|
|
2294
2468
|
enableFillHandle={enableFillHandle}
|
|
2295
2469
|
frozenCols={frozenColumns}
|
|
2296
2470
|
frozenRows={frozenRows}
|
|
2471
|
+
trailingCols={frozenTrailingColumns}
|
|
2472
|
+
trailingRows={frozenTrailingRows}
|
|
2297
2473
|
sinkAriaLabel={resolvedLabels.sinkAriaLabel}
|
|
2298
2474
|
onSinkMouseDown={onSinkMouseDown}
|
|
2299
2475
|
editPaintRef={editPaintRef}
|
package/src/grid/GridBody.tsx
CHANGED
|
@@ -19,6 +19,10 @@
|
|
|
19
19
|
* identical style objects (two-tier intern: paint identity, then canonical JSON for the
|
|
20
20
|
* per-call paints of edge / folded cells).
|
|
21
21
|
*
|
|
22
|
+
* v0.9 trailing freeze (plan §4.15): `frozenTrailingColumns` / `frozenTrailingRows` are
|
|
23
|
+
* engine-validated pass-throughs onto VirtualGrid's `frozenTrailingCols` / `frozenTrailingRows`
|
|
24
|
+
* — validation SSOT is the engine's fail-fast contract, no second layer here (§1.1).
|
|
25
|
+
*
|
|
22
26
|
* グリッド本体。VirtualGrid 結線 (両軸) とセルレンダラーを所有する。v0.4 から横軸は VirtualGrid
|
|
23
27
|
* の所有 (量子化列アンカー + 残差 transform + 横バー) — v0.3 の列スタック (useColumnWindow /
|
|
24
28
|
* --aqsp-hx CSS 変数 / 軸原点絶対 left / 自前 HScrollBar) は設計計画 §7-1 に従い削除。
|
|
@@ -33,6 +37,10 @@
|
|
|
33
37
|
* 全読みは能力分岐 (`adapter.x === undefined` ⇒ v0.1 の属性なしセル)、条件付き書式索引は root の宣言能力 (未指定 ⇒
|
|
34
38
|
* base 書式のみ)、無変化セルは同一の style object を保つ (2 段 intern: paint identity → 端 / 畳込み
|
|
35
39
|
* セルの呼出毎 paint は正準 JSON)。
|
|
40
|
+
*
|
|
41
|
+
* v0.9 末尾凍結 (計画 §4.15): `frozenTrailingColumns` / `frozenTrailingRows` は VirtualGrid の
|
|
42
|
+
* `frozenTrailingCols` / `frozenTrailingRows` へのエンジン検証素通し — 検証 SSOT はエンジンの
|
|
43
|
+
* fail-fast 契約で、ここに第二検証層は置かない (§1.1)。
|
|
36
44
|
*/
|
|
37
45
|
|
|
38
46
|
import { VirtualGrid, type VirtualGridHandle, type VirtualGridRange } from "@aiquants/virtualscroll"
|
|
@@ -257,6 +265,10 @@ type GridBodyProps = {
|
|
|
257
265
|
frozenColumns: number
|
|
258
266
|
/** Frozen leading rows (v0.6 — VirtualGrid frozenLeadingRows pass-through; engine-validated). / 先頭凍結行数 (v0.6 — エンジン検証の素通し)。 */
|
|
259
267
|
frozenRows: number
|
|
268
|
+
/** Trailing frozen columns (v0.9 — VirtualGrid frozenTrailingCols engine-validated pass-through; no second validation layer — §1.1 SSOT). / 末尾凍結列数 (v0.9 — VirtualGrid frozenTrailingCols のエンジン検証素通し。第二検証層なし — §1.1 SSOT)。 */
|
|
269
|
+
frozenTrailingColumns: number
|
|
270
|
+
/** Trailing frozen rows (v0.9 — VirtualGrid frozenTrailingRows engine-validated pass-through; the row twin). / 末尾凍結行数 (v0.9 — frozenTrailingRows のエンジン検証素通し。行双子)。 */
|
|
271
|
+
frozenTrailingRows: number
|
|
260
272
|
renderCell?: (ctx: RenderCellContext) => ReactNode
|
|
261
273
|
/** 2D scroll notification from the grid handle (the truth — §7-4). / グリッドハンドル発の 2 軸スクロール通知 (§7-4 の真実側)。 */
|
|
262
274
|
onScroll: (position: { x: number; y: number }) => void
|
|
@@ -303,6 +315,8 @@ const GridBodyInner = ({
|
|
|
303
315
|
defaultColumnWidth,
|
|
304
316
|
frozenColumns,
|
|
305
317
|
frozenRows,
|
|
318
|
+
frozenTrailingColumns,
|
|
319
|
+
frozenTrailingRows,
|
|
306
320
|
renderCell,
|
|
307
321
|
onScroll,
|
|
308
322
|
onRangeChange,
|
|
@@ -467,6 +481,8 @@ const GridBodyInner = ({
|
|
|
467
481
|
colCount={adapter.colCount}
|
|
468
482
|
frozenLeadingCols={frozenColumns}
|
|
469
483
|
frozenLeadingRows={frozenRows}
|
|
484
|
+
frozenTrailingCols={frozenTrailingColumns}
|
|
485
|
+
frozenTrailingRows={frozenTrailingRows}
|
|
470
486
|
getRowHeight={getRowHeight}
|
|
471
487
|
getColWidth={getColWidth}
|
|
472
488
|
getCell={getCell}
|