Revert "feat(ui): Select, dropdown, popover styles & transitions (#11675)"

This reverts commit 377bf7ff21.
This commit is contained in:
Adam
2026-02-02 11:46:25 -06:00
parent 2f76b49df3
commit 70cf609ce9
19 changed files with 129 additions and 620 deletions

View File

@@ -9,13 +9,7 @@
user-select: none;
cursor: default;
outline: none;
padding: 4px 8px;
white-space: nowrap;
transition-property: background-color, border-color, color, box-shadow, opacity;
transition-duration: var(--transition-duration);
transition-timing-function: var(--transition-easing);
outline: none;
line-height: 20px;
&[data-variant="primary"] {
background-color: var(--button-primary-base);
@@ -100,6 +94,7 @@
&:active:not(:disabled) {
background-color: var(--button-secondary-base);
scale: 0.99;
transition: all 150ms ease-out;
}
&:disabled {
border-color: var(--border-disabled);
@@ -115,32 +110,33 @@
&[data-size="small"] {
height: 22px;
padding: 4px 8px;
padding: 0 8px;
&[data-icon] {
padding: 4px 12px 4px 4px;
padding: 0 12px 0 4px;
}
font-size: var(--font-size-small);
line-height: var(--line-height-large);
gap: 4px;
/* text-12-medium */
font-family: var(--font-family-sans);
font-size: var(--font-size-base);
font-size: var(--font-size-small);
font-style: normal;
font-weight: var(--font-weight-medium);
line-height: var(--line-height-large); /* 166.667% */
letter-spacing: var(--letter-spacing-normal);
}
&[data-size="normal"] {
height: 24px;
padding: 4px 6px;
line-height: 24px;
padding: 0 6px;
&[data-icon] {
padding: 4px 12px 4px 4px;
}
&[aria-haspopup] {
padding: 4px 6px 4px 8px;
padding: 0 12px 0 4px;
}
font-size: var(--font-size-small);
gap: 6px;
/* text-12-medium */

View File

@@ -4,7 +4,7 @@ import { Icon, IconProps } from "./icon"
export interface ButtonProps
extends ComponentProps<typeof Kobalte>,
Pick<ComponentProps<"button">, "class" | "classList" | "children" | "style"> {
Pick<ComponentProps<"button">, "class" | "classList" | "children"> {
size?: "small" | "normal" | "large"
variant?: "primary" | "secondary" | "ghost"
icon?: IconProps["name"]

View File

@@ -1,49 +0,0 @@
.cycle-label {
--c-duration: 200ms;
--c-stagger: 30ms;
--c-opacity-start: 0;
--c-opacity-end: 1;
--c-blur-start: 0px;
--c-blur-end: 0px;
--c-skew: 10deg;
display: inline-flex;
position: relative;
transform-style: preserve-3d;
perspective: 500px;
transition: width var(--transition-duration) var(--transition-easing);
will-change: width;
overflow: hidden;
.cycle-char {
display: inline-block;
transform-style: preserve-3d;
min-width: 0.25em;
backface-visibility: hidden;
transition-property: transform, opacity, filter;
transition-duration: var(--transition-duration);
transition-timing-function: var(--transition-easing);
transition-delay: calc(var(--i, 0) * var(--c-stagger));
&.enter {
opacity: var(--c-opacity-end);
filter: blur(var(--c-blur-end));
transform: translateY(0) rotateX(0) skewX(0);
}
&.exit {
opacity: var(--c-opacity-start);
filter: blur(var(--c-blur-start));
transform: translateY(50%) rotateX(90deg) skewX(var(--c-skew));
}
&.pre {
opacity: var(--c-opacity-start);
filter: blur(var(--c-blur-start));
transition: none;
transform: translateY(-50%) rotateX(-90deg) skewX(calc(var(--c-skew) * -1));
}
}
}

View File

@@ -1,135 +0,0 @@
import "./cycle-label.css"
import { createEffect, createSignal, JSX, on } from "solid-js"
export interface CycleLabelProps extends JSX.HTMLAttributes<HTMLSpanElement> {
value: string
onValueChange?: (value: string) => void
duration?: number | ((value: string) => number)
stagger?: number
opacity?: [number, number]
blur?: [number, number]
skewX?: number
onAnimationStart?: () => void
onAnimationEnd?: () => void
}
const segmenter =
typeof Intl !== "undefined" && Intl.Segmenter ? new Intl.Segmenter("en", { granularity: "grapheme" }) : null
const getChars = (text: string): string[] =>
segmenter ? Array.from(segmenter.segment(text), (s) => s.segment) : text.split("")
const wait = (ms: number) => new Promise((resolve) => setTimeout(resolve, ms))
export function CycleLabel(props: CycleLabelProps) {
const getDuration = (text: string) => {
const d =
props.duration ??
Number(getComputedStyle(document.documentElement).getPropertyValue("--transition-duration")) ??
200
return typeof d === "function" ? d(text) : d
}
const stagger = () => props?.stagger ?? 30
const opacity = () => props?.opacity ?? [0, 1]
const blur = () => props?.blur ?? [0, 0]
const skewX = () => props?.skewX ?? 10
let containerRef: HTMLSpanElement | undefined
let isAnimating = false
const [currentText, setCurrentText] = createSignal(props.value)
const setChars = (el: HTMLElement, text: string, state: "enter" | "exit" | "pre" = "enter") => {
el.innerHTML = ""
const chars = getChars(text)
chars.forEach((char, i) => {
const span = document.createElement("span")
span.textContent = char === " " ? "\u00A0" : char
span.className = `cycle-char ${state}`
span.style.setProperty("--i", String(i))
el.appendChild(span)
})
}
const animateToText = async (newText: string) => {
if (!containerRef || isAnimating) return
if (newText === currentText()) return
isAnimating = true
props.onAnimationStart?.()
const dur = getDuration(newText)
const stag = stagger()
containerRef.style.width = containerRef.offsetWidth + "px"
const oldChars = containerRef.querySelectorAll(".cycle-char")
oldChars.forEach((c) => c.classList.replace("enter", "exit"))
const clone = containerRef.cloneNode(false) as HTMLElement
Object.assign(clone.style, {
position: "absolute",
visibility: "hidden",
width: "auto",
transition: "none",
})
setChars(clone, newText)
document.body.appendChild(clone)
const nextWidth = clone.offsetWidth
clone.remove()
const exitTime = oldChars.length * stag + dur
await wait(exitTime * 0.3)
containerRef.style.width = nextWidth + "px"
const widthDur = 200
await wait(widthDur * 0.3)
setChars(containerRef, newText, "pre")
containerRef.offsetWidth
Array.from(containerRef.children).forEach((c) => (c.className = "cycle-char enter"))
setCurrentText(newText)
props.onValueChange?.(newText)
const enterTime = getChars(newText).length * stag + dur
await wait(enterTime)
containerRef.style.width = ""
isAnimating = false
props.onAnimationEnd?.()
}
createEffect(
on(
() => props.value,
(newValue) => {
if (newValue !== currentText()) {
animateToText(newValue)
}
},
),
)
const initRef = (el: HTMLSpanElement) => {
containerRef = el
setChars(el, props.value)
}
return (
<span
ref={initRef}
class={`cycle-label ${props.class ?? ""}`}
style={{
"--c-duration": `${getDuration(currentText())}ms`,
"--c-stagger": `${stagger()}ms`,
"--c-opacity-start": opacity()[0],
"--c-opacity-end": opacity()[1],
"--c-blur-start": `${blur()[0]}px`,
"--c-blur-end": `${blur()[1]}px`,
"--c-skew": `${skewX()}deg`,
...(typeof props.style === "object" ? props.style : {}),
}}
/>
)
}

View File

@@ -2,29 +2,26 @@
[data-component="dropdown-menu-sub-content"] {
min-width: 8rem;
overflow: hidden;
border: none;
border-radius: var(--radius-md);
box-shadow: var(--shadow-xs-border);
border: 1px solid color-mix(in oklch, var(--border-base) 50%, transparent);
background-clip: padding-box;
background-color: var(--surface-raised-stronger-non-alpha);
padding: 4px;
z-index: 100;
box-shadow: var(--shadow-md);
z-index: 50;
transform-origin: var(--kb-menu-content-transform-origin);
&:focus-within,
&:focus {
&:focus,
&:focus-visible {
outline: none;
}
animation: dropdownMenuContentHide var(--transition-duration) var(--transition-easing) forwards;
@starting-style {
animation: none;
&[data-closed] {
animation: dropdown-menu-close 0.15s ease-out;
}
&[data-expanded] {
pointer-events: auto;
animation: dropdownMenuContentShow var(--transition-duration) var(--transition-easing) forwards;
animation: dropdown-menu-open 0.15s ease-out;
}
}
@@ -41,22 +38,18 @@
padding: 4px 8px;
border-radius: var(--radius-sm);
cursor: default;
user-select: none;
outline: none;
font-family: var(--font-family-sans);
font-size: var(--font-size-base);
font-size: var(--font-size-small);
font-weight: var(--font-weight-medium);
line-height: var(--line-height-large);
letter-spacing: var(--letter-spacing-normal);
color: var(--text-strong);
transition-property: background-color, color;
transition-duration: var(--transition-duration);
transition-timing-function: var(--transition-easing);
user-select: none;
&:hover {
background-color: var(--surface-raised-base-hover);
&[data-highlighted] {
background: var(--surface-raised-base-hover);
}
&[data-disabled] {
@@ -68,8 +61,6 @@
[data-slot="dropdown-menu-sub-trigger"] {
&[data-expanded] {
background: var(--surface-raised-base-hover);
outline: none;
border: none;
}
}
@@ -111,24 +102,24 @@
}
}
@keyframes dropdownMenuContentShow {
@keyframes dropdown-menu-open {
from {
opacity: 0;
transform: scaleY(0.95);
transform: scale(0.96);
}
to {
opacity: 1;
transform: scaleY(1);
transform: scale(1);
}
}
@keyframes dropdownMenuContentHide {
@keyframes dropdown-menu-close {
from {
opacity: 1;
transform: scaleY(1);
transform: scale(1);
}
to {
opacity: 0;
transform: scaleY(0.95);
transform: scale(0.96);
}
}

View File

@@ -80,16 +80,13 @@ const icons = {
export interface IconProps extends ComponentProps<"svg"> {
name: keyof typeof icons
size?: "small" | "normal" | "medium" | "large" | number
size?: "small" | "normal" | "medium" | "large"
}
export function Icon(props: IconProps) {
const [local, others] = splitProps(props, ["name", "size", "class", "classList"])
return (
<div
data-component="icon"
data-size={typeof local.size !== "number" ? local.size || "normal" : `size-[${local.size}px]`}
>
<div data-component="icon" data-size={local.size || "normal"}>
<svg
data-slot="icon-svg"
classList={{

View File

@@ -42,13 +42,13 @@ import { Checkbox } from "./checkbox"
import { DiffChanges } from "./diff-changes"
import { Markdown } from "./markdown"
import { ImagePreview } from "./image-preview"
import { findLast } from "@opencode-ai/util/array"
import { getDirectory as _getDirectory, getFilename } from "@opencode-ai/util/path"
import { checksum } from "@opencode-ai/util/encode"
import { Tooltip } from "./tooltip"
import { IconButton } from "./icon-button"
import { createAutoScroll } from "../hooks"
import { createResizeObserver } from "@solid-primitives/resize-observer"
import { MorphChevron } from "./morph-chevron"
interface Diagnostic {
range: {
@@ -415,7 +415,7 @@ export function UserMessageDisplay(props: { message: UserMessage; parts: PartTyp
toggleExpanded()
}}
>
<MorphChevron expanded={expanded()} />
<Icon name="chevron-down" size="small" />
</button>
<div data-slot="user-message-copy-wrapper">
<Tooltip
@@ -898,7 +898,7 @@ ToolRegistry.register({
if (!sessionId) return undefined
// Find the tool part that matches the permission's callID
const messages = data.store.message[sessionId] ?? []
const message = messages.findLast((m) => m.id === perm.tool!.messageID)
const message = findLast(messages, (m) => m.id === perm.tool!.messageID)
if (!message) return undefined
const parts = data.store.part[message.id] ?? []
for (const part of parts) {

View File

@@ -1,10 +0,0 @@
[data-slot="morph-chevron-svg"] {
width: 16px;
height: 16px;
display: block;
fill: none;
stroke-width: 1.5;
stroke: currentcolor;
stroke-linecap: round;
stroke-linejoin: round;
}

View File

@@ -1,73 +0,0 @@
import { createEffect, createUniqueId, on } from "solid-js"
export interface MorphChevronProps {
expanded: boolean
class?: string
}
const COLLAPSED = "M4 6L8 10L12 6"
const EXPANDED = "M4 10L8 6L12 10"
export function MorphChevron(props: MorphChevronProps) {
const id = createUniqueId()
let path: SVGPathElement | undefined
let expandAnim: SVGAnimateElement | undefined
let collapseAnim: SVGAnimateElement | undefined
createEffect(
on(
() => props.expanded,
(expanded, prev) => {
if (prev === undefined) {
// Set initial state without animation
path?.setAttribute("d", expanded ? EXPANDED : COLLAPSED)
return
}
if (expanded) {
expandAnim?.beginElement()
} else {
collapseAnim?.beginElement()
}
},
),
)
return (
<svg
viewBox="0 0 16 16"
data-slot="morph-chevron-svg"
class={props.class}
xmlns="http://www.w3.org/2000/svg"
aria-hidden="true"
>
<path ref={path} d={COLLAPSED} id={`morph-chevron-path-${id}`}>
<animate
ref={(el) => {
expandAnim = el
}}
id={`morph-expand-${id}`}
attributeName="d"
dur="200ms"
fill="freeze"
calcMode="spline"
keySplines="0.25 0 0.5 1"
values="M4 6L8 10L12 6;M4 10L8 6L12 10"
begin="indefinite"
/>
<animate
ref={(el) => {
collapseAnim = el
}}
id={`morph-collapse-${id}`}
attributeName="d"
dur="200ms"
fill="freeze"
calcMode="spline"
keySplines="0.25 0 0.5 1"
values="M4 10L8 6L12 10;M4 6L8 10L12 6"
begin="indefinite"
/>
</path>
</svg>
)
}

View File

@@ -15,35 +15,16 @@
transform-origin: var(--kb-popover-content-transform-origin);
animation: popoverContentHide var(--transition-duration) var(--transition-easing) forwards;
&:focus-within {
outline: none;
}
@starting-style {
animation: none;
&[data-closed] {
animation: popover-close 0.15s ease-out;
}
&[data-expanded] {
pointer-events: auto;
animation: popoverContentShow var(--transition-duration) var(--transition-easing) forwards;
}
[data-origin-top-right] {
transform-origin: top right;
}
[data-origin-top-left] {
transform-origin: top left;
}
[data-origin-bottom-right] {
transform-origin: bottom right;
}
[data-origin-bottom-left] {
transform-origin: bottom left;
}
&:focus-within {
outline: none;
animation: popover-open 0.15s ease-out;
}
[data-slot="popover-header"] {
@@ -94,39 +75,24 @@
}
}
@keyframes popoverContentShow {
@keyframes popover-open {
from {
opacity: 0;
transform: scaleY(0.95);
transform: scale(0.96);
}
to {
opacity: 1;
transform: scaleY(1);
transform: scale(1);
}
}
@keyframes popoverContentHide {
@keyframes popover-close {
from {
opacity: 1;
transform: scaleY(1);
transform: scale(1);
}
to {
opacity: 0;
transform: scaleY(0.95);
}
}
[data-component="model-popover-content"] {
transform-origin: var(--kb-popper-content-transform-origin);
pointer-events: none;
animation: popoverContentHide var(--transition-duration) var(--transition-easing) forwards;
@starting-style {
animation: none;
}
&[data-expanded] {
pointer-events: auto;
animation: popoverContentShow var(--transition-duration) var(--transition-easing) forwards;
transform: scale(0.96);
}
}

View File

@@ -1,9 +0,0 @@
[data-component="reasoning-icon"] {
color: var(--icon-strong-base);
[data-slot="reasoning-icon-percentage"] {
transition: clip-path 200ms cubic-bezier(0.25, 0, 0.5, 1);
clip-path: inset(calc(100% - var(--reasoning-icon-percentage) * 100%) 0 0 0);
opacity: calc(var(--reasoning-icon-percentage) * 0.75);
}
}

View File

@@ -1,46 +0,0 @@
import { type ComponentProps, splitProps } from "solid-js"
export interface ReasoningIconProps extends Pick<ComponentProps<"svg">, "class" | "classList"> {
percentage: number
size?: number
strokeWidth?: number
}
export function ReasoningIcon(props: ReasoningIconProps) {
const [split, rest] = splitProps(props, ["percentage", "size", "strokeWidth", "class", "classList"])
const size = () => split.size || 16
const strokeWidth = () => split.strokeWidth || 1.25
return (
<svg
{...rest}
width={size()}
height={size()}
viewBox={`0 0 16 16`}
fill="none"
data-component="reasoning-icon"
classList={{
...(split.classList ?? {}),
[split.class ?? ""]: !!split.class,
}}
>
<path
d="M5.83196 10.3225V11.1666C5.83196 11.7189 6.27967 12.1666 6.83196 12.1666H9.16687C9.71915 12.1666 10.1669 11.7189 10.1669 11.1666V10.3225M5.83196 10.3225C5.55695 10.1843 5.29695 10.0206 5.05505 9.83459C3.90601 8.95086 3.16549 7.56219 3.16549 6.00055C3.16549 3.33085 5.32971 1.16663 7.99941 1.16663C10.6691 1.16663 12.8333 3.33085 12.8333 6.00055C12.8333 7.56219 12.0928 8.95086 10.9438 9.83459C10.7019 10.0206 10.4419 10.1843 10.1669 10.3225M5.83196 10.3225H10.1669M6.5 14.1666H9.5"
stroke="currentColor"
stroke-linecap="round"
stroke-linejoin="round"
/>
<circle
cx="8"
cy="5.83325"
r="2.86364"
fill="currentColor"
stroke="currentColor"
stroke-width={strokeWidth()}
style={{ "--reasoning-icon-percentage": split.percentage / 100 }}
data-slot="reasoning-icon-percentage"
/>
</svg>
)
}

View File

@@ -1,13 +1,7 @@
[data-component="select"] {
[data-slot="select-select-trigger"] {
display: flex;
padding: 4px 8px !important;
align-items: center;
justify-content: space-between;
padding: 0 4px 0 8px;
box-shadow: none;
transition-property: background-color;
transition-duration: var(--transition-duration);
transition-timing-function: var(--transition-easing);
[data-slot="select-select-trigger-value"] {
overflow: hidden;
@@ -21,10 +15,10 @@
align-items: center;
justify-content: center;
flex-shrink: 0;
color: var(--icon-base);
color: var(--text-weak);
transition: transform 0.1s ease-in-out;
}
&:hover,
&[data-expanded] {
&[data-variant="secondary"] {
background-color: var(--button-secondary-hover);
@@ -36,13 +30,13 @@
background-color: var(--icon-strong-active);
}
}
&:not([data-expanded]):focus,
&:not([data-expanded]):focus-visible {
&[data-variant="secondary"] {
background-color: var(--button-secondary-base);
}
&[data-variant="ghost"] {
background-color: transparent;
background-color: var(--surface-raised-base-hover);
}
&[data-variant="primary"] {
background-color: var(--icon-strong-base);
@@ -52,10 +46,10 @@
&[data-trigger-style="settings"] {
[data-slot="select-select-trigger"] {
padding: 6px 6px 6px 10px;
padding: 6px 6px 6px 12px;
box-shadow: none;
border-radius: 6px;
field-sizing: content;
min-width: 160px;
height: 32px;
justify-content: flex-end;
gap: 12px;
@@ -67,7 +61,6 @@
white-space: nowrap;
font-size: var(--font-size-base);
font-weight: var(--font-weight-regular);
padding: 4px 8px 4px 4px;
}
[data-slot="select-select-trigger-icon"] {
width: 16px;
@@ -98,26 +91,17 @@
}
[data-component="select-content"] {
min-width: 8rem;
min-width: 104px;
max-width: 23rem;
overflow: hidden;
border-radius: var(--radius-md);
background-color: var(--surface-raised-stronger-non-alpha);
padding: 4px;
box-shadow: var(--shadow-xs-border);
z-index: 50;
transform-origin: var(--kb-popper-content-transform-origin);
pointer-events: none;
animation: selectContentHide var(--transition-duration) var(--transition-easing) forwards;
@starting-style {
animation: none;
}
z-index: 60;
&[data-expanded] {
pointer-events: auto;
animation: selectContentShow var(--transition-duration) var(--transition-easing) forwards;
animation: select-open 0.15s ease-out;
}
[data-slot="select-select-content-list"] {
@@ -127,38 +111,43 @@
overflow-x: hidden;
display: flex;
flex-direction: column;
&:focus {
outline: none;
}
> *:not([role="presentation"]) + *:not([role="presentation"]) {
margin-top: 2px;
}
}
[data-slot="select-select-item"] {
position: relative;
display: flex;
align-items: center;
padding: 4px 8px;
padding: 2px 8px;
gap: 12px;
border-radius: var(--radius-sm);
border-radius: 4px;
cursor: default;
/* text-12-medium */
font-family: var(--font-family-sans);
font-size: var(--font-size-base);
font-size: var(--font-size-small);
font-style: normal;
font-weight: var(--font-weight-medium);
line-height: var(--line-height-large); /* 166.667% */
letter-spacing: var(--letter-spacing-normal);
color: var(--text-strong);
transition-property: background-color, color;
transition-duration: var(--transition-duration);
transition-timing-function: var(--transition-easing);
transition:
background-color 0.2s ease-in-out,
color 0.2s ease-in-out;
outline: none;
user-select: none;
&:hover {
background-color: var(--surface-raised-base-hover);
&[data-highlighted] {
background: var(--surface-raised-base-hover);
}
&[data-disabled] {
background-color: var(--surface-raised-base);
@@ -171,11 +160,6 @@
margin-left: auto;
width: 16px;
height: 16px;
color: var(--icon-strong-base);
svg {
color: var(--icon-strong-base);
}
}
&:focus {
outline: none;
@@ -187,9 +171,13 @@
}
[data-component="select-content"][data-trigger-style="settings"] {
field-sizing: content;
min-width: 160px;
border-radius: 8px;
padding: 0 0 0 4px;
padding: 0;
[data-slot="select-select-content-list"] {
padding: 4px;
}
[data-slot="select-select-item"] {
/* text-14-regular */
@@ -202,24 +190,13 @@
}
}
@keyframes selectContentShow {
@keyframes select-open {
from {
opacity: 0;
transform: scaleY(0.95);
transform: scale(0.95);
}
to {
opacity: 1;
transform: scaleY(1);
}
}
@keyframes selectContentHide {
from {
opacity: 1;
transform: scaleY(1);
}
to {
opacity: 0;
transform: scaleY(0.95);
transform: scale(1);
}
}

View File

@@ -1,10 +1,8 @@
import { Select as Kobalte } from "@kobalte/core/select"
import { createMemo, createSignal, onCleanup, splitProps, type ComponentProps, type JSX } from "solid-js"
import { createMemo, onCleanup, splitProps, type ComponentProps, type JSX } from "solid-js"
import { pipe, groupBy, entries, map } from "remeda"
import { Show } from "solid-js"
import { Button, ButtonProps } from "./button"
import { Icon } from "./icon"
import { MorphChevron } from "./morph-chevron"
export type SelectProps<T> = Omit<ComponentProps<typeof Kobalte<T>>, "value" | "onSelect" | "children"> & {
placeholder?: string
@@ -40,8 +38,6 @@ export function Select<T>(props: SelectProps<T> & Omit<ButtonProps, "children">)
"triggerVariant",
])
const [isOpen, setIsOpen] = createSignal(false)
const state = {
key: undefined as string | undefined,
cleanup: undefined as (() => void) | void,
@@ -89,7 +85,7 @@ export function Select<T>(props: SelectProps<T> & Omit<ButtonProps, "children">)
data-component="select"
data-trigger-style={local.triggerVariant}
placement={local.triggerVariant === "settings" ? "bottom-end" : "bottom-start"}
gutter={8}
gutter={4}
value={local.current}
options={grouped()}
optionValue={(x) => (local.value ? local.value(x) : (x as string))}
@@ -119,7 +115,7 @@ export function Select<T>(props: SelectProps<T> & Omit<ButtonProps, "children">)
: (itemProps.item.rawValue as string)}
</Kobalte.ItemLabel>
<Kobalte.ItemIndicator data-slot="select-select-item-indicator">
<Icon name="check" size="small" />
<Icon name="check-small" size="small" />
</Kobalte.ItemIndicator>
</Kobalte.Item>
)}
@@ -128,7 +124,6 @@ export function Select<T>(props: SelectProps<T> & Omit<ButtonProps, "children">)
stop()
}}
onOpenChange={(open) => {
setIsOpen(open)
local.onOpenChange?.(open)
if (!open) stop()
}}
@@ -154,12 +149,7 @@ export function Select<T>(props: SelectProps<T> & Omit<ButtonProps, "children">)
}}
</Kobalte.Value>
<Kobalte.Icon data-slot="select-select-trigger-icon">
<Show when={local.triggerVariant === "settings"}>
<Icon name="selector" size="small" />
</Show>
<Show when={local.triggerVariant !== "settings"}>
<MorphChevron expanded={isOpen()} />
</Show>
<Icon name={local.triggerVariant === "settings" ? "selector" : "chevron-down"} size="small" />
</Kobalte.Icon>
</Kobalte.Trigger>
<Kobalte.Portal>

View File

@@ -49,8 +49,6 @@
@import "../components/toast.css" layer(components);
@import "../components/tooltip.css" layer(components);
@import "../components/typewriter.css" layer(components);
@import "../components/morph-chevron.css" layer(components);
@import "../components/reasoning-icon.css" layer(components);
@import "./utilities.css" layer(utilities);
@import "./animations.css" layer(utilities);

View File

@@ -1,17 +1,6 @@
:root {
interpolate-size: allow-keywords;
/* Transition tokens */
--transition-duration: 200ms;
--transition-easing: cubic-bezier(0.25, 0, 0.5, 1);
--transition-fast: 150ms;
--transition-slow: 300ms;
/* Allow height transitions from 0 to auto */
@supports (interpolate-size: allow-keywords) {
interpolate-size: allow-keywords;
}
[data-popper-positioner] {
pointer-events: none;
}
@@ -140,34 +129,3 @@
line-height: var(--line-height-x-large); /* 120% */
letter-spacing: var(--letter-spacing-tightest);
}
/* Transition utility classes */
.transition-colors {
transition-property: background-color, border-color, color, fill, stroke;
transition-duration: var(--transition-duration);
transition-timing-function: var(--transition-easing);
}
.transition-opacity {
transition-property: opacity;
transition-duration: var(--transition-duration);
transition-timing-function: var(--transition-easing);
}
.transition-transform {
transition-property: transform;
transition-duration: var(--transition-duration);
transition-timing-function: var(--transition-easing);
}
.transition-shadow {
transition-property: box-shadow;
transition-duration: var(--transition-duration);
transition-timing-function: var(--transition-easing);
}
.transition-interactive {
transition-property: background-color, border-color, color, box-shadow, opacity;
transition-duration: var(--transition-duration);
transition-timing-function: var(--transition-easing);
}