@opencode-ai/ui 1.18.2 → 1.18.4
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/dist/components/resize-handle.d.ts +2 -0
- package/dist/components/scroll-view.d.ts +13 -1
- package/dist/v2/components/button-v2.d.ts +1 -1
- package/package.json +1 -1
- package/src/components/dock-surface.css +14 -0
- package/src/components/resize-handle.tsx +21 -5
- package/src/components/scroll-view.css +1 -0
- package/src/components/scroll-view.tsx +103 -25
- package/src/components/tabs.css +61 -1
- package/src/v2/components/button-v2.css +23 -0
- package/src/v2/components/button-v2.tsx +1 -1
- package/src/v2/components/dialog-v2.tsx +1 -1
- package/src/v2/components/divider-v2.css +2 -2
- package/src/v2/components/inline-input-v2.css +7 -0
- package/src/v2/components/inline-input-v2.tsx +16 -1
- package/src/v2/components/text-input-v2.css +1 -0
|
@@ -7,6 +7,8 @@ export interface ResizeHandleProps extends Omit<JSX.HTMLAttributes<HTMLDivElemen
|
|
|
7
7
|
max: number;
|
|
8
8
|
onResize: (size: number) => void;
|
|
9
9
|
onCollapse?: () => void;
|
|
10
|
+
/** Called while dragging when size crosses `collapseThreshold`. */
|
|
11
|
+
onCollapseChange?: (collapsed: boolean) => void;
|
|
10
12
|
collapseThreshold?: number;
|
|
11
13
|
}
|
|
12
14
|
export declare function ResizeHandle(props: ResizeHandleProps): JSX.Element;
|
|
@@ -1,9 +1,19 @@
|
|
|
1
|
-
import { type ComponentProps } from "solid-js";
|
|
1
|
+
import { type Accessor, type ComponentProps } from "solid-js";
|
|
2
2
|
export type ScrollViewThumbVisibility = "hover" | "scroll";
|
|
3
3
|
export interface ScrollViewProps extends ComponentProps<"div"> {
|
|
4
4
|
viewportRef?: (el: HTMLDivElement) => void;
|
|
5
5
|
orientation?: "vertical" | "horizontal";
|
|
6
|
+
/**
|
|
7
|
+
* `hover`: show while hovered or scrolling. `scroll`: show only while scrolling.
|
|
8
|
+
*
|
|
9
|
+
* In most cases, scrolling a container = hovering over it, so this change has no effect.
|
|
10
|
+
* This is a special case to account for the home page scroll, where scrolling a container != hovering over it
|
|
11
|
+
* */
|
|
6
12
|
thumbVisibility?: ScrollViewThumbVisibility;
|
|
13
|
+
/** Mount the thumb into an external track. Scroll metrics still come from this ScrollView. */
|
|
14
|
+
thumbContainer?: HTMLElement | Accessor<HTMLElement | undefined>;
|
|
15
|
+
/** Element whose hover reveals the thumb. Defaults to the ScrollView root when unset. */
|
|
16
|
+
thumbHoverTarget?: HTMLElement | Accessor<HTMLElement | undefined>;
|
|
7
17
|
}
|
|
8
18
|
export declare const scrollKey: (event: Pick<KeyboardEvent, "key" | "altKey" | "ctrlKey" | "metaKey" | "shiftKey">) => "end" | "home" | "page-down" | "page-up" | "up" | "down" | undefined;
|
|
9
19
|
export declare function canScrollKey(element: HTMLElement, key: NonNullable<ReturnType<typeof scrollKey>>): boolean;
|
|
@@ -16,5 +26,7 @@ export declare function scrollTopFromThumbPointer(input: {
|
|
|
16
26
|
clientHeight: number;
|
|
17
27
|
scrollHeight: number;
|
|
18
28
|
thumbHeight: number;
|
|
29
|
+
/** Viewport height used for max scroll. Defaults to `clientHeight` (track == viewport). */
|
|
30
|
+
scrollClientHeight?: number;
|
|
19
31
|
}): number;
|
|
20
32
|
export declare function ScrollView(props: ScrollViewProps): import("solid-js").JSX.Element;
|
|
@@ -4,7 +4,7 @@ import { type IconProps } from "./icon";
|
|
|
4
4
|
import "./button-v2.css";
|
|
5
5
|
export interface ButtonV2Props extends ComponentProps<typeof Kobalte>, Pick<ComponentProps<"button">, "class" | "classList" | "children"> {
|
|
6
6
|
size?: "small" | "normal" | "large";
|
|
7
|
-
variant?: "neutral" | "danger" | "outline" | "contrast" | "ghost" | "ghost-muted" | "loading";
|
|
7
|
+
variant?: "neutral" | "danger" | "warning" | "outline" | "contrast" | "ghost" | "ghost-muted" | "loading";
|
|
8
8
|
icon?: IconProps["name"];
|
|
9
9
|
}
|
|
10
10
|
export declare function ButtonV2(props: ButtonV2Props): import("solid-js").JSX.Element;
|
package/package.json
CHANGED
|
@@ -7,6 +7,20 @@
|
|
|
7
7
|
overflow: clip;
|
|
8
8
|
}
|
|
9
9
|
|
|
10
|
+
[data-dock-border-underlay] {
|
|
11
|
+
/* Later shadows paint underneath, so this solid ring masks overlapping surfaces without changing border geometry. */
|
|
12
|
+
box-shadow:
|
|
13
|
+
var(--dock-shell-visual-shadow, var(--shadow-xs-border)),
|
|
14
|
+
0 0 0 var(--dock-shell-border-underlay-width, 1px)
|
|
15
|
+
var(--dock-shell-border-underlay-background, var(--surface-raised-stronger-non-alpha));
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
[data-dock-border-underlay="v2"] {
|
|
19
|
+
--dock-shell-visual-shadow: var(--v2-elevation-raised);
|
|
20
|
+
--dock-shell-border-underlay-width: 0.5px;
|
|
21
|
+
--dock-shell-border-underlay-background: var(--v2-background-bg-base);
|
|
22
|
+
}
|
|
23
|
+
|
|
10
24
|
[data-dock-surface="tray"] {
|
|
11
25
|
background-color: var(--background-base);
|
|
12
26
|
border: 1px solid var(--border-weak-base);
|
|
@@ -8,6 +8,8 @@ export interface ResizeHandleProps extends Omit<JSX.HTMLAttributes<HTMLDivElemen
|
|
|
8
8
|
max: number
|
|
9
9
|
onResize: (size: number) => void
|
|
10
10
|
onCollapse?: () => void
|
|
11
|
+
/** Called while dragging when size crosses `collapseThreshold`. */
|
|
12
|
+
onCollapseChange?: (collapsed: boolean) => void
|
|
11
13
|
collapseThreshold?: number
|
|
12
14
|
}
|
|
13
15
|
|
|
@@ -20,17 +22,26 @@ export function ResizeHandle(props: ResizeHandleProps) {
|
|
|
20
22
|
"max",
|
|
21
23
|
"onResize",
|
|
22
24
|
"onCollapse",
|
|
25
|
+
"onCollapseChange",
|
|
23
26
|
"collapseThreshold",
|
|
24
27
|
"class",
|
|
25
28
|
"classList",
|
|
26
29
|
])
|
|
27
30
|
|
|
28
31
|
const handleMouseDown = (e: MouseEvent) => {
|
|
32
|
+
if (e.detail > 1) return
|
|
29
33
|
e.preventDefault()
|
|
30
34
|
const edge = local.edge ?? (local.direction === "vertical" ? "start" : "end")
|
|
31
35
|
const start = local.direction === "horizontal" ? e.clientX : e.clientY
|
|
32
36
|
const startSize = local.size
|
|
37
|
+
const min = local.min
|
|
38
|
+
const max = local.max
|
|
39
|
+
const threshold = local.collapseThreshold ?? 0
|
|
40
|
+
const onResize = local.onResize
|
|
41
|
+
const onCollapse = local.onCollapse
|
|
42
|
+
const onCollapseChange = local.onCollapseChange
|
|
33
43
|
let current = startSize
|
|
44
|
+
let collapsed = false
|
|
34
45
|
|
|
35
46
|
document.body.style.userSelect = "none"
|
|
36
47
|
document.body.style.overflow = "hidden"
|
|
@@ -46,8 +57,12 @@ export function ResizeHandle(props: ResizeHandleProps) {
|
|
|
46
57
|
? start - pos
|
|
47
58
|
: pos - start
|
|
48
59
|
current = startSize + delta
|
|
49
|
-
const
|
|
50
|
-
|
|
60
|
+
const nextCollapsed = threshold > 0 && current < threshold
|
|
61
|
+
if (nextCollapsed !== collapsed) {
|
|
62
|
+
collapsed = nextCollapsed
|
|
63
|
+
onCollapseChange?.(collapsed)
|
|
64
|
+
}
|
|
65
|
+
onResize(Math.min(max, Math.max(min, current)))
|
|
51
66
|
}
|
|
52
67
|
|
|
53
68
|
const onMouseUp = () => {
|
|
@@ -56,10 +71,11 @@ export function ResizeHandle(props: ResizeHandleProps) {
|
|
|
56
71
|
document.removeEventListener("mousemove", onMouseMove)
|
|
57
72
|
document.removeEventListener("mouseup", onMouseUp)
|
|
58
73
|
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
74
|
+
if (collapsed) {
|
|
75
|
+
onCollapse?.()
|
|
76
|
+
return
|
|
62
77
|
}
|
|
78
|
+
onCollapseChange?.(false)
|
|
63
79
|
}
|
|
64
80
|
|
|
65
81
|
document.addEventListener("mousemove", onMouseMove)
|
|
@@ -1,4 +1,15 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
createEffect,
|
|
3
|
+
createMemo,
|
|
4
|
+
mergeProps,
|
|
5
|
+
onCleanup,
|
|
6
|
+
onMount,
|
|
7
|
+
Show,
|
|
8
|
+
splitProps,
|
|
9
|
+
type Accessor,
|
|
10
|
+
type ComponentProps,
|
|
11
|
+
} from "solid-js"
|
|
12
|
+
import { Portal } from "solid-js/web"
|
|
2
13
|
import { createResizeObserver } from "@solid-primitives/resize-observer"
|
|
3
14
|
import { createStore } from "solid-js/store"
|
|
4
15
|
import { useI18n } from "../context/i18n"
|
|
@@ -8,7 +19,17 @@ export type ScrollViewThumbVisibility = "hover" | "scroll"
|
|
|
8
19
|
export interface ScrollViewProps extends ComponentProps<"div"> {
|
|
9
20
|
viewportRef?: (el: HTMLDivElement) => void
|
|
10
21
|
orientation?: "vertical" | "horizontal" // currently only vertical is fully implemented for thumb
|
|
22
|
+
/**
|
|
23
|
+
* `hover`: show while hovered or scrolling. `scroll`: show only while scrolling.
|
|
24
|
+
*
|
|
25
|
+
* In most cases, scrolling a container = hovering over it, so this change has no effect.
|
|
26
|
+
* This is a special case to account for the home page scroll, where scrolling a container != hovering over it
|
|
27
|
+
* */
|
|
11
28
|
thumbVisibility?: ScrollViewThumbVisibility
|
|
29
|
+
/** Mount the thumb into an external track. Scroll metrics still come from this ScrollView. */
|
|
30
|
+
thumbContainer?: HTMLElement | Accessor<HTMLElement | undefined>
|
|
31
|
+
/** Element whose hover reveals the thumb. Defaults to the ScrollView root when unset. */
|
|
32
|
+
thumbHoverTarget?: HTMLElement | Accessor<HTMLElement | undefined>
|
|
12
33
|
}
|
|
13
34
|
|
|
14
35
|
export const scrollKey = (event: Pick<KeyboardEvent, "key" | "altKey" | "ctrlKey" | "metaKey" | "shiftKey">) => {
|
|
@@ -65,12 +86,14 @@ export function scrollTopFromThumbPointer(input: {
|
|
|
65
86
|
clientHeight: number
|
|
66
87
|
scrollHeight: number
|
|
67
88
|
thumbHeight: number
|
|
89
|
+
/** Viewport height used for max scroll. Defaults to `clientHeight` (track == viewport). */
|
|
90
|
+
scrollClientHeight?: number
|
|
68
91
|
}) {
|
|
69
92
|
const padding = 8
|
|
70
93
|
const maxThumbTop = input.clientHeight - padding * 2 - input.thumbHeight
|
|
71
94
|
if (maxThumbTop <= 0) return 0
|
|
72
95
|
const thumbTop = Math.max(0, Math.min(input.pointer - input.viewportTop - padding - input.grabOffset, maxThumbTop))
|
|
73
|
-
return (thumbTop / maxThumbTop) * Math.max(0, input.scrollHeight - input.clientHeight)
|
|
96
|
+
return (thumbTop / maxThumbTop) * Math.max(0, input.scrollHeight - (input.scrollClientHeight ?? input.clientHeight))
|
|
74
97
|
}
|
|
75
98
|
|
|
76
99
|
export function ScrollView(props: ScrollViewProps) {
|
|
@@ -78,7 +101,16 @@ export function ScrollView(props: ScrollViewProps) {
|
|
|
78
101
|
const merged = mergeProps({ orientation: "vertical", thumbVisibility: "hover" }, props)
|
|
79
102
|
const [local, events, rest] = splitProps(
|
|
80
103
|
merged,
|
|
81
|
-
[
|
|
104
|
+
[
|
|
105
|
+
"class",
|
|
106
|
+
"children",
|
|
107
|
+
"viewportRef",
|
|
108
|
+
"orientation",
|
|
109
|
+
"thumbVisibility",
|
|
110
|
+
"thumbContainer",
|
|
111
|
+
"thumbHoverTarget",
|
|
112
|
+
"style",
|
|
113
|
+
],
|
|
82
114
|
[
|
|
83
115
|
"onScroll",
|
|
84
116
|
"onWheel",
|
|
@@ -96,6 +128,15 @@ export function ScrollView(props: ScrollViewProps) {
|
|
|
96
128
|
let viewportRef!: HTMLDivElement
|
|
97
129
|
let thumbRef!: HTMLDivElement
|
|
98
130
|
|
|
131
|
+
const resolveEl = (value: HTMLElement | Accessor<HTMLElement | undefined> | undefined) => {
|
|
132
|
+
if (typeof value === "function") return value()
|
|
133
|
+
return value
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
const thumbMount = createMemo(() => resolveEl(local.thumbContainer))
|
|
137
|
+
const thumbHover = createMemo(() => resolveEl(local.thumbHoverTarget))
|
|
138
|
+
const hoverRoot = () => !local.thumbHoverTarget && !local.thumbContainer
|
|
139
|
+
|
|
99
140
|
const [state, setState] = createStore({
|
|
100
141
|
isHovered: false,
|
|
101
142
|
isDragging: false,
|
|
@@ -114,7 +155,6 @@ export function ScrollView(props: ScrollViewProps) {
|
|
|
114
155
|
let scrollIdleTimer: ReturnType<typeof setTimeout> | undefined
|
|
115
156
|
|
|
116
157
|
const markScrolling = () => {
|
|
117
|
-
if (local.thumbVisibility !== "scroll") return
|
|
118
158
|
setState("isScrolling", true)
|
|
119
159
|
if (scrollIdleTimer !== undefined) clearTimeout(scrollIdleTimer)
|
|
120
160
|
scrollIdleTimer = setTimeout(() => setState("isScrolling", false), 800)
|
|
@@ -122,8 +162,8 @@ export function ScrollView(props: ScrollViewProps) {
|
|
|
122
162
|
|
|
123
163
|
const thumbVisible = () => {
|
|
124
164
|
if (isDragging()) return true
|
|
125
|
-
if (
|
|
126
|
-
return isHovered()
|
|
165
|
+
if (isScrolling()) return true
|
|
166
|
+
return local.thumbVisibility === "hover" && isHovered()
|
|
127
167
|
}
|
|
128
168
|
|
|
129
169
|
onCleanup(() => {
|
|
@@ -141,7 +181,8 @@ export function ScrollView(props: ScrollViewProps) {
|
|
|
141
181
|
|
|
142
182
|
setState("showThumb", true)
|
|
143
183
|
const trackPadding = 8
|
|
144
|
-
const
|
|
184
|
+
const trackClientHeight = thumbMount()?.clientHeight || clientHeight
|
|
185
|
+
const trackHeight = trackClientHeight - trackPadding * 2
|
|
145
186
|
|
|
146
187
|
const minThumbHeight = 32
|
|
147
188
|
// Calculate raw thumb height based on ratio
|
|
@@ -165,16 +206,40 @@ export function ScrollView(props: ScrollViewProps) {
|
|
|
165
206
|
local.viewportRef(viewportRef)
|
|
166
207
|
}
|
|
167
208
|
|
|
168
|
-
createResizeObserver(
|
|
209
|
+
createResizeObserver(
|
|
210
|
+
() => [viewportRef, viewportRef.firstElementChild, thumbMount()].filter(Boolean) as HTMLElement[],
|
|
211
|
+
updateThumb,
|
|
212
|
+
)
|
|
169
213
|
|
|
170
214
|
updateThumb()
|
|
171
215
|
})
|
|
172
216
|
|
|
217
|
+
createEffect(() => {
|
|
218
|
+
thumbMount()
|
|
219
|
+
updateThumb()
|
|
220
|
+
})
|
|
221
|
+
|
|
222
|
+
createEffect(() => {
|
|
223
|
+
const target = thumbHover()
|
|
224
|
+
if (!target) return
|
|
225
|
+
|
|
226
|
+
const enter = () => setState("isHovered", true)
|
|
227
|
+
const leave = () => setState("isHovered", false)
|
|
228
|
+
target.addEventListener("pointerenter", enter)
|
|
229
|
+
target.addEventListener("pointerleave", leave)
|
|
230
|
+
onCleanup(() => {
|
|
231
|
+
target.removeEventListener("pointerenter", enter)
|
|
232
|
+
target.removeEventListener("pointerleave", leave)
|
|
233
|
+
setState("isHovered", false)
|
|
234
|
+
})
|
|
235
|
+
})
|
|
236
|
+
|
|
173
237
|
const onThumbPointerDown = (e: PointerEvent) => {
|
|
174
238
|
e.preventDefault()
|
|
175
239
|
e.stopPropagation()
|
|
176
240
|
setState("isDragging", true)
|
|
177
241
|
const grabOffset = e.clientY - thumbRef.getBoundingClientRect().top
|
|
242
|
+
const track = thumbMount() ?? viewportRef
|
|
178
243
|
|
|
179
244
|
thumbRef.setPointerCapture(e.pointerId)
|
|
180
245
|
|
|
@@ -182,9 +247,10 @@ export function ScrollView(props: ScrollViewProps) {
|
|
|
182
247
|
const { scrollHeight, clientHeight } = viewportRef
|
|
183
248
|
viewportRef.scrollTop = scrollTopFromThumbPointer({
|
|
184
249
|
pointer: e.clientY,
|
|
185
|
-
viewportTop:
|
|
250
|
+
viewportTop: track.getBoundingClientRect().top,
|
|
186
251
|
grabOffset,
|
|
187
|
-
clientHeight,
|
|
252
|
+
clientHeight: track.clientHeight,
|
|
253
|
+
scrollClientHeight: clientHeight,
|
|
188
254
|
scrollHeight,
|
|
189
255
|
thumbHeight: thumbHeight(),
|
|
190
256
|
})
|
|
@@ -203,6 +269,23 @@ export function ScrollView(props: ScrollViewProps) {
|
|
|
203
269
|
thumbRef.addEventListener("pointercancel", done)
|
|
204
270
|
}
|
|
205
271
|
|
|
272
|
+
const renderThumb = () => (
|
|
273
|
+
<div
|
|
274
|
+
ref={(el) => {
|
|
275
|
+
thumbRef = el
|
|
276
|
+
}}
|
|
277
|
+
onPointerDown={onThumbPointerDown}
|
|
278
|
+
class="scroll-view__thumb"
|
|
279
|
+
data-visible={thumbVisible()}
|
|
280
|
+
data-dragging={isDragging()}
|
|
281
|
+
style={{
|
|
282
|
+
height: `${thumbHeight()}px`,
|
|
283
|
+
transform: `translateY(${thumbTop()}px)`,
|
|
284
|
+
"z-index": 100, // ensure it displays over content
|
|
285
|
+
}}
|
|
286
|
+
/>
|
|
287
|
+
)
|
|
288
|
+
|
|
206
289
|
// Keybinds implementation
|
|
207
290
|
// We ensure the viewport has a tabindex so it can receive focus
|
|
208
291
|
// We can also explicitly catch PageUp/Down if we want smooth scroll or specific behavior,
|
|
@@ -253,8 +336,12 @@ export function ScrollView(props: ScrollViewProps) {
|
|
|
253
336
|
ref={rootRef}
|
|
254
337
|
class={`scroll-view ${local.class || ""}`}
|
|
255
338
|
style={local.style}
|
|
256
|
-
onPointerEnter={() =>
|
|
257
|
-
|
|
339
|
+
onPointerEnter={() => {
|
|
340
|
+
if (hoverRoot()) setState("isHovered", true)
|
|
341
|
+
}}
|
|
342
|
+
onPointerLeave={() => {
|
|
343
|
+
if (hoverRoot()) setState("isHovered", false)
|
|
344
|
+
}}
|
|
258
345
|
{...rest}
|
|
259
346
|
>
|
|
260
347
|
{/* Viewport */}
|
|
@@ -290,20 +377,11 @@ export function ScrollView(props: ScrollViewProps) {
|
|
|
290
377
|
{local.children}
|
|
291
378
|
</div>
|
|
292
379
|
|
|
293
|
-
{/* Thumb Overlay */}
|
|
380
|
+
{/* Thumb Overlay — optionally portaled into an external track */}
|
|
294
381
|
<Show when={showThumb()}>
|
|
295
|
-
<
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
class="scroll-view__thumb"
|
|
299
|
-
data-visible={thumbVisible()}
|
|
300
|
-
data-dragging={isDragging()}
|
|
301
|
-
style={{
|
|
302
|
-
height: `${thumbHeight()}px`,
|
|
303
|
-
transform: `translateY(${thumbTop()}px)`,
|
|
304
|
-
"z-index": 100, // ensure it displays over content
|
|
305
|
-
}}
|
|
306
|
-
/>
|
|
382
|
+
<Show when={thumbMount()} fallback={renderThumb()}>
|
|
383
|
+
{(mount) => <Portal mount={mount()}>{renderThumb()}</Portal>}
|
|
384
|
+
</Show>
|
|
307
385
|
</Show>
|
|
308
386
|
</div>
|
|
309
387
|
)
|
package/src/components/tabs.css
CHANGED
|
@@ -723,7 +723,11 @@ body[data-new-layout] #review-panel [data-component="tabs"][data-variant="normal
|
|
|
723
723
|
}
|
|
724
724
|
|
|
725
725
|
&:has([data-slot="tabs-trigger-close-button"]) {
|
|
726
|
-
padding-right:
|
|
726
|
+
padding-right: 8px;
|
|
727
|
+
|
|
728
|
+
[data-slot="tabs-trigger-close-button"] {
|
|
729
|
+
margin-left: 2px;
|
|
730
|
+
}
|
|
727
731
|
}
|
|
728
732
|
|
|
729
733
|
&:has([data-selected]) {
|
|
@@ -789,6 +793,62 @@ body[data-new-layout]
|
|
|
789
793
|
[data-slot="tabs-list"]
|
|
790
794
|
> .sticky {
|
|
791
795
|
padding-right: 0;
|
|
796
|
+
|
|
797
|
+
[data-component="icon-button-v2"] {
|
|
798
|
+
position: relative;
|
|
799
|
+
|
|
800
|
+
&::after {
|
|
801
|
+
content: "";
|
|
802
|
+
position: absolute;
|
|
803
|
+
left: 100%;
|
|
804
|
+
top: 50%;
|
|
805
|
+
transform: translateY(-50%);
|
|
806
|
+
width: 20px;
|
|
807
|
+
height: 28px;
|
|
808
|
+
background-color: var(--v2-background-bg-base);
|
|
809
|
+
pointer-events: none;
|
|
810
|
+
}
|
|
811
|
+
}
|
|
812
|
+
}
|
|
813
|
+
|
|
814
|
+
body[data-new-layout]
|
|
815
|
+
#review-panel
|
|
816
|
+
[data-component="tabs"]
|
|
817
|
+
.session-review-v2-tabs-bar
|
|
818
|
+
[data-slot="tabs-list"]
|
|
819
|
+
> .session-review-v2-sidebar-toggle-slot.sticky {
|
|
820
|
+
padding-right: 0;
|
|
821
|
+
|
|
822
|
+
&::before {
|
|
823
|
+
content: "";
|
|
824
|
+
position: absolute;
|
|
825
|
+
top: 50%;
|
|
826
|
+
bottom: auto;
|
|
827
|
+
left: auto;
|
|
828
|
+
right: 100%;
|
|
829
|
+
transform: translateY(-50%);
|
|
830
|
+
width: 12px;
|
|
831
|
+
height: 28px;
|
|
832
|
+
background-color: var(--v2-background-bg-base);
|
|
833
|
+
background-image: none;
|
|
834
|
+
pointer-events: none;
|
|
835
|
+
}
|
|
836
|
+
|
|
837
|
+
&::after {
|
|
838
|
+
content: "";
|
|
839
|
+
position: absolute;
|
|
840
|
+
top: 50%;
|
|
841
|
+
left: 100%;
|
|
842
|
+
transform: translateY(-50%);
|
|
843
|
+
width: 8px;
|
|
844
|
+
height: 28px;
|
|
845
|
+
pointer-events: none;
|
|
846
|
+
background: linear-gradient(90deg, var(--v2-background-bg-base), transparent);
|
|
847
|
+
}
|
|
848
|
+
|
|
849
|
+
[data-component="icon-button-v2"]::after {
|
|
850
|
+
display: none;
|
|
851
|
+
}
|
|
792
852
|
}
|
|
793
853
|
|
|
794
854
|
body[data-new-layout] #review-panel [data-component="tabs"] .session-review-v2-open-in-app-slot {
|
|
@@ -113,6 +113,29 @@
|
|
|
113
113
|
cursor: not-allowed;
|
|
114
114
|
}
|
|
115
115
|
|
|
116
|
+
[data-component="button-v2"][data-variant="warning"] {
|
|
117
|
+
background-color: var(--v2-background-bg-button-neutral);
|
|
118
|
+
color: var(--v2-state-fg-warning);
|
|
119
|
+
box-shadow: var(--v2-elevation-button-neutral);
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
[data-component="button-v2"][data-variant="warning"]:is(:hover, [data-state="hover"]):not(:disabled) {
|
|
123
|
+
background-image:
|
|
124
|
+
linear-gradient(90deg, var(--v2-overlay-simple-overlay-hover) 0%, var(--v2-overlay-simple-overlay-hover) 100%),
|
|
125
|
+
linear-gradient(90deg, var(--v2-background-bg-button-neutral) 0%, var(--v2-background-bg-button-neutral) 100%);
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
[data-component="button-v2"][data-variant="warning"]:is(:active, [data-state="pressed"]):not(:disabled) {
|
|
129
|
+
background-image:
|
|
130
|
+
linear-gradient(90deg, var(--v2-overlay-simple-overlay-pressed) 0%, var(--v2-overlay-simple-overlay-pressed) 100%),
|
|
131
|
+
linear-gradient(90deg, var(--v2-background-bg-button-neutral) 0%, var(--v2-background-bg-button-neutral) 100%);
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
[data-component="button-v2"][data-variant="warning"]:is(:disabled, [data-state="disabled"]) {
|
|
135
|
+
opacity: 0.5;
|
|
136
|
+
cursor: not-allowed;
|
|
137
|
+
}
|
|
138
|
+
|
|
116
139
|
/* Outline */
|
|
117
140
|
[data-component="button-v2"][data-variant="outline"] {
|
|
118
141
|
background-color: transparent;
|
|
@@ -7,7 +7,7 @@ export interface ButtonV2Props
|
|
|
7
7
|
extends ComponentProps<typeof Kobalte>,
|
|
8
8
|
Pick<ComponentProps<"button">, "class" | "classList" | "children"> {
|
|
9
9
|
size?: "small" | "normal" | "large"
|
|
10
|
-
variant?: "neutral" | "danger" | "outline" | "contrast" | "ghost" | "ghost-muted" | "loading"
|
|
10
|
+
variant?: "neutral" | "danger" | "warning" | "outline" | "contrast" | "ghost" | "ghost-muted" | "loading"
|
|
11
11
|
icon?: IconProps["name"]
|
|
12
12
|
}
|
|
13
13
|
|
|
@@ -101,7 +101,7 @@ export function Dialog(props: DialogProps) {
|
|
|
101
101
|
const autofocusEl = target?.querySelector("[autofocus]") as HTMLElement | null
|
|
102
102
|
if (autofocusEl) {
|
|
103
103
|
e.preventDefault()
|
|
104
|
-
autofocusEl.focus()
|
|
104
|
+
autofocusEl.focus({ preventScroll: true })
|
|
105
105
|
}
|
|
106
106
|
}}
|
|
107
107
|
>
|
|
@@ -67,9 +67,14 @@
|
|
|
67
67
|
gap: 4px;
|
|
68
68
|
background: var(--v2-background-bg-layer-01);
|
|
69
69
|
border-radius: 4px 0 0 4px;
|
|
70
|
+
cursor: default;
|
|
70
71
|
transition: background 85ms ease-out;
|
|
71
72
|
}
|
|
72
73
|
|
|
74
|
+
[data-component="inline-input-v2"]:where([data-disabled]) [data-slot="inline-input-v2-prefix"] {
|
|
75
|
+
cursor: not-allowed;
|
|
76
|
+
}
|
|
77
|
+
|
|
73
78
|
[data-component="inline-input-v2"][data-label-width] [data-slot="inline-input-v2-prefix"] {
|
|
74
79
|
width: var(--inline-input-v2-label-width);
|
|
75
80
|
min-width: var(--inline-input-v2-label-width);
|
|
@@ -89,6 +94,7 @@
|
|
|
89
94
|
letter-spacing: -0.04px;
|
|
90
95
|
color: var(--v2-text-text-muted);
|
|
91
96
|
font-variation-settings: "slnt" 0;
|
|
97
|
+
user-select: none;
|
|
92
98
|
}
|
|
93
99
|
|
|
94
100
|
[data-component="inline-input-v2"][data-numeric] [data-slot="inline-input-v2-prefix-text"] {
|
|
@@ -149,6 +155,7 @@
|
|
|
149
155
|
|
|
150
156
|
[data-component="inline-input-v2"] [data-slot="inline-input-v2-input"]::placeholder {
|
|
151
157
|
color: var(--v2-text-text-faint);
|
|
158
|
+
user-select: none;
|
|
152
159
|
}
|
|
153
160
|
|
|
154
161
|
[data-component="inline-input-v2"][data-numeric] [data-slot="inline-input-v2-input"] {
|
|
@@ -37,6 +37,8 @@ export function InlineInputV2(props: InlineInputV2Props) {
|
|
|
37
37
|
"style",
|
|
38
38
|
])
|
|
39
39
|
|
|
40
|
+
let input: HTMLInputElement | undefined
|
|
41
|
+
|
|
40
42
|
return (
|
|
41
43
|
<div
|
|
42
44
|
data-component="inline-input-v2"
|
|
@@ -59,7 +61,15 @@ export function InlineInputV2(props: InlineInputV2Props) {
|
|
|
59
61
|
: {}),
|
|
60
62
|
}}
|
|
61
63
|
>
|
|
62
|
-
<div
|
|
64
|
+
<div
|
|
65
|
+
data-slot="inline-input-v2-prefix"
|
|
66
|
+
onMouseDown={(event) => {
|
|
67
|
+
if (local.disabled || event.button !== 0) return
|
|
68
|
+
// Keep focus on the input without using a native <label>, so external labels still work.
|
|
69
|
+
event.preventDefault()
|
|
70
|
+
input?.focus()
|
|
71
|
+
}}
|
|
72
|
+
>
|
|
63
73
|
<span data-slot="inline-input-v2-prefix-text">{local.prefix}</span>
|
|
64
74
|
</div>
|
|
65
75
|
<div data-slot="inline-input-v2-divider" aria-hidden="true" />
|
|
@@ -67,6 +77,11 @@ export function InlineInputV2(props: InlineInputV2Props) {
|
|
|
67
77
|
<div data-slot="inline-input-v2-value">
|
|
68
78
|
<input
|
|
69
79
|
{...inputProps}
|
|
80
|
+
ref={(el) => {
|
|
81
|
+
input = el
|
|
82
|
+
const ref = inputProps.ref
|
|
83
|
+
if (typeof ref === "function") ref(el)
|
|
84
|
+
}}
|
|
70
85
|
type={inputProps.type ?? "text"}
|
|
71
86
|
disabled={local.disabled}
|
|
72
87
|
aria-invalid={local.invalid ? true : undefined}
|
|
@@ -98,6 +98,7 @@
|
|
|
98
98
|
|
|
99
99
|
[data-component="text-input-v2"] [data-slot="text-input-v2-input"]::placeholder {
|
|
100
100
|
color: var(--v2-text-text-faint);
|
|
101
|
+
user-select: none;
|
|
101
102
|
}
|
|
102
103
|
|
|
103
104
|
[data-component="text-input-v2"] [data-slot="text-input-v2-input"][type="search"]::-webkit-search-cancel-button {
|