@deepseek-ai/dsh-client-ui-dockkit 0.1.5-alpha.1 → 0.1.5-alpha.2
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/README.i18n.yaml +2 -2
- package/README.md +9 -9
- package/README.zh.md +9 -9
- package/lib/components/dockkit.module.css +405 -99
- package/lib/index.js +370 -161
- package/lib/types/components/DockSurface.d.ts +12 -4
- package/lib/types/components/FloatLayer.d.ts +4 -2
- package/lib/types/components/TabMenu.d.ts +2 -1
- package/lib/types/components/TabTitle.d.ts +6 -0
- package/lib/types/components/measure.d.ts +5 -1
- package/lib/types/components/render.d.ts +4 -2
- package/lib/types/contract/adapter.d.ts +6 -2
- package/lib/types/engine/geometry.d.ts +21 -8
- package/lib/types/engine/planner.d.ts +6 -3
- package/package.json +5 -7
|
@@ -7,10 +7,11 @@
|
|
|
7
7
|
* Colours come from the embedder's token layer; the kit names no literal. Type
|
|
8
8
|
* follows the embedder's content axis (`--dsh-content-font-size` and its
|
|
9
9
|
* secondary step) so a surface reads at the same size as the page around it.
|
|
10
|
-
* Emphasis —
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
10
|
+
* Emphasis — the drop caret, the drop-zone hint — takes the platform's accent
|
|
11
|
+
* (`--dsw-alias-brand-primary-new-colorprimary-new-color`), not
|
|
12
|
+
* `--dsw-alias-brand-primary`, which this platform binds to its near-black
|
|
13
|
+
* (light) or near-white (dark) foreground. A hovered divider takes the
|
|
14
|
+
* caption label ink instead, reading as a handle rather than a highlight.
|
|
14
15
|
*/
|
|
15
16
|
|
|
16
17
|
.split {
|
|
@@ -35,25 +36,87 @@
|
|
|
35
36
|
min-height: 0;
|
|
36
37
|
}
|
|
37
38
|
|
|
39
|
+
/* The divider owns no layout room (`SPLIT_MINIMUMS.divider` mirrors the 0):
|
|
40
|
+
the halves abut, so a rule a pane draws across its own edge — a header's
|
|
41
|
+
hairline — runs unbroken past the seam. The visible rule is a 0.5px hairline
|
|
42
|
+
centred on the seam, matching the embedder's other borders, and `::after`
|
|
43
|
+
widens the pointer target to 8px by reaching 4px over each neighbour.
|
|
44
|
+
`z-index` keeps that overhang above the later sibling, which would otherwise
|
|
45
|
+
take the hit. */
|
|
38
46
|
.divider {
|
|
39
47
|
position: relative;
|
|
48
|
+
z-index: 1;
|
|
40
49
|
flex: none;
|
|
41
|
-
background: var(--dsw-alias-border-l1);
|
|
42
50
|
touch-action: none;
|
|
43
51
|
}
|
|
44
52
|
|
|
53
|
+
.divider::before,
|
|
54
|
+
.divider::after {
|
|
55
|
+
content: '';
|
|
56
|
+
position: absolute;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
.divider::before {
|
|
60
|
+
background: var(--dsw-alias-border-l4);
|
|
61
|
+
}
|
|
62
|
+
|
|
45
63
|
.splitRow > .divider {
|
|
46
|
-
width:
|
|
64
|
+
width: 0;
|
|
47
65
|
cursor: col-resize;
|
|
48
66
|
}
|
|
49
67
|
|
|
68
|
+
.splitRow > .divider::before {
|
|
69
|
+
top: 0;
|
|
70
|
+
bottom: 0;
|
|
71
|
+
left: -0.25px;
|
|
72
|
+
width: 0.5px;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
.splitRow > .divider::after {
|
|
76
|
+
top: 0;
|
|
77
|
+
bottom: 0;
|
|
78
|
+
left: -4px;
|
|
79
|
+
right: -4px;
|
|
80
|
+
}
|
|
81
|
+
|
|
50
82
|
.splitColumn > .divider {
|
|
51
|
-
height:
|
|
83
|
+
height: 0;
|
|
52
84
|
cursor: row-resize;
|
|
53
85
|
}
|
|
54
86
|
|
|
55
|
-
.divider
|
|
56
|
-
|
|
87
|
+
.splitColumn > .divider::before {
|
|
88
|
+
left: 0;
|
|
89
|
+
right: 0;
|
|
90
|
+
top: -0.25px;
|
|
91
|
+
height: 0.5px;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
.splitColumn > .divider::after {
|
|
95
|
+
left: 0;
|
|
96
|
+
right: 0;
|
|
97
|
+
top: -4px;
|
|
98
|
+
bottom: -4px;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
/* Hover: a 1px grip fades in over the hairline, its caption ink deepest at
|
|
102
|
+
its middle and fading toward both ends. The grip is painted on the `::after`
|
|
103
|
+
hit target, centred on the seam, and crossfaded through opacity, because a
|
|
104
|
+
gradient cannot transition from the hairline's solid colour. */
|
|
105
|
+
.divider::after {
|
|
106
|
+
opacity: 0;
|
|
107
|
+
transition: opacity 120ms ease-out;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
.divider:hover::after {
|
|
111
|
+
opacity: 1;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
.splitRow > .divider::after {
|
|
115
|
+
background: linear-gradient(to bottom, transparent, var(--dsw-alias-label-caption) 50%, transparent) center / 1px 100% no-repeat;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
.splitColumn > .divider::after {
|
|
119
|
+
background: linear-gradient(to right, transparent, var(--dsw-alias-label-caption) 50%, transparent) center / 100% 1px no-repeat;
|
|
57
120
|
}
|
|
58
121
|
|
|
59
122
|
/* Both floors: a flex item's minimum is its content's, and a body's longest
|
|
@@ -74,17 +137,18 @@
|
|
|
74
137
|
min-width: 0;
|
|
75
138
|
min-height: 0;
|
|
76
139
|
overflow: hidden;
|
|
77
|
-
border: 1px solid transparent;
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
.pane[data-dockkit-pane-active] {
|
|
81
|
-
border-color: var(--dsw-alias-border-l2);
|
|
82
140
|
}
|
|
83
141
|
|
|
84
|
-
/*
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
142
|
+
/* A 38px row whose 28px content band sits at its bottom: chips fill the band,
|
|
143
|
+
so they end flush with the strip's bottom edge, and the 28px add control, the
|
|
144
|
+
28px split control, and the embedder's 28px chrome centre on the band's one
|
|
145
|
+
centre line, so chip text and control glyphs never sit at different heights.
|
|
146
|
+
The 10px above is the strip's own top margin, inside its box so the hit
|
|
147
|
+
area stays one element; the 10px at the start is the first chip's inset
|
|
148
|
+
from the edge, and the 6px at the end puts the last control's glyph 12px
|
|
149
|
+
from the edge. The strip draws no border: a body
|
|
150
|
+
that wants a rule under it draws its own. A floating panel's header is
|
|
151
|
+
this same row.
|
|
88
152
|
|
|
89
153
|
The strip never clips: the chip box below is its one shrinking part, and
|
|
90
154
|
every control after it is `flex: none`, so a narrow pane costs chips, never
|
|
@@ -94,27 +158,47 @@
|
|
|
94
158
|
flex: none;
|
|
95
159
|
gap: 4px;
|
|
96
160
|
align-items: center;
|
|
97
|
-
height:
|
|
98
|
-
padding: 0
|
|
99
|
-
border-bottom: 0.5px solid var(--dsw-alias-border-l1);
|
|
161
|
+
height: 28px;
|
|
162
|
+
padding: 10px 6px 0 10px;
|
|
100
163
|
touch-action: none;
|
|
101
164
|
}
|
|
102
165
|
|
|
103
|
-
/* The chips. Shrinks to nothing before any control after it moves;
|
|
104
|
-
longer fits
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
166
|
+
/* The chips. Shrinks to nothing before any control after it moves; chips keep
|
|
167
|
+
their 80px floor, so what no longer fits scrolls here on the wheel, with no
|
|
168
|
+
scrollbar drawn. `touch-action: none` keeps a touch press-and-move a tab drag
|
|
169
|
+
rather than a pan the scroller would claim and cancel the pointer for.
|
|
170
|
+
`data-dockkit-strip-scroll` names the hidden sides (`start`, `end`, or
|
|
171
|
+
both); each hidden side fades the chips out over 24px into whatever ground
|
|
172
|
+
the pane draws, so the row reads as continuing under the controls. */
|
|
108
173
|
.stripTabs {
|
|
109
174
|
display: flex;
|
|
110
175
|
flex: 0 1 auto;
|
|
111
|
-
gap: 4px;
|
|
112
176
|
align-items: center;
|
|
113
177
|
min-width: 0;
|
|
114
|
-
overflow:
|
|
178
|
+
overflow-x: auto;
|
|
179
|
+
overflow-y: hidden;
|
|
180
|
+
/* The scroll to a newly active chip glides rather than jumps. */
|
|
181
|
+
scroll-behavior: smooth;
|
|
182
|
+
scrollbar-width: none;
|
|
115
183
|
touch-action: none;
|
|
116
184
|
}
|
|
117
185
|
|
|
186
|
+
.stripTabs::-webkit-scrollbar {
|
|
187
|
+
display: none;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
.stripTabs[data-dockkit-strip-scroll='end'] {
|
|
191
|
+
mask-image: linear-gradient(to right, black calc(100% - 24px), transparent);
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
.stripTabs[data-dockkit-strip-scroll='start'] {
|
|
195
|
+
mask-image: linear-gradient(to right, transparent, black 24px);
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
.stripTabs[data-dockkit-strip-scroll='start end'] {
|
|
199
|
+
mask-image: linear-gradient(to right, transparent, black 24px, black calc(100% - 24px), transparent);
|
|
200
|
+
}
|
|
201
|
+
|
|
118
202
|
/* Takes the free space and gives it all back first: a zero basis shrinks
|
|
119
203
|
nothing, so shortage lands on the chip box alone. */
|
|
120
204
|
.stripFill {
|
|
@@ -122,37 +206,64 @@
|
|
|
122
206
|
min-width: 0;
|
|
123
207
|
}
|
|
124
208
|
|
|
125
|
-
/* Embedder controls at the strip's end,
|
|
126
|
-
control
|
|
209
|
+
/* Embedder controls at the strip's end, spaced from the kit's own split
|
|
210
|
+
control as they are from each other: the strip's 4px gap plus this 4px
|
|
211
|
+
margin equals the 8px between the controls. */
|
|
127
212
|
.stripChrome {
|
|
128
213
|
display: flex;
|
|
129
214
|
flex: none;
|
|
130
|
-
gap:
|
|
215
|
+
gap: 8px;
|
|
131
216
|
align-items: center;
|
|
132
|
-
height:
|
|
133
|
-
margin-left:
|
|
134
|
-
padding-left: 4px;
|
|
135
|
-
border-left: 0.5px solid var(--dsw-alias-border-l1);
|
|
217
|
+
height: 28px;
|
|
218
|
+
margin-left: 4px;
|
|
136
219
|
}
|
|
137
220
|
|
|
138
|
-
.
|
|
221
|
+
/* The slot between two chips: a 10px box with a hairline down its centre.
|
|
222
|
+
Targeted by a drag, the same box draws the caret instead, so the chips
|
|
223
|
+
around it never move. */
|
|
224
|
+
.slot {
|
|
225
|
+
display: flex;
|
|
139
226
|
flex: none;
|
|
140
|
-
align-
|
|
227
|
+
align-items: center;
|
|
228
|
+
justify-content: center;
|
|
229
|
+
width: 10px;
|
|
230
|
+
height: 28px;
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
.slot::before {
|
|
234
|
+
content: '';
|
|
235
|
+
width: 0.5px;
|
|
236
|
+
height: 14px;
|
|
237
|
+
background: var(--dsw-alias-border-l4);
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
/* The active chip is a filled capsule and needs no rule against it: the two
|
|
241
|
+
slots beside it go blank, so the row reads as the capsule between bare
|
|
242
|
+
chips. A caret in either slot still draws. */
|
|
243
|
+
.tabActive + .slot:not(.slotCaret)::before,
|
|
244
|
+
.slot:not(.slotCaret):has(+ .tabActive)::before {
|
|
245
|
+
background: transparent;
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
.slotCaret::before {
|
|
141
249
|
width: 2px;
|
|
142
250
|
height: 20px;
|
|
143
251
|
background: var(--dsw-alias-brand-primary-new-colorprimary-new-color);
|
|
144
252
|
}
|
|
145
253
|
|
|
254
|
+
/* The chip: a 28px capsule whose title runs to the right inset. The close
|
|
255
|
+
control is not in the flow — it sits over the title's last 14px and shows
|
|
256
|
+
while the chip is active, hovered, or holds focus — so a chip is the same
|
|
257
|
+
width with and without it and nothing shifts on hover. */
|
|
146
258
|
.tab {
|
|
147
259
|
position: relative;
|
|
148
260
|
display: flex;
|
|
149
261
|
flex: 0 1 auto;
|
|
150
|
-
gap: 4px;
|
|
151
262
|
align-items: center;
|
|
152
|
-
min-width:
|
|
263
|
+
min-width: 80px;
|
|
153
264
|
max-width: 170px;
|
|
154
|
-
height:
|
|
155
|
-
padding: 0
|
|
265
|
+
height: 28px;
|
|
266
|
+
padding: 0 10px;
|
|
156
267
|
color: var(--dsw-alias-label-secondary);
|
|
157
268
|
font-size: var(--dsh-content-font-size-secondary, 13px);
|
|
158
269
|
line-height: 1;
|
|
@@ -163,35 +274,82 @@
|
|
|
163
274
|
user-select: none;
|
|
164
275
|
}
|
|
165
276
|
|
|
277
|
+
/* A flex row with a 5px gap, so an embedder's leading glyph (`renderTabTitle`)
|
|
278
|
+
centres on the text's line rather than sitting on its baseline and keeps
|
|
279
|
+
one distance from it. The clip is horizontal in intent; the line box must
|
|
280
|
+
hold the descenders it would otherwise cut, hence a line-height above the
|
|
281
|
+
chip's own 1. No ellipsis: a title wider than its box (`TabTitle` sets
|
|
282
|
+
`data-dockkit-tab-clipped`) fades out over its last 16px instead. A mask on
|
|
283
|
+
the title rather than a painted gradient: the chip's fill is bare,
|
|
284
|
+
translucent hover, or the active tag colour, and a mask matches every one
|
|
285
|
+
without naming it. */
|
|
166
286
|
.tabTitle {
|
|
287
|
+
display: flex;
|
|
288
|
+
flex: 1 1 auto;
|
|
289
|
+
gap: 5px;
|
|
290
|
+
align-items: center;
|
|
291
|
+
min-width: 0;
|
|
167
292
|
overflow: hidden;
|
|
168
|
-
|
|
293
|
+
line-height: 1.4;
|
|
169
294
|
}
|
|
170
295
|
|
|
296
|
+
.tabTitle[data-dockkit-tab-clipped] {
|
|
297
|
+
mask-image: linear-gradient(to right, black calc(100% - 16px), transparent);
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
/* While the close shows, the title is gone under the close's circle and fades
|
|
301
|
+
out over the 16px before it: the circle spans the chip's last 24px and the
|
|
302
|
+
title ends 10px inside the chip, so the title's last 14px are under it.
|
|
303
|
+
Later than the clipped mask, so a clipped chip showing its close fades
|
|
304
|
+
under the close. A floating panel's header chip has no close, so it keeps
|
|
305
|
+
the clipped mask alone. */
|
|
306
|
+
.tab:not(.floatTitle):hover .tabTitle,
|
|
307
|
+
.tab:not(.floatTitle):focus-within .tabTitle,
|
|
308
|
+
.tabActive .tabTitle {
|
|
309
|
+
mask-image: linear-gradient(to right, black calc(100% - 30px), transparent calc(100% - 14px));
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
/* A 20px icon button inset 4px from the chip's end, holding a 14px glyph in
|
|
313
|
+
the tertiary ink, so it sits back from the title beside it. */
|
|
171
314
|
.tabClose {
|
|
315
|
+
position: absolute;
|
|
316
|
+
top: 4px;
|
|
317
|
+
right: 4px;
|
|
172
318
|
display: flex;
|
|
173
|
-
flex: none;
|
|
174
319
|
align-items: center;
|
|
175
320
|
justify-content: center;
|
|
176
|
-
width:
|
|
177
|
-
height:
|
|
321
|
+
width: 20px;
|
|
322
|
+
height: 20px;
|
|
178
323
|
padding: 0;
|
|
179
|
-
color:
|
|
324
|
+
color: var(--dsw-alias-label-tertiary);
|
|
180
325
|
line-height: 1;
|
|
181
326
|
background: transparent;
|
|
182
327
|
border: none;
|
|
183
|
-
border-radius:
|
|
184
|
-
corner-shape: round;
|
|
328
|
+
border-radius: 20px;
|
|
185
329
|
cursor: pointer;
|
|
330
|
+
opacity: 0;
|
|
331
|
+
/* Hidden means untouchable too: without this a touch press on the chip's
|
|
332
|
+
trailing 20px would close the tab instead of activating it. */
|
|
333
|
+
pointer-events: none;
|
|
186
334
|
}
|
|
187
335
|
|
|
336
|
+
/* Shown while the chip is hovered or holds focus, and always on the active
|
|
337
|
+
chip: the tab in view is the one a reader closes next. */
|
|
338
|
+
.tab:hover .tabClose,
|
|
339
|
+
.tab:focus-within .tabClose,
|
|
340
|
+
.tabActive .tabClose {
|
|
341
|
+
opacity: 1;
|
|
342
|
+
pointer-events: auto;
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
/* The chip's height and corner, so it reads as one more capsule in the row. */
|
|
188
346
|
.addTab {
|
|
189
347
|
display: flex;
|
|
190
348
|
flex: none;
|
|
191
349
|
align-items: center;
|
|
192
350
|
justify-content: center;
|
|
193
|
-
width:
|
|
194
|
-
height:
|
|
351
|
+
width: 28px;
|
|
352
|
+
height: 28px;
|
|
195
353
|
padding: 0;
|
|
196
354
|
color: var(--dsw-alias-label-secondary);
|
|
197
355
|
line-height: 1;
|
|
@@ -208,46 +366,72 @@
|
|
|
208
366
|
|
|
209
367
|
.tabClose:hover {
|
|
210
368
|
color: var(--dsw-alias-label-primary);
|
|
211
|
-
background: var(--dsw-alias-interactive-bg-hover
|
|
369
|
+
background: var(--dsw-alias-interactive-bg-hover);
|
|
212
370
|
}
|
|
213
371
|
|
|
214
372
|
.tab:hover {
|
|
215
373
|
background: var(--dsw-alias-interactive-bg-hover);
|
|
216
374
|
}
|
|
217
375
|
|
|
218
|
-
/* The active chip is the filled capsule; the rest are bare text. */
|
|
376
|
+
/* The active chip is the filled capsule, in the tag fill; the rest are bare text. */
|
|
219
377
|
.tabActive {
|
|
220
378
|
color: var(--dsw-alias-label-primary);
|
|
221
|
-
background: var(--dsw-alias-
|
|
379
|
+
background: var(--dsw-alias-markdown-tag);
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
/* A pane's lone unclosable chip is a label, not a choice: no capsule, no
|
|
383
|
+
hover fill — the primary ink on the pane's own ground. Its title never
|
|
384
|
+
yields to a close control, so it keeps the clipped fade alone. */
|
|
385
|
+
.tab.tabQuiet,
|
|
386
|
+
.tab.tabQuiet:hover {
|
|
387
|
+
color: var(--dsw-alias-label-primary);
|
|
388
|
+
background: transparent;
|
|
389
|
+
cursor: default;
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
.tab.tabQuiet .tabTitle,
|
|
393
|
+
.tab.tabQuiet:hover .tabTitle,
|
|
394
|
+
.tab.tabQuiet:focus-within .tabTitle {
|
|
395
|
+
mask-image: none;
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
.tab.tabQuiet .tabTitle[data-dockkit-tab-clipped] {
|
|
399
|
+
mask-image: linear-gradient(to right, black calc(100% - 16px), transparent);
|
|
222
400
|
}
|
|
223
401
|
|
|
224
402
|
.tabDragging {
|
|
225
403
|
opacity: 0.5;
|
|
226
404
|
}
|
|
227
405
|
|
|
406
|
+
/* The geometry of a message's action row button (ui-chat MessageIconActions):
|
|
407
|
+
a 28px circle around a 15px glyph. */
|
|
228
408
|
.iconButton {
|
|
229
|
-
display: flex;
|
|
409
|
+
display: inline-flex;
|
|
230
410
|
flex: none;
|
|
231
411
|
align-items: center;
|
|
232
412
|
justify-content: center;
|
|
233
|
-
width:
|
|
234
|
-
height:
|
|
235
|
-
padding:
|
|
413
|
+
width: 28px;
|
|
414
|
+
height: 28px;
|
|
415
|
+
padding: 6px;
|
|
236
416
|
color: var(--dsw-alias-label-secondary);
|
|
237
417
|
line-height: 1;
|
|
238
418
|
background: transparent;
|
|
239
419
|
border: none;
|
|
240
|
-
border-radius:
|
|
420
|
+
border-radius: 28px;
|
|
241
421
|
cursor: pointer;
|
|
242
422
|
}
|
|
243
423
|
|
|
424
|
+
.iconButton svg {
|
|
425
|
+
width: 15px;
|
|
426
|
+
height: 15px;
|
|
427
|
+
}
|
|
428
|
+
|
|
244
429
|
.iconButton:hover:not(:disabled) {
|
|
245
|
-
color: var(--dsw-alias-label-primary);
|
|
246
430
|
background: var(--dsw-alias-interactive-bg-hover);
|
|
247
431
|
}
|
|
248
432
|
|
|
249
433
|
.iconButton:disabled {
|
|
250
|
-
|
|
434
|
+
opacity: 0.4;
|
|
251
435
|
cursor: default;
|
|
252
436
|
}
|
|
253
437
|
|
|
@@ -269,6 +453,10 @@
|
|
|
269
453
|
border-radius: 6px;
|
|
270
454
|
}
|
|
271
455
|
|
|
456
|
+
.menu:not(:has([role='menuitem'], [role='menuitemcheckbox'], [role='menuitemradio'])) {
|
|
457
|
+
display: none;
|
|
458
|
+
}
|
|
459
|
+
|
|
272
460
|
.menuItem {
|
|
273
461
|
padding: 5px 8px;
|
|
274
462
|
color: var(--dsw-alias-label-primary);
|
|
@@ -284,12 +472,14 @@
|
|
|
284
472
|
background: var(--dsw-alias-interactive-bg-hover);
|
|
285
473
|
}
|
|
286
474
|
|
|
475
|
+
/* No padding of its own: a tab's body reaches the pane's edges and the strip's
|
|
476
|
+
bottom edge, and keeps its own insets, so a header row it draws sits flush
|
|
477
|
+
under the strip. */
|
|
287
478
|
.paneBody {
|
|
288
479
|
position: relative;
|
|
289
480
|
flex: 1 1 auto;
|
|
290
481
|
min-width: 0;
|
|
291
482
|
min-height: 0;
|
|
292
|
-
padding: 12px;
|
|
293
483
|
overflow: auto; /* This sheet draws elevated surfaces (the strip and the menu), so a scroller
|
|
294
484
|
inside it rebinds the thumb indirection in a complete pair — a base-surface
|
|
295
485
|
thumb on an elevated ground reads as a smudge. */
|
|
@@ -299,14 +489,40 @@
|
|
|
299
489
|
|
|
300
490
|
.empty {
|
|
301
491
|
margin: 0;
|
|
492
|
+
padding: 12px;
|
|
302
493
|
color: var(--dsw-alias-label-tertiary);
|
|
303
494
|
font-size: var(--dsh-content-font-size-secondary, 13px);
|
|
304
495
|
}
|
|
305
496
|
|
|
497
|
+
/* The drop hint is a scrim and, over it, one box pair per landing region.
|
|
498
|
+
The scrim (`.dockScrim`) covers the whole body with the translucent, blurred
|
|
499
|
+
ground, so the insets between and around the cards dim the body's content
|
|
500
|
+
instead of letting it show through raw. The outer box (`.dockHint`) is the
|
|
501
|
+
region a release fills — the whole body, or 40% (edge bands) or 50%
|
|
502
|
+
(horizontal halves) of it — and draws nothing; it is a padded frame that
|
|
503
|
+
keeps the card inside it 8px clear of the body's edges and, between two
|
|
504
|
+
horizontal halves, 4px clear of the seam, so neighbouring cards sit 8px
|
|
505
|
+
apart like the body's own insets. The card (`.dockHintCard`) is what the eye
|
|
506
|
+
lands on: a dashed frame with the zone's glyph and caption stacked at its
|
|
507
|
+
centre. A card that is not under the pointer stays as a quiet outline so the
|
|
508
|
+
reader sees where the other release would land. */
|
|
509
|
+
.dockScrim {
|
|
510
|
+
position: absolute;
|
|
511
|
+
inset: 0;
|
|
512
|
+
pointer-events: none;
|
|
513
|
+
/* The ground the panes sit on, not a raised layer: in dark mode `bg-layer-2`
|
|
514
|
+
is a lighter bluish step than the column's `bg-base`, which tinted the
|
|
515
|
+
whole scrim away from the content beneath it. */
|
|
516
|
+
background: color-mix(in srgb, var(--dsw-alias-bg-base) 72%, transparent);
|
|
517
|
+
backdrop-filter: blur(6px);
|
|
518
|
+
animation: dockScrimIn 140ms ease-out;
|
|
519
|
+
}
|
|
520
|
+
|
|
306
521
|
.dockHint {
|
|
307
522
|
position: absolute;
|
|
308
|
-
|
|
309
|
-
|
|
523
|
+
display: flex;
|
|
524
|
+
box-sizing: border-box;
|
|
525
|
+
padding: 8px;
|
|
310
526
|
pointer-events: none;
|
|
311
527
|
}
|
|
312
528
|
|
|
@@ -328,15 +544,82 @@
|
|
|
328
544
|
width: 40%;
|
|
329
545
|
}
|
|
330
546
|
|
|
331
|
-
[data-dockkit-drop-zones='horizontal'] .dockHint[data-dockkit-dock-zone='left']
|
|
547
|
+
[data-dockkit-drop-zones='horizontal'] .dockHint[data-dockkit-dock-zone='left'] {
|
|
548
|
+
width: 50%;
|
|
549
|
+
padding-right: 4px;
|
|
550
|
+
}
|
|
551
|
+
|
|
332
552
|
[data-dockkit-drop-zones='horizontal'] .dockHint[data-dockkit-dock-zone='right'] {
|
|
333
553
|
width: 50%;
|
|
554
|
+
padding-left: 4px;
|
|
334
555
|
}
|
|
335
556
|
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
557
|
+
.dockHintCard {
|
|
558
|
+
display: flex;
|
|
559
|
+
flex: 1 1 auto;
|
|
560
|
+
flex-direction: column;
|
|
561
|
+
gap: 8px;
|
|
562
|
+
align-items: center;
|
|
563
|
+
justify-content: center;
|
|
564
|
+
min-width: 0;
|
|
565
|
+
min-height: 0;
|
|
566
|
+
padding: 12px;
|
|
567
|
+
overflow: hidden;
|
|
568
|
+
color: var(--dsw-alias-label-tertiary);
|
|
569
|
+
border: 1.5px dashed var(--dsw-alias-border-l2);
|
|
570
|
+
border-radius: 12px;
|
|
571
|
+
transition: color 120ms ease-out, background-color 120ms ease-out, border-color 120ms ease-out;
|
|
572
|
+
animation: dockHintIn 140ms ease-out;
|
|
573
|
+
}
|
|
574
|
+
|
|
575
|
+
/* The card under the pointer takes the accent: a tinted ground over the scrim,
|
|
576
|
+
an accent dashed frame, and secondary ink for the glyph and caption. */
|
|
577
|
+
.dockHint[data-dockkit-drop-active] .dockHintCard {
|
|
578
|
+
color: var(--dsw-alias-label-secondary);
|
|
579
|
+
background: color-mix(in srgb, var(--dsw-alias-brand-primary-new-colorprimary-new-color) 8%, transparent);
|
|
580
|
+
border-color: var(--dsw-alias-brand-primary-new-colorprimary-new-color);
|
|
581
|
+
}
|
|
582
|
+
|
|
583
|
+
.dockHintCard svg {
|
|
584
|
+
flex: none;
|
|
585
|
+
width: 20px;
|
|
586
|
+
height: 20px;
|
|
587
|
+
}
|
|
588
|
+
|
|
589
|
+
/* One line, clipped rather than wrapped: the card in a narrow half is still
|
|
590
|
+
wide enough for its glyph, and the caption fades under the frame. */
|
|
591
|
+
.dockHintLabel {
|
|
592
|
+
max-width: 100%;
|
|
593
|
+
overflow: hidden;
|
|
594
|
+
font-size: var(--dsh-content-font-size-secondary, 13px);
|
|
595
|
+
font-weight: 500;
|
|
596
|
+
line-height: 1.4;
|
|
597
|
+
white-space: nowrap;
|
|
598
|
+
text-overflow: ellipsis;
|
|
599
|
+
}
|
|
600
|
+
|
|
601
|
+
@keyframes dockHintIn {
|
|
602
|
+
from {
|
|
603
|
+
opacity: 0;
|
|
604
|
+
transform: scale(0.98);
|
|
605
|
+
}
|
|
606
|
+
|
|
607
|
+
to {
|
|
608
|
+
opacity: 1;
|
|
609
|
+
transform: none;
|
|
610
|
+
}
|
|
611
|
+
}
|
|
612
|
+
|
|
613
|
+
/* The scrim fades in without the cards' scale: a full-body cover that shrinks
|
|
614
|
+
would expose an uncovered rim of raw content on entry. */
|
|
615
|
+
@keyframes dockScrimIn {
|
|
616
|
+
from {
|
|
617
|
+
opacity: 0;
|
|
618
|
+
}
|
|
619
|
+
|
|
620
|
+
to {
|
|
621
|
+
opacity: 1;
|
|
622
|
+
}
|
|
340
623
|
}
|
|
341
624
|
|
|
342
625
|
.dockHint[data-dockkit-dock-zone='top'] {
|
|
@@ -357,43 +640,50 @@
|
|
|
357
640
|
position: fixed;
|
|
358
641
|
display: flex;
|
|
359
642
|
flex-direction: column;
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
643
|
+
/* The body inside is unpadded and reaches the edges, so the frame clips it
|
|
644
|
+
to its own corners. */
|
|
645
|
+
overflow: hidden;
|
|
646
|
+
background: var(--dsw-alias-bg-layer-2);
|
|
647
|
+
border-radius: 20px;
|
|
648
|
+
/* The menu's shadow with the stroke rebound one step lighter than the
|
|
649
|
+
default (l2): the panel reads as the same kind of raised surface, and the
|
|
650
|
+
shadow's hairline outlines it, so the frame draws no border of its own. */
|
|
651
|
+
--dsw-elevation-stroke-color: var(--dsw-alias-border-l2);
|
|
652
|
+
box-shadow: var(--dsw-elevation-prominent);
|
|
364
653
|
pointer-events: auto;
|
|
365
654
|
}
|
|
366
655
|
|
|
367
|
-
/* The active panel keeps the same
|
|
368
|
-
|
|
369
|
-
|
|
656
|
+
/* The active panel keeps the same frame: it is already on top of the z order
|
|
657
|
+
and casts the same shadow, and a heavier or darker frame read as a defect.
|
|
658
|
+
`data-dockkit-float-active` stays on the element for tests. */
|
|
370
659
|
|
|
660
|
+
/* The panel's header is the pane strip's row (`.tabStrip` supplies the
|
|
661
|
+
metrics) and the whole of it is the move grip. */
|
|
371
662
|
.floatHeader {
|
|
372
|
-
display: flex;
|
|
373
|
-
flex: none;
|
|
374
|
-
gap: 2px;
|
|
375
|
-
align-items: center;
|
|
376
|
-
height: 28px;
|
|
377
|
-
padding: 0 4px 0 10px;
|
|
378
|
-
border-bottom: 0.5px solid var(--dsw-alias-border-l1);
|
|
379
663
|
cursor: move;
|
|
380
|
-
touch-action: none;
|
|
381
664
|
user-select: none;
|
|
382
665
|
}
|
|
383
666
|
|
|
667
|
+
/* The one tab, drawn as its chip would be in a strip but never selected,
|
|
668
|
+
hovered, or closable from here: the frame's controls do that. */
|
|
384
669
|
.floatTitle {
|
|
385
|
-
flex:
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
670
|
+
flex: 0 1 auto;
|
|
671
|
+
cursor: inherit;
|
|
672
|
+
}
|
|
673
|
+
|
|
674
|
+
.tab.floatTitle:hover {
|
|
675
|
+
background: transparent;
|
|
676
|
+
}
|
|
677
|
+
|
|
678
|
+
/* Mirrored so the filled pane sits at the right, where the docked surface is. */
|
|
679
|
+
.dockGlyph {
|
|
680
|
+
transform: scaleX(-1);
|
|
391
681
|
}
|
|
392
682
|
|
|
683
|
+
/* Unpadded like `.paneBody`: the same body draws the same insets in a float. */
|
|
393
684
|
.floatBody {
|
|
394
685
|
flex: 1 1 auto;
|
|
395
686
|
min-height: 0;
|
|
396
|
-
padding: 10px;
|
|
397
687
|
overflow: auto; /* This sheet draws elevated surfaces (the strip and the menu), so a scroller
|
|
398
688
|
inside it rebinds the thumb indirection in a complete pair — a base-surface
|
|
399
689
|
thumb on an elevated ground reads as a smudge. */
|
|
@@ -405,19 +695,35 @@
|
|
|
405
695
|
position: absolute;
|
|
406
696
|
right: 0;
|
|
407
697
|
bottom: 0;
|
|
408
|
-
width:
|
|
409
|
-
height:
|
|
698
|
+
width: 20px;
|
|
699
|
+
height: 20px;
|
|
410
700
|
cursor: nwse-resize;
|
|
411
701
|
touch-action: none;
|
|
412
702
|
}
|
|
413
703
|
|
|
704
|
+
/* The grip is a quarter arc concentric with the frame's 20px corner (16px
|
|
705
|
+
radius at a 4px inset), so it reads as part of the frame. It shows only
|
|
706
|
+
while the pointer is over the panel — an idle panel keeps a clean corner —
|
|
707
|
+
and `:active` keeps it lit while a drag holds the pointer capture. */
|
|
414
708
|
.floatResize::after {
|
|
415
|
-
position: absolute;
|
|
416
|
-
right: 3px;
|
|
417
|
-
bottom: 3px;
|
|
418
|
-
width: 6px;
|
|
419
|
-
height: 6px;
|
|
420
|
-
border-right: 2px solid var(--dsw-alias-label-tertiary);
|
|
421
|
-
border-bottom: 2px solid var(--dsw-alias-label-tertiary);
|
|
422
709
|
content: '';
|
|
710
|
+
position: absolute;
|
|
711
|
+
right: 4px;
|
|
712
|
+
bottom: 4px;
|
|
713
|
+
width: 16px;
|
|
714
|
+
height: 16px;
|
|
715
|
+
border-right: 1.5px solid var(--dsw-alias-label-caption);
|
|
716
|
+
border-bottom: 1.5px solid var(--dsw-alias-label-caption);
|
|
717
|
+
border-bottom-right-radius: 16px;
|
|
718
|
+
opacity: 0;
|
|
719
|
+
transition: opacity 120ms ease-out;
|
|
720
|
+
}
|
|
721
|
+
|
|
722
|
+
.float:hover .floatResize::after,
|
|
723
|
+
.floatResize:active::after {
|
|
724
|
+
opacity: 1;
|
|
725
|
+
}
|
|
726
|
+
|
|
727
|
+
.floatResize:hover::after {
|
|
728
|
+
border-color: var(--dsw-alias-label-tertiary);
|
|
423
729
|
}
|