@aiquants/spreadsheet 0.8.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 +1103 -0
- package/LICENSE.md +155 -0
- package/README.md +817 -0
- package/dist/index.cjs +21 -0
- package/dist/index.d.cts +1960 -0
- package/dist/index.d.ts +1960 -0
- package/dist/index.js +7711 -0
- package/dist/styles/spreadsheet.css +2 -0
- package/dist/styles/spreadsheet.standalone.css +3 -0
- package/package.json +94 -0
- package/src/Spreadsheet.tsx +2313 -0
- package/src/clipboard/clipPayload.ts +1242 -0
- package/src/clipboard/fixtures/excel.fixture.ts +301 -0
- package/src/clipboard/fixtures/html.fixture.ts +90 -0
- package/src/clipboard/fixtures/sheets.fixture.ts +83 -0
- package/src/clipboard/htmlInterop.ts +1694 -0
- package/src/clipboard/numberFormatCodec.ts +870 -0
- package/src/clipboard/pasteSpecial.ts +608 -0
- package/src/clipboard/tiling.ts +370 -0
- package/src/clipboard/tsv.ts +186 -0
- package/src/clipboard/useClipboard.ts +1154 -0
- package/src/commands/selfCalc.ts +279 -0
- package/src/commands/useCommands.ts +946 -0
- package/src/editor/useCellEditor.ts +708 -0
- package/src/grid/CellView.tsx +51 -0
- package/src/grid/GridBody.tsx +489 -0
- package/src/header/ColumnHeader.tsx +167 -0
- package/src/header/RowHeader.tsx +144 -0
- package/src/header/columnName.ts +31 -0
- package/src/header/resizeGates.ts +146 -0
- package/src/header/resizeStrips.ts +79 -0
- package/src/header/useHeaderResize.ts +598 -0
- package/src/header/useHeaderSelection.ts +454 -0
- package/src/index.ts +122 -0
- package/src/keyboard/compositionGuard.ts +53 -0
- package/src/keyboard/ensureCellVisible.ts +77 -0
- package/src/keyboard/shortcuts.ts +718 -0
- package/src/keyboard/useGridKeyboard.ts +940 -0
- package/src/model/axisModel.ts +186 -0
- package/src/model/cellAnnotations.ts +92 -0
- package/src/model/cellCoord.ts +114 -0
- package/src/model/cellFormat.ts +562 -0
- package/src/model/cellPaint.ts +537 -0
- package/src/model/conditionalFormat.ts +805 -0
- package/src/model/dataAdapter.ts +478 -0
- package/src/model/dataValidation.ts +542 -0
- package/src/model/formulaRefs.ts +984 -0
- package/src/model/frozenPartition.ts +100 -0
- package/src/model/labels.ts +228 -0
- package/src/model/viewStore.ts +124 -0
- package/src/overlay/SelectionOverlay.tsx +1425 -0
- package/src/overlay/useFillHandle.ts +432 -0
- package/src/popover/CommentPopover.tsx +109 -0
- package/src/popover/LinkPopover.tsx +108 -0
- package/src/popover/ListPopover.tsx +161 -0
- package/src/popover/MessagePopover.tsx +36 -0
- package/src/popover/NotePopover.tsx +106 -0
- package/src/popover/NoteTip.tsx +26 -0
- package/src/popover/PopoverLayer.tsx +210 -0
- package/src/popover/placement.ts +138 -0
- package/src/popover/usePopovers.ts +642 -0
- package/src/selection/selectionState.ts +239 -0
- package/src/selection/useAutoScroller.ts +226 -0
- package/src/selection/usePointDrag.ts +273 -0
- package/src/selection/useSelectionEngine.ts +687 -0
- package/src/styles/components.entry.css +10 -0
- package/src/styles/spreadsheet.css +1029 -0
- package/src/styles/standalone.entry.css +9 -0
|
@@ -0,0 +1,1029 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* @aiquants/spreadsheet — hand-written component classes (.aqsp-*). No Tailwind utilities in JSX.
|
|
3
|
+
* 手書きコンポーネントクラス (.aqsp-*)。JSX に Tailwind ユーティリティは書かない (§6.10)。
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
/*
|
|
7
|
+
* 機能要件: コンポーネント全域を border-box に固定する。AxisModel の整数 px 幾何 (style の
|
|
8
|
+
* width / height) が DOM 実寸と 1:1 で一致する前提 — content-box だと padding / border が
|
|
9
|
+
* 加算されて軸幾何と実寸が乖離し、ヘッダーとセルの ±0px 同期 (§7 Phase 1 ゲート) が壊れる。
|
|
10
|
+
* standalone ホストは preflight を持たないため、root 配下スコープの全称セレクタで自前確保する。
|
|
11
|
+
*/
|
|
12
|
+
.aqsp-root,
|
|
13
|
+
.aqsp-root *,
|
|
14
|
+
.aqsp-root *::before,
|
|
15
|
+
.aqsp-root *::after {
|
|
16
|
+
box-sizing: border-box;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
.aqsp-root {
|
|
20
|
+
--aqsp-row-header-width: 64px; /* 7 桁行番号 (1,000,000) が 13px tabular-nums で収まる幅 */
|
|
21
|
+
--aqsp-col-header-height: 24px;
|
|
22
|
+
/* v0.8 強調帯の既定パレット (計画 §1.9)。単一書き手は overlay の layout effect (highlightColors prop) —
|
|
23
|
+
能力なしはこの既定が効く。毎フレームの repaint は変数を書かない */
|
|
24
|
+
--aqsp-band-row: #0084ff;
|
|
25
|
+
--aqsp-band-column: #42ff4f;
|
|
26
|
+
--aqsp-band-intersection: #e1ff00;
|
|
27
|
+
--aqsp-band-opacity: 0.2;
|
|
28
|
+
position: relative;
|
|
29
|
+
width: 100%;
|
|
30
|
+
height: 100%;
|
|
31
|
+
overflow: hidden;
|
|
32
|
+
background: #ffffff;
|
|
33
|
+
color: #1f2937;
|
|
34
|
+
font-size: 13px;
|
|
35
|
+
line-height: 1;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/*
|
|
39
|
+
* ズームラッパー (v0.3): grid レイアウトの実体。視覚は transform: scale(z)、レイアウトは
|
|
40
|
+
* 100%/z (インライン上書き — z=1 は無スタイルで v0.2 幾何と同一)。origin 0 0 で左上アンカー。
|
|
41
|
+
*/
|
|
42
|
+
/*
|
|
43
|
+
* minmax(0, 1fr) は必須 (v0.3.1 [M159]): 素の 1fr は暗黙最小 = min-content で、横バー帯内の
|
|
44
|
+
* ScrollBar インライン幅 (旧 bodyWidth) が列 2 の下限になり「計測 → −12px → 再計測」の
|
|
45
|
+
* 12px/フレーム収縮スパイラルを作る (実測 ≈ 2 秒の追随遅れ)。トラック自体の下限を 0 にする
|
|
46
|
+
* 正準対策で、将来この列 / 行へどんな intrinsic 寸法の項目が入っても帰還ループが構造的に
|
|
47
|
+
* 再発しない (項目個別の min-width: 0 より SSOT — body-stack の旧宣言は死文として撤去済み)。
|
|
48
|
+
*/
|
|
49
|
+
.aqsp-zoom {
|
|
50
|
+
display: grid;
|
|
51
|
+
grid-template-columns: var(--aqsp-row-header-width) minmax(0, 1fr);
|
|
52
|
+
/* 横バー行は無い — v0.4 から横バーは VirtualGrid 内在 (§7-1。v0.3 の第 3 行 auto は退役) */
|
|
53
|
+
grid-template-rows: var(--aqsp-col-header-height) minmax(0, 1fr);
|
|
54
|
+
width: 100%;
|
|
55
|
+
height: 100%;
|
|
56
|
+
transform-origin: 0 0;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
.aqsp-corner {
|
|
60
|
+
grid-column: 1;
|
|
61
|
+
grid-row: 1;
|
|
62
|
+
border-right: 1px solid #d1d5db;
|
|
63
|
+
border-bottom: 1px solid #d1d5db;
|
|
64
|
+
background: #f3f4f6;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
.aqsp-col-header {
|
|
68
|
+
grid-column: 2;
|
|
69
|
+
grid-row: 1;
|
|
70
|
+
position: relative;
|
|
71
|
+
overflow: hidden;
|
|
72
|
+
border-bottom: 1px solid #d1d5db;
|
|
73
|
+
background: #f3f4f6;
|
|
74
|
+
user-select: none;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/* 列 track の transform は repaintColHeaders (命令パス) の専有物 — React / CSS は書かない
|
|
78
|
+
(§7-5 — 行 track §6.8-2 の双子。v0.3 の --aqsp-hx CSS 変数駆動は退役) */
|
|
79
|
+
/* 凍結ヘッダー帯のスクロール側クリップ (v0.5 — エンジン §8-b のヘッダー同文)。
|
|
80
|
+
* left はインライン (W_F — TS 定数導出のため CSS へ複製しない)。 */
|
|
81
|
+
.aqsp-col-header-scroll {
|
|
82
|
+
position: absolute;
|
|
83
|
+
top: 0;
|
|
84
|
+
height: 100%;
|
|
85
|
+
right: 0;
|
|
86
|
+
overflow: hidden;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/* 行ヘッダーのスクロールクリップ (v0.6 — col-header-scroll の転置)。top: H_F は JSX インライン。 */
|
|
90
|
+
.aqsp-row-header-scroll {
|
|
91
|
+
position: absolute;
|
|
92
|
+
left: 0;
|
|
93
|
+
width: 100%;
|
|
94
|
+
bottom: 0;
|
|
95
|
+
overflow: hidden;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
.aqsp-col-header-track {
|
|
99
|
+
position: absolute;
|
|
100
|
+
inset: 0;
|
|
101
|
+
will-change: transform;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
.aqsp-col-header-cell {
|
|
105
|
+
position: absolute;
|
|
106
|
+
top: 0;
|
|
107
|
+
height: 100%;
|
|
108
|
+
display: flex;
|
|
109
|
+
align-items: center;
|
|
110
|
+
justify-content: center;
|
|
111
|
+
border-right: 1px solid #e5e7eb;
|
|
112
|
+
overflow: hidden;
|
|
113
|
+
white-space: nowrap;
|
|
114
|
+
color: #4b5563;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
.aqsp-row-header {
|
|
118
|
+
grid-column: 1;
|
|
119
|
+
grid-row: 2;
|
|
120
|
+
position: relative;
|
|
121
|
+
overflow: hidden;
|
|
122
|
+
/* 下端の横バー帯ぶんの margin-bottom は RowHeader.tsx が SCROLLBAR_WIDTH からインライン
|
|
123
|
+
指定する (TS 定数の単一 SSOT — SelectionOverlay の right / bottom と同方式) */
|
|
124
|
+
border-right: 1px solid #d1d5db;
|
|
125
|
+
background: #f3f4f6;
|
|
126
|
+
user-select: none;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
/* 行 track の transform は repaintHeaders (命令パス) の専有物 — React / CSS は書かない (§6.8-2) */
|
|
130
|
+
.aqsp-row-header-track {
|
|
131
|
+
position: absolute;
|
|
132
|
+
left: 0;
|
|
133
|
+
right: 0;
|
|
134
|
+
top: 0;
|
|
135
|
+
will-change: transform;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
.aqsp-row-header-cell {
|
|
139
|
+
position: absolute;
|
|
140
|
+
left: 0;
|
|
141
|
+
right: 0;
|
|
142
|
+
display: flex;
|
|
143
|
+
align-items: center;
|
|
144
|
+
justify-content: flex-end;
|
|
145
|
+
padding-right: 6px;
|
|
146
|
+
border-bottom: 1px solid #e5e7eb;
|
|
147
|
+
overflow: hidden;
|
|
148
|
+
white-space: nowrap;
|
|
149
|
+
color: #4b5563;
|
|
150
|
+
font-variant-numeric: tabular-nums;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
/*
|
|
154
|
+
* 機能要件: stack 内では absolute 全面が必須 — 通常フローだと高さが auto (= 0) に潰れ、
|
|
155
|
+
* セルは overflow で描画され続けるのに hit-test だけが死ぬ (ホイール・クリック全滅の事故類型)。
|
|
156
|
+
* grid 配置 (2/2) は親 .aqsp-body-stack が担う。
|
|
157
|
+
*/
|
|
158
|
+
.aqsp-body {
|
|
159
|
+
position: absolute;
|
|
160
|
+
inset: 0;
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
/*
|
|
164
|
+
* 配置 (position / 寸法 / 横残差 translateX) は VirtualGrid の .aqvs-grid-row が所有する (§7-1
|
|
165
|
+
* — v0.3 の .aqsp-cells 中間ラッパーと --aqsp-hx 変数は退役)。ここは描画特性のみ:
|
|
166
|
+
* cursor: default は非編集セルの既定矢印 (利用者選択: 非編集=矢印 / 編集=キャレット)。既定 auto は
|
|
167
|
+
* セル本文の上で I ビームになり「編集中でないのにキャレット」に見えるため明示 default で矢印に固定。
|
|
168
|
+
* 編集中だけ可視シンクが cursor: text (キャレット) を出す — 値変化は編集開始時の 1 回のみ (旧
|
|
169
|
+
* v0.3.2 の cursor: cell は「十字→矢印→十字」の点滅として実測されたため矢印基調へ差し替え)
|
|
170
|
+
*/
|
|
171
|
+
.aqsp-row {
|
|
172
|
+
cursor: default;
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
/* 配置 (absolute / left / width / top / height / overflow) は VirtualGrid の .aqvs-grid-cell が
|
|
176
|
+
所有 (§7-3) — ここは描画特性のみ */
|
|
177
|
+
.aqsp-cell {
|
|
178
|
+
display: flex;
|
|
179
|
+
align-items: center;
|
|
180
|
+
padding: 0 4px;
|
|
181
|
+
border-right: 1px solid #e5e7eb;
|
|
182
|
+
border-bottom: 1px solid #e5e7eb;
|
|
183
|
+
white-space: nowrap;
|
|
184
|
+
background: #ffffff;
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
/*
|
|
188
|
+
* v0.8 リッチセルの塗り (計画 §4.2.14)。色 / 字体 / 罫線は getCellProps がインライン style で書く
|
|
189
|
+
* (罫線は border-right/bottom の**インライン上書き**で .aqsp-cell の罫線を置換 — box-shadow は不使用。
|
|
190
|
+
* border-box なので 3px までの太さでレイアウト不変)。ここは属性フック経由の描画特性だけ:
|
|
191
|
+
* 垂直揃え / 折返し / 指標三角 / リンク。遷移 (transition) は一切書かない。
|
|
192
|
+
*/
|
|
193
|
+
.aqsp-cell[data-aqsp-valign="top"] {
|
|
194
|
+
align-items: flex-start;
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
.aqsp-cell[data-aqsp-valign="bottom"] {
|
|
198
|
+
align-items: flex-end;
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
.aqsp-cell[data-aqsp-wrap] {
|
|
202
|
+
white-space: pre-wrap;
|
|
203
|
+
overflow-wrap: anywhere;
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
/*
|
|
207
|
+
* 指標三角 (border 三角形 — 辺 5px、透明 3 辺 + 1 辺色)。セル要素は VirtualGrid の absolute 配置なので
|
|
208
|
+
* 疑似要素の包含ブロックになる。右上 = ノート (濃灰) / コメント (橙、後置で優先)、左下 = 不正 (赤) は
|
|
209
|
+
* ::before に分けて同一セルの note + invalid が共存する
|
|
210
|
+
*/
|
|
211
|
+
.aqsp-cell[data-aqsp-note]::after,
|
|
212
|
+
.aqsp-cell[data-aqsp-comment]::after {
|
|
213
|
+
content: "";
|
|
214
|
+
position: absolute;
|
|
215
|
+
top: 0;
|
|
216
|
+
right: 0;
|
|
217
|
+
width: 0;
|
|
218
|
+
height: 0;
|
|
219
|
+
border: 5px solid transparent;
|
|
220
|
+
border-top-color: #4b5563;
|
|
221
|
+
border-right-color: #4b5563;
|
|
222
|
+
pointer-events: none;
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
.aqsp-cell[data-aqsp-comment]::after {
|
|
226
|
+
border-top-color: #f97316;
|
|
227
|
+
border-right-color: #f97316;
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
.aqsp-cell[data-aqsp-invalid]::before {
|
|
231
|
+
content: "";
|
|
232
|
+
position: absolute;
|
|
233
|
+
left: 0;
|
|
234
|
+
bottom: 0;
|
|
235
|
+
width: 0;
|
|
236
|
+
height: 0;
|
|
237
|
+
border: 5px solid transparent;
|
|
238
|
+
border-bottom-color: #dc2626;
|
|
239
|
+
border-left-color: #dc2626;
|
|
240
|
+
pointer-events: none;
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
/* リンクセル — 書式の color インライン指定が優先する (インライン > クラス) */
|
|
244
|
+
.aqsp-cell[data-aqsp-link] {
|
|
245
|
+
text-decoration: underline;
|
|
246
|
+
color: #1d4ed8;
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
/*
|
|
250
|
+
* body と overlay の重ね置きコンテナ (grid セル 1 枠に両者を積む)。項目側の min-width/height: 0
|
|
251
|
+
* は置かない — トラック側が minmax(0, 1fr) (.aqsp-zoom) である限り自動最小は適用されず死文で、
|
|
252
|
+
* 帰還ループの実防壁はトラック定義が単独で担う (v0.3.1 [M159] — 二重防壁は SSOT 違反)。
|
|
253
|
+
*/
|
|
254
|
+
.aqsp-body-stack {
|
|
255
|
+
grid-column: 2;
|
|
256
|
+
grid-row: 2;
|
|
257
|
+
position: relative;
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
/*
|
|
261
|
+
* 機能要件 (ADR-4): overlay は pointer-events: none — ホイールとタッチドラッグは ScrollPane
|
|
262
|
+
* 要素自身にしかリスナーが無いため、auto のままだとグリッド上の縦スクロールが全て死ぬ
|
|
263
|
+
* (実測済みの既知事故類型)。右オフセット (縦バー幅) は JSX インラインが SSOT (§6.7.2-1)。
|
|
264
|
+
*/
|
|
265
|
+
.aqsp-overlay {
|
|
266
|
+
position: absolute;
|
|
267
|
+
inset: 0;
|
|
268
|
+
overflow: hidden;
|
|
269
|
+
pointer-events: none;
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
/* v0.6 の overlay 象限 (計画 §3-4 — v0.5 の 2 層を両軸へ拡張): 各象限が専用コンテナと自前
|
|
273
|
+
* クリップを持ち、境界跨ぎ矩形を切り分ける。位置 (left / width / top / height / right / bottom)
|
|
274
|
+
* は全てインライン (W_F / H_F — TS 導出のため CSS へ複製しない)。クリップ器は 1 クラスに集約。 */
|
|
275
|
+
.aqsp-overlay-quad {
|
|
276
|
+
position: absolute;
|
|
277
|
+
overflow: hidden;
|
|
278
|
+
pointer-events: none;
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
/*
|
|
282
|
+
* 確定塗り (ADR-4: 選択はセルでなくオーバーレイが描く)。forced-colors では outline へ切替。
|
|
283
|
+
* 外周 border は Excel / Sheets の「選択範囲の枠」パリティ (v0.7 UX 監査) — アクティブ枠 (2px)
|
|
284
|
+
* との階層を保つ 1px。box-sizing: border-box (コンポーネント全域規約) で命令的 w / h の内側に
|
|
285
|
+
* 描かれ幾何は不変。凍結象限では range が象限毎の断片に割れて境界に縫い目が出るが、凍結分割線が
|
|
286
|
+
* 同位置に描かれるため視覚上は分割線に吸収される (仕様登記 — spec 05)。
|
|
287
|
+
*/
|
|
288
|
+
.aqsp-selection-fill {
|
|
289
|
+
position: absolute;
|
|
290
|
+
top: 0;
|
|
291
|
+
left: 0;
|
|
292
|
+
background: rgb(59 130 246 / 0.18);
|
|
293
|
+
border: 1px solid rgb(37 99 235 / 0.85);
|
|
294
|
+
mix-blend-mode: multiply;
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
.aqsp-active-frame {
|
|
298
|
+
position: absolute;
|
|
299
|
+
top: 0;
|
|
300
|
+
left: 0;
|
|
301
|
+
border: 2px solid #2563eb;
|
|
302
|
+
box-sizing: border-box;
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
.aqsp-drag-rect {
|
|
306
|
+
position: absolute;
|
|
307
|
+
top: 0;
|
|
308
|
+
left: 0;
|
|
309
|
+
border: 1px solid #2563eb;
|
|
310
|
+
background: rgb(59 130 246 / 0.1);
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
/* 減算ドラッグ (§3.2): writeDragFrame が data-aqsp-drag-mode を set / clear する */
|
|
314
|
+
.aqsp-drag-rect[data-aqsp-drag-mode="subtract"] {
|
|
315
|
+
border: 1px dashed #dc2626;
|
|
316
|
+
background: rgb(220 38 38 / 0.08);
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
/* 参照ドラッグ (v0.8 ポインティング): 数式へ挿入するレンジの矩形 — 緑の破線 */
|
|
320
|
+
.aqsp-drag-rect[data-aqsp-drag-mode="point"] {
|
|
321
|
+
border: 1px dashed #16a34a;
|
|
322
|
+
background: rgb(22 163 74 / 0.08);
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
/*
|
|
326
|
+
* v0.8 強調帯 (計画 §2.4 / §4.2.14): レンジ毎に行 2 セグメント / 列 2 セグメント / 交点の常設ノード。
|
|
327
|
+
* 位置 (transform) と寸法は overlay の writer が直書き — ここは色と不透明度だけ。fill の DOM 前置
|
|
328
|
+
* (= 下層) に挿入され、fill / アクティブ枠 / マーキーの下に沈む
|
|
329
|
+
*/
|
|
330
|
+
.aqsp-band {
|
|
331
|
+
position: absolute;
|
|
332
|
+
top: 0;
|
|
333
|
+
left: 0;
|
|
334
|
+
opacity: var(--aqsp-band-opacity);
|
|
335
|
+
pointer-events: none;
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
.aqsp-band[data-aqsp-band="row"] {
|
|
339
|
+
background: var(--aqsp-band-row);
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
.aqsp-band[data-aqsp-band="column"] {
|
|
343
|
+
background: var(--aqsp-band-column);
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
.aqsp-band[data-aqsp-band="intersection"] {
|
|
347
|
+
background: var(--aqsp-band-intersection);
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
/*
|
|
351
|
+
* クリップマーキー (v0.3.2 — copy / cut 共通のマーチングアンツ)。選択塗り・アクティブ枠と重なって
|
|
352
|
+
* も判別できるよう、静的破線でなく 4 辺グラデーションを時計回りに送るアニメーション破線にする
|
|
353
|
+
* (Excel / Google Sheets 準拠 — kind によらず同一視覚、判別は data-aqsp-clip-kind)。ダッシュは
|
|
354
|
+
* 周期 8px × 厚 2px。reduced-motion では送りだけ止まり静的破線として残る (視認性は維持)。
|
|
355
|
+
*/
|
|
356
|
+
.aqsp-clip-marquee {
|
|
357
|
+
position: absolute;
|
|
358
|
+
top: 0;
|
|
359
|
+
left: 0;
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
/*
|
|
363
|
+
* アンツ本体は ::after が担い、選択枠 (アクティブリング 2px = 矩形内縁) の**外側 3px** に描く。
|
|
364
|
+
* ノード自体の矩形は writer が書く論理レンジ矩形の SSOT のまま。外側オフセットの正準定数は
|
|
365
|
+
* writer 側の CLIP_MARQUEE_OUTSET = 3 (漸進端別クランプの分子) で、CSS はその出力
|
|
366
|
+
* (--aqsp-clip-outset-*) を消費する — 下の -3px はマーキー非表示時にだけ効くフォールバック。
|
|
367
|
+
* ズーム下も .aqsp-zoom の transform が疑似要素ごと拡縮するため論理 3px のまま一貫する。
|
|
368
|
+
*/
|
|
369
|
+
.aqsp-clip-marquee::after {
|
|
370
|
+
content: "";
|
|
371
|
+
position: absolute;
|
|
372
|
+
/* 端別アウトセット (漸進): writer が各辺の余白ぶんだけ外へ出す (-min(3, 余白)px) — overlay の
|
|
373
|
+
overflow: hidden に切られて行 0 / 列 0 やビューポート端で辺が消える欠陥の根治 (連続クランプ
|
|
374
|
+
で閾値跳ねなし) */
|
|
375
|
+
top: var(--aqsp-clip-outset-top, -3px);
|
|
376
|
+
right: var(--aqsp-clip-outset-right, -3px);
|
|
377
|
+
bottom: var(--aqsp-clip-outset-bottom, -3px);
|
|
378
|
+
left: var(--aqsp-clip-outset-left, -3px);
|
|
379
|
+
/* 二色 (青 / 白 — Excel 同型): 透明コマだと下地が青リング / 青塗りのとき「青一色の実線」に
|
|
380
|
+
化けてアンツが知覚不能になる (R2(H) 画素実測)。白コマはどの下地でも必ず対比を作る */
|
|
381
|
+
background-image: linear-gradient(90deg, #2563eb 50%, #ffffff 50%), linear-gradient(90deg, #2563eb 50%, #ffffff 50%), linear-gradient(0deg, #2563eb 50%, #ffffff 50%), linear-gradient(0deg, #2563eb 50%, #ffffff 50%);
|
|
382
|
+
background-repeat: repeat-x, repeat-x, repeat-y, repeat-y;
|
|
383
|
+
background-size:
|
|
384
|
+
8px 2px,
|
|
385
|
+
8px 2px,
|
|
386
|
+
2px 8px,
|
|
387
|
+
2px 8px;
|
|
388
|
+
background-position:
|
|
389
|
+
0 0,
|
|
390
|
+
8px 100%,
|
|
391
|
+
0 8px,
|
|
392
|
+
100% 0;
|
|
393
|
+
animation: aqsp-marching-ants 0.4s linear infinite;
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
@keyframes aqsp-marching-ants {
|
|
397
|
+
to {
|
|
398
|
+
background-position:
|
|
399
|
+
8px 0,
|
|
400
|
+
0 100%,
|
|
401
|
+
0 0,
|
|
402
|
+
100% 8px;
|
|
403
|
+
}
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
@media (prefers-reduced-motion: reduce) {
|
|
407
|
+
.aqsp-clip-marquee::after {
|
|
408
|
+
animation: none;
|
|
409
|
+
}
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
/* §7.1 リサイズストリップ (視覚とヒット判定のみ — リスナーは帯の wire-once capture) */
|
|
413
|
+
.aqsp-col-resize-strip {
|
|
414
|
+
position: absolute;
|
|
415
|
+
top: 0;
|
|
416
|
+
height: 100%;
|
|
417
|
+
cursor: col-resize;
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
.aqsp-row-resize-strip {
|
|
421
|
+
position: absolute;
|
|
422
|
+
left: 0;
|
|
423
|
+
right: 0;
|
|
424
|
+
cursor: row-resize;
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
/* §7.1 unhide マーカー (二重線スタイル — ストリップより DOM 後置 = 上層) */
|
|
428
|
+
.aqsp-col-header .aqsp-unhide-marker {
|
|
429
|
+
position: absolute;
|
|
430
|
+
top: 0;
|
|
431
|
+
height: 100%;
|
|
432
|
+
cursor: col-resize;
|
|
433
|
+
background: repeating-linear-gradient(90deg, #2563eb 0 1px, transparent 1px 3px);
|
|
434
|
+
opacity: 0.7;
|
|
435
|
+
}
|
|
436
|
+
|
|
437
|
+
.aqsp-row-header .aqsp-unhide-marker {
|
|
438
|
+
position: absolute;
|
|
439
|
+
left: 0;
|
|
440
|
+
right: 0;
|
|
441
|
+
cursor: row-resize;
|
|
442
|
+
background: repeating-linear-gradient(180deg, #2563eb 0 1px, transparent 1px 3px);
|
|
443
|
+
opacity: 0.7;
|
|
444
|
+
}
|
|
445
|
+
|
|
446
|
+
/* §7.2 リサイズガイドライン (overlay 常設ノード — writer が寸法 / 位置を直書き) */
|
|
447
|
+
.aqsp-resize-guide {
|
|
448
|
+
position: absolute;
|
|
449
|
+
top: 0;
|
|
450
|
+
left: 0;
|
|
451
|
+
background: #2563eb;
|
|
452
|
+
pointer-events: none;
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
/* §8.1 fill ハンドル (pointer-events: auto の例外第 2 号) */
|
|
456
|
+
.aqsp-autofill-handle {
|
|
457
|
+
position: absolute;
|
|
458
|
+
top: 0;
|
|
459
|
+
left: 0;
|
|
460
|
+
width: 6px;
|
|
461
|
+
height: 6px;
|
|
462
|
+
background: #2563eb;
|
|
463
|
+
border: 1px solid #fff;
|
|
464
|
+
box-sizing: content-box;
|
|
465
|
+
pointer-events: auto;
|
|
466
|
+
cursor: crosshair;
|
|
467
|
+
}
|
|
468
|
+
|
|
469
|
+
/* §8.2 fill プレビュー帯 (破線の常設ノード) */
|
|
470
|
+
.aqsp-autofill-preview {
|
|
471
|
+
position: absolute;
|
|
472
|
+
top: 0;
|
|
473
|
+
left: 0;
|
|
474
|
+
border: 1px dashed #16a34a;
|
|
475
|
+
}
|
|
476
|
+
|
|
477
|
+
/*
|
|
478
|
+
* 機能要件 (forced-colors — §6.10): 半透明 background + mix-blend-mode は強制配色で剥がされ
|
|
479
|
+
* 不可視になるため、選択塗りを Highlight outline へ、マーキーは ::after の Highlight 破線
|
|
480
|
+
* border へ切り替える (outline は端別クランプできず原点で切られる — [M164])。
|
|
481
|
+
*/
|
|
482
|
+
@media (forced-colors: active) {
|
|
483
|
+
/* 強調帯: 半透明背景は剥がされるため Highlight の outline へ (fill と同型) */
|
|
484
|
+
.aqsp-band {
|
|
485
|
+
background: transparent;
|
|
486
|
+
outline: 2px solid Highlight;
|
|
487
|
+
outline-offset: -2px;
|
|
488
|
+
}
|
|
489
|
+
/* 指標三角: transparent 辺が再着色されると三角が四角に化けるため、最初から 6px の CanvasText 四角にする */
|
|
490
|
+
.aqsp-cell[data-aqsp-note]::after,
|
|
491
|
+
.aqsp-cell[data-aqsp-comment]::after,
|
|
492
|
+
.aqsp-cell[data-aqsp-invalid]::before {
|
|
493
|
+
width: 6px;
|
|
494
|
+
height: 6px;
|
|
495
|
+
border: 1px solid CanvasText;
|
|
496
|
+
}
|
|
497
|
+
.aqsp-drag-rect[data-aqsp-drag-mode="point"] {
|
|
498
|
+
border-color: Highlight;
|
|
499
|
+
background: transparent;
|
|
500
|
+
}
|
|
501
|
+
.aqsp-selection-fill {
|
|
502
|
+
background: transparent;
|
|
503
|
+
/* 通常モードの外周罫は退役 (outline-offset -2px の Highlight が同帯を覆うため視覚上は
|
|
504
|
+
occluded だが、強制色の再着色を避ける衛生リセット) */
|
|
505
|
+
border: none;
|
|
506
|
+
outline: 2px solid Highlight;
|
|
507
|
+
outline-offset: -2px;
|
|
508
|
+
}
|
|
509
|
+
.aqsp-clip-marquee::after {
|
|
510
|
+
/* グラデーション背景は強制カラーで塗り潰されるため、端別クランプが効く ::after の
|
|
511
|
+
border 破線へ切り替える (outline は端別にできず原点で切られる) */
|
|
512
|
+
background-image: none;
|
|
513
|
+
animation: none;
|
|
514
|
+
border: 2px dashed Highlight;
|
|
515
|
+
}
|
|
516
|
+
}
|
|
517
|
+
|
|
518
|
+
/* ヘッダー強調 (§6.8-4 — ドラッグ中は凍結 = 既知特性) */
|
|
519
|
+
.aqsp-col-header-cell[data-aqsp-in-selection],
|
|
520
|
+
.aqsp-row-header-cell[data-aqsp-in-selection] {
|
|
521
|
+
background: #dbeafe;
|
|
522
|
+
color: #1d4ed8;
|
|
523
|
+
font-weight: 600;
|
|
524
|
+
}
|
|
525
|
+
|
|
526
|
+
/* SR 専用 live region (§6.9-9) — 視覚的に不可視、AT には読める */
|
|
527
|
+
.aqsp-live-region {
|
|
528
|
+
position: absolute;
|
|
529
|
+
width: 1px;
|
|
530
|
+
height: 1px;
|
|
531
|
+
margin: -1px;
|
|
532
|
+
padding: 0;
|
|
533
|
+
overflow: hidden;
|
|
534
|
+
clip-path: inset(50%);
|
|
535
|
+
white-space: nowrap;
|
|
536
|
+
}
|
|
537
|
+
|
|
538
|
+
/*
|
|
539
|
+
* 機能要件 (ADR-3/4): シンクは overlay 内の唯一の pointer-events: auto。常駐 1px + opacity 0。
|
|
540
|
+
* display:none / visibility:hidden はフォーカスと IME が死ぬため禁止。
|
|
541
|
+
*/
|
|
542
|
+
.aqsp-sink {
|
|
543
|
+
position: absolute;
|
|
544
|
+
width: 1px;
|
|
545
|
+
height: 1px;
|
|
546
|
+
padding: 0;
|
|
547
|
+
border: 0;
|
|
548
|
+
opacity: 0;
|
|
549
|
+
resize: none;
|
|
550
|
+
pointer-events: auto;
|
|
551
|
+
/* 待機中 (1×1) の UA 既定 text カーソルを殺し、非編集セルと同じ既定矢印にする — キャレットは
|
|
552
|
+
編集中のみ (利用者選択: 非編集=矢印 / 編集=キャレット) */
|
|
553
|
+
cursor: default;
|
|
554
|
+
}
|
|
555
|
+
|
|
556
|
+
/*
|
|
557
|
+
* 編集セッション中の可視エディタ化 (v0.3 要望改善): 常時 opacity 0 のままだと打鍵は受けても
|
|
558
|
+
* 本文もキャレットも見えない。セル面積化 (§6.7.2-4) と同じ書込点で立つ data-aqsp-editing で
|
|
559
|
+
* だけ可視化する。フォント / パディングはセル描画 (.aqsp-cell: 13px / 左右 4px / flex 中央 =
|
|
560
|
+
* 上下 max(0, (行高 − 下罫 1 − 13) / 2) — 下罫 1px を落とすと 0.5px の縦段差、14px 未満の
|
|
561
|
+
* 行は 0 床) と視覚連続にし、枠は
|
|
562
|
+
* アクティブリングと同色。白背景でセルの旧値を覆う
|
|
563
|
+
* (再スライスは確定時のみのため、透けると旧値と入力が二重に見える)。
|
|
564
|
+
*/
|
|
565
|
+
.aqsp-sink[data-aqsp-editing] {
|
|
566
|
+
opacity: 1;
|
|
567
|
+
z-index: 1;
|
|
568
|
+
box-sizing: border-box;
|
|
569
|
+
padding: 0 4px; /* 上パディングはオーバーレイが行高から動的直書き — セル flex 中央と一致 */
|
|
570
|
+
background: #ffffff;
|
|
571
|
+
color: #1f2937;
|
|
572
|
+
caret-color: #1f2937;
|
|
573
|
+
font-family: inherit;
|
|
574
|
+
font-size: 13px;
|
|
575
|
+
line-height: 1;
|
|
576
|
+
white-space: pre;
|
|
577
|
+
overflow: hidden;
|
|
578
|
+
outline: 2px solid #2563eb;
|
|
579
|
+
outline-offset: -2px;
|
|
580
|
+
/* 編集中だけキャレット (I ビーム) — 編集セルの文字上でキャレットを出す (利用者要望)。非編集は
|
|
581
|
+
.aqsp-row / 待機シンクとも既定矢印なので、カーソル値が変わるのは編集開始の 1 回のみ。旧
|
|
582
|
+
v0.3.2 の「非編集=十字 (cell) → 編集=text」は十字とキャレットの間にブラウザ既定矢印が挟まる
|
|
583
|
+
「十字→矢印→十字」の点滅を招いた (実測)。矢印基調に統一し、点滅の起点となる十字を撤去した
|
|
584
|
+
(利用者選択: 非編集=矢印 / 編集=キャレット) */
|
|
585
|
+
cursor: text;
|
|
586
|
+
}
|
|
587
|
+
|
|
588
|
+
/*
|
|
589
|
+
* 参照ポインティング中 (v0.8 計画 §4.2.14): キャレット色を参照矩形と同色にする視覚ヒント。属性は
|
|
590
|
+
* エディタが input / 処理済みキー / selectionchange で書く (漸進的・非依存)。遷移は書かない
|
|
591
|
+
*/
|
|
592
|
+
.aqsp-sink[data-aqsp-pointing] {
|
|
593
|
+
caret-color: #16a34a;
|
|
594
|
+
}
|
|
595
|
+
|
|
596
|
+
/*
|
|
597
|
+
* v0.8 ポップオーバー層 (ADR-15 / 計画 §4.2.14): .aqsp-body-stack 内で overlay の**後**の兄弟 (DOM 順 =
|
|
598
|
+
* 描画上位)。層自体は pointer-events: none。アンカーはセル上の位置決めだけで、これも none — アンカーは
|
|
599
|
+
* セル面積で開いている間もセルに重なるため、auto にすると開いた瞬間にセルのホバー (note tip の
|
|
600
|
+
* 入退出) とクリックを奪って tip が明滅する。pointer-events: auto の例外 #3 / #4 はアンカーの中身で
|
|
601
|
+
* あるポップオーバー本体 (.aqsp-popover) が担う (アンカーの pointerenter / leave は子の hit から
|
|
602
|
+
* 祖先へ届く。層は body の兄弟なので tip への進入は body の pointerleave も起こす — ホバー可能 tip の
|
|
603
|
+
* 成立はフック usePopovers の tipHoveredRef が担い、CSS の責務ではない)。非表示は visibility: hidden +
|
|
604
|
+
* inert (display: none は入力フォーカスを壊すため禁止)。
|
|
605
|
+
* 遷移は書かない
|
|
606
|
+
*/
|
|
607
|
+
.aqsp-popover-layer {
|
|
608
|
+
position: absolute;
|
|
609
|
+
inset: 0;
|
|
610
|
+
overflow: visible;
|
|
611
|
+
pointer-events: none;
|
|
612
|
+
}
|
|
613
|
+
|
|
614
|
+
.aqsp-popover-anchor {
|
|
615
|
+
position: absolute;
|
|
616
|
+
top: 0;
|
|
617
|
+
left: 0;
|
|
618
|
+
pointer-events: none;
|
|
619
|
+
}
|
|
620
|
+
|
|
621
|
+
/* 閉じたアンカー (PopoverLayer が inert を書く — フレームは未マウント) は寸法を保ったまま不可視 */
|
|
622
|
+
.aqsp-popover-anchor[inert] {
|
|
623
|
+
visibility: hidden;
|
|
624
|
+
}
|
|
625
|
+
|
|
626
|
+
/*
|
|
627
|
+
* フレーム (pointer-events: auto の例外 #3 / #4)。幅 320px は placement.ts の POPOVER_MAX_WIDTH と
|
|
628
|
+
* 同値の既定値 (見た目の契約): 配置は PopoverLayer.place が popoverWidth(層) = min(320, 使用可能幅 − 8)
|
|
629
|
+
* をインラインで書いて**から** offsetHeight を測るため、CSS 幅は計測の前提ではない (340px 未満の層では
|
|
630
|
+
* インライン幅 < 320 が勝ち、その幅で折り返した実高で候補判定する)。max-height もインライン
|
|
631
|
+
* (placePopover の出力 — 全高で収まらなければアンカー脇の空きへ縮めた高さ) — 収まらない分は kind ルートの
|
|
632
|
+
* 縦 flex が内側のスクロール領域 (スレッド / 候補一覧 / tip 本文) へ押し込み、overflow: hidden が角丸で
|
|
633
|
+
* 切る。余白はフレームでなく kind ルートが持つ (list の候補一覧と拒否アクセントを端まで描くため)。
|
|
634
|
+
* フォントはセル書式と独立なシステム UI 書体 (Excel / Sheets の注釈 UI と同型)。遷移は書かない
|
|
635
|
+
*/
|
|
636
|
+
.aqsp-popover {
|
|
637
|
+
position: absolute;
|
|
638
|
+
display: flex;
|
|
639
|
+
flex-direction: column;
|
|
640
|
+
width: 320px;
|
|
641
|
+
max-width: 320px;
|
|
642
|
+
overflow: hidden;
|
|
643
|
+
border: 1px solid #d1d5db;
|
|
644
|
+
border-radius: 8px;
|
|
645
|
+
background: #ffffff;
|
|
646
|
+
color: #1f2937;
|
|
647
|
+
box-shadow:
|
|
648
|
+
0 1px 2px rgb(0 0 0 / 0.08),
|
|
649
|
+
0 8px 24px rgb(0 0 0 / 0.14);
|
|
650
|
+
font-family: system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", "Noto Sans JP", sans-serif;
|
|
651
|
+
font-size: 13px;
|
|
652
|
+
line-height: 1.4;
|
|
653
|
+
text-align: start;
|
|
654
|
+
white-space: normal;
|
|
655
|
+
cursor: default;
|
|
656
|
+
pointer-events: auto;
|
|
657
|
+
}
|
|
658
|
+
|
|
659
|
+
/* 消費者レンダラ (autofocus 対象なし) はフレーム自体が焦点着地点 — 内側リングで所在を示す */
|
|
660
|
+
.aqsp-popover:focus-visible {
|
|
661
|
+
outline: 2px solid #2563eb;
|
|
662
|
+
outline-offset: -2px;
|
|
663
|
+
}
|
|
664
|
+
|
|
665
|
+
/* ホバー tip のフレーム (kind はフレームの data-aqsp-popover-frame、中身の data-aqsp-popover は部品側のフック) */
|
|
666
|
+
.aqsp-popover[data-aqsp-popover-frame="note-tip"] {
|
|
667
|
+
border-color: #f59e0b;
|
|
668
|
+
background: #fffbeb;
|
|
669
|
+
box-shadow: 0 2px 8px rgb(0 0 0 / 0.12);
|
|
670
|
+
}
|
|
671
|
+
|
|
672
|
+
/*
|
|
673
|
+
* kind ルート (既定部品 6 種): 余白と縦 flex の所有者。min-height: 0 でフレームの max-height クランプを
|
|
674
|
+
* 受け、固定高の子 (textarea / 操作列) は flex: none、可変の子 (スレッド / 候補一覧) が縮んでスクロール
|
|
675
|
+
*/
|
|
676
|
+
.aqsp-popover-note,
|
|
677
|
+
.aqsp-popover-comment,
|
|
678
|
+
.aqsp-popover-link,
|
|
679
|
+
.aqsp-popover-message {
|
|
680
|
+
display: flex;
|
|
681
|
+
flex-direction: column;
|
|
682
|
+
min-height: 0;
|
|
683
|
+
padding: 10px 12px;
|
|
684
|
+
}
|
|
685
|
+
|
|
686
|
+
.aqsp-popover-list {
|
|
687
|
+
display: flex;
|
|
688
|
+
flex-direction: column;
|
|
689
|
+
min-height: 0;
|
|
690
|
+
padding: 6px;
|
|
691
|
+
}
|
|
692
|
+
|
|
693
|
+
/* tip 本文: 改行 / 長語を保って折り返し、フレームのクランプ内でスクロール (tip はホバー可) */
|
|
694
|
+
.aqsp-popover-note-tip {
|
|
695
|
+
min-height: 0;
|
|
696
|
+
padding: 8px 10px;
|
|
697
|
+
overflow-y: auto;
|
|
698
|
+
overscroll-behavior: contain;
|
|
699
|
+
white-space: pre-wrap;
|
|
700
|
+
overflow-wrap: anywhere;
|
|
701
|
+
}
|
|
702
|
+
|
|
703
|
+
/*
|
|
704
|
+
* 拒否状態 (data-aqsp-popover-rejected — 部品ルートが立てる): 始端 3px の赤アクセント。パディングを
|
|
705
|
+
* 3px 減らして本文位置を保つ (拒否再提示は同じフレームを保持するため、本文が動くと再試行中の
|
|
706
|
+
* 下書きが跳ねる)。forced-colors では border が CanvasText へ再着色されて太い縦線として残る
|
|
707
|
+
*/
|
|
708
|
+
[data-aqsp-popover][data-aqsp-popover-rejected] {
|
|
709
|
+
border-inline-start: 3px solid #dc2626;
|
|
710
|
+
padding-inline-start: 9px;
|
|
711
|
+
}
|
|
712
|
+
|
|
713
|
+
.aqsp-popover-title {
|
|
714
|
+
display: flex;
|
|
715
|
+
align-items: baseline;
|
|
716
|
+
gap: 6px;
|
|
717
|
+
margin: 0 0 6px;
|
|
718
|
+
font-size: 12px;
|
|
719
|
+
font-weight: 600;
|
|
720
|
+
color: #374151;
|
|
721
|
+
}
|
|
722
|
+
|
|
723
|
+
.aqsp-popover-count {
|
|
724
|
+
font-weight: 400;
|
|
725
|
+
color: #6b7280;
|
|
726
|
+
}
|
|
727
|
+
|
|
728
|
+
/*
|
|
729
|
+
* 入力欄 (textarea / input): UA 既定 (monospace / 13.33px Arial / 独自 padding) を捨ててポップオーバーの
|
|
730
|
+
* 書体へ揃える。フォーカスは :focus-visible の内側リング (border に重ねる 2px — 角丸フレームの
|
|
731
|
+
* overflow: hidden に切られない)。aria-invalid (拒否 / 不正 URL — 部品が書く ARIA 状態) は赤枠
|
|
732
|
+
*/
|
|
733
|
+
.aqsp-popover-textarea,
|
|
734
|
+
.aqsp-popover-input {
|
|
735
|
+
display: block;
|
|
736
|
+
width: 100%;
|
|
737
|
+
margin: 0;
|
|
738
|
+
padding: 5px 8px;
|
|
739
|
+
border: 1px solid #d1d5db;
|
|
740
|
+
border-radius: 6px;
|
|
741
|
+
background: #ffffff;
|
|
742
|
+
color: inherit;
|
|
743
|
+
font: inherit;
|
|
744
|
+
line-height: 1.4;
|
|
745
|
+
}
|
|
746
|
+
|
|
747
|
+
/*
|
|
748
|
+
* ノート本文は縦の可変領域 (flex 1 / min-height): 拒否再提示はフレーム (max-height 据置き) の中で
|
|
749
|
+
* ヒントが 1 行伸びるため、textarea が縮んで操作列を見せる (flex: none だと Save が切られる)
|
|
750
|
+
*/
|
|
751
|
+
.aqsp-popover-textarea {
|
|
752
|
+
flex: 1 1 auto;
|
|
753
|
+
height: 104px;
|
|
754
|
+
min-height: 56px;
|
|
755
|
+
overflow: auto;
|
|
756
|
+
resize: none;
|
|
757
|
+
white-space: pre-wrap;
|
|
758
|
+
}
|
|
759
|
+
|
|
760
|
+
/* 返信欄は固定高 — スレッドがコメント編集の可変領域 */
|
|
761
|
+
.aqsp-popover-comment .aqsp-popover-textarea {
|
|
762
|
+
flex: none;
|
|
763
|
+
height: 64px;
|
|
764
|
+
}
|
|
765
|
+
|
|
766
|
+
.aqsp-popover-input {
|
|
767
|
+
flex: none;
|
|
768
|
+
height: 28px;
|
|
769
|
+
}
|
|
770
|
+
|
|
771
|
+
.aqsp-popover-textarea:focus-visible,
|
|
772
|
+
.aqsp-popover-input:focus-visible {
|
|
773
|
+
border-color: #2563eb;
|
|
774
|
+
outline: 2px solid #2563eb;
|
|
775
|
+
outline-offset: -1px;
|
|
776
|
+
}
|
|
777
|
+
|
|
778
|
+
.aqsp-popover-textarea[aria-invalid="true"],
|
|
779
|
+
.aqsp-popover-input[aria-invalid="true"] {
|
|
780
|
+
border-color: #dc2626;
|
|
781
|
+
}
|
|
782
|
+
|
|
783
|
+
.aqsp-popover-textarea[aria-invalid="true"]:focus-visible,
|
|
784
|
+
.aqsp-popover-input[aria-invalid="true"]:focus-visible {
|
|
785
|
+
border-color: #dc2626;
|
|
786
|
+
outline-color: #dc2626;
|
|
787
|
+
}
|
|
788
|
+
|
|
789
|
+
/* ヒント (Escape の挙動 / 拒否の再試行案内) — 12px の控えめ色、拒否時は赤 */
|
|
790
|
+
.aqsp-popover-hint {
|
|
791
|
+
margin: 4px 0 0;
|
|
792
|
+
font-size: 12px;
|
|
793
|
+
color: #6b7280;
|
|
794
|
+
}
|
|
795
|
+
|
|
796
|
+
[data-aqsp-popover-rejected] .aqsp-popover-hint {
|
|
797
|
+
color: #b91c1c;
|
|
798
|
+
}
|
|
799
|
+
|
|
800
|
+
/* リンク編集の欄 (ラベル + 入力) */
|
|
801
|
+
.aqsp-popover-field {
|
|
802
|
+
display: flex;
|
|
803
|
+
flex: none;
|
|
804
|
+
flex-direction: column;
|
|
805
|
+
gap: 3px;
|
|
806
|
+
margin: 0 0 8px;
|
|
807
|
+
}
|
|
808
|
+
|
|
809
|
+
.aqsp-popover-field-label {
|
|
810
|
+
font-size: 12px;
|
|
811
|
+
color: #6b7280;
|
|
812
|
+
}
|
|
813
|
+
|
|
814
|
+
/* 操作列: 主操作が先頭、閉じる (×) は margin-inline-start: auto で終端へ */
|
|
815
|
+
.aqsp-popover-actions {
|
|
816
|
+
display: flex;
|
|
817
|
+
flex: none;
|
|
818
|
+
align-items: center;
|
|
819
|
+
gap: 6px;
|
|
820
|
+
margin-top: 8px;
|
|
821
|
+
}
|
|
822
|
+
|
|
823
|
+
.aqsp-popover-button {
|
|
824
|
+
display: inline-flex;
|
|
825
|
+
align-items: center;
|
|
826
|
+
justify-content: center;
|
|
827
|
+
min-width: 56px;
|
|
828
|
+
height: 26px;
|
|
829
|
+
margin: 0;
|
|
830
|
+
padding: 0 10px;
|
|
831
|
+
border: 1px solid #d1d5db;
|
|
832
|
+
border-radius: 6px;
|
|
833
|
+
background: #f9fafb;
|
|
834
|
+
color: #1f2937;
|
|
835
|
+
font: inherit;
|
|
836
|
+
font-size: 12px;
|
|
837
|
+
font-weight: 500;
|
|
838
|
+
line-height: 1;
|
|
839
|
+
cursor: pointer;
|
|
840
|
+
}
|
|
841
|
+
|
|
842
|
+
.aqsp-popover-button:not(:disabled):hover {
|
|
843
|
+
border-color: #9ca3af;
|
|
844
|
+
background: #f3f4f6;
|
|
845
|
+
}
|
|
846
|
+
|
|
847
|
+
.aqsp-popover-button:focus-visible {
|
|
848
|
+
outline: 2px solid #2563eb;
|
|
849
|
+
outline-offset: 1px;
|
|
850
|
+
}
|
|
851
|
+
|
|
852
|
+
.aqsp-popover-button:disabled {
|
|
853
|
+
opacity: 0.5;
|
|
854
|
+
cursor: not-allowed;
|
|
855
|
+
}
|
|
856
|
+
|
|
857
|
+
/* 主操作 (保存 / 投稿 — 部品の役割属性で判別) */
|
|
858
|
+
.aqsp-popover-button[data-aqsp-popover-save],
|
|
859
|
+
.aqsp-popover-button[data-aqsp-popover-post] {
|
|
860
|
+
border-color: #2563eb;
|
|
861
|
+
background: #2563eb;
|
|
862
|
+
color: #ffffff;
|
|
863
|
+
}
|
|
864
|
+
|
|
865
|
+
.aqsp-popover-button[data-aqsp-popover-save]:not(:disabled):hover,
|
|
866
|
+
.aqsp-popover-button[data-aqsp-popover-post]:not(:disabled):hover {
|
|
867
|
+
border-color: #1d4ed8;
|
|
868
|
+
background: #1d4ed8;
|
|
869
|
+
}
|
|
870
|
+
|
|
871
|
+
/* 閉じる (×): 終端のゴースト正方形 */
|
|
872
|
+
.aqsp-popover-button[data-aqsp-popover-close] {
|
|
873
|
+
min-width: 0;
|
|
874
|
+
width: 26px;
|
|
875
|
+
margin-inline-start: auto;
|
|
876
|
+
padding: 0;
|
|
877
|
+
border-color: transparent;
|
|
878
|
+
background: transparent;
|
|
879
|
+
color: #6b7280;
|
|
880
|
+
font-size: 16px;
|
|
881
|
+
font-weight: 400;
|
|
882
|
+
}
|
|
883
|
+
|
|
884
|
+
.aqsp-popover-button[data-aqsp-popover-close]:not(:disabled):hover {
|
|
885
|
+
border-color: transparent;
|
|
886
|
+
background: #f3f4f6;
|
|
887
|
+
color: #1f2937;
|
|
888
|
+
}
|
|
889
|
+
|
|
890
|
+
/* コメントスレッド: 可変領域 (縮んでスクロール)。項目は薄い区切り線、先頭は線なし */
|
|
891
|
+
.aqsp-popover-thread {
|
|
892
|
+
flex: 1 1 auto;
|
|
893
|
+
min-height: 48px;
|
|
894
|
+
max-height: 220px;
|
|
895
|
+
margin: 0 0 8px;
|
|
896
|
+
padding: 0;
|
|
897
|
+
list-style: none;
|
|
898
|
+
overflow-y: auto;
|
|
899
|
+
overscroll-behavior: contain;
|
|
900
|
+
}
|
|
901
|
+
|
|
902
|
+
.aqsp-popover-comment-item {
|
|
903
|
+
padding: 6px 0;
|
|
904
|
+
border-top: 1px solid #f3f4f6;
|
|
905
|
+
}
|
|
906
|
+
|
|
907
|
+
.aqsp-popover-comment-item:first-child {
|
|
908
|
+
padding-top: 0;
|
|
909
|
+
border-top: 0;
|
|
910
|
+
}
|
|
911
|
+
|
|
912
|
+
.aqsp-popover-comment-author {
|
|
913
|
+
font-size: 12px;
|
|
914
|
+
font-weight: 600;
|
|
915
|
+
color: #111827;
|
|
916
|
+
}
|
|
917
|
+
|
|
918
|
+
.aqsp-popover-comment-time {
|
|
919
|
+
margin-inline-start: 6px;
|
|
920
|
+
font-size: 11px;
|
|
921
|
+
color: #6b7280;
|
|
922
|
+
font-variant-numeric: tabular-nums;
|
|
923
|
+
}
|
|
924
|
+
|
|
925
|
+
.aqsp-popover-comment-text {
|
|
926
|
+
margin: 2px 0 0;
|
|
927
|
+
white-space: pre-wrap;
|
|
928
|
+
overflow-wrap: anywhere;
|
|
929
|
+
}
|
|
930
|
+
|
|
931
|
+
/* 検証リスト: 入力 + 候補一覧 (可変領域)。活性は部品が書く aria-selected、ホバーは薄灰 (活性が後置で優先) */
|
|
932
|
+
.aqsp-popover-list .aqsp-popover-input {
|
|
933
|
+
margin-bottom: 4px;
|
|
934
|
+
}
|
|
935
|
+
|
|
936
|
+
.aqsp-popover-options {
|
|
937
|
+
flex: 1 1 auto;
|
|
938
|
+
min-height: 0;
|
|
939
|
+
max-height: 240px;
|
|
940
|
+
overflow-y: auto;
|
|
941
|
+
overscroll-behavior: contain;
|
|
942
|
+
}
|
|
943
|
+
|
|
944
|
+
.aqsp-popover-option {
|
|
945
|
+
padding: 5px 8px;
|
|
946
|
+
border-radius: 4px;
|
|
947
|
+
overflow: hidden;
|
|
948
|
+
white-space: nowrap;
|
|
949
|
+
text-overflow: ellipsis;
|
|
950
|
+
cursor: pointer;
|
|
951
|
+
}
|
|
952
|
+
|
|
953
|
+
.aqsp-popover-option:hover {
|
|
954
|
+
background: #f3f4f6;
|
|
955
|
+
}
|
|
956
|
+
|
|
957
|
+
.aqsp-popover-option[aria-selected="true"] {
|
|
958
|
+
background: #dbeafe;
|
|
959
|
+
color: #1e3a8a;
|
|
960
|
+
}
|
|
961
|
+
|
|
962
|
+
.aqsp-popover-option:focus-visible {
|
|
963
|
+
outline: 2px solid #2563eb;
|
|
964
|
+
outline-offset: -2px;
|
|
965
|
+
}
|
|
966
|
+
|
|
967
|
+
.aqsp-popover-empty {
|
|
968
|
+
padding: 6px 8px;
|
|
969
|
+
font-size: 12px;
|
|
970
|
+
color: #6b7280;
|
|
971
|
+
}
|
|
972
|
+
|
|
973
|
+
/* 検証メッセージ (受動 — role="status"): 閉じるボタンは右上へ絶対配置、本文はその幅を空ける */
|
|
974
|
+
.aqsp-popover-message {
|
|
975
|
+
position: relative;
|
|
976
|
+
padding-inline-end: 40px;
|
|
977
|
+
}
|
|
978
|
+
|
|
979
|
+
.aqsp-popover-message .aqsp-popover-title {
|
|
980
|
+
margin-bottom: 2px;
|
|
981
|
+
}
|
|
982
|
+
|
|
983
|
+
.aqsp-popover-message-text {
|
|
984
|
+
margin: 0;
|
|
985
|
+
white-space: pre-wrap;
|
|
986
|
+
overflow-wrap: anywhere;
|
|
987
|
+
}
|
|
988
|
+
|
|
989
|
+
.aqsp-popover-message .aqsp-popover-button[data-aqsp-popover-close] {
|
|
990
|
+
position: absolute;
|
|
991
|
+
inset-block-start: 6px;
|
|
992
|
+
inset-inline-end: 6px;
|
|
993
|
+
}
|
|
994
|
+
|
|
995
|
+
/* 拒否メッセージ (strict 検証の拒否再提示): 淡い赤地 + 赤い見出し (アクセント線は共通規則) */
|
|
996
|
+
.aqsp-popover-message[data-aqsp-popover-rejected] {
|
|
997
|
+
background: #fef2f2;
|
|
998
|
+
}
|
|
999
|
+
|
|
1000
|
+
.aqsp-popover-message[data-aqsp-popover-rejected] .aqsp-popover-title {
|
|
1001
|
+
color: #b91c1c;
|
|
1002
|
+
}
|
|
1003
|
+
|
|
1004
|
+
/*
|
|
1005
|
+
* forced-colors (ポップオーバー分 — 本体ブロックの後置が必須: 候補の活性規則と同詳細度のため、先に
|
|
1006
|
+
* 置くと通常規則に負ける)。背景色 / 影 / 文字色は強制配色が自動置換するため、消えると区別が
|
|
1007
|
+
* 失われるものだけを線で残す: 候補の活性 / ホバー (背景 → Highlight outline)、不正入力 (赤枠 →
|
|
1008
|
+
* 破線)、ゴーストの閉じるボタン (透明 border → ButtonText)
|
|
1009
|
+
*/
|
|
1010
|
+
@media (forced-colors: active) {
|
|
1011
|
+
.aqsp-popover-option:hover,
|
|
1012
|
+
.aqsp-popover-option[aria-selected="true"] {
|
|
1013
|
+
outline: 2px solid Highlight;
|
|
1014
|
+
outline-offset: -2px;
|
|
1015
|
+
}
|
|
1016
|
+
.aqsp-popover-textarea[aria-invalid="true"],
|
|
1017
|
+
.aqsp-popover-input[aria-invalid="true"] {
|
|
1018
|
+
border-style: dashed;
|
|
1019
|
+
}
|
|
1020
|
+
.aqsp-popover-button[data-aqsp-popover-close] {
|
|
1021
|
+
border-color: ButtonText;
|
|
1022
|
+
}
|
|
1023
|
+
}
|
|
1024
|
+
|
|
1025
|
+
[data-aqsp-empty] {
|
|
1026
|
+
display: block;
|
|
1027
|
+
width: 100%;
|
|
1028
|
+
height: 100%;
|
|
1029
|
+
}
|