@deepseek-ai/dsh-client-ui-primitives 0.1.6-alpha.2 → 0.1.7-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 +31 -13
- package/README.zh.md +31 -13
- package/lib/CodeCard.module.css +83 -0
- package/lib/ConnectionIndicator.module.css +1 -10
- package/lib/DiffBlock.module.css +24 -53
- package/lib/HoverCard.module.css +27 -0
- package/lib/Menu.module.css +68 -48
- package/lib/Modal.module.css +6 -2
- package/lib/OnboardingSurface.module.css +1 -2
- package/lib/PathLabel.module.css +28 -0
- package/lib/ReadBlock.module.css +13 -81
- package/lib/RiskConfirmation.module.css +1 -1
- package/lib/SegmentedControl.module.css +76 -0
- package/lib/SegmentedTabs.module.css +55 -0
- package/lib/StateDot.module.css +64 -37
- package/lib/TerminalBlock.module.css +13 -6
- package/lib/TextShimmer.module.css +27 -0
- package/lib/Toast.module.css +31 -2
- package/lib/Tooltip.module.css +12 -0
- package/lib/index.js +5892 -3142
- package/lib/markdown/CodeBlock.module.css +15 -0
- package/lib/markdown/MarkdownText.module.css +1 -19
- package/lib/settings-form/SettingsForm.module.css +53 -0
- package/lib/settings-form/fields.module.css +145 -0
- package/lib/types/CodeToolbar.d.ts +30 -0
- package/lib/types/ConfigField.d.ts +33 -0
- package/lib/types/DiffBlock.d.ts +3 -3
- package/lib/types/DisclosureRow.d.ts +4 -1
- package/lib/types/HoverCard.d.ts +14 -4
- package/lib/types/LinkIcon.d.ts +15 -30
- package/lib/types/Menu.d.ts +53 -8
- package/lib/types/PathLabel.d.ts +13 -0
- package/lib/types/PermissionIcon.d.ts +39 -0
- package/lib/types/ReadBlock.d.ts +2 -1
- package/lib/types/ReferenceIcon.d.ts +12 -7
- package/lib/types/SegmentedControl.d.ts +35 -0
- package/lib/types/SegmentedTabs.d.ts +26 -0
- package/lib/types/SiteGlyph.d.ts +1 -1
- package/lib/types/StateDot.d.ts +6 -4
- package/lib/types/TerminalBlock.d.ts +15 -3
- package/lib/types/TextShimmer.d.ts +13 -0
- package/lib/types/Toast.d.ts +19 -2
- package/lib/types/Tooltip.d.ts +13 -2
- package/lib/types/code-file-types.d.ts +1 -1
- package/lib/types/code-highlighting.d.ts +19 -0
- package/lib/types/icons/index.d.ts +376 -195
- package/lib/types/icons/props.d.ts +1 -1
- package/lib/types/icons/shared-artwork.d.ts +36 -0
- package/lib/types/index.d.ts +22 -4
- package/lib/types/markdown/CodeBlock.d.ts +6 -1
- package/lib/types/markdown/render.d.ts +3 -0
- package/lib/types/overlay-top-margin.d.ts +14 -0
- package/lib/types/plugin-artwork.d.ts +17 -0
- package/lib/types/settings-form/SettingsForm.d.ts +46 -0
- package/lib/types/settings-form/fields.d.ts +69 -0
- package/lib/types/settings-form/form-model.d.ts +214 -0
- package/lib/types/useAnchoredMaxHeight.d.ts +4 -1
- package/lib/types/useAnchoredPosition.d.ts +3 -1
- package/lib/types/user-text.d.ts +2 -2
- package/lib/user-text.module.css +4 -1
- package/package.json +5 -3
package/lib/Menu.module.css
CHANGED
|
@@ -3,19 +3,19 @@
|
|
|
3
3
|
display: inline-flex;
|
|
4
4
|
}
|
|
5
5
|
|
|
6
|
-
/*
|
|
7
|
-
* r12, elevation-prominent (hairline stroke in shadow), 4px inset padding. */
|
|
6
|
+
/* Compact translucent dropdown card shared by feature menus. */
|
|
8
7
|
.list,
|
|
9
8
|
.submenu {
|
|
10
9
|
/* min-widths below are the design's outer card widths — include the pad. */
|
|
11
10
|
box-sizing: border-box;
|
|
12
|
-
padding:
|
|
11
|
+
padding: 3px;
|
|
13
12
|
display: flex;
|
|
14
13
|
flex-direction: column;
|
|
15
14
|
gap: 0;
|
|
16
15
|
border: 0;
|
|
17
|
-
border-radius:
|
|
16
|
+
border-radius: 16px;
|
|
18
17
|
background: var(--dsw-specific-menu);
|
|
18
|
+
backdrop-filter: var(--dsw-menu-backdrop-filter);
|
|
19
19
|
--dsw-elevation-stroke-color: var(--dsw-alias-border-l1);
|
|
20
20
|
box-shadow: var(--dsw-elevation-prominent);
|
|
21
21
|
/* Elevated surface: the scrollbar thumb takes the l2 elevation tokens. The
|
|
@@ -27,13 +27,13 @@
|
|
|
27
27
|
--dsh-scrollbar-thumb-hover: var(--dsw-alias-scrollbar-hover-l2);
|
|
28
28
|
}
|
|
29
29
|
|
|
30
|
-
/* Primary
|
|
30
|
+
/* Primary cards grow with their content between compact and readable bounds. */
|
|
31
31
|
.list {
|
|
32
32
|
position: absolute;
|
|
33
33
|
top: calc(100% + 4px);
|
|
34
34
|
left: 0;
|
|
35
35
|
z-index: 100;
|
|
36
|
-
min-width:
|
|
36
|
+
min-width: 144px;
|
|
37
37
|
max-width: 360px;
|
|
38
38
|
}
|
|
39
39
|
|
|
@@ -60,12 +60,13 @@
|
|
|
60
60
|
}
|
|
61
61
|
|
|
62
62
|
/* Viewport fit: the card stops 12px short of the viewport's top/bottom edges
|
|
63
|
-
* (
|
|
63
|
+
* (the portal MARGIN in Menu.tsx; the top side widens to the frame's published
|
|
64
|
+
* top clearance, the macOS window strip) and taller content scrolls inside
|
|
64
65
|
* .viewport, so a pinned .footer stays visible. Menus with submenu rows skip
|
|
65
66
|
* this class — the overflow clip would crop the side card, so they rely on
|
|
66
67
|
* staying short. */
|
|
67
68
|
.scrollable {
|
|
68
|
-
max-height: calc(100vh -
|
|
69
|
+
max-height: calc(100vh - 12px - max(12px, var(--dsh-frame-top-clearance, 12px)));
|
|
69
70
|
}
|
|
70
71
|
|
|
71
72
|
.viewport {
|
|
@@ -84,8 +85,8 @@
|
|
|
84
85
|
flex: none;
|
|
85
86
|
display: flex;
|
|
86
87
|
flex-direction: column;
|
|
87
|
-
margin-top:
|
|
88
|
-
padding-top:
|
|
88
|
+
margin-top: 3px;
|
|
89
|
+
padding-top: 3px;
|
|
89
90
|
border-top: 0.5px solid var(--dsw-alias-border-l2);
|
|
90
91
|
}
|
|
91
92
|
|
|
@@ -93,21 +94,20 @@
|
|
|
93
94
|
position: relative;
|
|
94
95
|
}
|
|
95
96
|
|
|
96
|
-
/* Menu cell
|
|
97
|
-
* gap 8 between leading icon / label / trailing check. */
|
|
97
|
+
/* Menu cell: compact text, icon, and selection spacing. */
|
|
98
98
|
.item {
|
|
99
99
|
display: flex;
|
|
100
100
|
align-items: center;
|
|
101
|
-
gap:
|
|
101
|
+
gap: 6px;
|
|
102
102
|
width: 100%;
|
|
103
|
-
min-height:
|
|
104
|
-
padding: 8px
|
|
103
|
+
min-height: 34px;
|
|
104
|
+
padding: 6px 8px;
|
|
105
105
|
border: none;
|
|
106
|
-
border-radius:
|
|
106
|
+
border-radius: 8px;
|
|
107
107
|
background: transparent;
|
|
108
108
|
cursor: pointer;
|
|
109
|
-
font-size:
|
|
110
|
-
line-height:
|
|
109
|
+
font-size: 13px;
|
|
110
|
+
line-height: 20px;
|
|
111
111
|
color: var(--dsw-alias-label-primary);
|
|
112
112
|
text-align: left;
|
|
113
113
|
}
|
|
@@ -125,33 +125,33 @@
|
|
|
125
125
|
}
|
|
126
126
|
|
|
127
127
|
.denseList .item {
|
|
128
|
-
min-height:
|
|
129
|
-
padding-block:
|
|
128
|
+
min-height: 30px;
|
|
129
|
+
padding-block: 4px;
|
|
130
130
|
}
|
|
131
131
|
|
|
132
132
|
.denseList .label {
|
|
133
|
-
padding-block:
|
|
133
|
+
padding-block: 3px;
|
|
134
134
|
}
|
|
135
135
|
|
|
136
136
|
.list.compactList,
|
|
137
137
|
.submenu.compactList {
|
|
138
|
-
min-width:
|
|
138
|
+
min-width: 156px;
|
|
139
139
|
padding: 2px;
|
|
140
140
|
border-radius: 7px;
|
|
141
141
|
}
|
|
142
142
|
|
|
143
143
|
.compactList .item {
|
|
144
|
-
min-height:
|
|
145
|
-
gap:
|
|
146
|
-
padding:
|
|
144
|
+
min-height: 24px;
|
|
145
|
+
gap: 5px;
|
|
146
|
+
padding: 2px 6px;
|
|
147
147
|
border-radius: 5px;
|
|
148
|
-
font-size:
|
|
149
|
-
line-height:
|
|
148
|
+
font-size: 11px;
|
|
149
|
+
line-height: 17px;
|
|
150
150
|
}
|
|
151
151
|
|
|
152
152
|
.compactList .itemIcon {
|
|
153
|
-
width:
|
|
154
|
-
height:
|
|
153
|
+
width: 12px;
|
|
154
|
+
height: 12px;
|
|
155
155
|
}
|
|
156
156
|
|
|
157
157
|
.compactList .separator {
|
|
@@ -159,9 +159,9 @@
|
|
|
159
159
|
}
|
|
160
160
|
|
|
161
161
|
.compactList .label {
|
|
162
|
-
padding:
|
|
163
|
-
font-size:
|
|
164
|
-
line-height:
|
|
162
|
+
padding: 3px 6px;
|
|
163
|
+
font-size: 10px;
|
|
164
|
+
line-height: 15px;
|
|
165
165
|
}
|
|
166
166
|
|
|
167
167
|
.item:disabled {
|
|
@@ -172,13 +172,25 @@
|
|
|
172
172
|
.itemIcon {
|
|
173
173
|
display: inline-flex;
|
|
174
174
|
flex: none;
|
|
175
|
-
width:
|
|
176
|
-
height:
|
|
175
|
+
width: 14px;
|
|
176
|
+
height: 14px;
|
|
177
177
|
align-items: center;
|
|
178
178
|
justify-content: center;
|
|
179
179
|
color: var(--dsw-alias-label-tertiary);
|
|
180
180
|
}
|
|
181
181
|
|
|
182
|
+
.itemIcon svg,
|
|
183
|
+
.check {
|
|
184
|
+
width: 14px;
|
|
185
|
+
height: 14px;
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
.compactList .itemIcon svg,
|
|
189
|
+
.compactList .check {
|
|
190
|
+
width: 12px;
|
|
191
|
+
height: 12px;
|
|
192
|
+
}
|
|
193
|
+
|
|
182
194
|
.itemLabel {
|
|
183
195
|
flex: 1;
|
|
184
196
|
min-width: 0;
|
|
@@ -223,30 +235,38 @@
|
|
|
223
235
|
|
|
224
236
|
/* Heading row: non-interactive small grey text, padding aligned with items. */
|
|
225
237
|
.label {
|
|
226
|
-
padding: 8px
|
|
227
|
-
font-size:
|
|
228
|
-
line-height:
|
|
238
|
+
padding: 6px 8px;
|
|
239
|
+
font-size: 11px;
|
|
240
|
+
line-height: 15px;
|
|
229
241
|
color: var(--dsw-alias-label-tertiary);
|
|
230
242
|
}
|
|
231
243
|
|
|
232
|
-
/* Separator cell (figma 122:9481): py 4 / px 2 around the hairline.
|
|
244
|
+
/* Separator cell (figma 122:9481): py 4 / px 2 around the hairline. l2, not
|
|
245
|
+
* l1, for the same reason as .footer: l1 is near-invisible on this surface. */
|
|
233
246
|
.separator {
|
|
234
247
|
height: 0.5px;
|
|
235
|
-
margin:
|
|
236
|
-
background: var(--dsw-alias-border-
|
|
248
|
+
margin: 3px 2px;
|
|
249
|
+
background: var(--dsw-alias-border-l2);
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
/* A data separator directly followed by a row that starts a group draws one
|
|
253
|
+
* line, not two; a group start on the list's first row draws none. */
|
|
254
|
+
.separator + .separator,
|
|
255
|
+
.separator + .itemWrap > .separator:first-child,
|
|
256
|
+
.itemWrap:first-child > .separator:first-child {
|
|
257
|
+
display: none;
|
|
237
258
|
}
|
|
238
259
|
|
|
239
|
-
/* Nested card to the right of the parent row
|
|
260
|
+
/* Nested card to the right of the parent row.
|
|
240
261
|
* Bottom-aligned with the parent menu card (grows upward): itemWrap sits in
|
|
241
|
-
* .list's
|
|
242
|
-
* Horizontal: list pad (
|
|
243
|
-
* `100% + 6px` collapses to ~2px between outer card edges.
|
|
262
|
+
* .list's 3px pad, so bottom: -3px matches the list's outer bottom edge.
|
|
263
|
+
* Horizontal: list pad (3px) + 6px card gap = 9px past itemWrap.
|
|
244
264
|
* ::before bridges the full gap so the pointer can cross without mouseLeave. */
|
|
245
265
|
.submenu {
|
|
246
266
|
position: absolute;
|
|
247
267
|
top: auto;
|
|
248
|
-
bottom: -
|
|
249
|
-
left: calc(100% +
|
|
268
|
+
bottom: -3px;
|
|
269
|
+
left: calc(100% + 9px);
|
|
250
270
|
z-index: 101;
|
|
251
271
|
min-width: 163px;
|
|
252
272
|
}
|
|
@@ -256,6 +276,6 @@
|
|
|
256
276
|
position: absolute;
|
|
257
277
|
top: 0;
|
|
258
278
|
bottom: 0;
|
|
259
|
-
left: -
|
|
260
|
-
width:
|
|
279
|
+
left: -9px;
|
|
280
|
+
width: 9px;
|
|
261
281
|
}
|
package/lib/Modal.module.css
CHANGED
|
@@ -1,4 +1,8 @@
|
|
|
1
|
-
/* Full-viewport layer (figma Mask + Dialog 451:18655): mask + centered card.
|
|
1
|
+
/* Full-viewport layer (figma Mask + Dialog 451:18655): mask + centered card.
|
|
2
|
+
24px of air on every side; the top/bottom widen to the frame's published
|
|
3
|
+
top clearance (the macOS window strip) so a tall card stays clear of it.
|
|
4
|
+
Cards size against this padding box: consumers cap growth with
|
|
5
|
+
`max-height: 100%`, never their own viewport calc. */
|
|
2
6
|
.root {
|
|
3
7
|
position: fixed;
|
|
4
8
|
inset: 0;
|
|
@@ -6,7 +10,7 @@
|
|
|
6
10
|
display: flex;
|
|
7
11
|
align-items: center;
|
|
8
12
|
justify-content: center;
|
|
9
|
-
padding: 24px;
|
|
13
|
+
padding: max(24px, var(--dsh-frame-top-clearance, 24px)) 24px;
|
|
10
14
|
}
|
|
11
15
|
|
|
12
16
|
/* User/spec mask: rgba(0,0,0,0.24) + blur(2px) via --dsw-alias-bg-mask-1 /
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/* Auto margin keeps fitting text at the left. On overflow it becomes zero,
|
|
2
|
+
so flex-end preserves the filename suffix at the right edge. */
|
|
3
|
+
.path {
|
|
4
|
+
display: flex;
|
|
5
|
+
flex: 1 1 auto;
|
|
6
|
+
justify-content: flex-end;
|
|
7
|
+
min-width: 0;
|
|
8
|
+
overflow: hidden;
|
|
9
|
+
font-size: 12px;
|
|
10
|
+
white-space: nowrap;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
.path[data-path-clipped] {
|
|
14
|
+
mask-image: linear-gradient(to right, transparent, black 28px);
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
.text {
|
|
18
|
+
flex: none;
|
|
19
|
+
margin-right: auto;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
.directory {
|
|
23
|
+
color: var(--dsw-alias-label-tertiary);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
.name {
|
|
27
|
+
color: var(--dsw-alias-label-primary);
|
|
28
|
+
}
|
package/lib/ReadBlock.module.css
CHANGED
|
@@ -1,105 +1,37 @@
|
|
|
1
|
-
.block {
|
|
2
|
-
--dsl-read-radius: 12px;
|
|
3
|
-
--dsl-read-line-height: 22px;
|
|
4
|
-
/* Fixed-width gutter column for the line numbers, so the content edge stays
|
|
5
|
-
put down the whole window regardless of how wide the numbers grow. */
|
|
6
|
-
--dsl-read-gutter: 48px;
|
|
7
|
-
|
|
8
|
-
position: relative;
|
|
9
|
-
margin: 16px 0;
|
|
10
|
-
color: var(--dsw-alias-label-primary);
|
|
11
|
-
background: var(--dsw-alias-markdown-code-block);
|
|
12
|
-
border-radius: var(--dsl-read-radius);
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
.banner {
|
|
16
|
-
display: flex;
|
|
17
|
-
justify-content: space-between;
|
|
18
|
-
align-items: center;
|
|
19
|
-
gap: 12px;
|
|
20
|
-
padding: 9px 14px;
|
|
21
|
-
background: var(--dsw-alias-markdown-code-block-banner);
|
|
22
|
-
border-top-left-radius: var(--dsl-read-radius);
|
|
23
|
-
border-top-right-radius: var(--dsl-read-radius);
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
.label {
|
|
27
|
-
min-width: 0;
|
|
28
|
-
overflow: hidden;
|
|
29
|
-
text-overflow: ellipsis;
|
|
30
|
-
white-space: nowrap;
|
|
31
|
-
color: var(--dsw-alias-label-primary);
|
|
32
|
-
font-family: var(--ds-font-family-code);
|
|
33
|
-
font-size: 12px;
|
|
34
|
-
line-height: 18px;
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
.action {
|
|
38
|
-
display: flex;
|
|
39
|
-
align-items: center;
|
|
40
|
-
flex-shrink: 0;
|
|
41
|
-
gap: 12px;
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
.count {
|
|
45
|
-
color: var(--dsw-alias-label-tertiary);
|
|
46
|
-
font: var(--dsw-font-xs-13);
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
.lang {
|
|
50
|
-
color: var(--dsw-alias-label-tertiary);
|
|
51
|
-
font-family: var(--ds-font-family-code);
|
|
52
|
-
font-size: 12px;
|
|
53
|
-
line-height: 18px;
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
.copyButton {
|
|
57
|
-
background-color: transparent;
|
|
58
|
-
border: none;
|
|
59
|
-
padding: 0;
|
|
60
|
-
margin: 0;
|
|
61
|
-
color: var(--dsw-alias-label-secondary);
|
|
62
|
-
cursor: pointer;
|
|
63
|
-
font: var(--dsw-font-xs-13);
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
.body {
|
|
67
|
-
padding: 12px 0;
|
|
68
|
-
font: var(--dsw-font-markdown-code-block);
|
|
69
|
-
overflow-x: auto;
|
|
70
|
-
overflow-y: hidden;
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
/* One row per file line: a fixed gutter column, then the content. No wrapping —
|
|
74
|
-
a source line's leading whitespace is meaningful and scrolls sideways. */
|
|
75
1
|
.line {
|
|
76
2
|
display: flex;
|
|
77
|
-
min-height:
|
|
78
|
-
line-height: var(--dsl-read-line-height);
|
|
3
|
+
min-height: 1lh;
|
|
79
4
|
white-space: pre;
|
|
80
5
|
}
|
|
81
6
|
|
|
82
7
|
.gutter {
|
|
83
8
|
flex: none;
|
|
84
9
|
width: var(--dsl-read-gutter);
|
|
85
|
-
|
|
10
|
+
margin-right: 12px;
|
|
86
11
|
text-align: right;
|
|
87
12
|
color: var(--dsw-alias-label-tertiary);
|
|
88
|
-
/* The gutter is chrome, not content: keep it out of a text selection so a
|
|
89
|
-
copy of the visible rows carries the source, not the line numbers. */
|
|
90
13
|
user-select: none;
|
|
91
14
|
}
|
|
92
15
|
|
|
93
16
|
.content {
|
|
17
|
+
min-width: 0;
|
|
94
18
|
color: var(--dsw-alias-label-primary);
|
|
95
19
|
}
|
|
96
20
|
|
|
21
|
+
.block[data-code-wrap='true'] .line {
|
|
22
|
+
white-space: pre-wrap;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
.block[data-code-wrap='true'] .content {
|
|
26
|
+
overflow-wrap: anywhere;
|
|
27
|
+
}
|
|
28
|
+
|
|
97
29
|
.expand {
|
|
98
30
|
display: block;
|
|
99
31
|
width: 100%;
|
|
100
|
-
padding: 0 0 0 var(--dsl-read-gutter);
|
|
32
|
+
padding: 0 0 0 calc(var(--dsl-read-gutter) + 12px);
|
|
101
33
|
border: none;
|
|
102
|
-
background
|
|
34
|
+
background: transparent;
|
|
103
35
|
color: var(--dsw-alias-label-tertiary);
|
|
104
36
|
cursor: pointer;
|
|
105
37
|
font: inherit;
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
/* The track is the same translucent fill the hover state uses, so it reads as
|
|
2
|
+
* a place rather than a second button; the one raised part is the indicator,
|
|
3
|
+
* a white pill that slides under the selected segment. Its stroke rides inside
|
|
4
|
+
* the soft elevation shadow (border: 0), the way every elevated surface draws
|
|
5
|
+
* its edge, so the elevation gate keeps it off the alias-border set.
|
|
6
|
+
*
|
|
7
|
+
* Segments are equal-width grid tracks sized to the widest label, which is
|
|
8
|
+
* what lets one indicator be placed arithmetically: the tablist carries the
|
|
9
|
+
* segment count and the selected index as custom properties, and the indicator
|
|
10
|
+
* derives its width and offset from them instead of measuring the DOM. */
|
|
11
|
+
.control {
|
|
12
|
+
position: relative;
|
|
13
|
+
display: inline-grid;
|
|
14
|
+
grid-auto-flow: column;
|
|
15
|
+
grid-auto-columns: 1fr;
|
|
16
|
+
gap: 2px;
|
|
17
|
+
padding: 3px;
|
|
18
|
+
border-radius: 9px;
|
|
19
|
+
background: var(--dsw-alias-interactive-bg-hover);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
.indicator {
|
|
23
|
+
position: absolute;
|
|
24
|
+
top: 3px;
|
|
25
|
+
left: 3px;
|
|
26
|
+
width: calc((100% - 6px - 2px * (var(--dsh-segment-count) - 1)) / var(--dsh-segment-count));
|
|
27
|
+
height: calc(100% - 6px);
|
|
28
|
+
border: 0;
|
|
29
|
+
border-radius: 7px;
|
|
30
|
+
background: var(--dsw-alias-bg-layer-1);
|
|
31
|
+
box-shadow: var(--dsw-elevation-soft);
|
|
32
|
+
transform: translateX(calc(var(--dsh-segment-index) * (100% + 2px)));
|
|
33
|
+
transition: transform 160ms ease;
|
|
34
|
+
pointer-events: none;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
.tab {
|
|
38
|
+
box-sizing: border-box;
|
|
39
|
+
position: relative;
|
|
40
|
+
z-index: 1;
|
|
41
|
+
height: 28px;
|
|
42
|
+
padding: 0 16px;
|
|
43
|
+
border: 0;
|
|
44
|
+
border-radius: 7px;
|
|
45
|
+
background: transparent;
|
|
46
|
+
color: var(--dsw-alias-label-secondary);
|
|
47
|
+
font: inherit;
|
|
48
|
+
font-size: 13px;
|
|
49
|
+
line-height: 20px;
|
|
50
|
+
font-weight: 500;
|
|
51
|
+
white-space: nowrap;
|
|
52
|
+
cursor: pointer;
|
|
53
|
+
transition: color 120ms ease;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
.tab:hover:not(:disabled),
|
|
57
|
+
.tab[aria-selected='true'] {
|
|
58
|
+
color: var(--dsw-alias-label-primary);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
.tab:disabled {
|
|
62
|
+
cursor: default;
|
|
63
|
+
opacity: 0.4;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
.tab:focus-visible {
|
|
67
|
+
outline: 2px solid var(--dsw-alias-brand-primary);
|
|
68
|
+
outline-offset: -2px;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
@media (prefers-reduced-motion: reduce) {
|
|
72
|
+
.indicator,
|
|
73
|
+
.tab {
|
|
74
|
+
transition: none;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
.tabs {
|
|
2
|
+
position: relative;
|
|
3
|
+
display: grid;
|
|
4
|
+
padding: 4px;
|
|
5
|
+
border-radius: 12px;
|
|
6
|
+
background: var(--dsw-alias-bg-module-platform);
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
.indicator {
|
|
10
|
+
position: absolute;
|
|
11
|
+
inset: 4px auto 4px 4px;
|
|
12
|
+
box-sizing: border-box;
|
|
13
|
+
border: 0.5px solid var(--dsw-alias-border-l3);
|
|
14
|
+
border-radius: 8px;
|
|
15
|
+
background: var(--dsw-alias-bg-layer-3);
|
|
16
|
+
transition: transform 180ms ease;
|
|
17
|
+
pointer-events: none;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
.tab {
|
|
21
|
+
position: relative;
|
|
22
|
+
justify-content: center;
|
|
23
|
+
height: 34px;
|
|
24
|
+
padding: 0 12px;
|
|
25
|
+
border-radius: 8px;
|
|
26
|
+
font-size: 14px;
|
|
27
|
+
line-height: 20px;
|
|
28
|
+
background: transparent;
|
|
29
|
+
color: var(--dsw-alias-label-secondary);
|
|
30
|
+
transition: color 180ms ease;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
.tab:hover,
|
|
34
|
+
.tab[aria-selected='true'] {
|
|
35
|
+
background: transparent;
|
|
36
|
+
color: var(--dsw-alias-label-primary);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
.tab[aria-selected='true'] {
|
|
40
|
+
font-weight: 600;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
.tab:focus-visible {
|
|
44
|
+
outline: none;
|
|
45
|
+
text-decoration: underline;
|
|
46
|
+
text-decoration-thickness: 1px;
|
|
47
|
+
text-underline-offset: 4px;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
@media (prefers-reduced-motion: reduce) {
|
|
51
|
+
.indicator,
|
|
52
|
+
.tab {
|
|
53
|
+
transition: none;
|
|
54
|
+
}
|
|
55
|
+
}
|
package/lib/StateDot.module.css
CHANGED
|
@@ -1,28 +1,10 @@
|
|
|
1
|
-
/*
|
|
2
|
-
* not this 450) — component-level var pinned to the static scale instead. */
|
|
3
|
-
.dot,
|
|
4
|
-
.matrix {
|
|
5
|
-
--dsh-state-ongoing: var(--dsw-static-deepseek-450);
|
|
6
|
-
}
|
|
7
|
-
|
|
8
|
-
/* Solid states: same-color halo via a 0.10-opacity outer layer (::before)
|
|
9
|
-
* with a 6/10-scale solid core. Layer color rides currentColor set per state. */
|
|
1
|
+
/* Solid states keep the 10px layout slot but paint one 6px currentColor core. */
|
|
10
2
|
.dot {
|
|
11
3
|
position: relative;
|
|
12
4
|
display: inline-block;
|
|
13
5
|
flex: none;
|
|
14
6
|
}
|
|
15
7
|
|
|
16
|
-
.dot::before {
|
|
17
|
-
content: '';
|
|
18
|
-
position: absolute;
|
|
19
|
-
inset: 0;
|
|
20
|
-
border-radius: 50%;
|
|
21
|
-
corner-shape: round;
|
|
22
|
-
background: currentColor;
|
|
23
|
-
opacity: 0.1;
|
|
24
|
-
}
|
|
25
|
-
|
|
26
8
|
.dot::after {
|
|
27
9
|
content: '';
|
|
28
10
|
position: absolute;
|
|
@@ -44,30 +26,75 @@
|
|
|
44
26
|
color: var(--dsw-alias-state-error-primary);
|
|
45
27
|
}
|
|
46
28
|
|
|
47
|
-
/* Idle is the absence of activity
|
|
48
|
-
* tertiary label color so it recedes beside the three outcome colors. */
|
|
29
|
+
/* Idle is the absence of activity and uses the theme's neutral state step. */
|
|
49
30
|
.dot[data-state='idle'] {
|
|
50
|
-
color: var(--dsw-alias-
|
|
31
|
+
color: var(--dsw-alias-state-idle-primary);
|
|
51
32
|
}
|
|
52
33
|
|
|
53
|
-
/*
|
|
54
|
-
*
|
|
55
|
-
*
|
|
56
|
-
|
|
57
|
-
.matrix {
|
|
34
|
+
/* Ongoing is the sole non-dot state: a quiet full ring sits behind a centered
|
|
35
|
+
* breathing arc while the complete glyph rotates continuously. Both animations
|
|
36
|
+
* share one 1.5s period so pinning their start times aligns them together. */
|
|
37
|
+
.spinner {
|
|
58
38
|
flex: none;
|
|
59
|
-
color: var(--
|
|
39
|
+
color: var(--dsw-alias-label-tertiary);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
.spinnerMotion {
|
|
43
|
+
transform-origin: center;
|
|
44
|
+
animation: dsh-state-dot-spin 1.5s linear infinite;
|
|
60
45
|
}
|
|
61
46
|
|
|
62
|
-
.
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
47
|
+
.spinnerTrack,
|
|
48
|
+
.spinnerArc {
|
|
49
|
+
fill: none;
|
|
50
|
+
stroke: currentColor;
|
|
51
|
+
stroke-width: 2;
|
|
52
|
+
stroke-linecap: round;
|
|
66
53
|
}
|
|
67
54
|
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
12.5%, 24.9% { opacity: 0.6; }
|
|
71
|
-
25%, 37.4% { opacity: 0.35; }
|
|
72
|
-
37.5%, 100% { opacity: 0.15; }
|
|
55
|
+
.spinnerTrack {
|
|
56
|
+
opacity: 0.25;
|
|
73
57
|
}
|
|
58
|
+
|
|
59
|
+
.spinnerArc {
|
|
60
|
+
stroke-dasharray: 12 150;
|
|
61
|
+
animation: dsh-state-dot-dash 1.5s ease-in-out infinite;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
@keyframes dsh-state-dot-spin {
|
|
65
|
+
to { transform: rotate(360deg); }
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
@keyframes dsh-state-dot-dash {
|
|
69
|
+
0% {
|
|
70
|
+
stroke-dasharray: 12 150;
|
|
71
|
+
stroke-dashoffset: 0;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
50% {
|
|
75
|
+
stroke-dasharray: 24 150;
|
|
76
|
+
stroke-dashoffset: -6;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
100% {
|
|
80
|
+
stroke-dasharray: 12 150;
|
|
81
|
+
stroke-dashoffset: 0;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
@media (prefers-reduced-motion: reduce) {
|
|
86
|
+
.spinnerMotion,
|
|
87
|
+
.spinnerArc {
|
|
88
|
+
animation: none;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
.spinnerArc {
|
|
92
|
+
stroke-dasharray: 18 150;
|
|
93
|
+
stroke-dashoffset: -3;
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
.step { display: inline-flex; flex: none; align-items: center; justify-content: center; box-sizing: border-box; border-radius: 50%; corner-shape: round; border: 1.5px solid var(--dsw-alias-label-tertiary); color: var(--dsw-alias-label-primary-foreground); }
|
|
98
|
+
.step[data-state='done'] { border-color: var(--dsw-alias-state-success-primary); background: var(--dsw-alias-state-success-primary); }
|
|
99
|
+
.step[data-state='error'] { border-color: var(--dsw-alias-state-error-primary); background: var(--dsw-alias-state-error-primary); }
|
|
100
|
+
.step[data-state='warning'] { border-color: var(--dsw-alias-state-warn-primary); }
|