chore: merge dev into v2
This commit is contained in:
commit
655dad8bf3
209 changed files with 6882 additions and 2469 deletions
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "@opencode-ai/ui",
|
||||
"version": "1.18.3",
|
||||
"version": "1.18.4",
|
||||
"type": "module",
|
||||
"license": "MIT",
|
||||
"repository": {
|
||||
|
|
|
|||
|
|
@ -7,6 +7,20 @@
|
|||
overflow: clip;
|
||||
}
|
||||
|
||||
[data-dock-border-underlay] {
|
||||
/* Later shadows paint underneath, so this solid ring masks overlapping surfaces without changing border geometry. */
|
||||
box-shadow:
|
||||
var(--dock-shell-visual-shadow, var(--shadow-xs-border)),
|
||||
0 0 0 var(--dock-shell-border-underlay-width, 1px)
|
||||
var(--dock-shell-border-underlay-background, var(--surface-raised-stronger-non-alpha));
|
||||
}
|
||||
|
||||
[data-dock-border-underlay="v2"] {
|
||||
--dock-shell-visual-shadow: var(--v2-elevation-raised);
|
||||
--dock-shell-border-underlay-width: 0.5px;
|
||||
--dock-shell-border-underlay-background: var(--v2-background-bg-base);
|
||||
}
|
||||
|
||||
[data-dock-surface="tray"] {
|
||||
background-color: var(--background-base);
|
||||
border: 1px solid var(--border-weak-base);
|
||||
|
|
|
|||
|
|
@ -8,6 +8,8 @@ export interface ResizeHandleProps extends Omit<JSX.HTMLAttributes<HTMLDivElemen
|
|||
max: number
|
||||
onResize: (size: number) => void
|
||||
onCollapse?: () => void
|
||||
/** Called while dragging when size crosses `collapseThreshold`. */
|
||||
onCollapseChange?: (collapsed: boolean) => void
|
||||
collapseThreshold?: number
|
||||
}
|
||||
|
||||
|
|
@ -20,17 +22,26 @@ export function ResizeHandle(props: ResizeHandleProps) {
|
|||
"max",
|
||||
"onResize",
|
||||
"onCollapse",
|
||||
"onCollapseChange",
|
||||
"collapseThreshold",
|
||||
"class",
|
||||
"classList",
|
||||
])
|
||||
|
||||
const handleMouseDown = (e: MouseEvent) => {
|
||||
if (e.detail > 1) return
|
||||
e.preventDefault()
|
||||
const edge = local.edge ?? (local.direction === "vertical" ? "start" : "end")
|
||||
const start = local.direction === "horizontal" ? e.clientX : e.clientY
|
||||
const startSize = local.size
|
||||
const min = local.min
|
||||
const max = local.max
|
||||
const threshold = local.collapseThreshold ?? 0
|
||||
const onResize = local.onResize
|
||||
const onCollapse = local.onCollapse
|
||||
const onCollapseChange = local.onCollapseChange
|
||||
let current = startSize
|
||||
let collapsed = false
|
||||
|
||||
document.body.style.userSelect = "none"
|
||||
document.body.style.overflow = "hidden"
|
||||
|
|
@ -46,8 +57,12 @@ export function ResizeHandle(props: ResizeHandleProps) {
|
|||
? start - pos
|
||||
: pos - start
|
||||
current = startSize + delta
|
||||
const clamped = Math.min(local.max, Math.max(local.min, current))
|
||||
local.onResize(clamped)
|
||||
const nextCollapsed = threshold > 0 && current < threshold
|
||||
if (nextCollapsed !== collapsed) {
|
||||
collapsed = nextCollapsed
|
||||
onCollapseChange?.(collapsed)
|
||||
}
|
||||
onResize(Math.min(max, Math.max(min, current)))
|
||||
}
|
||||
|
||||
const onMouseUp = () => {
|
||||
|
|
@ -56,10 +71,11 @@ export function ResizeHandle(props: ResizeHandleProps) {
|
|||
document.removeEventListener("mousemove", onMouseMove)
|
||||
document.removeEventListener("mouseup", onMouseUp)
|
||||
|
||||
const threshold = local.collapseThreshold ?? 0
|
||||
if (local.onCollapse && threshold > 0 && current < threshold) {
|
||||
local.onCollapse()
|
||||
if (collapsed) {
|
||||
onCollapse?.()
|
||||
return
|
||||
}
|
||||
onCollapseChange?.(false)
|
||||
}
|
||||
|
||||
document.addEventListener("mousemove", onMouseMove)
|
||||
|
|
|
|||
|
|
@ -723,7 +723,11 @@ body[data-new-layout] #review-panel [data-component="tabs"][data-variant="normal
|
|||
}
|
||||
|
||||
&:has([data-slot="tabs-trigger-close-button"]) {
|
||||
padding-right: 10px;
|
||||
padding-right: 8px;
|
||||
|
||||
[data-slot="tabs-trigger-close-button"] {
|
||||
margin-left: 2px;
|
||||
}
|
||||
}
|
||||
|
||||
&:has([data-selected]) {
|
||||
|
|
@ -789,6 +793,62 @@ body[data-new-layout]
|
|||
[data-slot="tabs-list"]
|
||||
> .sticky {
|
||||
padding-right: 0;
|
||||
|
||||
[data-component="icon-button-v2"] {
|
||||
position: relative;
|
||||
|
||||
&::after {
|
||||
content: "";
|
||||
position: absolute;
|
||||
left: 100%;
|
||||
top: 50%;
|
||||
transform: translateY(-50%);
|
||||
width: 20px;
|
||||
height: 28px;
|
||||
background-color: var(--v2-background-bg-base);
|
||||
pointer-events: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
body[data-new-layout]
|
||||
#review-panel
|
||||
[data-component="tabs"]
|
||||
.session-review-v2-tabs-bar
|
||||
[data-slot="tabs-list"]
|
||||
> .session-review-v2-sidebar-toggle-slot.sticky {
|
||||
padding-right: 0;
|
||||
|
||||
&::before {
|
||||
content: "";
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
bottom: auto;
|
||||
left: auto;
|
||||
right: 100%;
|
||||
transform: translateY(-50%);
|
||||
width: 12px;
|
||||
height: 28px;
|
||||
background-color: var(--v2-background-bg-base);
|
||||
background-image: none;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
&::after {
|
||||
content: "";
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 100%;
|
||||
transform: translateY(-50%);
|
||||
width: 8px;
|
||||
height: 28px;
|
||||
pointer-events: none;
|
||||
background: linear-gradient(90deg, var(--v2-background-bg-base), transparent);
|
||||
}
|
||||
|
||||
[data-component="icon-button-v2"]::after {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
body[data-new-layout] #review-panel [data-component="tabs"] .session-review-v2-open-in-app-slot {
|
||||
|
|
|
|||
|
|
@ -113,6 +113,29 @@
|
|||
cursor: not-allowed;
|
||||
}
|
||||
|
||||
[data-component="button-v2"][data-variant="warning"] {
|
||||
background-color: var(--v2-background-bg-button-neutral);
|
||||
color: var(--v2-state-fg-warning);
|
||||
box-shadow: var(--v2-elevation-button-neutral);
|
||||
}
|
||||
|
||||
[data-component="button-v2"][data-variant="warning"]:is(:hover, [data-state="hover"]):not(:disabled) {
|
||||
background-image:
|
||||
linear-gradient(90deg, var(--v2-overlay-simple-overlay-hover) 0%, var(--v2-overlay-simple-overlay-hover) 100%),
|
||||
linear-gradient(90deg, var(--v2-background-bg-button-neutral) 0%, var(--v2-background-bg-button-neutral) 100%);
|
||||
}
|
||||
|
||||
[data-component="button-v2"][data-variant="warning"]:is(:active, [data-state="pressed"]):not(:disabled) {
|
||||
background-image:
|
||||
linear-gradient(90deg, var(--v2-overlay-simple-overlay-pressed) 0%, var(--v2-overlay-simple-overlay-pressed) 100%),
|
||||
linear-gradient(90deg, var(--v2-background-bg-button-neutral) 0%, var(--v2-background-bg-button-neutral) 100%);
|
||||
}
|
||||
|
||||
[data-component="button-v2"][data-variant="warning"]:is(:disabled, [data-state="disabled"]) {
|
||||
opacity: 0.5;
|
||||
cursor: not-allowed;
|
||||
}
|
||||
|
||||
/* Outline */
|
||||
[data-component="button-v2"][data-variant="outline"] {
|
||||
background-color: transparent;
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ const docs = `### Overview
|
|||
Button v2 with visual variants and three sizes.
|
||||
|
||||
### API
|
||||
- \`variant\`: "neutral" | "danger" | "contrast" | "ghost" | "ghost-muted" | "loading".
|
||||
- \`variant\`: "neutral" | "danger" | "warning" | "contrast" | "ghost" | "ghost-muted" | "loading".
|
||||
- \`size\`: "small" | "normal" | "large".
|
||||
- \`icon\`: Optional icon name.
|
||||
- Inherits Kobalte Button props and native button attributes.
|
||||
|
|
@ -39,7 +39,7 @@ export default {
|
|||
},
|
||||
variant: {
|
||||
control: "select",
|
||||
options: ["neutral", "danger", "contrast", "ghost", "ghost-muted", "loading"],
|
||||
options: ["neutral", "danger", "warning", "contrast", "ghost", "ghost-muted", "loading"],
|
||||
},
|
||||
size: {
|
||||
control: "select",
|
||||
|
|
@ -62,6 +62,7 @@ export const Variants = {
|
|||
>
|
||||
<ButtonV2 variant="neutral">Neutral</ButtonV2>
|
||||
<ButtonV2 variant="danger">Danger</ButtonV2>
|
||||
<ButtonV2 variant="warning">Warning</ButtonV2>
|
||||
<ButtonV2 variant="contrast">Contrast</ButtonV2>
|
||||
<ButtonV2 variant="ghost">Ghost</ButtonV2>
|
||||
<ButtonV2 variant="ghost-muted" icon="edit">
|
||||
|
|
@ -117,7 +118,7 @@ export const Icon = {
|
|||
|
||||
export const AllStates = {
|
||||
render: () => {
|
||||
const variants = ["neutral", "danger", "contrast", "ghost", "ghost-muted", "loading"] as const
|
||||
const variants = ["neutral", "danger", "warning", "contrast", "ghost", "ghost-muted", "loading"] as const
|
||||
const states = ["default", "hover", "pressed", "focus", "disabled"] as const
|
||||
const toTitleCase = (value: string) => value.charAt(0).toUpperCase() + value.slice(1)
|
||||
return (
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ export interface ButtonV2Props
|
|||
extends ComponentProps<typeof Kobalte>,
|
||||
Pick<ComponentProps<"button">, "class" | "classList" | "children"> {
|
||||
size?: "small" | "normal" | "large"
|
||||
variant?: "neutral" | "danger" | "outline" | "contrast" | "ghost" | "ghost-muted" | "loading"
|
||||
variant?: "neutral" | "danger" | "warning" | "outline" | "contrast" | "ghost" | "ghost-muted" | "loading"
|
||||
icon?: IconProps["name"]
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -101,7 +101,7 @@ export function Dialog(props: DialogProps) {
|
|||
const autofocusEl = target?.querySelector("[autofocus]") as HTMLElement | null
|
||||
if (autofocusEl) {
|
||||
e.preventDefault()
|
||||
autofocusEl.focus()
|
||||
autofocusEl.focus({ preventScroll: true })
|
||||
}
|
||||
}}
|
||||
>
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
[data-component="divider-v2"] {
|
||||
box-sizing: border-box;
|
||||
width: 100%;
|
||||
height: 0.5px;
|
||||
margin-block: 0.25px;
|
||||
height: 1px;
|
||||
transform: scaleY(0.5);
|
||||
border: none;
|
||||
background: var(--v2-border-border-strong);
|
||||
flex: none;
|
||||
|
|
|
|||
|
|
@ -67,9 +67,14 @@
|
|||
gap: 4px;
|
||||
background: var(--v2-background-bg-layer-01);
|
||||
border-radius: 4px 0 0 4px;
|
||||
cursor: default;
|
||||
transition: background 85ms ease-out;
|
||||
}
|
||||
|
||||
[data-component="inline-input-v2"]:where([data-disabled]) [data-slot="inline-input-v2-prefix"] {
|
||||
cursor: not-allowed;
|
||||
}
|
||||
|
||||
[data-component="inline-input-v2"][data-label-width] [data-slot="inline-input-v2-prefix"] {
|
||||
width: var(--inline-input-v2-label-width);
|
||||
min-width: var(--inline-input-v2-label-width);
|
||||
|
|
@ -89,6 +94,7 @@
|
|||
letter-spacing: -0.04px;
|
||||
color: var(--v2-text-text-muted);
|
||||
font-variation-settings: "slnt" 0;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
[data-component="inline-input-v2"][data-numeric] [data-slot="inline-input-v2-prefix-text"] {
|
||||
|
|
@ -149,6 +155,7 @@
|
|||
|
||||
[data-component="inline-input-v2"] [data-slot="inline-input-v2-input"]::placeholder {
|
||||
color: var(--v2-text-text-faint);
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
[data-component="inline-input-v2"][data-numeric] [data-slot="inline-input-v2-input"] {
|
||||
|
|
|
|||
|
|
@ -37,6 +37,8 @@ export function InlineInputV2(props: InlineInputV2Props) {
|
|||
"style",
|
||||
])
|
||||
|
||||
let input: HTMLInputElement | undefined
|
||||
|
||||
return (
|
||||
<div
|
||||
data-component="inline-input-v2"
|
||||
|
|
@ -59,7 +61,15 @@ export function InlineInputV2(props: InlineInputV2Props) {
|
|||
: {}),
|
||||
}}
|
||||
>
|
||||
<div data-slot="inline-input-v2-prefix">
|
||||
<div
|
||||
data-slot="inline-input-v2-prefix"
|
||||
onMouseDown={(event) => {
|
||||
if (local.disabled || event.button !== 0) return
|
||||
// Keep focus on the input without using a native <label>, so external labels still work.
|
||||
event.preventDefault()
|
||||
input?.focus()
|
||||
}}
|
||||
>
|
||||
<span data-slot="inline-input-v2-prefix-text">{local.prefix}</span>
|
||||
</div>
|
||||
<div data-slot="inline-input-v2-divider" aria-hidden="true" />
|
||||
|
|
@ -67,6 +77,11 @@ export function InlineInputV2(props: InlineInputV2Props) {
|
|||
<div data-slot="inline-input-v2-value">
|
||||
<input
|
||||
{...inputProps}
|
||||
ref={(el) => {
|
||||
input = el
|
||||
const ref = inputProps.ref
|
||||
if (typeof ref === "function") ref(el)
|
||||
}}
|
||||
type={inputProps.type ?? "text"}
|
||||
disabled={local.disabled}
|
||||
aria-invalid={local.invalid ? true : undefined}
|
||||
|
|
|
|||
|
|
@ -98,6 +98,7 @@
|
|||
|
||||
[data-component="text-input-v2"] [data-slot="text-input-v2-input"]::placeholder {
|
||||
color: var(--v2-text-text-faint);
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
[data-component="text-input-v2"] [data-slot="text-input-v2-input"][type="search"]::-webkit-search-cancel-button {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue