feat: Transitions, spacing, scroll fade, prompt area update (#11168)

Co-authored-by: Github Action <action@github.com>
Co-authored-by: Copilot <198982749+Copilot@users.noreply.github.com>
Co-authored-by: aaroniker <4730431+aaroniker@users.noreply.github.com>
This commit is contained in:
Aaron Iker
2026-01-30 18:57:49 +01:00
committed by GitHub
parent 1bbe84ed8d
commit 20619a6a26
70 changed files with 5836 additions and 4807 deletions

View File

@@ -90,7 +90,7 @@ const ModelList: Component<{
export function ModelSelectorPopover<T extends ValidComponent = "div">(props: {
provider?: string
children?: JSX.Element
children?: JSX.Element | ((open: boolean) => JSX.Element)
triggerAs?: T
triggerProps?: ComponentProps<T>
}) {
@@ -182,12 +182,13 @@ export function ModelSelectorPopover<T extends ValidComponent = "div">(props: {
as={props.triggerAs ?? "div"}
{...(props.triggerProps as any)}
>
{props.children}
{typeof props.children === "function" ? props.children(store.open) : props.children}
</Kobalte.Trigger>
<Kobalte.Portal>
<Kobalte.Content
class="w-72 h-80 flex flex-col rounded-md border border-border-base bg-surface-raised-stronger-non-alpha shadow-md z-50 outline-none overflow-hidden"
data-component="model-popover-content"
ref={(el) => setStore("content", el)}
class="w-72 h-80 flex flex-col p-2 rounded-md border border-border-base bg-surface-raised-stronger-non-alpha shadow-md z-50 outline-none overflow-hidden"
onEscapeKeyDown={(event) => {
setStore("dismiss", "escape")
setStore("open", false)

View File

@@ -32,7 +32,9 @@ import { useNavigate, useParams } from "@solidjs/router"
import { useSync } from "@/context/sync"
import { useComments } from "@/context/comments"
import { FileIcon } from "@opencode-ai/ui/file-icon"
import { MorphChevron } from "@opencode-ai/ui/morph-chevron"
import { Button } from "@opencode-ai/ui/button"
import { CycleLabel } from "@opencode-ai/ui/cycle-label"
import { Icon } from "@opencode-ai/ui/icon"
import { ProviderIcon } from "@opencode-ai/ui/provider-icon"
import type { IconName } from "@opencode-ai/ui/icons/provider"
@@ -42,6 +44,7 @@ import { Select } from "@opencode-ai/ui/select"
import { getDirectory, getFilename, getFilenameTruncated } from "@opencode-ai/util/path"
import { useDialog } from "@opencode-ai/ui/context/dialog"
import { ImagePreview } from "@opencode-ai/ui/image-preview"
import { ReasoningIcon } from "@opencode-ai/ui/reasoning-icon"
import { ModelSelectorPopover } from "@/components/dialog-select-model"
import { DialogSelectModelUnpaid } from "@/components/dialog-select-model-unpaid"
import { useProviders } from "@/hooks/use-providers"
@@ -922,7 +925,7 @@ export const PromptInput: Component<PromptInputProps> = (props) => {
.abort({
sessionID,
})
.catch(() => {})
.catch(() => { })
}
const addToHistory = (prompt: Prompt, mode: "normal" | "shell") => {
@@ -1252,7 +1255,7 @@ export const PromptInput: Component<PromptInputProps> = (props) => {
clearInput()
client.session
.shell({
sessionID: session.id,
sessionID: session?.id || "",
agent,
model,
command: text,
@@ -1275,7 +1278,7 @@ export const PromptInput: Component<PromptInputProps> = (props) => {
clearInput()
client.session
.command({
sessionID: session.id,
sessionID: session?.id || "",
command: commandName,
arguments: args.join(" "),
agent,
@@ -1348,18 +1351,18 @@ export const PromptInput: Component<PromptInputProps> = (props) => {
const contextParts: Array<
| {
id: string
type: "text"
text: string
synthetic?: boolean
}
id: string
type: "text"
text: string
synthetic?: boolean
}
| {
id: string
type: "file"
mime: string
url: string
filename?: string
}
id: string
type: "file"
mime: string
url: string
filename?: string
}
> = []
const commentNote = (path: string, selection: FileSelection | undefined, comment: string) => {
@@ -1431,13 +1434,13 @@ export const PromptInput: Component<PromptInputProps> = (props) => {
const optimisticParts = requestParts.map((part) => ({
...part,
sessionID: session.id,
sessionID: session?.id || "",
messageID,
})) as unknown as Part[]
const optimisticMessage: Message = {
id: messageID,
sessionID: session.id,
sessionID: session?.id || "",
role: "user",
time: { created: Date.now() },
agent,
@@ -1448,9 +1451,9 @@ export const PromptInput: Component<PromptInputProps> = (props) => {
if (sessionDirectory === projectDirectory) {
sync.set(
produce((draft) => {
const messages = draft.message[session.id]
const messages = draft.message[session?.id || ""]
if (!messages) {
draft.message[session.id] = [optimisticMessage]
draft.message[session?.id || ""] = [optimisticMessage]
} else {
const result = Binary.search(messages, messageID, (m) => m.id)
messages.splice(result.index, 0, optimisticMessage)
@@ -1466,9 +1469,9 @@ export const PromptInput: Component<PromptInputProps> = (props) => {
globalSync.child(sessionDirectory)[1](
produce((draft) => {
const messages = draft.message[session.id]
const messages = draft.message[session?.id || ""]
if (!messages) {
draft.message[session.id] = [optimisticMessage]
draft.message[session?.id || ""] = [optimisticMessage]
} else {
const result = Binary.search(messages, messageID, (m) => m.id)
messages.splice(result.index, 0, optimisticMessage)
@@ -1485,7 +1488,7 @@ export const PromptInput: Component<PromptInputProps> = (props) => {
if (sessionDirectory === projectDirectory) {
sync.set(
produce((draft) => {
const messages = draft.message[session.id]
const messages = draft.message[session?.id || ""]
if (messages) {
const result = Binary.search(messages, messageID, (m) => m.id)
if (result.found) messages.splice(result.index, 1)
@@ -1498,7 +1501,7 @@ export const PromptInput: Component<PromptInputProps> = (props) => {
globalSync.child(sessionDirectory)[1](
produce((draft) => {
const messages = draft.message[session.id]
const messages = draft.message[session?.id || ""]
if (messages) {
const result = Binary.search(messages, messageID, (m) => m.id)
if (result.found) messages.splice(result.index, 1)
@@ -1519,15 +1522,15 @@ export const PromptInput: Component<PromptInputProps> = (props) => {
const worktree = WorktreeState.get(sessionDirectory)
if (!worktree || worktree.status !== "pending") return true
if (sessionDirectory === projectDirectory) {
sync.set("session_status", session.id, { type: "busy" })
if (sessionDirectory === projectDirectory && session?.id) {
sync.set("session_status", session?.id, { type: "busy" })
}
const controller = new AbortController()
const cleanup = () => {
if (sessionDirectory === projectDirectory) {
sync.set("session_status", session.id, { type: "idle" })
if (sessionDirectory === projectDirectory && session?.id) {
sync.set("session_status", session?.id, { type: "idle" })
}
removeOptimisticMessage()
for (const item of commentItems) {
@@ -1544,7 +1547,7 @@ export const PromptInput: Component<PromptInputProps> = (props) => {
restoreInput()
}
pending.set(session.id, { abort: controller, cleanup })
pending.set(session?.id || "", { abort: controller, cleanup })
const abort = new Promise<Awaited<ReturnType<typeof WorktreeState.wait>>>((resolve) => {
if (controller.signal.aborted) {
@@ -1572,7 +1575,7 @@ export const PromptInput: Component<PromptInputProps> = (props) => {
if (timer.id === undefined) return
clearTimeout(timer.id)
})
pending.delete(session.id)
pending.delete(session?.id || "")
if (controller.signal.aborted) return false
if (result.status === "failed") throw new Error(result.message)
return true
@@ -1582,7 +1585,7 @@ export const PromptInput: Component<PromptInputProps> = (props) => {
const ok = await waitForWorktree()
if (!ok) return
await client.session.prompt({
sessionID: session.id,
sessionID: session?.id || "",
agent,
model,
messageID,
@@ -1592,9 +1595,9 @@ export const PromptInput: Component<PromptInputProps> = (props) => {
}
void send().catch((err) => {
pending.delete(session.id)
if (sessionDirectory === projectDirectory) {
sync.set("session_status", session.id, { type: "idle" })
pending.delete(session?.id || "")
if (sessionDirectory === projectDirectory && session?.id) {
sync.set("session_status", session?.id, { type: "idle" })
}
showToast({
title: language.t("prompt.toast.promptSendFailed.title"),
@@ -1616,6 +1619,28 @@ export const PromptInput: Component<PromptInputProps> = (props) => {
})
}
const currrentModelVariant = createMemo(() => {
const modelVariant = local.model.variant.current() ?? ""
return modelVariant === "xhigh"
? "xHigh"
: modelVariant.length > 0
? modelVariant[0].toUpperCase() + modelVariant.slice(1)
: "Default"
})
const reasoningPercentage = createMemo(() => {
const variants = local.model.variant.list()
const current = local.model.variant.current()
const totalEntries = variants.length + 1
if (totalEntries <= 2 || current === "Default") {
return 0
}
const currentIndex = current ? variants.indexOf(current) + 1 : 0
return ((currentIndex + 1) / totalEntries) * 100
}, [local.model.variant])
return (
<div class="relative size-full _max-h-[320px] flex flex-col gap-3">
<Show when={store.popover}>
@@ -1668,7 +1693,7 @@ export const PromptInput: Component<PromptInputProps> = (props) => {
</>
}
>
<Icon name="brain" size="small" class="text-icon-info-active shrink-0" />
<Icon name="brain" size="normal" class="text-icon-info-active shrink-0" />
<span class="text-14-regular text-text-strong whitespace-nowrap">
@{(item as { type: "agent"; name: string }).name}
</span>
@@ -1729,9 +1754,9 @@ export const PromptInput: Component<PromptInputProps> = (props) => {
}}
>
<Show when={store.dragging}>
<div class="absolute inset-0 z-10 flex items-center justify-center bg-surface-raised-stronger-non-alpha/90 pointer-events-none">
<div class="absolute inset-0 z-10 flex items-center justify-center bg-surface-raised-stronger-non-alpha/90 mr-1 pointer-events-none">
<div class="flex flex-col items-center gap-2 text-text-weak">
<Icon name="photo" class="size-8" />
<Icon name="photo" size={18} class="text-icon-base stroke-1.5" />
<span class="text-14-regular">{language.t("prompt.dropzone.label")}</span>
</div>
</div>
@@ -1770,7 +1795,7 @@ export const PromptInput: Component<PromptInputProps> = (props) => {
}}
>
<div class="flex items-center gap-1.5">
<FileIcon node={{ path: item.path, type: "file" }} class="shrink-0 size-3.5" />
<FileIcon node={{ path: item.path, type: "file" }} class="shrink-0 size-7" />
<div class="flex items-center text-11-regular min-w-0 font-medium">
<span class="text-text-strong whitespace-nowrap">{getFilenameTruncated(item.path, 14)}</span>
<Show when={item.selection}>
@@ -1787,7 +1812,7 @@ export const PromptInput: Component<PromptInputProps> = (props) => {
type="button"
icon="close-small"
variant="ghost"
class="ml-auto h-5 w-5 opacity-0 group-hover:opacity-100 transition-all"
class="ml-auto size-7 opacity-0 group-hover:opacity-100 transition-all"
onClick={(e) => {
e.stopPropagation()
if (item.commentID) comments.remove(item.path, item.commentID)
@@ -1817,7 +1842,7 @@ export const PromptInput: Component<PromptInputProps> = (props) => {
when={attachment.mime.startsWith("image/")}
fallback={
<div class="size-16 rounded-md bg-surface-base flex items-center justify-center border border-border-base">
<Icon name="folder" class="size-6 text-text-weak" />
<Icon name="folder" size="normal" class="size-6 text-text-base" />
</div>
}
>
@@ -1891,7 +1916,7 @@ export const PromptInput: Component<PromptInputProps> = (props) => {
</Show>
</div>
<div class="relative p-3 flex items-center justify-between">
<div class="flex items-center justify-start gap-0.5">
<div class="flex items-center justify-start gap-2">
<Switch>
<Match when={store.mode === "shell"}>
<div class="flex items-center gap-2 px-2 h-6">
@@ -1922,12 +1947,17 @@ export const PromptInput: Component<PromptInputProps> = (props) => {
title={language.t("command.model.choose")}
keybind={command.keybind("model.choose")}
>
<Button as="div" variant="ghost" onClick={() => dialog.show(() => <DialogSelectModelUnpaid />)}>
<Button
as="div"
variant="ghost"
class="px-2"
onClick={() => dialog.render(<DialogSelectModelUnpaid />, "select-model")}
>
<Show when={local.model.current()?.provider?.id}>
<ProviderIcon id={local.model.current()!.provider.id as IconName} class="size-4 shrink-0" />
</Show>
{local.model.current()?.name ?? language.t("dialog.model.select.title")}
<Icon name="chevron-down" size="small" />
<MorphChevron expanded={dialog.isActive("select-model")} />
</Button>
</TooltipKeybind>
}
@@ -1938,11 +1968,15 @@ export const PromptInput: Component<PromptInputProps> = (props) => {
keybind={command.keybind("model.choose")}
>
<ModelSelectorPopover triggerAs={Button} triggerProps={{ variant: "ghost" }}>
<Show when={local.model.current()?.provider?.id}>
<ProviderIcon id={local.model.current()!.provider.id as IconName} class="size-4 shrink-0" />
</Show>
{local.model.current()?.name ?? language.t("dialog.model.select.title")}
<Icon name="chevron-down" size="small" />
{(open) => (
<>
<Show when={local.model.current()?.provider?.id}>
<ProviderIcon id={local.model.current()!.provider.id as IconName} class="size-4 shrink-0" />
</Show>
{local.model.current()?.name ?? language.t("dialog.model.select.title")}
<MorphChevron expanded={open} class="text-text-weak" />
</>
)}
</ModelSelectorPopover>
</TooltipKeybind>
</Show>
@@ -1955,10 +1989,13 @@ export const PromptInput: Component<PromptInputProps> = (props) => {
<Button
data-action="model-variant-cycle"
variant="ghost"
class="text-text-base _hidden group-hover/prompt-input:inline-block capitalize text-12-regular"
class="text-text-strong text-12-regular"
onClick={() => local.model.variant.cycle()}
>
{local.model.variant.current() ?? language.t("common.default")}
<Show when={local.model.variant.list().length > 1}>
<ReasoningIcon percentage={reasoningPercentage()} size={16} strokeWidth={1.25} />
</Show>
<CycleLabel value={currrentModelVariant()} />
</Button>
</TooltipKeybind>
</Show>
@@ -1972,7 +2009,7 @@ export const PromptInput: Component<PromptInputProps> = (props) => {
variant="ghost"
onClick={() => permission.toggleAutoAccept(params.id!, sdk.directory)}
classList={{
"_hidden group-hover/prompt-input:flex size-6 items-center justify-center": true,
"_hidden group-hover/prompt-input:flex items-center justify-center": true,
"text-text-base": !permission.isAutoAccepting(params.id!, sdk.directory),
"hover:bg-surface-success-base": permission.isAutoAccepting(params.id!, sdk.directory),
}}
@@ -1994,7 +2031,7 @@ export const PromptInput: Component<PromptInputProps> = (props) => {
</Match>
</Switch>
</div>
<div class="flex items-center gap-3 absolute right-3 bottom-3">
<div class="flex items-center gap-1 absolute right-3 bottom-3">
<input
ref={fileInputRef}
type="file"
@@ -2006,18 +2043,19 @@ export const PromptInput: Component<PromptInputProps> = (props) => {
e.currentTarget.value = ""
}}
/>
<div class="flex items-center gap-2">
<div class="flex items-center gap-1.5 mr-1.5">
<SessionContextUsage />
<Show when={store.mode === "normal"}>
<Tooltip placement="top" value={language.t("prompt.action.attachFile")}>
<Button
type="button"
variant="ghost"
class="size-6"
size="small"
class="px-1"
onClick={() => fileInputRef.click()}
aria-label={language.t("prompt.action.attachFile")}
>
<Icon name="photo" class="size-4.5" />
<Icon name="photo" class="size-6 text-icon-base" />
</Button>
</Tooltip>
</Show>
@@ -2036,7 +2074,7 @@ export const PromptInput: Component<PromptInputProps> = (props) => {
<Match when={true}>
<div class="flex items-center gap-2">
<span>{language.t("prompt.action.send")}</span>
<Icon name="enter" size="small" class="text-icon-base" />
<Icon name="enter" size="normal" class="text-icon-base" />
</div>
</Match>
</Switch>
@@ -2047,7 +2085,7 @@ export const PromptInput: Component<PromptInputProps> = (props) => {
disabled={!prompt.dirty() && !working()}
icon={working() ? "stop" : "arrow-up"}
variant="primary"
class="h-6 w-4.5"
class="h-6 w-5.5"
aria-label={working() ? language.t("prompt.action.stop") : language.t("prompt.action.send")}
/>
</Tooltip>

View File

@@ -64,8 +64,8 @@ export function SessionContextUsage(props: SessionContextUsageProps) {
}
const circle = () => (
<div class="p-1">
<ProgressCircle size={16} strokeWidth={2} percentage={context()?.percentage ?? 0} />
<div class="text-icon-base">
<ProgressCircle size={18} percentage={context()?.percentage ?? 0} />
</div>
)
@@ -101,7 +101,7 @@ export function SessionContextUsage(props: SessionContextUsageProps) {
<Button
type="button"
variant="ghost"
class="size-6"
class="size-7 text-icon-base"
onClick={openContext}
aria-label={language.t("context.usage.view")}
>

View File

@@ -10,6 +10,7 @@ import { usePlatform } from "@/context/platform"
import { useSettings, monoFontFamily } from "@/context/settings"
import { playSound, SOUND_OPTIONS } from "@/utils/sound"
import { Link } from "./link"
import { ScrollFade } from "@opencode-ai/ui/scroll-fade"
let demoSoundState = {
cleanup: undefined as (() => void) | undefined,
@@ -60,24 +61,24 @@ export const SettingsGeneral: Component = () => {
const actions =
platform.update && platform.restart
? [
{
label: language.t("toast.update.action.installRestart"),
onClick: async () => {
await platform.update!()
await platform.restart!()
},
{
label: language.t("toast.update.action.installRestart"),
onClick: async () => {
await platform.update!()
await platform.restart!()
},
{
label: language.t("toast.update.action.notYet"),
onClick: "dismiss" as const,
},
]
},
{
label: language.t("toast.update.action.notYet"),
onClick: "dismiss" as const,
},
]
: [
{
label: language.t("toast.update.action.notYet"),
onClick: "dismiss" as const,
},
]
{
label: language.t("toast.update.action.notYet"),
onClick: "dismiss" as const,
},
]
showToast({
persistent: true,
@@ -130,7 +131,12 @@ export const SettingsGeneral: Component = () => {
const soundOptions = [...SOUND_OPTIONS]
return (
<div class="flex flex-col h-full overflow-y-auto no-scrollbar px-4 pb-10 sm:px-10 sm:pb-10">
<ScrollFade
direction="vertical"
fadeStartSize={0}
fadeEndSize={16}
class="flex flex-col h-full overflow-y-auto no-scrollbar px-4 pb-10 sm:px-10 sm:pb-10"
>
<div class="sticky top-0 z-10 bg-[linear-gradient(to_bottom,var(--surface-raised-stronger-non-alpha)_calc(100%_-_24px),transparent)]">
<div class="flex flex-col gap-1 pt-6 pb-8">
<h2 class="text-16-medium text-text-strong">{language.t("settings.tab.general")}</h2>
@@ -394,7 +400,7 @@ export const SettingsGeneral: Component = () => {
</div>
</div>
</div>
</div>
</ScrollFade>
)
}

View File

@@ -9,6 +9,7 @@ import fuzzysort from "fuzzysort"
import { formatKeybind, parseKeybind, useCommand } from "@/context/command"
import { useLanguage } from "@/context/language"
import { useSettings } from "@/context/settings"
import { ScrollFade } from "@opencode-ai/ui/scroll-fade"
const IS_MAC = typeof navigator === "object" && /(Mac|iPod|iPhone|iPad)/.test(navigator.platform)
const PALETTE_ID = "command.palette"
@@ -352,7 +353,12 @@ export const SettingsKeybinds: Component = () => {
})
return (
<div class="flex flex-col h-full overflow-y-auto no-scrollbar px-4 pb-10 sm:px-10 sm:pb-10">
<ScrollFade
direction="vertical"
fadeStartSize={0}
fadeEndSize={16}
class="flex flex-col h-full overflow-y-auto no-scrollbar px-4 pb-10 sm:px-10 sm:pb-10"
>
<div class="sticky top-0 z-10 bg-[linear-gradient(to_bottom,var(--surface-raised-stronger-non-alpha)_calc(100%_-_24px),transparent)]">
<div class="flex flex-col gap-4 pt-6 pb-6 max-w-[720px]">
<div class="flex items-center justify-between gap-4">
@@ -429,6 +435,6 @@ export const SettingsKeybinds: Component = () => {
</div>
</Show>
</div>
</div>
</ScrollFade>
)
}

View File

@@ -345,6 +345,7 @@ pub fn run() {
.decorations(false);
let window = window_builder.build().expect("Failed to create window");
let _ = window.show();
#[cfg(windows)]
let _ = window.create_overlay_titlebar();

View File

@@ -1,98 +1,107 @@
[data-component="accordion"] {
display: flex;
flex-direction: column;
align-items: flex-start;
gap: 8px;
align-self: stretch;
display: flex;
flex-direction: column;
align-items: flex-start;
gap: 8px;
align-self: stretch;
[data-slot="accordion-item"] {
width: 100%;
display: flex;
flex-direction: column;
align-items: flex-start;
align-self: stretch;
overflow: clip;
[data-slot="accordion-item"] {
width: 100%;
display: flex;
flex-direction: column;
align-items: flex-start;
align-self: stretch;
overflow: clip;
[data-slot="accordion-header"] {
width: 100%;
display: flex;
align-items: center;
margin: 0;
padding: 0;
[data-slot="accordion-header"] {
width: 100%;
display: flex;
align-items: center;
margin: 0;
padding: 0;
[data-slot="accordion-trigger"] {
width: 100%;
display: flex;
height: 32px;
padding: 8px 12px;
justify-content: space-between;
align-items: center;
align-self: stretch;
cursor: default;
user-select: none;
[data-slot="accordion-trigger"] {
width: 100%;
display: flex;
height: 32px;
padding: 8px 12px;
justify-content: space-between;
align-items: center;
align-self: stretch;
cursor: default;
user-select: none;
background-color: var(--surface-base);
border: 1px solid var(--border-weak-base);
border-radius: var(--radius-md);
overflow: clip;
color: var(--text-strong);
transition: background-color 0.15s ease;
background-color: var(--surface-base);
border: 1px solid var(--border-weak-base);
border-radius: var(--radius-md);
overflow: clip;
color: var(--text-strong);
transition-property: background-color, border-color;
transition-duration: var(--transition-duration);
transition-timing-function: var(--transition-easing);
/* text-12-regular */
font-family: var(--font-family-sans);
font-size: var(--font-size-small);
font-style: normal;
font-weight: var(--font-weight-regular);
line-height: var(--line-height-large); /* 166.667% */
letter-spacing: var(--letter-spacing-normal);
/* text-12-regular */
font-family: var(--font-family-sans);
font-size: var(--font-size-small);
font-style: normal;
font-weight: var(--font-weight-regular);
line-height: var(--line-height-large); /* 166.667% */
letter-spacing: var(--letter-spacing-normal);
&:hover {
background-color: var(--surface-base);
}
&:focus-visible {
outline: none;
}
&[data-disabled] {
cursor: not-allowed;
}
}
}
&:hover {
background-color: var(--surface-base);
}
&:focus-visible {
outline: none;
}
&[data-disabled] {
cursor: not-allowed;
}
}
}
&[data-expanded] {
[data-slot="accordion-trigger"] {
border-bottom-left-radius: 0;
border-bottom-right-radius: 0;
}
[data-slot="accordion-arrow"] {
flex-shrink: 0;
width: 16px;
height: 16px;
display: flex;
align-items: center;
justify-content: center;
color: var(--text-weak);
}
[data-slot="accordion-content"] {
border: 1px solid var(--border-weak-base);
border-top: none;
border-bottom-left-radius: var(--radius-md);
border-bottom-right-radius: var(--radius-md);
}
}
[data-slot="accordion-content"] {
display: grid;
grid-template-rows: 0fr;
transition-property: grid-template-rows, opacity;
transition-duration: var(--transition-duration);
transition-timing-function: var(--transition-easing);
width: 100%;
[data-slot="accordion-content"] {
overflow: hidden;
width: 100%;
}
}
}
@keyframes slideDown {
from {
height: 0;
}
to {
height: var(--kb-accordion-content-height);
}
}
@keyframes slideUp {
from {
height: var(--kb-accordion-content-height);
}
to {
height: 0;
}
> * {
overflow: hidden;
}
}
[data-slot="accordion-content"][data-expanded] {
grid-template-rows: 1fr;
}
[data-slot="accordion-content"][data-closed] {
grid-template-rows: 0fr;
}
&[data-expanded] [data-slot="accordion-trigger"] {
border-bottom-left-radius: 0;
border-bottom-right-radius: 0;
}
&[data-expanded] [data-slot="accordion-content"] {
border: 1px solid var(--border-weak-base);
border-top: none;
border-bottom-left-radius: var(--radius-md);
border-bottom-right-radius: var(--radius-md);
height: auto;
}
}
}

View File

@@ -1,6 +1,7 @@
import { Accordion as Kobalte } from "@kobalte/core/accordion"
import { splitProps } from "solid-js"
import { Accessor, createContext, splitProps, useContext } from "solid-js"
import type { ComponentProps, ParentProps } from "solid-js"
import { MorphChevron } from "./morph-chevron"
export interface AccordionProps extends ComponentProps<typeof Kobalte> {}
export interface AccordionItemProps extends ComponentProps<typeof Kobalte.Item> {}
@@ -8,6 +9,8 @@ export interface AccordionHeaderProps extends ComponentProps<typeof Kobalte.Head
export interface AccordionTriggerProps extends ComponentProps<typeof Kobalte.Trigger> {}
export interface AccordionContentProps extends ComponentProps<typeof Kobalte.Content> {}
const AccordionItemContext = createContext<Accessor<boolean>>()
function AccordionRoot(props: AccordionProps) {
const [split, rest] = splitProps(props, ["class", "classList"])
return (
@@ -22,17 +25,19 @@ function AccordionRoot(props: AccordionProps) {
)
}
function AccordionItem(props: AccordionItemProps) {
const [split, rest] = splitProps(props, ["class", "classList"])
function AccordionItem(props: AccordionItemProps & { expanded?: boolean }) {
const [split, rest] = splitProps(props, ["class", "classList", "expanded"])
return (
<Kobalte.Item
{...rest}
data-slot="accordion-item"
classList={{
...(split.classList ?? {}),
[split.class ?? ""]: !!split.class,
}}
/>
<AccordionItemContext.Provider value={() => split.expanded ?? false}>
<Kobalte.Item
{...rest}
data-slot="accordion-item"
classList={{
...(split.classList ?? {}),
[split.class ?? ""]: !!split.class,
}}
/>
</AccordionItemContext.Provider>
)
}
@@ -84,9 +89,25 @@ function AccordionContent(props: ParentProps<AccordionContentProps>) {
)
}
export interface AccordionArrowProps extends ComponentProps<"div"> {
expanded?: boolean
}
function AccordionArrow(props: AccordionArrowProps = {}) {
const [local, rest] = splitProps(props, ["expanded"])
const contextExpanded = useContext(AccordionItemContext)
const isExpanded = () => local.expanded ?? contextExpanded?.() ?? false
return (
<div data-slot="accordion-arrow" {...rest}>
<MorphChevron expanded={isExpanded()} />
</div>
)
}
export const Accordion = Object.assign(AccordionRoot, {
Item: AccordionItem,
Header: AccordionHeader,
Trigger: AccordionTrigger,
Content: AccordionContent,
Arrow: AccordionArrow,
})

View File

@@ -1,49 +1,49 @@
[data-component="avatar"] {
--avatar-bg: var(--color-surface-info-base);
--avatar-fg: var(--color-text-base);
display: flex;
align-items: center;
justify-content: center;
flex-shrink: 0;
border-radius: var(--radius-sm);
border: 1px solid var(--color-border-weak-base);
font-family: var(--font-mono);
font-weight: 500;
text-transform: uppercase;
background-color: var(--avatar-bg);
color: var(--avatar-fg);
--avatar-bg: var(--color-surface-info-base);
--avatar-fg: var(--color-text-base);
display: flex;
align-items: center;
justify-content: center;
flex-shrink: 0;
border-radius: var(--radius-sm);
border: 1px solid var(--color-border-weak-base);
font-family: var(--font-mono);
font-weight: 500;
text-transform: uppercase;
background-color: var(--avatar-bg);
color: var(--avatar-fg);
}
[data-component="avatar"][data-has-image] {
background-color: transparent;
border: none;
background-color: transparent;
border: none;
}
[data-component="avatar"][data-size="small"] {
width: 1.25rem;
height: 1.25rem;
font-size: 0.75rem;
line-height: 1;
width: 1.25rem;
height: 1.25rem;
font-size: 0.75rem;
line-height: 1;
}
[data-component="avatar"][data-size="normal"] {
width: 1.5rem;
height: 1.5rem;
font-size: 1.125rem;
line-height: 1.5rem;
width: 1.5rem;
height: 1.5rem;
font-size: 1.125rem;
line-height: 1.5rem;
}
[data-component="avatar"][data-size="large"] {
width: 2rem;
height: 2rem;
font-size: 1.25rem;
line-height: 2rem;
width: 2rem;
height: 2rem;
font-size: 1.25rem;
line-height: 2rem;
}
[data-component="avatar"] [data-slot="avatar-image"] {
width: 100%;
height: 100%;
display: block;
object-fit: cover;
border-radius: inherit;
width: 100%;
height: 100%;
display: block;
object-fit: cover;
border-radius: inherit;
}

View File

@@ -1,97 +1,97 @@
[data-component="tool-trigger"] {
content-visibility: auto;
width: 100%;
display: flex;
align-items: center;
align-self: stretch;
gap: 20px;
justify-content: space-between;
content-visibility: auto;
width: 100%;
display: flex;
align-items: center;
align-self: stretch;
gap: 20px;
justify-content: space-between;
[data-slot="basic-tool-tool-trigger-content"] {
width: 100%;
display: flex;
align-items: center;
align-self: stretch;
gap: 20px;
}
[data-slot="basic-tool-tool-trigger-content"] {
width: 100%;
display: flex;
align-items: center;
align-self: stretch;
gap: 20px;
}
[data-slot="icon-svg"] {
flex-shrink: 0;
}
[data-slot="icon-svg"] {
flex-shrink: 0;
}
[data-slot="basic-tool-tool-info"] {
flex-grow: 1;
min-width: 0;
}
[data-slot="basic-tool-tool-info"] {
flex-grow: 1;
min-width: 0;
}
[data-slot="basic-tool-tool-info-structured"] {
width: 100%;
display: flex;
align-items: center;
gap: 8px;
justify-content: space-between;
}
[data-slot="basic-tool-tool-info-structured"] {
width: 100%;
display: flex;
align-items: center;
gap: 8px;
justify-content: space-between;
}
[data-slot="basic-tool-tool-info-main"] {
display: flex;
align-items: center;
gap: 8px;
min-width: 0;
overflow: hidden;
}
[data-slot="basic-tool-tool-info-main"] {
display: flex;
align-items: center;
gap: 8px;
min-width: 0;
overflow: hidden;
}
[data-slot="basic-tool-tool-title"] {
flex-shrink: 0;
font-family: var(--font-family-sans);
font-size: var(--font-size-small);
font-style: normal;
font-weight: var(--font-weight-medium);
line-height: var(--line-height-large);
letter-spacing: var(--letter-spacing-normal);
color: var(--text-base);
[data-slot="basic-tool-tool-title"] {
flex-shrink: 0;
font-family: var(--font-family-sans);
font-size: var(--font-size-small);
font-style: normal;
font-weight: var(--font-weight-medium);
line-height: var(--line-height-large);
letter-spacing: var(--letter-spacing-normal);
color: var(--text-base);
&.capitalize {
text-transform: capitalize;
}
}
&.capitalize {
text-transform: capitalize;
}
}
[data-slot="basic-tool-tool-subtitle"] {
flex-shrink: 1;
min-width: 0;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
font-family: var(--font-family-sans);
font-size: var(--font-size-small);
font-style: normal;
font-weight: var(--font-weight-medium);
line-height: var(--line-height-large);
letter-spacing: var(--letter-spacing-normal);
color: var(--text-weak);
[data-slot="basic-tool-tool-subtitle"] {
flex-shrink: 1;
min-width: 0;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
font-family: var(--font-family-sans);
font-size: var(--font-size-small);
font-style: normal;
font-weight: var(--font-weight-medium);
line-height: var(--line-height-large);
letter-spacing: var(--letter-spacing-normal);
color: var(--text-weak);
&.clickable {
cursor: pointer;
text-decoration: underline;
transition: color 0.15s ease;
&.clickable {
cursor: pointer;
text-decoration: underline;
transition: color 0.15s ease;
&:hover {
color: var(--text-base);
}
}
}
&:hover {
color: var(--text-base);
}
}
}
[data-slot="basic-tool-tool-arg"] {
flex-shrink: 1;
min-width: 0;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
font-family: var(--font-family-sans);
font-size: var(--font-size-small);
font-style: normal;
font-weight: var(--font-weight-regular);
line-height: var(--line-height-large);
letter-spacing: var(--letter-spacing-normal);
color: var(--text-weak);
}
[data-slot="basic-tool-tool-arg"] {
flex-shrink: 1;
min-width: 0;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
font-family: var(--font-family-sans);
font-size: var(--font-size-small);
font-style: normal;
font-weight: var(--font-weight-regular);
line-height: var(--line-height-large);
letter-spacing: var(--letter-spacing-normal);
color: var(--text-weak);
}
}

View File

@@ -1,172 +1,168 @@
[data-component="button"] {
display: inline-flex;
align-items: center;
justify-content: center;
border-style: solid;
border-width: 1px;
border-radius: var(--radius-md);
text-decoration: none;
user-select: none;
cursor: default;
outline: none;
white-space: nowrap;
display: inline-flex;
align-items: center;
justify-content: center;
border-style: solid;
border-width: 1px;
border-radius: var(--radius-md);
text-decoration: none;
user-select: none;
cursor: default;
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);
border-color: var(--border-weak-base);
color: var(--icon-invert-base);
&[data-variant="primary"] {
background-color: var(--button-primary-base);
border-color: var(--border-weak-base);
color: var(--icon-invert-base);
[data-slot="icon-svg"] {
color: var(--icon-invert-base);
}
[data-slot="icon-svg"] {
color: var(--icon-invert-base);
}
&:hover:not(:disabled) {
background-color: var(--icon-strong-hover);
}
&:focus:not(:disabled) {
background-color: var(--icon-strong-focus);
}
&:active:not(:disabled) {
background-color: var(--icon-strong-active);
}
&:disabled {
background-color: var(--icon-strong-disabled);
&:hover:not(:disabled) {
background-color: var(--icon-strong-hover);
}
&:focus:not(:disabled) {
background-color: var(--icon-strong-focus);
}
&:active:not(:disabled) {
background-color: var(--icon-strong-active);
}
&:disabled {
background-color: var(--icon-strong-disabled);
[data-slot="icon-svg"] {
color: var(--icon-invert-base);
}
}
}
[data-slot="icon-svg"] {
color: var(--icon-invert-base);
}
}
}
&[data-variant="ghost"] {
border-color: transparent;
background-color: transparent;
color: var(--text-strong);
&[data-variant="ghost"] {
border-color: transparent;
background-color: transparent;
color: var(--text-strong);
[data-slot="icon-svg"] {
color: var(--icon-base);
}
[data-slot="icon-svg"] {
color: var(--icon-base);
}
&:hover:not(:disabled) {
background-color: var(--surface-raised-base-hover);
}
&:focus-visible:not(:disabled) {
background-color: var(--surface-raised-base-hover);
}
&:active:not(:disabled) {
background-color: var(--surface-raised-base-active);
}
&:disabled {
color: var(--text-weak);
cursor: not-allowed;
&:hover:not(:disabled) {
background-color: var(--surface-raised-base-hover);
}
&:focus-visible:not(:disabled) {
background-color: var(--surface-raised-base-hover);
}
&:active:not(:disabled) {
background-color: var(--surface-raised-base-active);
}
&:disabled {
color: var(--text-weak);
cursor: not-allowed;
[data-slot="icon-svg"] {
color: var(--icon-disabled);
}
}
&[data-selected="true"]:not(:disabled) {
background-color: var(--surface-raised-base-hover);
}
&[data-active="true"] {
background-color: var(--surface-raised-base-active);
}
}
[data-slot="icon-svg"] {
color: var(--icon-disabled);
}
}
&[data-selected="true"]:not(:disabled) {
background-color: var(--surface-raised-base-hover);
}
&[data-active="true"] {
background-color: var(--surface-raised-base-active);
}
}
&[data-variant="secondary"] {
border: transparent;
background-color: var(--button-secondary-base);
color: var(--text-strong);
box-shadow: var(--shadow-xs-border);
&[data-variant="secondary"] {
border: transparent;
background-color: var(--button-secondary-base);
color: var(--text-strong);
box-shadow: var(--shadow-xs-border);
&:hover:not(:disabled) {
background-color: var(--button-secondary-hover);
}
&:focus:not(:disabled) {
background-color: var(--button-secondary-base);
}
&:focus-visible:not(:active) {
background-color: var(--button-secondary-base);
box-shadow: var(--shadow-xs-border-focus);
}
&:focus-visible:active {
box-shadow: none;
}
&:active:not(:disabled) {
background-color: var(--button-secondary-base);
scale: 0.99;
transition: all 150ms ease-out;
}
&:disabled {
border-color: var(--border-disabled);
background-color: var(--surface-disabled);
color: var(--text-weak);
cursor: not-allowed;
}
&:hover:not(:disabled) {
background-color: var(--button-secondary-hover);
}
&:focus:not(:disabled) {
background-color: var(--button-secondary-base);
}
&:focus-visible:not(:active) {
background-color: var(--button-secondary-base);
box-shadow: var(--shadow-xs-border-focus);
}
&:focus-visible:active {
box-shadow: none;
}
&:active:not(:disabled) {
background-color: var(--button-secondary-base);
scale: 0.99;
}
&:disabled {
border-color: var(--border-disabled);
background-color: var(--surface-disabled);
color: var(--text-weak);
cursor: not-allowed;
}
[data-slot="icon-svg"] {
color: var(--icon-strong-base);
}
}
[data-slot="icon-svg"] {
color: var(--icon-strong-base);
}
}
&[data-size="small"] {
height: 22px;
padding: 0 8px;
&[data-icon] {
padding: 0 12px 0 4px;
}
&[data-size="small"] {
padding: 2px 8px;
&[data-icon] {
padding: 2px 12px 2px 4px;
}
font-size: var(--font-size-small);
line-height: var(--line-height-large);
gap: 4px;
gap: 4px;
/* text-12-medium */
font-family: var(--font-family-sans);
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);
}
/* text-12-medium */
font-family: var(--font-family-sans);
font-size: var(--font-size-base);
font-style: normal;
font-weight: var(--font-weight-medium);
letter-spacing: var(--letter-spacing-normal);
}
&[data-size="normal"] {
height: 24px;
line-height: 24px;
padding: 0 6px;
&[data-icon] {
padding: 0 12px 0 4px;
}
&[data-size="normal"] {
padding: 4px 6px;
&[data-icon] {
padding: 4px 12px 4px 4px;
}
font-size: var(--font-size-small);
gap: 6px;
gap: 6px;
/* text-12-medium */
font-family: var(--font-family-sans);
font-size: var(--font-size-small);
font-style: normal;
font-weight: var(--font-weight-medium);
letter-spacing: var(--letter-spacing-normal);
}
/* text-12-medium */
font-family: var(--font-family-sans);
font-size: var(--font-size-small);
font-style: normal;
font-weight: var(--font-weight-medium);
letter-spacing: var(--letter-spacing-normal);
}
&[data-size="large"] {
height: 32px;
padding: 6px 12px;
&[data-size="large"] {
padding: 6px 12px;
&[data-icon] {
padding: 0 12px 0 8px;
}
&[data-icon] {
padding: 6px 12px 6px 8px;
}
gap: 4px;
gap: 4px;
/* text-14-medium */
font-family: var(--font-family-sans);
font-size: 14px;
font-style: normal;
font-weight: var(--font-weight-medium);
line-height: var(--line-height-large); /* 142.857% */
letter-spacing: var(--letter-spacing-normal);
}
/* text-14-medium */
font-family: var(--font-family-sans);
font-size: 14px;
font-style: normal;
font-weight: var(--font-weight-medium);
letter-spacing: var(--letter-spacing-normal);
}
&:focus {
outline: none;
}
&:focus {
outline: none;
}
}

View File

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

View File

@@ -1,29 +1,31 @@
[data-component="card"] {
width: 100%;
display: flex;
flex-direction: column;
background-color: var(--surface-inset-base);
border: 1px solid var(--border-weaker-base);
transition: background-color 0.15s ease;
border-radius: var(--radius-md);
padding: 6px 12px;
overflow: clip;
width: 100%;
display: flex;
flex-direction: column;
background-color: var(--surface-inset-base);
border: 1px solid var(--border-weaker-base);
transition-property: background-color, border-color;
transition-duration: var(--transition-duration);
transition-timing-function: var(--transition-easing);
border-radius: var(--radius-md);
padding: 6px 12px;
overflow: clip;
&[data-variant="error"] {
background-color: var(--surface-critical-weak);
border: 1px solid var(--border-critical-base);
color: rgba(218, 51, 25, 0.6);
&[data-variant="error"] {
background-color: var(--surface-critical-weak);
border: 1px solid var(--border-critical-base);
color: rgba(218, 51, 25, 0.6);
/* text-12-regular */
font-family: var(--font-family-sans);
font-size: var(--font-size-small);
font-style: normal;
font-weight: var(--font-weight-regular);
line-height: var(--line-height-large); /* 166.667% */
letter-spacing: var(--letter-spacing-normal);
/* text-12-regular */
font-family: var(--font-family-sans);
font-size: var(--font-size-small);
font-style: normal;
font-weight: var(--font-weight-regular);
line-height: var(--line-height-large); /* 166.667% */
letter-spacing: var(--letter-spacing-normal);
&[data-component="icon"] {
color: var(--icon-critical-active);
}
}
&[data-component="icon"] {
color: var(--icon-critical-active);
}
}
}

View File

@@ -1,121 +1,136 @@
[data-component="checkbox"] {
display: flex;
align-items: center;
gap: 12px;
cursor: default;
display: flex;
align-items: center;
gap: 12px;
cursor: default;
[data-slot="checkbox-checkbox-input"] {
position: absolute;
width: 1px;
height: 1px;
padding: 0;
margin: -1px;
overflow: hidden;
clip: rect(0, 0, 0, 0);
white-space: nowrap;
border-width: 0;
}
[data-slot="checkbox-checkbox-control"] {
transition-property: border-color, background-color, box-shadow;
transition-duration: var(--transition-duration);
transition-timing-function: var(--transition-easing);
}
[data-slot="checkbox-checkbox-control"] {
display: flex;
align-items: center;
justify-content: center;
width: 16px;
height: 16px;
padding: 2px;
aspect-ratio: 1;
flex-shrink: 0;
border-radius: var(--radius-sm);
border: 1px solid var(--border-weak-base);
/* background-color: var(--surface-weak); */
}
[data-slot="checkbox-checkbox-indicator"] {
transition-property: opacity;
transition-duration: var(--transition-duration);
transition-timing-function: var(--transition-easing);
}
[data-slot="checkbox-checkbox-indicator"] {
display: flex;
align-items: center;
justify-content: center;
width: 100%;
height: 100%;
color: var(--icon-base);
opacity: 0;
}
[data-slot="checkbox-checkbox-input"] {
position: absolute;
width: 1px;
height: 1px;
padding: 0;
margin: -1px;
overflow: hidden;
clip: rect(0, 0, 0, 0);
white-space: nowrap;
border-width: 0;
}
/* [data-slot="checkbox-checkbox-content"] { */
/* } */
[data-slot="checkbox-checkbox-control"] {
display: flex;
align-items: center;
justify-content: center;
width: 16px;
height: 16px;
padding: 2px;
aspect-ratio: 1;
flex-shrink: 0;
border-radius: var(--radius-sm);
border: 1px solid var(--border-weak-base);
/* background-color: var(--surface-weak); */
}
[data-slot="checkbox-checkbox-label"] {
user-select: none;
color: var(--text-base);
[data-slot="checkbox-checkbox-indicator"] {
display: flex;
align-items: center;
justify-content: center;
width: 100%;
height: 100%;
color: var(--icon-base);
opacity: 0;
}
/* text-12-regular */
font-family: var(--font-family-sans);
font-size: var(--font-size-small);
font-style: normal;
font-weight: var(--font-weight-regular);
line-height: var(--line-height-large); /* 166.667% */
letter-spacing: var(--letter-spacing-normal);
}
/* [data-slot="checkbox-checkbox-content"] { */
/* } */
[data-slot="checkbox-checkbox-description"] {
color: var(--text-base);
font-family: var(--font-family-sans);
font-size: 12px;
font-weight: var(--font-weight-regular);
line-height: var(--line-height-normal);
letter-spacing: var(--letter-spacing-normal);
}
[data-slot="checkbox-checkbox-label"] {
user-select: none;
color: var(--text-base);
[data-slot="checkbox-checkbox-error"] {
color: var(--text-error);
font-family: var(--font-family-sans);
font-size: 12px;
font-weight: var(--font-weight-regular);
line-height: var(--line-height-normal);
letter-spacing: var(--letter-spacing-normal);
}
/* text-12-regular */
font-family: var(--font-family-sans);
font-size: var(--font-size-small);
font-style: normal;
font-weight: var(--font-weight-regular);
line-height: var(--line-height-large); /* 166.667% */
letter-spacing: var(--letter-spacing-normal);
}
&:hover:not([data-disabled], [data-readonly]) [data-slot="checkbox-checkbox-control"] {
border-color: var(--border-hover);
background-color: var(--surface-hover);
}
[data-slot="checkbox-checkbox-description"] {
color: var(--text-base);
font-family: var(--font-family-sans);
font-size: 12px;
font-weight: var(--font-weight-regular);
line-height: var(--line-height-normal);
letter-spacing: var(--letter-spacing-normal);
}
&:focus-within:not([data-readonly]) [data-slot="checkbox-checkbox-control"] {
border-color: var(--border-focus);
box-shadow: 0 0 0 2px var(--surface-focus);
}
[data-slot="checkbox-checkbox-error"] {
color: var(--text-error);
font-family: var(--font-family-sans);
font-size: 12px;
font-weight: var(--font-weight-regular);
line-height: var(--line-height-normal);
letter-spacing: var(--letter-spacing-normal);
}
&[data-checked] [data-slot="checkbox-checkbox-control"],
&[data-indeterminate] [data-slot="checkbox-checkbox-control"] {
border-color: var(--border-base);
background-color: var(--surface-weak);
}
&:hover:not([data-disabled], [data-readonly])
[data-slot="checkbox-checkbox-control"] {
border-color: var(--border-hover);
background-color: var(--surface-hover);
}
&[data-checked]:hover:not([data-disabled], [data-readonly]) [data-slot="checkbox-checkbox-control"],
&[data-indeterminate]:hover:not([data-disabled]) [data-slot="checkbox-checkbox-control"] {
border-color: var(--border-hover);
background-color: var(--surface-hover);
}
&:focus-within:not([data-readonly]) [data-slot="checkbox-checkbox-control"] {
border-color: var(--border-focus);
box-shadow: 0 0 0 2px var(--surface-focus);
}
&[data-checked] [data-slot="checkbox-checkbox-indicator"],
&[data-indeterminate] [data-slot="checkbox-checkbox-indicator"] {
opacity: 1;
}
&[data-checked] [data-slot="checkbox-checkbox-control"],
&[data-indeterminate] [data-slot="checkbox-checkbox-control"] {
border-color: var(--border-base);
background-color: var(--surface-weak);
}
&[data-disabled] {
cursor: not-allowed;
}
&[data-checked]:hover:not([data-disabled], [data-readonly])
[data-slot="checkbox-checkbox-control"],
&[data-indeterminate]:hover:not([data-disabled])
[data-slot="checkbox-checkbox-control"] {
border-color: var(--border-hover);
background-color: var(--surface-hover);
}
&[data-disabled] [data-slot="checkbox-checkbox-control"] {
border-color: var(--border-disabled);
background-color: var(--surface-disabled);
}
&[data-checked] [data-slot="checkbox-checkbox-indicator"],
&[data-indeterminate] [data-slot="checkbox-checkbox-indicator"] {
opacity: 1;
}
&[data-invalid] [data-slot="checkbox-checkbox-control"] {
border-color: var(--border-error);
}
&[data-disabled] {
cursor: not-allowed;
}
&[data-readonly] {
cursor: default;
pointer-events: none;
}
&[data-disabled] [data-slot="checkbox-checkbox-control"] {
border-color: var(--border-disabled);
background-color: var(--surface-disabled);
}
&[data-invalid] [data-slot="checkbox-checkbox-control"] {
border-color: var(--border-error);
}
&[data-readonly] {
cursor: default;
pointer-events: none;
}
}

View File

@@ -1,4 +1,4 @@
[data-component="code"] {
content-visibility: auto;
overflow: hidden;
content-visibility: auto;
overflow: hidden;
}

View File

@@ -1,103 +1,99 @@
[data-component="collapsible"] {
width: 100%;
display: flex;
flex-direction: column;
background-color: var(--surface-inset-base);
border: 1px solid var(--border-weaker-base);
transition: background-color 0.15s ease;
border-radius: var(--radius-md);
overflow: clip;
width: 100%;
display: flex;
flex-direction: column;
background-color: var(--surface-inset-base);
border: 1px solid var(--border-weaker-base);
transition-property: background-color, border-color;
transition-duration: var(--transition-duration);
transition-timing-function: var(--transition-easing);
border-radius: var(--radius-md);
overflow: clip;
[data-slot="collapsible-trigger"] {
width: 100%;
display: flex;
height: 32px;
padding: 6px 8px 6px 12px;
align-items: center;
align-self: stretch;
cursor: default;
user-select: none;
color: var(--text-base);
[data-slot="collapsible-trigger"] {
width: 100%;
display: flex;
height: 32px;
padding: 6px 8px 6px 12px;
align-items: center;
align-self: stretch;
cursor: default;
user-select: none;
color: var(--text-base);
/* text-12-medium */
font-family: var(--font-family-sans);
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);
/* text-12-medium */
font-family: var(--font-family-sans);
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);
/* &:hover { */
/* background-color: var(--surface-base); */
/* } */
&:focus-visible {
outline: none;
}
&[data-disabled] {
cursor: not-allowed;
}
/* &:hover { */
/* background-color: var(--surface-base); */
/* } */
&:focus-visible {
outline: none;
}
&[data-disabled] {
cursor: not-allowed;
}
[data-slot="collapsible-arrow"] {
flex-shrink: 0;
width: 24px;
height: 24px;
display: flex;
align-items: center;
justify-content: center;
}
}
[data-slot="collapsible-arrow"] {
flex-shrink: 0;
width: 24px;
height: 24px;
display: flex;
align-items: center;
justify-content: center;
color: var(--text-weak);
}
}
[data-slot="collapsible-content"] {
overflow: hidden;
/* animation: slideUp 250ms ease-out; */
[data-slot="collapsible-content"] {
display: grid;
grid-template-rows: 0fr;
transition-property: grid-template-rows, opacity;
transition-duration: var(--transition-duration);
transition-timing-function: var(--transition-easing);
/* &[data-expanded] { */
/* animation: slideDown 250ms ease-out; */
/* } */
}
> * {
overflow: hidden;
}
&[data-variant="ghost"] {
background-color: transparent;
border: none;
&[data-expanded] {
grid-template-rows: 1fr;
}
> [data-slot="collapsible-trigger"] {
background-color: transparent;
border: none;
padding: 0;
&[data-closed] {
grid-template-rows: 0fr;
}
}
/* &:hover { */
/* color: var(--text-strong); */
/* } */
&:focus-visible {
outline: none;
}
&[data-disabled] {
cursor: not-allowed;
}
}
}
&[data-variant="ghost"] {
background-color: transparent;
border: none;
&[data-variant="ghost"][data-scope="filetree"] {
> [data-slot="collapsible-trigger"] {
height: 24px;
}
}
}
@keyframes slideDown {
from {
height: 0;
}
to {
height: var(--kb-collapsible-content-height);
}
}
@keyframes slideUp {
from {
height: var(--kb-collapsible-content-height);
}
to {
height: 0;
}
> [data-slot="collapsible-trigger"] {
background-color: transparent;
border: none;
padding: 0;
/* &:hover { */
/* color: var(--text-strong); */
/* } */
&:focus-visible {
outline: none;
}
&[data-disabled] {
cursor: not-allowed;
}
}
}
&[data-variant="ghost"][data-scope="filetree"] {
> [data-slot="collapsible-trigger"] {
height: 24px;
}
}
}

View File

@@ -1,6 +1,8 @@
import { Collapsible as Kobalte, CollapsibleRootProps } from "@kobalte/core/collapsible"
import { ComponentProps, ParentProps, splitProps } from "solid-js"
import { Icon } from "./icon"
import { Accessor, ComponentProps, createContext, createSignal, ParentProps, splitProps, useContext } from "solid-js"
import { MorphChevron } from "./morph-chevron"
const CollapsibleContext = createContext<Accessor<boolean>>()
export interface CollapsibleProps extends ParentProps<CollapsibleRootProps> {
class?: string
@@ -9,17 +11,30 @@ export interface CollapsibleProps extends ParentProps<CollapsibleRootProps> {
}
function CollapsibleRoot(props: CollapsibleProps) {
const [local, others] = splitProps(props, ["class", "classList", "variant"])
const [local, others] = splitProps(props, ["class", "classList", "variant", "open", "onOpenChange", "children"])
const [internalOpen, setInternalOpen] = createSignal(local.open ?? false)
const handleOpenChange = (open: boolean) => {
setInternalOpen(open)
local.onOpenChange?.(open)
}
return (
<Kobalte
data-component="collapsible"
data-variant={local.variant || "normal"}
classList={{
...(local.classList ?? {}),
[local.class ?? ""]: !!local.class,
}}
{...others}
/>
<CollapsibleContext.Provider value={internalOpen}>
<Kobalte
data-component="collapsible"
data-variant={local.variant || "normal"}
open={local.open}
onOpenChange={handleOpenChange}
classList={{
...(local.classList ?? {}),
[local.class ?? ""]: !!local.class,
}}
{...others}
>
{local.children}
</Kobalte>
</CollapsibleContext.Provider>
)
}
@@ -32,9 +47,10 @@ function CollapsibleContent(props: ComponentProps<typeof Kobalte.Content>) {
}
function CollapsibleArrow(props?: ComponentProps<"div">) {
const isOpen = useContext(CollapsibleContext)
return (
<div data-slot="collapsible-arrow" {...(props || {})}>
<Icon name="chevron-grabber-vertical" size="small" />
<MorphChevron expanded={isOpen?.() ?? false} />
</div>
)
}

View File

@@ -0,0 +1,52 @@
.cycle-label {
--c-dur: 200ms;
--c-stag: 30ms;
--c-ease: cubic-bezier(0.25, 0, 0.5, 1);
--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 200ms var(--c-ease);
will-change: width;
overflow: hidden;
.cycle-char {
display: inline-block;
transform-style: preserve-3d;
min-width: 0.25em;
backface-visibility: hidden;
transition:
transform var(--c-dur) var(--c-ease),
opacity var(--c-dur) var(--c-ease),
filter var(--c-dur) var(--c-ease);
transition-delay: calc(var(--i, 0) * var(--c-stag));
&.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

@@ -0,0 +1,132 @@
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 ?? 200
return typeof d === "function" ? d(text) : d
}
const stagger = () => props?.stagger ?? 20
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-dur": `${getDuration(currentText())}ms`,
"--c-stag": `${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

@@ -1,181 +1,196 @@
/* [data-component="dialog-trigger"] { } */
[data-component="dialog-overlay"] {
position: fixed;
inset: 0;
z-index: 50;
background-color: hsl(from var(--background-base) h s l / 0.2);
position: fixed;
inset: 0;
z-index: 50;
background-color: hsl(from var(--background-base) h s l / 0.2);
animation: overlayHide var(--transition-duration) var(--transition-easing)
forwards;
&[data-expanded] {
animation: overlayShow var(--transition-duration) var(--transition-easing)
forwards;
}
@starting-style {
animation: none;
}
}
[data-component="dialog"] {
position: fixed;
inset: 0;
z-index: 50;
display: flex;
align-items: center;
justify-content: center;
pointer-events: none;
position: fixed;
inset: 0;
z-index: 50;
display: flex;
align-items: center;
justify-content: center;
pointer-events: none;
[data-slot="dialog-container"] {
position: relative;
z-index: 50;
width: min(calc(100vw - 16px), 640px);
height: min(calc(100vh - 16px), 512px);
display: flex;
flex-direction: column;
align-items: center;
justify-items: start;
overflow: visible;
[data-slot="dialog-container"] {
position: relative;
z-index: 50;
width: min(calc(100vw - 16px), 640px);
height: min(calc(100vh - 16px), 512px);
display: flex;
flex-direction: column;
align-items: center;
justify-items: start;
[data-slot="dialog-content"] {
display: flex;
flex-direction: column;
align-items: flex-start;
align-self: stretch;
width: 100%;
max-height: 100%;
min-height: 280px;
overflow: auto;
pointer-events: auto;
[data-slot="dialog-content"] {
display: flex;
flex-direction: column;
align-items: flex-start;
align-self: stretch;
width: 100%;
max-height: 100%;
min-height: 280px;
pointer-events: auto;
/* Hide scrollbar */
scrollbar-width: none;
-ms-overflow-style: none;
&::-webkit-scrollbar {
display: none;
}
/* padding: 8px; */
/* padding: 8px 8px 0 8px; */
border-radius: var(--radius-xl);
background: var(--surface-raised-stronger-non-alpha);
background-clip: padding-box;
box-shadow: var(--shadow-lg-border-base);
/* padding: 8px; */
/* padding: 8px 8px 0 8px; */
border-radius: var(--radius-xl);
background: var(--surface-raised-stronger-non-alpha);
background-clip: padding-box;
box-shadow: var(--shadow-lg-border-base);
animation: contentHide var(--transition-duration) var(--transition-easing)
forwards;
[data-slot="dialog-header"] {
display: flex;
padding: 20px;
justify-content: space-between;
align-items: center;
flex-shrink: 0;
align-self: stretch;
&[data-expanded] {
animation: contentShow var(--transition-duration)
var(--transition-easing) forwards;
}
[data-slot="dialog-title"] {
color: var(--text-strong);
@starting-style {
animation: none;
}
/* text-16-medium */
font-family: var(--font-family-sans);
font-size: var(--font-size-large);
font-style: normal;
font-weight: var(--font-weight-medium);
line-height: var(--line-height-x-large); /* 150% */
letter-spacing: var(--letter-spacing-tight);
}
/* [data-slot="dialog-close-button"] {} */
}
[data-slot="dialog-header"] {
display: flex;
padding: 20px;
justify-content: space-between;
align-items: center;
flex-shrink: 0;
align-self: stretch;
[data-slot="dialog-description"] {
display: flex;
padding: 16px;
padding-left: 24px;
padding-top: 0;
margin-top: -8px;
justify-content: space-between;
align-items: center;
flex-shrink: 0;
align-self: stretch;
[data-slot="dialog-title"] {
color: var(--text-strong);
color: var(--text-base);
/* text-16-medium */
font-family: var(--font-family-sans);
font-size: var(--font-size-large);
font-style: normal;
font-weight: var(--font-weight-medium);
line-height: var(--line-height-x-large); /* 150% */
letter-spacing: var(--letter-spacing-tight);
}
/* [data-slot="dialog-close-button"] {} */
}
/* text-14-regular */
font-family: var(--font-family-sans);
font-size: 14px;
font-style: normal;
font-weight: var(--font-weight-regular);
line-height: var(--line-height-large); /* 142.857% */
letter-spacing: var(--letter-spacing-normal);
}
[data-slot="dialog-description"] {
display: flex;
padding: 16px;
padding-left: 24px;
padding-top: 0;
margin-top: -8px;
justify-content: space-between;
align-items: center;
flex-shrink: 0;
align-self: stretch;
[data-slot="dialog-body"] {
width: 100%;
position: relative;
display: flex;
flex-direction: column;
flex: 1;
overflow: hidden;
color: var(--text-base);
&:focus-visible {
outline: none;
}
}
&:focus-visible {
outline: none;
}
}
}
/* text-14-regular */
font-family: var(--font-family-sans);
font-size: 14px;
font-style: normal;
font-weight: var(--font-weight-regular);
line-height: var(--line-height-large); /* 142.857% */
letter-spacing: var(--letter-spacing-normal);
}
&[data-fit] {
[data-slot="dialog-container"] {
height: auto;
[data-slot="dialog-body"] {
width: 100%;
position: relative;
display: flex;
flex-direction: column;
flex: 1;
overflow: hidden;
[data-slot="dialog-content"] {
min-height: 0;
}
}
}
&:focus-visible {
outline: none;
}
}
&:focus-visible {
outline: none;
}
}
}
&[data-size="large"] [data-slot="dialog-container"] {
width: min(calc(100vw - 32px), 800px);
height: min(calc(100vh - 32px), 600px);
}
&[data-fit] {
[data-slot="dialog-container"] {
height: auto;
&[data-size="x-large"] [data-slot="dialog-container"] {
width: min(calc(100vw - 32px), 960px);
height: min(calc(100vh - 32px), 600px);
}
[data-slot="dialog-content"] {
min-height: 0;
}
}
}
&[data-size="large"] [data-slot="dialog-container"] {
width: min(calc(100vw - 32px), 800px);
height: min(calc(100vh - 32px), 600px);
}
&[data-size="x-large"] [data-slot="dialog-container"] {
width: min(calc(100vw - 32px), 960px);
height: min(calc(100vh - 32px), 600px);
}
}
[data-component="dialog"][data-transition] [data-slot="dialog-content"] {
animation: contentHide 100ms ease-in forwards;
animation: contentHide 100ms ease-in forwards;
&[data-expanded] {
animation: contentShow 150ms ease-out;
}
&[data-expanded] {
animation: contentShow 150ms ease-out;
}
}
@keyframes overlayShow {
from {
opacity: 0;
}
to {
opacity: 1;
}
from {
opacity: 0;
}
to {
opacity: 1;
}
}
@keyframes overlayHide {
from {
opacity: 1;
}
to {
opacity: 0;
}
from {
opacity: 1;
}
to {
opacity: 0;
}
}
@keyframes contentShow {
from {
opacity: 0;
transform: scale(0.98);
}
to {
opacity: 1;
transform: scale(1);
}
from {
opacity: 0;
transform: translateY(2.5%) scale(0.975);
}
to {
opacity: 1;
transform: scale(1);
}
}
@keyframes contentHide {
from {
opacity: 1;
transform: scale(1);
}
to {
opacity: 0;
transform: scale(0.98);
}
from {
opacity: 1;
transform: scale(1);
}
to {
opacity: 0;
transform: translateY(-2.5%) scale(0.975);
}
}

View File

@@ -1,41 +1,41 @@
[data-component="diff-changes"] {
display: flex;
gap: 8px;
justify-content: flex-end;
align-items: center;
display: flex;
gap: 8px;
justify-content: flex-end;
align-items: center;
[data-slot="diff-changes-additions"] {
font-family: var(--font-family-mono);
font-feature-settings: var(--font-family-mono--font-feature-settings);
font-size: var(--font-size-small);
font-style: normal;
font-weight: var(--font-weight-regular);
line-height: var(--line-height-large);
letter-spacing: var(--letter-spacing-normal);
text-align: right;
color: var(--text-diff-add-base);
}
[data-slot="diff-changes-additions"] {
font-family: var(--font-family-mono);
font-feature-settings: var(--font-family-mono--font-feature-settings);
font-size: var(--font-size-small);
font-style: normal;
font-weight: var(--font-weight-regular);
line-height: var(--line-height-large);
letter-spacing: var(--letter-spacing-normal);
text-align: right;
color: var(--text-diff-add-base);
}
[data-slot="diff-changes-deletions"] {
font-family: var(--font-family-mono);
font-feature-settings: var(--font-family-mono--font-feature-settings);
font-size: var(--font-size-small);
font-style: normal;
font-weight: var(--font-weight-regular);
line-height: var(--line-height-large);
letter-spacing: var(--letter-spacing-normal);
text-align: right;
color: var(--text-diff-delete-base);
}
[data-slot="diff-changes-deletions"] {
font-family: var(--font-family-mono);
font-feature-settings: var(--font-family-mono--font-feature-settings);
font-size: var(--font-size-small);
font-style: normal;
font-weight: var(--font-weight-regular);
line-height: var(--line-height-large);
letter-spacing: var(--letter-spacing-normal);
text-align: right;
color: var(--text-diff-delete-base);
}
}
[data-component="diff-changes"][data-variant="bars"] {
width: 18px;
flex-shrink: 0;
width: 18px;
flex-shrink: 0;
svg {
display: block;
width: 100%;
height: auto;
}
svg {
display: block;
width: 100%;
height: auto;
}
}

View File

@@ -1,35 +1,35 @@
[data-component="diff"] {
content-visibility: auto;
content-visibility: auto;
[data-slot="diff-hunk-separator-line-number"] {
position: sticky;
left: 0;
background-color: var(--surface-diff-hidden-strong);
z-index: 2;
display: flex;
align-items: center;
justify-content: center;
[data-slot="diff-hunk-separator-line-number"] {
position: sticky;
left: 0;
background-color: var(--surface-diff-hidden-strong);
z-index: 2;
display: flex;
align-items: center;
justify-content: center;
[data-slot="diff-hunk-separator-line-number-icon"] {
aspect-ratio: 1;
width: 24px;
height: 24px;
color: var(--icon-strong-base);
}
}
[data-slot="diff-hunk-separator-content"] {
position: sticky;
background-color: var(--surface-diff-hidden-base);
color: var(--text-base);
width: var(--diffs-column-content-width);
left: var(--diffs-column-number-width);
padding-left: 8px;
user-select: none;
cursor: default;
text-align: left;
[data-slot="diff-hunk-separator-line-number-icon"] {
aspect-ratio: 1;
width: 24px;
height: 24px;
color: var(--icon-strong-base);
}
}
[data-slot="diff-hunk-separator-content"] {
position: sticky;
background-color: var(--surface-diff-hidden-base);
color: var(--text-base);
width: var(--diffs-column-content-width);
left: var(--diffs-column-number-width);
padding-left: 8px;
user-select: none;
cursor: default;
text-align: left;
[data-slot="diff-hunk-separator-content-span"] {
mix-blend-mode: var(--text-mix-blend-mode);
}
}
[data-slot="diff-hunk-separator-content-span"] {
mix-blend-mode: var(--text-mix-blend-mode);
}
}
}

View File

@@ -1,125 +1,136 @@
[data-component="dropdown-menu-content"],
[data-component="dropdown-menu-sub-content"] {
min-width: 8rem;
overflow: hidden;
border-radius: var(--radius-md);
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;
box-shadow: var(--shadow-md);
z-index: 50;
transform-origin: var(--kb-menu-content-transform-origin);
min-width: 8rem;
overflow: hidden;
border: none;
border-radius: var(--radius-md);
box-shadow: var(--shadow-xs-border);
background-clip: padding-box;
background-color: var(--surface-raised-stronger-non-alpha);
padding: 4px;
z-index: 100;
transform-origin: var(--kb-menu-content-transform-origin);
&:focus,
&:focus-visible {
outline: none;
}
&:focus-within,
&:focus {
outline: none;
}
&[data-closed] {
animation: dropdown-menu-close 0.15s ease-out;
}
animation: dropdownMenuContentHide var(--transition-duration)
var(--transition-easing) forwards;
&[data-expanded] {
animation: dropdown-menu-open 0.15s ease-out;
}
@starting-style {
animation: none;
}
&[data-expanded] {
pointer-events: auto;
animation: dropdownMenuContentShow var(--transition-duration)
var(--transition-easing) forwards;
}
}
[data-component="dropdown-menu-content"],
[data-component="dropdown-menu-sub-content"] {
[data-slot="dropdown-menu-item"],
[data-slot="dropdown-menu-checkbox-item"],
[data-slot="dropdown-menu-radio-item"],
[data-slot="dropdown-menu-sub-trigger"] {
position: relative;
display: flex;
align-items: center;
gap: 8px;
padding: 4px 8px;
border-radius: var(--radius-sm);
cursor: default;
user-select: none;
outline: none;
[data-slot="dropdown-menu-item"],
[data-slot="dropdown-menu-checkbox-item"],
[data-slot="dropdown-menu-radio-item"],
[data-slot="dropdown-menu-sub-trigger"] {
position: relative;
display: flex;
align-items: center;
gap: 8px;
padding: 4px 8px;
border-radius: var(--radius-sm);
cursor: default;
outline: none;
font-family: var(--font-family-sans);
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);
font-family: var(--font-family-sans);
font-size: var(--font-size-base);
font-weight: var(--font-weight-medium);
line-height: var(--line-height-large);
letter-spacing: var(--letter-spacing-normal);
color: var(--text-strong);
&[data-highlighted] {
background: var(--surface-raised-base-hover);
}
transition-property: background-color, color;
transition-duration: var(--transition-duration);
transition-timing-function: var(--transition-easing);
user-select: none;
&[data-disabled] {
color: var(--text-weak);
pointer-events: none;
}
}
&:hover {
background-color: var(--surface-raised-base-hover);
}
[data-slot="dropdown-menu-sub-trigger"] {
&[data-expanded] {
background: var(--surface-raised-base-hover);
}
}
&[data-disabled] {
color: var(--text-weak);
pointer-events: none;
}
}
[data-slot="dropdown-menu-item-indicator"] {
display: flex;
align-items: center;
justify-content: center;
width: 16px;
height: 16px;
}
[data-slot="dropdown-menu-sub-trigger"] {
&[data-expanded] {
background: var(--surface-raised-base-hover);
outline: none;
border: none;
}
}
[data-slot="dropdown-menu-item-label"] {
flex: 1;
}
[data-slot="dropdown-menu-item-indicator"] {
display: flex;
align-items: center;
justify-content: center;
width: 16px;
height: 16px;
}
[data-slot="dropdown-menu-item-description"] {
font-size: var(--font-size-x-small);
color: var(--text-weak);
}
[data-slot="dropdown-menu-item-label"] {
flex: 1;
}
[data-slot="dropdown-menu-separator"] {
height: 1px;
margin: 4px -4px;
border-top-color: var(--border-weak-base);
}
[data-slot="dropdown-menu-item-description"] {
font-size: var(--font-size-x-small);
color: var(--text-weak);
}
[data-slot="dropdown-menu-group-label"] {
padding: 4px 8px;
font-family: var(--font-family-sans);
font-size: var(--font-size-x-small);
font-weight: var(--font-weight-medium);
line-height: var(--line-height-large);
letter-spacing: var(--letter-spacing-normal);
color: var(--text-weak);
}
[data-slot="dropdown-menu-separator"] {
height: 1px;
margin: 4px -4px;
border-top-color: var(--border-weak-base);
}
[data-slot="dropdown-menu-arrow"] {
fill: var(--surface-raised-stronger-non-alpha);
}
[data-slot="dropdown-menu-group-label"] {
padding: 4px 8px;
font-family: var(--font-family-sans);
font-size: var(--font-size-x-small);
font-weight: var(--font-weight-medium);
line-height: var(--line-height-large);
letter-spacing: var(--letter-spacing-normal);
color: var(--text-weak);
}
[data-slot="dropdown-menu-arrow"] {
fill: var(--surface-raised-stronger-non-alpha);
}
}
@keyframes dropdown-menu-open {
from {
opacity: 0;
transform: scale(0.96);
}
to {
opacity: 1;
transform: scale(1);
}
@keyframes dropdownMenuContentShow {
from {
opacity: 0;
transform: scaleY(0.95);
}
to {
opacity: 1;
transform: scaleY(1);
}
}
@keyframes dropdown-menu-close {
from {
opacity: 1;
transform: scale(1);
}
to {
opacity: 0;
transform: scale(0.96);
}
@keyframes dropdownMenuContentHide {
from {
opacity: 1;
transform: scaleY(1);
}
to {
opacity: 0;
transform: scaleY(0.95);
}
}

View File

@@ -1,5 +1,5 @@
[data-component="file-icon"] {
flex-shrink: 0;
width: 16px;
height: 16px;
flex-shrink: 0;
width: 16px;
height: 16px;
}

View File

@@ -1,61 +1,63 @@
[data-slot="hover-card-trigger"] {
display: flex;
width: 100%;
min-width: 0;
display: flex;
width: 100%;
min-width: 0;
}
[data-component="hover-card-content"] {
z-index: 50;
min-width: 200px;
max-width: 320px;
max-height: calc(100vh - 1rem);
border-radius: 8px;
background-color: var(--surface-raised-stronger-non-alpha);
pointer-events: auto;
z-index: 50;
min-width: 200px;
max-width: 320px;
max-height: calc(100vh - 1rem);
border-radius: 8px;
background-color: var(--surface-raised-stronger-non-alpha);
pointer-events: auto;
border: 1px solid color-mix(in oklch, var(--border-base) 50%, transparent);
background-clip: padding-box;
box-shadow: var(--shadow-md);
border: 1px solid color-mix(in oklch, var(--border-base) 50%, transparent);
background-clip: padding-box;
box-shadow: var(--shadow-md);
transform-origin: var(--kb-hovercard-content-transform-origin);
transform-origin: var(--kb-hovercard-content-transform-origin);
&:focus-within {
outline: none;
}
&:focus-within {
outline: none;
}
&[data-closed] {
animation: hover-card-close 0.15s ease-out;
}
&[data-closed] {
animation: hover-card-close var(--transition-duration)
var(--transition-easing);
}
&[data-expanded] {
animation: hover-card-open 0.15s ease-out;
}
&[data-expanded] {
animation: hover-card-open var(--transition-duration)
var(--transition-easing);
}
[data-slot="hover-card-body"] {
padding: 4px;
max-height: inherit;
overflow: hidden;
}
[data-slot="hover-card-body"] {
padding: 4px;
max-height: inherit;
overflow: hidden;
}
}
@keyframes hover-card-open {
from {
opacity: 0;
transform: scale(0.96);
}
to {
opacity: 1;
transform: scale(1);
}
from {
opacity: 0;
transform: scale(0.96);
}
to {
opacity: 1;
transform: scale(1);
}
}
@keyframes hover-card-close {
from {
opacity: 1;
transform: scale(1);
}
to {
opacity: 0;
transform: scale(0.96);
}
from {
opacity: 1;
transform: scale(1);
}
to {
opacity: 0;
transform: scale(0.96);
}
}

View File

@@ -1,140 +1,143 @@
[data-component="icon-button"] {
display: inline-flex;
align-items: center;
justify-content: center;
border-radius: var(--radius-sm);
text-decoration: none;
user-select: none;
aspect-ratio: 1;
flex-shrink: 0;
display: inline-flex;
align-items: center;
justify-content: center;
border-radius: var(--radius-sm);
text-decoration: none;
user-select: none;
aspect-ratio: 1;
flex-shrink: 0;
transition-property: background-color, color, opacity, box-shadow;
transition-duration: var(--transition-duration);
transition-timing-function: var(--transition-easing);
&[data-variant="primary"] {
background-color: var(--icon-strong-base);
&[data-variant="primary"] {
background-color: var(--icon-strong-base);
[data-slot="icon-svg"] {
/* color: var(--icon-weak-base); */
color: var(--icon-invert-base);
[data-slot="icon-svg"] {
/* color: var(--icon-weak-base); */
color: var(--icon-invert-base);
/* &:hover:not(:disabled) { */
/* color: var(--icon-weak-hover); */
/* } */
/* &:active:not(:disabled) { */
/* color: var(--icon-strong-active); */
/* } */
}
/* &:hover:not(:disabled) { */
/* color: var(--icon-weak-hover); */
/* } */
/* &:active:not(:disabled) { */
/* color: var(--icon-strong-active); */
/* } */
}
&:hover:not(:disabled) {
background-color: var(--icon-strong-hover);
}
&:focus:not(:disabled) {
background-color: var(--icon-strong-focus);
}
&:active:not(:disabled) {
background-color: var(--icon-strong-active);
}
&:disabled {
background-color: var(--icon-strong-disabled);
&:hover:not(:disabled) {
background-color: var(--icon-strong-hover);
}
&:focus:not(:disabled) {
background-color: var(--icon-strong-focus);
}
&:active:not(:disabled) {
background-color: var(--icon-strong-active);
}
&:disabled {
background-color: var(--icon-strong-disabled);
[data-slot="icon-svg"] {
color: var(--icon-invert-base);
}
}
}
[data-slot="icon-svg"] {
color: var(--icon-invert-base);
}
}
}
&[data-variant="secondary"] {
border: transparent;
background-color: var(--button-secondary-base);
color: var(--text-strong);
box-shadow: var(--shadow-xs-border);
&[data-variant="secondary"] {
border: transparent;
background-color: var(--button-secondary-base);
color: var(--text-strong);
box-shadow: var(--shadow-xs-border);
&:hover:not(:disabled) {
background-color: var(--button-secondary-hover);
}
&:focus:not(:disabled) {
background-color: var(--button-secondary-base);
}
&:focus-visible:not(:active) {
background-color: var(--button-secondary-base);
box-shadow: var(--shadow-xs-border-focus);
}
&:focus-visible:active {
box-shadow: none;
}
&:active:not(:disabled) {
background-color: var(--button-secondary-base);
}
&:hover:not(:disabled) {
background-color: var(--button-secondary-hover);
}
&:focus:not(:disabled) {
background-color: var(--button-secondary-base);
}
&:focus-visible:not(:active) {
background-color: var(--button-secondary-base);
box-shadow: var(--shadow-xs-border-focus);
}
&:focus-visible:active {
box-shadow: none;
}
&:active:not(:disabled) {
background-color: var(--button-secondary-base);
}
[data-slot="icon-svg"] {
color: var(--icon-strong-base);
}
[data-slot="icon-svg"] {
color: var(--icon-strong-base);
}
&:disabled {
background-color: var(--icon-strong-disabled);
color: var(--icon-invert-base);
cursor: not-allowed;
}
}
&:disabled {
background-color: var(--icon-strong-disabled);
color: var(--icon-invert-base);
cursor: not-allowed;
}
}
&[data-variant="ghost"] {
background-color: transparent;
/* color: var(--icon-base); */
&[data-variant="ghost"] {
background-color: transparent;
/* color: var(--icon-base); */
[data-slot="icon-svg"] {
color: var(--icon-base);
}
[data-slot="icon-svg"] {
color: var(--icon-base);
}
&:hover:not(:disabled) {
background-color: var(--surface-raised-base-hover);
&:hover:not(:disabled) {
background-color: var(--surface-raised-base-hover);
/* [data-slot="icon-svg"] { */
/* color: var(--icon-hover); */
/* } */
}
&:focus-visible:not(:disabled) {
background-color: var(--surface-raised-base-hover);
}
&:active:not(:disabled) {
background-color: var(--surface-raised-base-active);
/* [data-slot="icon-svg"] { */
/* color: var(--icon-active); */
/* } */
}
&:selected:not(:disabled) {
background-color: var(--surface-raised-base-active);
/* [data-slot="icon-svg"] { */
/* color: var(--icon-selected); */
/* } */
}
&:disabled {
color: var(--icon-invert-base);
cursor: not-allowed;
}
}
/* [data-slot="icon-svg"] { */
/* color: var(--icon-hover); */
/* } */
}
&:focus-visible:not(:disabled) {
background-color: var(--surface-raised-base-hover);
}
&:active:not(:disabled) {
background-color: var(--surface-raised-base-active);
/* [data-slot="icon-svg"] { */
/* color: var(--icon-active); */
/* } */
}
&[data-selected]:not(:disabled) {
background-color: var(--surface-raised-base-active);
/* [data-slot="icon-svg"] { */
/* color: var(--icon-selected); */
/* } */
}
&:disabled {
color: var(--icon-invert-base);
cursor: not-allowed;
}
}
&[data-size="normal"] {
width: 24px;
height: 24px;
&[data-size="normal"] {
width: 24px;
height: 24px;
font-size: var(--font-size-small);
line-height: var(--line-height-large);
gap: calc(var(--spacing) * 0.5);
}
font-size: var(--font-size-small);
line-height: var(--line-height-large);
gap: calc(var(--spacing) * 0.5);
}
&[data-size="large"] {
height: 32px;
/* padding: 0 8px 0 6px; */
gap: 8px;
&[data-size="large"] {
height: 32px;
/* padding: 0 8px 0 6px; */
gap: 8px;
/* text-12-medium */
font-family: var(--font-family-sans);
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);
}
/* text-12-medium */
font-family: var(--font-family-sans);
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);
}
&:focus {
outline: none;
}
&:focus {
outline: none;
}
}

View File

@@ -1,34 +1,34 @@
[data-component="icon"] {
display: inline-flex;
align-items: center;
justify-content: center;
flex-shrink: 0;
/* resize: both; */
aspect-ratio: 1/1;
color: var(--icon-base);
display: inline-flex;
align-items: center;
justify-content: center;
flex-shrink: 0;
/* resize: both; */
aspect-ratio: 1 / 1;
color: var(--icon-base);
&[data-size="small"] {
width: 16px;
height: 16px;
}
&[data-size="small"] {
width: 16px;
height: 16px;
}
&[data-size="normal"] {
width: 20px;
height: 20px;
}
&[data-size="normal"] {
width: 20px;
height: 20px;
}
&[data-size="medium"] {
width: 24px;
height: 24px;
}
&[data-size="medium"] {
width: 24px;
height: 24px;
}
&[data-size="large"] {
width: 24px;
height: 24px;
}
&[data-size="large"] {
width: 24px;
height: 24px;
}
[data-slot="icon-svg"] {
width: 100%;
height: auto;
}
[data-slot="icon-svg"] {
width: 100%;
height: auto;
}
}

View File

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

View File

@@ -1,63 +1,63 @@
[data-component="image-preview"] {
position: fixed;
inset: 0;
z-index: 50;
display: flex;
align-items: center;
justify-content: center;
position: fixed;
inset: 0;
z-index: 50;
display: flex;
align-items: center;
justify-content: center;
[data-slot="image-preview-container"] {
position: relative;
z-index: 50;
width: min(calc(100vw - 32px), 90vw);
max-width: 1200px;
height: min(calc(100vh - 32px), 90vh);
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
[data-slot="image-preview-container"] {
position: relative;
z-index: 50;
width: min(calc(100vw - 32px), 90vw);
max-width: 1200px;
height: min(calc(100vh - 32px), 90vh);
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
[data-slot="image-preview-content"] {
display: flex;
flex-direction: column;
align-items: center;
width: 100%;
max-height: 100%;
border-radius: var(--radius-lg);
background: var(--surface-raised-stronger-non-alpha);
box-shadow:
0 15px 45px 0 rgba(19, 16, 16, 0.35),
0 3.35px 10.051px 0 rgba(19, 16, 16, 0.25),
0 0.998px 2.993px 0 rgba(19, 16, 16, 0.2);
overflow: hidden;
[data-slot="image-preview-content"] {
display: flex;
flex-direction: column;
align-items: center;
width: 100%;
max-height: 100%;
border-radius: var(--radius-lg);
background: var(--surface-raised-stronger-non-alpha);
box-shadow:
0 15px 45px 0 rgba(19, 16, 16, 0.35),
0 3.35px 10.051px 0 rgba(19, 16, 16, 0.25),
0 0.998px 2.993px 0 rgba(19, 16, 16, 0.2);
overflow: hidden;
&:focus-visible {
outline: none;
}
&:focus-visible {
outline: none;
}
[data-slot="image-preview-header"] {
display: flex;
padding: 8px 8px 0;
justify-content: flex-end;
align-items: center;
align-self: stretch;
}
[data-slot="image-preview-header"] {
display: flex;
padding: 8px 8px 0;
justify-content: flex-end;
align-items: center;
align-self: stretch;
}
[data-slot="image-preview-body"] {
width: 100%;
display: flex;
align-items: center;
justify-content: center;
padding: 16px;
overflow: auto;
}
[data-slot="image-preview-body"] {
width: 100%;
display: flex;
align-items: center;
justify-content: center;
padding: 16px;
overflow: auto;
}
[data-slot="image-preview-image"] {
max-width: 100%;
max-height: calc(90vh - 100px);
object-fit: contain;
border-radius: var(--radius-md);
}
}
}
[data-slot="image-preview-image"] {
max-width: 100%;
max-height: calc(90vh - 100px);
object-fit: contain;
border-radius: var(--radius-md);
}
}
}
}

View File

@@ -1,17 +1,17 @@
[data-component="inline-input"] {
color: inherit;
background: transparent;
border: 0;
border-radius: var(--radius-md);
padding: 0;
min-width: 0;
font: inherit;
letter-spacing: inherit;
line-height: inherit;
box-sizing: border-box;
color: inherit;
background: transparent;
border: 0;
border-radius: var(--radius-md);
padding: 0;
min-width: 0;
font: inherit;
letter-spacing: inherit;
line-height: inherit;
box-sizing: border-box;
&:focus {
outline: none;
box-shadow: 0 0 0 1px var(--border-interactive-focus);
}
&:focus {
outline: none;
box-shadow: 0 0 0 1px var(--border-interactive-focus);
}
}

View File

@@ -1,18 +1,18 @@
[data-component="keybind"] {
display: flex;
align-items: center;
justify-content: center;
flex-shrink: 0;
height: 20px;
padding: 0 8px;
border-radius: 2px;
background: var(--surface-base);
box-shadow: var(--shadow-xxs-border);
display: flex;
align-items: center;
justify-content: center;
flex-shrink: 0;
height: 20px;
padding: 0 8px;
border-radius: 2px;
background: var(--surface-base);
box-shadow: var(--shadow-xxs-border);
/* text-12-medium */
font-family: var(--font-family-sans);
font-size: 12px;
font-weight: var(--font-weight-medium);
line-height: 1;
color: var(--text-weak);
/* text-12-medium */
font-family: var(--font-family-sans);
font-size: 12px;
font-weight: var(--font-weight-medium);
line-height: 1;
color: var(--text-weak);
}

View File

@@ -1,115 +1,117 @@
[data-component="line-comment"] {
position: absolute;
right: 24px;
z-index: var(--line-comment-z, 30);
position: absolute;
right: 24px;
z-index: var(--line-comment-z, 30);
}
[data-component="line-comment"][data-open] {
z-index: var(--line-comment-open-z, 100);
z-index: var(--line-comment-open-z, 100);
}
[data-component="line-comment"] [data-slot="line-comment-button"] {
width: 20px;
height: 20px;
border-radius: var(--radius-md);
display: flex;
align-items: center;
justify-content: center;
background: var(--icon-interactive-base);
box-shadow: var(--shadow-xs);
cursor: default;
border: none;
width: 20px;
height: 20px;
border-radius: var(--radius-md);
display: flex;
align-items: center;
justify-content: center;
background: var(--icon-interactive-base);
box-shadow: var(--shadow-xs);
cursor: default;
border: none;
}
[data-component="line-comment"] [data-component="icon"] {
color: var(--white);
color: var(--white);
}
[data-component="line-comment"] [data-slot="line-comment-button"]:focus {
outline: none;
outline: none;
}
[data-component="line-comment"] [data-slot="line-comment-button"]:focus-visible {
box-shadow: var(--shadow-xs-border-focus);
[data-component="line-comment"]
[data-slot="line-comment-button"]:focus-visible {
box-shadow: var(--shadow-xs-border-focus);
}
[data-component="line-comment"] [data-slot="line-comment-popover"] {
position: absolute;
top: calc(100% + 4px);
right: -8px;
z-index: var(--line-comment-popover-z, 40);
min-width: 200px;
max-width: min(320px, calc(100vw - 48px));
border-radius: 8px;
background: var(--surface-raised-stronger-non-alpha);
box-shadow: var(--shadow-lg-border-base);
padding: 12px;
position: absolute;
top: calc(100% + 4px);
right: -8px;
z-index: var(--line-comment-popover-z, 40);
min-width: 200px;
max-width: min(320px, calc(100vw - 48px));
border-radius: 8px;
background: var(--surface-raised-stronger-non-alpha);
box-shadow: var(--shadow-lg-border-base);
padding: 12px;
}
[data-component="line-comment"][data-variant="editor"] [data-slot="line-comment-popover"] {
width: 380px;
max-width: min(380px, calc(100vw - 48px));
padding: 8px;
border-radius: 14px;
[data-component="line-comment"][data-variant="editor"]
[data-slot="line-comment-popover"] {
width: 380px;
max-width: min(380px, calc(100vw - 48px));
padding: 8px;
border-radius: 14px;
}
[data-component="line-comment"] [data-slot="line-comment-content"] {
display: flex;
flex-direction: column;
gap: 6px;
display: flex;
flex-direction: column;
gap: 6px;
}
[data-component="line-comment"] [data-slot="line-comment-text"] {
font-family: var(--font-family-sans);
font-size: var(--font-size-base);
font-weight: var(--font-weight-regular);
line-height: var(--line-height-x-large);
letter-spacing: var(--letter-spacing-normal);
color: var(--text-strong);
white-space: pre-wrap;
font-family: var(--font-family-sans);
font-size: var(--font-size-base);
font-weight: var(--font-weight-regular);
line-height: var(--line-height-x-large);
letter-spacing: var(--letter-spacing-normal);
color: var(--text-strong);
white-space: pre-wrap;
}
[data-component="line-comment"] [data-slot="line-comment-label"],
[data-component="line-comment"] [data-slot="line-comment-editor-label"] {
font-family: var(--font-family-sans);
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-weak);
white-space: nowrap;
font-family: var(--font-family-sans);
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-weak);
white-space: nowrap;
}
[data-component="line-comment"] [data-slot="line-comment-editor"] {
display: flex;
flex-direction: column;
gap: 8px;
display: flex;
flex-direction: column;
gap: 8px;
}
[data-component="line-comment"] [data-slot="line-comment-textarea"] {
width: 100%;
resize: vertical;
padding: 8px;
border-radius: var(--radius-md);
background: var(--surface-base);
border: 1px solid var(--border-base);
color: var(--text-strong);
font-family: var(--font-family-sans);
font-size: var(--font-size-small);
line-height: var(--line-height-large);
width: 100%;
resize: vertical;
padding: 8px;
border-radius: var(--radius-md);
background: var(--surface-base);
border: 1px solid var(--border-base);
color: var(--text-strong);
font-family: var(--font-family-sans);
font-size: var(--font-size-small);
line-height: var(--line-height-large);
}
[data-component="line-comment"] [data-slot="line-comment-textarea"]:focus {
outline: none;
box-shadow: var(--shadow-xs-border-select);
outline: none;
box-shadow: var(--shadow-xs-border-select);
}
[data-component="line-comment"] [data-slot="line-comment-actions"] {
display: flex;
align-items: center;
gap: 8px;
display: flex;
align-items: center;
gap: 8px;
}
[data-component="line-comment"] [data-slot="line-comment-editor-label"] {
margin-right: auto;
margin-right: auto;
}

View File

@@ -1,331 +1,337 @@
@property --bottom-fade {
syntax: "<length>";
inherits: false;
initial-value: 0px;
syntax: "<length>";
inherits: false;
initial-value: 0px;
}
@keyframes scroll {
0% {
--bottom-fade: 20px;
}
90% {
--bottom-fade: 20px;
}
100% {
--bottom-fade: 0;
}
0% {
--bottom-fade: 20px;
}
90% {
--bottom-fade: 20px;
}
100% {
--bottom-fade: 0;
}
}
[data-component="list"] {
display: flex;
flex-direction: column;
gap: 12px;
overflow: hidden;
padding: 0 12px;
display: flex;
flex-direction: column;
gap: 8px;
overflow: hidden;
padding: 0 12px;
[data-slot="list-search-wrapper"] {
display: flex;
flex-shrink: 0;
align-items: center;
gap: 8px;
align-self: stretch;
margin-bottom: 4px;
[data-slot="list-search-wrapper"] {
display: flex;
flex-shrink: 0;
align-items: center;
gap: 8px;
align-self: stretch;
margin-bottom: 4px;
> [data-component="icon-button"] {
width: 24px;
height: 24px;
flex-shrink: 0;
background-color: transparent;
opacity: 0.5;
transition: opacity 0.15s ease;
> [data-component="icon-button"] {
width: 24px;
height: 24px;
flex-shrink: 0;
background-color: transparent;
opacity: 0.5;
transition-property: opacity;
transition-duration: var(--transition-duration);
transition-timing-function: var(--transition-easing);
&:hover:not(:disabled),
&:focus-visible:not(:disabled),
&:active:not(:disabled) {
background-color: transparent;
opacity: 0.7;
}
&:hover:not(:disabled),
&:focus-visible:not(:disabled),
&:active:not(:disabled) {
background-color: transparent;
opacity: 0.7;
}
&:hover:not(:disabled) [data-slot="icon-svg"] {
color: var(--icon-hover);
}
&:hover:not(:disabled) [data-slot="icon-svg"] {
color: var(--icon-hover);
}
&:active:not(:disabled) [data-slot="icon-svg"] {
color: var(--icon-active);
}
}
}
&:active:not(:disabled) [data-slot="icon-svg"] {
color: var(--icon-active);
}
}
}
[data-slot="list-search"] {
display: flex;
flex: 1;
padding: 8px;
align-items: center;
gap: 12px;
[data-slot="list-search"] {
display: flex;
flex: 1;
padding: 8px;
align-items: center;
gap: 12px;
border-radius: var(--radius-md);
background: var(--surface-base);
border-radius: var(--radius-md);
background: var(--surface-base);
[data-slot="list-search-container"] {
display: flex;
align-items: center;
gap: 8px;
flex: 1 0 0;
max-height: 20px;
[data-slot="list-search-container"] {
display: flex;
align-items: center;
gap: 8px;
flex: 1 0 0;
max-height: 20px;
[data-slot="list-search-input"] {
width: 100%;
[data-slot="list-search-input"] {
width: 100%;
&[data-slot="input-input"] {
line-height: 20px;
max-height: 20px;
}
}
}
&[data-slot="input-input"] {
line-height: 20px;
max-height: 20px;
}
}
}
> [data-component="icon-button"] {
width: 20px;
height: 20px;
background-color: transparent;
opacity: 0.5;
transition: opacity 0.15s ease;
> [data-component="icon-button"] {
width: 20px;
height: 20px;
background-color: transparent;
opacity: 0.5;
transition-property: opacity;
transition-duration: var(--transition-duration);
transition-timing-function: var(--transition-easing);
&:hover:not(:disabled),
&:focus-visible:not(:disabled),
&:active:not(:disabled) {
background-color: transparent;
opacity: 0.7;
}
&:hover:not(:disabled),
&:focus-visible:not(:disabled),
&:active:not(:disabled) {
background-color: transparent;
opacity: 0.7;
}
&:hover:not(:disabled) [data-slot="icon-svg"] {
color: var(--icon-hover);
}
&:hover:not(:disabled) [data-slot="icon-svg"] {
color: var(--icon-hover);
}
&:active:not(:disabled) [data-slot="icon-svg"] {
color: var(--icon-active);
}
}
&:active:not(:disabled) [data-slot="icon-svg"] {
color: var(--icon-active);
}
}
> [data-component="icon-button"] {
background-color: transparent;
> [data-component="icon-button"] {
background-color: transparent;
&:hover:not(:disabled),
&:focus:not(:disabled),
&:active:not(:disabled) {
background-color: transparent;
}
&:hover:not(:disabled),
&:focus:not(:disabled),
&:active:not(:disabled) {
background-color: transparent;
}
&:hover:not(:disabled) [data-slot="icon-svg"] {
color: var(--icon-hover);
}
&:hover:not(:disabled) [data-slot="icon-svg"] {
color: var(--icon-hover);
}
&:active:not(:disabled) [data-slot="icon-svg"] {
color: var(--icon-active);
}
}
}
&:active:not(:disabled) [data-slot="icon-svg"] {
color: var(--icon-active);
}
}
}
[data-slot="list-scroll"] {
display: flex;
flex-direction: column;
gap: 12px;
overflow-y: auto;
overscroll-behavior: contain;
mask: linear-gradient(to bottom, #ffff calc(100% - var(--bottom-fade)), #0000);
animation: scroll;
animation-timeline: --scroll;
scroll-timeline: --scroll y;
scrollbar-width: none;
-ms-overflow-style: none;
&::-webkit-scrollbar {
display: none;
}
[data-slot="list-scroll"] {
display: flex;
flex-direction: column;
gap: 12px;
overflow-y: auto;
overscroll-behavior: contain;
[data-slot="list-empty-state"] {
display: flex;
padding: 32px 48px;
flex-direction: column;
justify-content: center;
align-items: center;
gap: 8px;
align-self: stretch;
[data-slot="list-empty-state"] {
display: flex;
padding: 32px 48px;
flex-direction: column;
justify-content: center;
align-items: center;
gap: 8px;
align-self: stretch;
[data-slot="list-message"] {
display: flex;
justify-content: center;
align-items: center;
gap: 2px;
max-width: 100%;
color: var(--text-weak);
white-space: nowrap;
[data-slot="list-message"] {
display: flex;
justify-content: center;
align-items: center;
gap: 2px;
max-width: 100%;
color: var(--text-weak);
white-space: nowrap;
/* text-14-regular */
font-family: var(--font-family-sans);
font-size: 14px;
font-style: normal;
font-weight: var(--font-weight-regular);
line-height: var(--line-height-large); /* 142.857% */
letter-spacing: var(--letter-spacing-normal);
}
/* text-14-regular */
font-family: var(--font-family-sans);
font-size: 14px;
font-style: normal;
font-weight: var(--font-weight-regular);
line-height: var(--line-height-large); /* 142.857% */
letter-spacing: var(--letter-spacing-normal);
}
[data-slot="list-filter"] {
color: var(--text-strong);
overflow: hidden;
text-overflow: ellipsis;
}
}
[data-slot="list-filter"] {
color: var(--text-strong);
overflow: hidden;
text-overflow: ellipsis;
}
}
[data-slot="list-group"] {
position: relative;
display: flex;
flex-direction: column;
[data-slot="list-group"] {
position: relative;
display: flex;
flex-direction: column;
&:last-child {
padding-bottom: 12px;
}
&:last-child {
padding-bottom: 12px;
}
[data-slot="list-header"] {
display: flex;
z-index: 10;
padding: 8px 12px 8px 8px;
justify-content: space-between;
align-items: center;
align-self: stretch;
background: var(--surface-raised-stronger-non-alpha);
position: sticky;
top: 0;
[data-slot="list-header"] {
display: flex;
z-index: 10;
padding: 8px 12px 8px 8px;
justify-content: space-between;
align-items: center;
align-self: stretch;
background: var(--surface-raised-stronger-non-alpha);
position: sticky;
top: 0;
color: var(--text-weak);
color: var(--text-weak);
/* text-14-medium */
font-family: var(--font-family-sans);
font-size: 14px;
font-style: normal;
font-weight: var(--font-weight-medium);
line-height: var(--line-height-large); /* 142.857% */
letter-spacing: var(--letter-spacing-normal);
/* text-14-medium */
font-family: var(--font-family-sans);
font-size: 14px;
font-style: normal;
font-weight: var(--font-weight-medium);
line-height: var(--line-height-large); /* 142.857% */
letter-spacing: var(--letter-spacing-normal);
&::after {
content: "";
position: absolute;
top: 100%;
left: 0;
right: 0;
height: 16px;
background: linear-gradient(to bottom, var(--surface-raised-stronger-non-alpha), transparent);
pointer-events: none;
opacity: 0;
transition: opacity 0.15s ease;
}
&::after {
content: "";
position: absolute;
top: 100%;
left: 0;
right: 0;
height: 16px;
background: linear-gradient(
to bottom,
var(--surface-raised-stronger-non-alpha),
transparent
);
pointer-events: none;
opacity: 0;
transition-property: opacity;
transition-duration: var(--transition-duration);
transition-timing-function: var(--transition-easing);
}
&[data-stuck="true"]::after {
opacity: 1;
}
}
&[data-stuck="true"]::after {
opacity: 1;
}
}
[data-slot="list-items"] {
display: flex;
flex-direction: column;
align-items: flex-start;
align-self: stretch;
[data-slot="list-items"] {
display: flex;
flex-direction: column;
align-items: flex-start;
align-self: stretch;
[data-slot="list-item"] {
display: flex;
position: relative;
width: 100%;
padding: 6px 8px 6px 8px;
align-items: center;
color: var(--text-strong);
scroll-margin-top: 28px;
[data-slot="list-item"] {
display: flex;
position: relative;
width: 100%;
padding: 6px 8px 6px 8px;
align-items: center;
color: var(--text-strong);
scroll-margin-top: 28px;
/* text-14-medium */
font-family: var(--font-family-sans);
font-size: 14px;
font-style: normal;
font-weight: var(--font-weight-medium);
line-height: var(--line-height-large); /* 142.857% */
letter-spacing: var(--letter-spacing-normal);
/* text-14-medium */
font-family: var(--font-family-sans);
font-size: 14px;
font-style: normal;
font-weight: var(--font-weight-medium);
line-height: var(--line-height-large); /* 142.857% */
letter-spacing: var(--letter-spacing-normal);
[data-slot="list-item-selected-icon"] {
display: inline-flex;
align-items: center;
justify-content: center;
flex-shrink: 0;
aspect-ratio: 1/1;
[data-component="icon"] {
color: var(--icon-strong-base);
}
}
[data-slot="list-item-active-icon"] {
display: none;
align-items: center;
justify-content: center;
flex-shrink: 0;
aspect-ratio: 1/1;
[data-component="icon"] {
color: var(--icon-strong-base);
}
}
[data-slot="list-item-selected-icon"] {
display: inline-flex;
align-items: center;
justify-content: center;
flex-shrink: 0;
aspect-ratio: 1 / 1;
[data-component="icon"] {
color: var(--icon-strong-base);
}
}
[data-slot="list-item-extra-icon"] {
color: var(--icon-base);
margin-left: -4px;
}
[name="check"] {
color: var(--icon-strong-base);
}
[data-slot="list-item-divider"] {
position: absolute;
bottom: 0;
left: var(--list-divider-inset, 16px);
right: var(--list-divider-inset, 16px);
height: 1px;
background: var(--border-weak-base);
pointer-events: none;
}
[data-slot="list-item-active-icon"] {
display: none;
align-items: center;
justify-content: center;
flex-shrink: 0;
aspect-ratio: 1 / 1;
[data-component="icon"] {
color: var(--icon-strong-base);
}
}
[data-slot="list-item"]:last-child [data-slot="list-item-divider"] {
display: none;
}
[data-slot="list-item-extra-icon"] {
color: var(--icon-base);
margin-left: -4px;
}
&[data-active="true"] {
border-radius: var(--radius-md);
background: var(--surface-raised-base-hover);
[data-slot="list-item-active-icon"] {
display: inline-flex;
}
[data-slot="list-item-extra-icon"] {
display: block !important;
color: var(--icon-strong-base) !important;
}
}
&:active {
background: var(--surface-raised-base-active);
}
&:focus-visible {
outline: none;
}
}
[data-slot="list-item-divider"] {
position: absolute;
bottom: 0;
left: var(--list-divider-inset, 16px);
right: var(--list-divider-inset, 16px);
height: 1px;
background: var(--border-weak-base);
pointer-events: none;
}
[data-slot="list-item-add"] {
display: flex;
position: relative;
width: 100%;
padding: 6px 8px 6px 8px;
align-items: center;
color: var(--text-strong);
[data-slot="list-item"]:last-child [data-slot="list-item-divider"] {
display: none;
}
/* text-14-medium */
font-family: var(--font-family-sans);
font-size: 14px;
font-style: normal;
font-weight: var(--font-weight-medium);
line-height: var(--line-height-large); /* 142.857% */
letter-spacing: var(--letter-spacing-normal);
&[data-active="true"] {
border-radius: var(--radius-md);
background: var(--surface-raised-base-hover);
[data-slot="list-item-active-icon"] {
display: inline-flex;
}
[data-slot="list-item-extra-icon"] {
display: block !important;
color: var(--icon-strong-base) !important;
}
}
&:active {
background: var(--surface-raised-base-active);
}
&:focus-visible {
outline: none;
}
}
[data-component="input"] {
width: 100%;
}
}
}
}
}
[data-slot="list-item-add"] {
display: flex;
position: relative;
width: 100%;
padding: 6px 8px 6px 8px;
align-items: center;
color: var(--text-strong);
/* text-14-medium */
font-family: var(--font-family-sans);
font-size: 14px;
font-style: normal;
font-weight: var(--font-weight-medium);
line-height: var(--line-height-large); /* 142.857% */
letter-spacing: var(--letter-spacing-normal);
[data-component="input"] {
width: 100%;
}
}
}
}
}
}

View File

@@ -5,6 +5,7 @@ import { useI18n } from "../context/i18n"
import { Icon, type IconProps } from "./icon"
import { IconButton } from "./icon-button"
import { TextField } from "./text-field"
import { ScrollFade } from "./scroll-fade"
function findByKey(container: HTMLElement, key: string) {
const nodes = container.querySelectorAll<HTMLElement>('[data-slot="list-item"][data-key]')
@@ -267,7 +268,13 @@ export function List<T>(props: ListProps<T> & { ref?: (ref: ListRef) => void })
{searchAction()}
</div>
</Show>
<div ref={setScrollRef} data-slot="list-scroll">
<ScrollFade
ref={setScrollRef}
direction="vertical"
fadeStartSize={0}
fadeEndSize={20}
data-slot="list-scroll"
>
<Show
when={flat().length > 0 || showAdd()}
fallback={
@@ -339,7 +346,7 @@ export function List<T>(props: ListProps<T> & { ref?: (ref: ListRef) => void })
</div>
</Show>
</Show>
</div>
</ScrollFade>
</div>
)
}

View File

@@ -1,4 +1,4 @@
[data-component="logo-mark"] {
width: 16px;
aspect-ratio: 4/5;
width: 16px;
aspect-ratio: 4 / 5;
}

View File

@@ -1,209 +1,211 @@
[data-component="markdown"] {
/* Reset & Base Typography */
min-width: 0;
max-width: 100%;
overflow-wrap: break-word;
color: var(--text-base);
font-family: var(--font-family-sans);
font-size: var(--font-size-base); /* 14px */
line-height: var(--line-height-x-large);
/* Reset & Base Typography */
min-width: 0;
max-width: 100%;
overflow-wrap: break-word;
color: var(--text-base);
font-family: var(--font-family-sans);
font-size: var(--font-size-base); /* 14px */
line-height: var(--line-height-x-large);
/* Spacing for flow */
> *:first-child {
margin-top: 0;
}
> *:last-child {
margin-bottom: 0;
}
/* Spacing for flow */
> *:first-child {
margin-top: 0;
}
> *:last-child {
margin-bottom: 0;
}
/* Headings: Same size, distinguished by color and spacing */
h1,
h2,
h3,
h4,
h5,
h6 {
font-size: var(--font-size-base);
color: var(--text-strong);
font-weight: var(--font-weight-medium);
margin-top: 2rem;
margin-bottom: 0.75rem;
line-height: var(--line-height-large);
}
/* Headings: Same size, distinguished by color and spacing */
h1,
h2,
h3,
h4,
h5,
h6 {
font-size: var(--font-size-base);
color: var(--text-strong);
font-weight: var(--font-weight-medium);
margin-top: 2rem;
margin-bottom: 0.75rem;
line-height: var(--line-height-large);
}
/* Emphasis & Strong: Neutral strong color */
strong,
b {
color: var(--text-strong);
font-weight: var(--font-weight-medium);
}
/* Emphasis & Strong: Neutral strong color */
strong,
b {
color: var(--text-strong);
font-weight: var(--font-weight-medium);
}
/* Paragraphs */
p {
margin-bottom: 1rem;
}
/* Paragraphs */
p {
margin-bottom: 1rem;
}
/* Links */
a {
color: var(--text-interactive-base);
text-decoration: none;
font-weight: inherit;
}
/* Links */
a {
color: var(--text-interactive-base);
text-decoration: none;
font-weight: inherit;
}
a:hover {
text-decoration: underline;
text-underline-offset: 2px;
}
a:hover {
text-decoration: underline;
text-underline-offset: 2px;
}
/* Lists */
ul,
ol {
margin-top: 0.5rem;
margin-bottom: 1rem;
padding-left: 1.5rem;
list-style-position: outside;
}
/* Lists */
ul,
ol {
margin-top: 0.5rem;
margin-bottom: 1rem;
padding-left: 1.5rem;
list-style-position: outside;
}
ul {
list-style-type: disc;
}
ul {
list-style-type: disc;
}
ol {
list-style-type: decimal;
}
ol {
list-style-type: decimal;
}
li {
margin-bottom: 0.5rem;
}
li {
margin-bottom: 0.5rem;
}
li > p:first-child {
display: inline;
margin: 0;
}
li > p:first-child {
display: inline;
margin: 0;
}
li > p + p {
display: block;
margin-top: 0.5rem;
}
li > p + p {
display: block;
margin-top: 0.5rem;
}
li::marker {
color: var(--text-weak);
}
li::marker {
color: var(--text-weak);
}
/* Nested lists spacing */
li > ul,
li > ol {
margin-top: 0.25rem;
margin-bottom: 0.25rem;
padding-left: 1rem; /* Minimal indent for nesting only */
}
/* Nested lists spacing */
li > ul,
li > ol {
margin-top: 0.25rem;
margin-bottom: 0.25rem;
padding-left: 1rem; /* Minimal indent for nesting only */
}
/* Blockquotes */
blockquote {
border-left: 2px solid var(--border-weak-base);
margin: 1.5rem 0;
padding-left: 0.5rem;
color: var(--text-weak);
font-style: normal;
}
/* Blockquotes */
blockquote {
border-left: 2px solid var(--border-weak-base);
margin: 1.5rem 0;
padding-left: 0.5rem;
color: var(--text-weak);
font-style: normal;
}
/* Horizontal Rule - Invisible spacing only */
hr {
border: none;
height: 0;
margin: 2.5rem 0;
}
/* Horizontal Rule - Invisible spacing only */
hr {
border: none;
height: 0;
margin: 2.5rem 0;
}
.shiki {
font-size: 13px;
padding: 8px 12px;
border-radius: 4px;
border: 0.5px solid var(--border-weak-base);
}
.shiki {
font-size: 13px;
padding: 8px 12px;
border-radius: 4px;
border: 0.5px solid var(--border-weak-base);
}
[data-component="markdown-code"] {
position: relative;
}
[data-component="markdown-code"] {
position: relative;
}
[data-slot="markdown-copy-button"] {
position: absolute;
top: 8px;
right: 8px;
opacity: 0;
transition: opacity 0.15s ease;
z-index: 1;
}
[data-slot="markdown-copy-button"] {
position: absolute;
top: 8px;
right: 8px;
opacity: 0;
transition: opacity 0.15s ease;
z-index: 1;
}
[data-component="markdown-code"]:hover [data-slot="markdown-copy-button"] {
opacity: 1;
}
[data-component="markdown-code"]:hover [data-slot="markdown-copy-button"] {
opacity: 1;
}
[data-slot="markdown-copy-button"] [data-slot="check-icon"] {
display: none;
}
[data-slot="markdown-copy-button"] [data-slot="check-icon"] {
display: none;
}
[data-slot="markdown-copy-button"][data-copied="true"] [data-slot="copy-icon"] {
display: none;
}
[data-slot="markdown-copy-button"][data-copied="true"]
[data-slot="copy-icon"] {
display: none;
}
[data-slot="markdown-copy-button"][data-copied="true"] [data-slot="check-icon"] {
display: inline-flex;
}
[data-slot="markdown-copy-button"][data-copied="true"]
[data-slot="check-icon"] {
display: inline-flex;
}
pre {
margin-top: 2rem;
margin-bottom: 2rem;
overflow: auto;
pre {
margin-top: 2rem;
margin-bottom: 2rem;
overflow: auto;
scrollbar-width: none;
&::-webkit-scrollbar {
display: none;
}
}
scrollbar-width: none;
&::-webkit-scrollbar {
display: none;
}
}
:not(pre) > code {
font-family: var(--font-family-mono);
font-feature-settings: var(--font-family-mono--font-feature-settings);
color: var(--syntax-string);
font-weight: var(--font-weight-medium);
/* font-size: 13px; */
:not(pre) > code {
font-family: var(--font-family-mono);
font-feature-settings: var(--font-family-mono--font-feature-settings);
color: var(--syntax-string);
font-weight: var(--font-weight-medium);
/* font-size: 13px; */
/* padding: 2px 2px; */
/* margin: 0 1.5px; */
/* border-radius: 2px; */
/* background: var(--surface-base); */
/* box-shadow: 0 0 0 0.5px var(--border-weak-base); */
}
/* padding: 2px 2px; */
/* margin: 0 1.5px; */
/* border-radius: 2px; */
/* background: var(--surface-base); */
/* box-shadow: 0 0 0 0.5px var(--border-weak-base); */
}
/* Tables */
table {
width: 100%;
border-collapse: collapse;
margin: 1.5rem 0;
font-size: var(--font-size-base);
}
/* Tables */
table {
width: 100%;
border-collapse: collapse;
margin: 1.5rem 0;
font-size: var(--font-size-base);
}
th,
td {
/* Minimal borders for structure, matching TUI "lines" roughly but keeping it web-clean */
border-bottom: 1px solid var(--border-weaker-base);
padding: 0.75rem 0.5rem;
text-align: left;
vertical-align: top;
}
th,
td {
/* Minimal borders for structure, matching TUI "lines" roughly but keeping it web-clean */
border-bottom: 1px solid var(--border-weaker-base);
padding: 0.75rem 0.5rem;
text-align: left;
vertical-align: top;
}
th {
color: var(--text-strong);
font-weight: var(--font-weight-medium);
border-bottom: 1px solid var(--border-weak-base);
}
th {
color: var(--text-strong);
font-weight: var(--font-weight-medium);
border-bottom: 1px solid var(--border-weak-base);
}
/* Images */
img {
max-width: 100%;
height: auto;
border-radius: 4px;
margin: 1.5rem 0;
display: block;
}
/* Images */
img {
max-width: 100%;
height: auto;
border-radius: 4px;
margin: 1.5rem 0;
display: block;
}
}

View File

@@ -1,122 +1,123 @@
[data-component="message-nav"] {
flex-shrink: 0;
display: flex;
flex-direction: column;
align-items: flex-start;
padding-left: 0;
list-style: none;
flex-shrink: 0;
display: flex;
flex-direction: column;
align-items: flex-start;
padding-left: 0;
list-style: none;
&[data-size="normal"] {
width: 240px;
gap: 4px;
}
&[data-size="normal"] {
width: 240px;
gap: 4px;
}
&[data-size="compact"] {
width: 24px;
}
&[data-size="compact"] {
width: 24px;
}
}
[data-slot="message-nav-item"] {
display: flex;
align-items: center;
align-self: stretch;
justify-content: flex-end;
display: flex;
align-items: center;
align-self: stretch;
justify-content: flex-end;
[data-component="message-nav"][data-size="normal"] & {
justify-content: flex-start;
}
[data-component="message-nav"][data-size="normal"] & {
justify-content: flex-start;
}
}
[data-slot="message-nav-tick-button"] {
display: flex;
align-items: center;
justify-content: flex-start;
height: 12px;
width: 24px;
border: none;
background: none;
padding: 0;
display: flex;
align-items: center;
justify-content: flex-start;
height: 12px;
width: 24px;
border: none;
background: none;
padding: 0;
&[data-active] [data-slot="message-nav-tick-line"] {
background-color: var(--icon-strong-base);
width: 100%;
}
&[data-active] [data-slot="message-nav-tick-line"] {
background-color: var(--icon-strong-base);
width: 100%;
}
}
[data-slot="message-nav-tick-line"] {
height: 1px;
width: 16px;
background-color: var(--icon-base);
transition:
width 0.2s,
background-color 0.2s;
height: 1px;
width: 16px;
background-color: var(--icon-base);
transition:
width 0.2s,
background-color 0.2s;
}
[data-slot="message-nav-tick-button"]:hover [data-slot="message-nav-tick-line"] {
width: 100%;
background-color: var(--icon-strong-base);
[data-slot="message-nav-tick-button"]:hover
[data-slot="message-nav-tick-line"] {
width: 100%;
background-color: var(--icon-strong-base);
}
[data-slot="message-nav-message-button"] {
display: flex;
align-items: center;
align-self: stretch;
width: 100%;
column-gap: 12px;
cursor: default;
border: none;
background: none;
padding: 4px 12px;
border-radius: var(--radius-sm);
display: flex;
align-items: center;
align-self: stretch;
width: 100%;
column-gap: 12px;
cursor: default;
border: none;
background: none;
padding: 4px 12px;
border-radius: var(--radius-sm);
}
[data-slot="message-nav-title-preview"] {
font-size: 14px; /* text-14-regular */
color: var(--text-base);
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
min-width: 0;
text-align: left;
font-size: 14px; /* text-14-regular */
color: var(--text-base);
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
min-width: 0;
text-align: left;
&[data-active] {
color: var(--text-strong);
}
&[data-active] {
color: var(--text-strong);
}
}
[data-slot="message-nav-item"]:hover [data-slot="message-nav-message-button"] {
background-color: var(--surface-base);
background-color: var(--surface-base);
}
[data-slot="message-nav-item"]:active [data-slot="message-nav-message-button"] {
background-color: var(--surface-base-active);
background-color: var(--surface-base-active);
}
[data-slot="message-nav-item"]:active [data-slot="message-nav-title-preview"] {
color: var(--text-base);
color: var(--text-base);
}
[data-slot="message-nav-tooltip"] {
z-index: 1000;
z-index: 1000;
}
[data-slot="message-nav-tooltip-content"] {
display: flex;
padding: 4px 4px 6px 4px;
justify-content: center;
align-items: center;
border-radius: var(--radius-md);
background: var(--surface-raised-stronger-non-alpha);
max-height: calc(100vh - 6rem);
overflow-y: auto;
display: flex;
padding: 4px 4px 6px 4px;
justify-content: center;
align-items: center;
border-radius: var(--radius-md);
background: var(--surface-raised-stronger-non-alpha);
max-height: calc(100vh - 6rem);
overflow-y: auto;
/* border/shadow-xs/base */
box-shadow:
0 0 0 1px var(--border-weak-base, rgba(17, 0, 0, 0.12)),
0 1px 2px -1px rgba(19, 16, 16, 0.04),
0 1px 2px 0 rgba(19, 16, 16, 0.06),
0 1px 3px 0 rgba(19, 16, 16, 0.08);
/* border/shadow-xs/base */
box-shadow:
0 0 0 1px var(--border-weak-base, rgba(17, 0, 0, 0.12)),
0 1px 2px -1px rgba(19, 16, 16, 0.04),
0 1px 2px 0 rgba(19, 16, 16, 0.06),
0 1px 3px 0 rgba(19, 16, 16, 0.08);
* {
margin: 0 !important;
}
* {
margin: 0 !important;
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -49,6 +49,7 @@ 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 +416,7 @@ export function UserMessageDisplay(props: { message: UserMessage; parts: PartTyp
toggleExpanded()
}}
>
<Icon name="chevron-down" size="small" />
<MorphChevron expanded={expanded()} />
</button>
<div data-slot="user-message-copy-wrapper">
<Tooltip

View File

@@ -0,0 +1,10 @@
[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

@@ -0,0 +1,73 @@
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

@@ -1,98 +1,136 @@
[data-slot="popover-trigger"] {
display: inline-flex;
display: inline-flex;
}
[data-component="popover-content"] {
z-index: 50;
min-width: 200px;
max-width: 320px;
border-radius: var(--radius-md);
background-color: var(--surface-raised-stronger-non-alpha);
z-index: 50;
min-width: 200px;
max-width: 320px;
border-radius: var(--radius-md);
background-color: var(--surface-raised-stronger-non-alpha);
border: 1px solid color-mix(in oklch, var(--border-base) 50%, transparent);
background-clip: padding-box;
box-shadow: var(--shadow-md);
border: 1px solid color-mix(in oklch, var(--border-base) 50%, transparent);
background-clip: padding-box;
box-shadow: var(--shadow-md);
transform-origin: var(--kb-popover-content-transform-origin);
transform-origin: var(--kb-popover-content-transform-origin);
&:focus-within {
outline: none;
}
animation: popoverContentHide var(--transition-duration)
var(--transition-easing) forwards;
&[data-closed] {
animation: popover-close 0.15s ease-out;
}
@starting-style {
animation: none;
}
&[data-expanded] {
animation: popover-open 0.15s ease-out;
}
&[data-expanded] {
pointer-events: auto;
animation: popoverContentShow var(--transition-duration)
var(--transition-easing) forwards;
}
[data-slot="popover-header"] {
display: flex;
padding: 12px;
padding-bottom: 0;
justify-content: space-between;
align-items: center;
gap: 8px;
[data-origin-top-right] {
transform-origin: top right;
}
[data-slot="popover-title"] {
flex: 1;
color: var(--text-strong);
margin: 0;
[data-origin-top-left] {
transform-origin: top left;
}
font-family: var(--font-family-sans);
font-size: var(--font-size-base);
font-style: normal;
font-weight: var(--font-weight-medium);
line-height: var(--line-height-large);
letter-spacing: var(--letter-spacing-normal);
}
[data-origin-bottom-right] {
transform-origin: bottom right;
}
[data-slot="popover-close-button"] {
flex-shrink: 0;
}
}
[data-origin-bottom-left] {
transform-origin: bottom left;
}
[data-slot="popover-description"] {
padding: 0 12px;
margin: 0;
color: var(--text-base);
&:focus-within {
outline: none;
}
font-family: var(--font-family-sans);
font-size: var(--font-size-small);
font-style: normal;
font-weight: var(--font-weight-regular);
line-height: var(--line-height-large);
letter-spacing: var(--letter-spacing-normal);
}
[data-slot="popover-header"] {
display: flex;
padding: 12px;
padding-bottom: 0;
justify-content: space-between;
align-items: center;
gap: 8px;
[data-slot="popover-body"] {
padding: 12px;
}
[data-slot="popover-title"] {
flex: 1;
color: var(--text-strong);
margin: 0;
[data-slot="popover-arrow"] {
fill: var(--surface-raised-stronger-non-alpha);
}
font-family: var(--font-family-sans);
font-size: var(--font-size-base);
font-style: normal;
font-weight: var(--font-weight-medium);
line-height: var(--line-height-large);
letter-spacing: var(--letter-spacing-normal);
}
[data-slot="popover-close-button"] {
flex-shrink: 0;
}
}
[data-slot="popover-description"] {
padding: 0 12px;
margin: 0;
color: var(--text-base);
font-family: var(--font-family-sans);
font-size: var(--font-size-small);
font-style: normal;
font-weight: var(--font-weight-regular);
line-height: var(--line-height-large);
letter-spacing: var(--letter-spacing-normal);
}
[data-slot="popover-body"] {
padding: 12px;
}
[data-slot="popover-arrow"] {
fill: var(--surface-raised-stronger-non-alpha);
}
}
@keyframes popover-open {
from {
opacity: 0;
transform: scale(0.96);
}
to {
opacity: 1;
transform: scale(1);
}
@keyframes popoverContentShow {
from {
opacity: 0;
transform: scaleY(0.95);
}
to {
opacity: 1;
transform: scaleY(1);
}
}
@keyframes popover-close {
from {
opacity: 1;
transform: scale(1);
}
to {
opacity: 0;
transform: scale(0.96);
}
@keyframes popoverContentHide {
from {
opacity: 1;
transform: scaleY(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;
}
}

View File

@@ -1,12 +1,10 @@
[data-component="progress-circle"] {
transform: rotate(-90deg);
color: inherit;
[data-slot="progress-circle-background"] {
stroke: var(--border-weak-base);
}
[data-slot="progress-circle-progress"] {
stroke: var(--border-active);
transition: stroke-dashoffset 0.35s cubic-bezier(0.65, 0, 0.35, 1);
}
[data-slot="progress-circle-background"] {
transform-origin: 50% 50%;
transform: rotate(270deg);
stroke-opacity: 0.5;
transition: stroke-dashoffset 0.35s cubic-bezier(0.65, 0, 0.35, 1);
}
}

View File

@@ -1,4 +1,4 @@
import { type ComponentProps, createMemo, splitProps } from "solid-js"
import { type ComponentProps, splitProps } from "solid-js"
export interface ProgressCircleProps extends Pick<ComponentProps<"svg">, "class" | "classList"> {
percentage: number
@@ -9,26 +9,15 @@ export interface ProgressCircleProps extends Pick<ComponentProps<"svg">, "class"
export function ProgressCircle(props: ProgressCircleProps) {
const [split, rest] = splitProps(props, ["percentage", "size", "strokeWidth", "class", "classList"])
const size = () => split.size || 16
const strokeWidth = () => split.strokeWidth || 3
const viewBoxSize = 16
const center = viewBoxSize / 2
const radius = () => center - strokeWidth() / 2
const circumference = createMemo(() => 2 * Math.PI * radius())
const offset = createMemo(() => {
const clampedPercentage = Math.max(0, Math.min(100, split.percentage || 0))
const progress = clampedPercentage / 100
return circumference() * (1 - progress)
})
const size = () => split.size || 18
const r = 7
return (
<svg
{...rest}
width={size()}
height={size()}
viewBox={`0 0 ${viewBoxSize} ${viewBoxSize}`}
viewBox="0 0 18 18"
fill="none"
data-component="progress-circle"
classList={{
@@ -36,21 +25,18 @@ export function ProgressCircle(props: ProgressCircleProps) {
[split.class ?? ""]: !!split.class,
}}
>
<circle
cx={center}
cy={center}
r={radius()}
data-slot="progress-circle-background"
stroke-width={strokeWidth()}
/>
<circle
cx={center}
cy={center}
r={radius()}
data-slot="progress-circle-progress"
stroke-width={strokeWidth()}
stroke-dasharray={circumference().toString()}
stroke-dashoffset={offset()}
<circle cx="9" cy="9" r="7.75" stroke="currentColor" stroke-width="1.5" />
<path
opacity="0.5"
d={(() => {
const pct = Math.min(100, Math.max(0, split.percentage))
const angle = (pct / 100) * 2 * Math.PI - Math.PI / 2
const x = 9 + r * Math.cos(angle)
const y = 9 + r * Math.sin(angle)
const largeArc = pct > 50 ? 1 : 0
return `M9 2A${r} ${r} 0 ${largeArc} 1 ${x} ${y}L9 9Z`
})()}
fill="currentColor"
/>
</svg>
)

View File

@@ -1,5 +1,5 @@
[data-component="provider-icon"] {
flex-shrink: 0;
width: 16px;
height: 16px;
flex-shrink: 0;
width: 16px;
height: 16px;
}

View File

@@ -1,157 +1,169 @@
[data-component="radio-group"] {
display: flex;
flex-direction: column;
gap: calc(var(--spacing) * 2);
display: flex;
flex-direction: column;
gap: calc(var(--spacing) * 2);
[data-slot="radio-group-wrapper"] {
all: unset;
background-color: var(--surface-base);
border-radius: var(--radius-md);
box-shadow: var(--shadow-xs-border);
margin: 0;
padding: 0;
position: relative;
width: fit-content;
}
[data-slot="radio-group-wrapper"] {
all: unset;
background-color: var(--surface-base);
border-radius: var(--radius-md);
box-shadow: var(--shadow-xs-border);
margin: 0;
padding: 0;
position: relative;
width: fit-content;
}
[data-slot="radio-group-items"] {
display: inline-flex;
list-style: none;
flex-direction: row;
}
[data-slot="radio-group-items"] {
display: inline-flex;
list-style: none;
flex-direction: row;
}
[data-slot="radio-group-indicator"] {
background: var(--button-secondary-base);
border-radius: var(--radius-md);
box-shadow: var(--shadow-xs-border);
content: "";
opacity: var(--indicator-opacity, 1);
position: absolute;
transition:
opacity 300ms ease-in-out,
box-shadow 100ms ease-in-out,
width 150ms ease,
height 150ms ease,
transform 150ms ease;
}
[data-slot="radio-group-indicator"] {
background: var(--button-secondary-base);
border-radius: var(--radius-md);
box-shadow: var(--shadow-xs-border);
content: "";
opacity: var(--indicator-opacity, 1);
position: absolute;
transition-property: opacity, box-shadow, width, height, transform;
transition-duration: var(--transition-duration);
transition-timing-function: var(--transition-easing);
}
[data-slot="radio-group-item"] {
position: relative;
}
[data-slot="radio-group-item"] {
position: relative;
}
/* Separator between items */
[data-slot="radio-group-item"]:not(:first-of-type)::before {
background: var(--border-weak-base);
border-radius: var(--radius-xs);
content: "";
inset: 6px 0;
position: absolute;
transition: opacity 150ms ease;
width: 1px;
transform: translateX(-0.5px);
}
/* Separator between items */
[data-slot="radio-group-item"]:not(:first-of-type)::before {
background: var(--border-weak-base);
border-radius: var(--radius-xs);
content: "";
inset: 6px 0;
position: absolute;
transition-property: opacity;
transition-duration: var(--transition-duration);
transition-timing-function: var(--transition-easing);
width: 1px;
transform: translateX(-0.5px);
}
/* Hide separator when item or previous item is checked */
[data-slot="radio-group-item"]:has([data-slot="radio-group-item-input"][data-checked])::before,
[data-slot="radio-group-item"]:has([data-slot="radio-group-item-input"][data-checked])
+ [data-slot="radio-group-item"]::before {
opacity: 0;
}
/* Hide separator when item or previous item is checked */
[data-slot="radio-group-item"]:has(
[data-slot="radio-group-item-input"][data-checked]
)::before,
[data-slot="radio-group-item"]:has(
[data-slot="radio-group-item-input"][data-checked]
)
+ [data-slot="radio-group-item"]::before {
opacity: 0;
}
[data-slot="radio-group-item-label"] {
color: var(--text-weak);
font-family: var(--font-family-sans);
font-size: var(--font-size-small);
font-weight: var(--font-weight-medium);
border-radius: var(--radius-md);
cursor: pointer;
display: flex;
flex-wrap: nowrap;
gap: calc(var(--spacing) * 1);
line-height: 1;
padding: 6px 12px;
place-content: center;
position: relative;
transition-duration: 150ms;
transition-property: color, opacity;
transition-timing-function: ease-in-out;
user-select: none;
}
[data-slot="radio-group-item-label"] {
color: var(--text-weak);
font-family: var(--font-family-sans);
font-size: var(--font-size-small);
font-weight: var(--font-weight-medium);
border-radius: var(--radius-md);
cursor: pointer;
display: flex;
flex-wrap: nowrap;
gap: calc(var(--spacing) * 1);
line-height: 1;
padding: 6px 12px;
place-content: center;
position: relative;
transition-property: color, opacity;
transition-duration: var(--transition-duration);
transition-timing-function: var(--transition-easing);
user-select: none;
}
[data-slot="radio-group-item-input"] {
all: unset;
}
[data-slot="radio-group-item-input"] {
all: unset;
}
/* Checked state */
[data-slot="radio-group-item-input"][data-checked] + [data-slot="radio-group-item-label"] {
color: var(--text-strong);
}
/* Checked state */
[data-slot="radio-group-item-input"][data-checked]
+ [data-slot="radio-group-item-label"] {
color: var(--text-strong);
}
/* Disabled state */
[data-slot="radio-group-item-input"][data-disabled] + [data-slot="radio-group-item-label"] {
cursor: not-allowed;
opacity: 0.5;
}
/* Disabled state */
[data-slot="radio-group-item-input"][data-disabled]
+ [data-slot="radio-group-item-label"] {
cursor: not-allowed;
opacity: 0.5;
}
/* Hover state for unchecked, enabled items */
[data-slot="radio-group-item-input"]:not([data-checked], [data-disabled]) + [data-slot="radio-group-item-label"] {
cursor: pointer;
user-select: none;
}
/* Hover state for unchecked, enabled items */
[data-slot="radio-group-item-input"]:not([data-checked], [data-disabled])
+ [data-slot="radio-group-item-label"] {
cursor: pointer;
user-select: none;
}
[data-slot="radio-group-item-input"]:not([data-checked], [data-disabled])
+ [data-slot="radio-group-item-label"]:hover {
color: var(--text-base);
}
[data-slot="radio-group-item-input"]:not([data-checked], [data-disabled])
+ [data-slot="radio-group-item-label"]:hover {
color: var(--text-base);
}
[data-slot="radio-group-item-input"]:not([data-checked], [data-disabled])
+ [data-slot="radio-group-item-label"]:active {
opacity: 0.7;
}
[data-slot="radio-group-item-input"]:not([data-checked], [data-disabled])
+ [data-slot="radio-group-item-label"]:active {
opacity: 0.7;
}
/* Focus state */
[data-slot="radio-group-wrapper"]:has([data-slot="radio-group-item-input"]:focus-visible)
[data-slot="radio-group-indicator"] {
box-shadow: var(--shadow-xs-border-focus);
}
/* Focus state */
[data-slot="radio-group-wrapper"]:has(
[data-slot="radio-group-item-input"]:focus-visible
)
[data-slot="radio-group-indicator"] {
box-shadow: var(--shadow-xs-border-focus);
}
/* Hide indicator when nothing is checked */
[data-slot="radio-group-wrapper"]:not(:has([data-slot="radio-group-item-input"][data-checked]))
[data-slot="radio-group-indicator"] {
--indicator-opacity: 0;
}
/* Hide indicator when nothing is checked */
[data-slot="radio-group-wrapper"]:not(
:has([data-slot="radio-group-item-input"][data-checked])
)
[data-slot="radio-group-indicator"] {
--indicator-opacity: 0;
}
/* Vertical orientation */
&[aria-orientation="vertical"] [data-slot="radio-group-items"] {
flex-direction: column;
}
/* Vertical orientation */
&[aria-orientation="vertical"] [data-slot="radio-group-items"] {
flex-direction: column;
}
&[aria-orientation="vertical"] [data-slot="radio-group-item"]:not(:first-of-type)::before {
height: 1px;
width: auto;
inset: 0 6px;
transform: translateY(-0.5px);
}
&[aria-orientation="vertical"]
[data-slot="radio-group-item"]:not(:first-of-type)::before {
height: 1px;
width: auto;
inset: 0 6px;
transform: translateY(-0.5px);
}
/* Small size variant */
&[data-size="small"] {
[data-slot="radio-group-item-label"] {
font-size: 12px;
padding: 4px 8px;
}
/* Small size variant */
&[data-size="small"] {
[data-slot="radio-group-item-label"] {
font-size: 12px;
padding: 4px 8px;
}
[data-slot="radio-group-item"]:not(:first-of-type)::before {
inset: 4px 0;
}
[data-slot="radio-group-item"]:not(:first-of-type)::before {
inset: 4px 0;
}
&[aria-orientation="vertical"] [data-slot="radio-group-item"]:not(:first-of-type)::before {
inset: 0 4px;
}
}
&[aria-orientation="vertical"]
[data-slot="radio-group-item"]:not(:first-of-type)::before {
inset: 0 4px;
}
}
/* Disabled root state */
&[data-disabled] {
opacity: 0.5;
cursor: not-allowed;
}
/* Disabled root state */
&[data-disabled] {
opacity: 0.5;
cursor: not-allowed;
}
}

View File

@@ -0,0 +1,10 @@
[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
);
}
}

View File

@@ -0,0 +1,32 @@
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,58 +1,60 @@
[data-component="resize-handle"] {
position: absolute;
z-index: 10;
position: absolute;
z-index: 10;
&::after {
content: "";
position: absolute;
opacity: 0;
transition: opacity 0.15s ease-in-out;
}
&::after {
content: "";
position: absolute;
opacity: 0;
transition-property: opacity;
transition-duration: var(--transition-duration);
transition-timing-function: var(--transition-easing);
}
&:hover::after,
&:active::after {
opacity: 1;
}
&:hover::after,
&:active::after {
opacity: 1;
}
&[data-direction="horizontal"] {
inset-block: 0;
inset-inline-end: 0;
width: 8px;
transform: translateX(50%);
cursor: col-resize;
&[data-direction="horizontal"] {
inset-block: 0;
inset-inline-end: 0;
width: 8px;
transform: translateX(50%);
cursor: col-resize;
&[data-edge="start"] {
inset-inline-start: 0;
inset-inline-end: auto;
transform: translateX(-50%);
}
&[data-edge="start"] {
inset-inline-start: 0;
inset-inline-end: auto;
transform: translateX(-50%);
}
&::after {
width: 3px;
inset-block: 0;
inset-inline-start: 50%;
transform: translateX(-50%);
}
}
&::after {
width: 3px;
inset-block: 0;
inset-inline-start: 50%;
transform: translateX(-50%);
}
}
&[data-direction="vertical"] {
inset-inline: 0;
inset-block-start: 0;
height: 8px;
transform: translateY(-50%);
cursor: row-resize;
&[data-direction="vertical"] {
inset-inline: 0;
inset-block-start: 0;
height: 8px;
transform: translateY(-50%);
cursor: row-resize;
&[data-edge="end"] {
inset-block-start: auto;
inset-block-end: 0;
transform: translateY(50%);
}
&[data-edge="end"] {
inset-block-start: auto;
inset-block-end: 0;
transform: translateY(50%);
}
&::after {
height: 3px;
inset-inline: 0;
inset-block-start: 50%;
transform: translateY(-50%);
}
}
&::after {
height: 3px;
inset-inline: 0;
inset-block-start: 50%;
transform: translateY(-50%);
}
}
}

View File

@@ -0,0 +1,122 @@
[data-component="scroll-fade"] {
overflow: auto;
overscroll-behavior: contain;
scrollbar-width: none;
box-sizing: border-box;
color: inherit;
font: inherit;
-ms-overflow-style: none;
&::-webkit-scrollbar {
display: none;
}
&[data-direction="horizontal"] {
overflow-x: auto;
overflow-y: hidden;
/* Both fades */
&[data-fade-start][data-fade-end] {
mask-image: linear-gradient(
to right,
transparent,
black var(--scroll-fade-start),
black calc(100% - var(--scroll-fade-end)),
transparent
);
-webkit-mask-image: linear-gradient(
to right,
transparent,
black var(--scroll-fade-start),
black calc(100% - var(--scroll-fade-end)),
transparent
);
}
/* Only start fade */
&[data-fade-start]:not([data-fade-end]) {
mask-image: linear-gradient(
to right,
transparent,
black var(--scroll-fade-start),
black 100%
);
-webkit-mask-image: linear-gradient(
to right,
transparent,
black var(--scroll-fade-start),
black 100%
);
}
/* Only end fade */
&:not([data-fade-start])[data-fade-end] {
mask-image: linear-gradient(
to right,
black 0%,
black calc(100% - var(--scroll-fade-end)),
transparent
);
-webkit-mask-image: linear-gradient(
to right,
black 0%,
black calc(100% - var(--scroll-fade-end)),
transparent
);
}
}
&[data-direction="vertical"] {
overflow-y: auto;
overflow-x: hidden;
&[data-fade-start][data-fade-end] {
mask-image: linear-gradient(
to bottom,
transparent,
black var(--scroll-fade-start),
black calc(100% - var(--scroll-fade-end)),
transparent
);
-webkit-mask-image: linear-gradient(
to bottom,
transparent,
black var(--scroll-fade-start),
black calc(100% - var(--scroll-fade-end)),
transparent
);
}
/* Only start fade */
&[data-fade-start]:not([data-fade-end]) {
mask-image: linear-gradient(
to bottom,
transparent,
black var(--scroll-fade-start),
black 100%
);
-webkit-mask-image: linear-gradient(
to bottom,
transparent,
black var(--scroll-fade-start),
black 100%
);
}
/* Only end fade */
&:not([data-fade-start])[data-fade-end] {
mask-image: linear-gradient(
to bottom,
black 0%,
black calc(100% - var(--scroll-fade-end)),
transparent
);
-webkit-mask-image: linear-gradient(
to bottom,
black 0%,
black calc(100% - var(--scroll-fade-end)),
transparent
);
}
}
}

View File

@@ -0,0 +1,207 @@
import { type JSX, createEffect, createSignal, onCleanup, onMount, splitProps } from "solid-js"
import "./scroll-fade.css"
export interface ScrollFadeProps extends JSX.HTMLAttributes<HTMLDivElement> {
direction?: "horizontal" | "vertical"
fadeStartSize?: number
fadeEndSize?: number
trackTransformSelector?: string
ref?: (el: HTMLDivElement) => void
}
export function ScrollFade(props: ScrollFadeProps) {
const [local, others] = splitProps(props, [
"children",
"direction",
"fadeStartSize",
"fadeEndSize",
"trackTransformSelector",
"class",
"style",
"ref",
])
const direction = () => local.direction ?? "vertical"
const fadeStartSize = () => local.fadeStartSize ?? 20
const fadeEndSize = () => local.fadeEndSize ?? 20
const getTransformOffset = (element: Element): number => {
const style = getComputedStyle(element)
const transform = style.transform
if (!transform || transform === "none") return 0
const match = transform.match(/matrix(?:3d)?\(([^)]+)\)/)
if (!match) return 0
const values = match[1].split(",").map((v) => parseFloat(v.trim()))
const isHorizontal = direction() === "horizontal"
if (transform.startsWith("matrix3d")) {
return isHorizontal ? -(values[12] || 0) : -(values[13] || 0)
} else {
return isHorizontal ? -(values[4] || 0) : -(values[5] || 0)
}
}
let containerRef: HTMLDivElement | undefined
const [fadeStart, setFadeStart] = createSignal(0)
const [fadeEnd, setFadeEnd] = createSignal(0)
const [isScrollable, setIsScrollable] = createSignal(false)
let lastScrollPos = 0
let lastTransformPos = 0
let lastScrollSize = 0
let lastClientSize = 0
const updateFade = () => {
if (!containerRef) return
const isHorizontal = direction() === "horizontal"
const scrollPos = isHorizontal ? containerRef.scrollLeft : containerRef.scrollTop
const scrollSize = isHorizontal ? containerRef.scrollWidth : containerRef.scrollHeight
const clientSize = isHorizontal ? containerRef.clientWidth : containerRef.clientHeight
let transformPos = 0
if (local.trackTransformSelector) {
const transformElement = containerRef.querySelector(local.trackTransformSelector)
if (transformElement) {
transformPos = getTransformOffset(transformElement)
}
}
const effectiveScrollPos = Math.max(scrollPos, transformPos)
if (
effectiveScrollPos === lastScrollPos &&
transformPos === lastTransformPos &&
scrollSize === lastScrollSize &&
clientSize === lastClientSize
) {
return
}
lastScrollPos = effectiveScrollPos
lastTransformPos = transformPos
lastScrollSize = scrollSize
lastClientSize = clientSize
const maxScroll = scrollSize - clientSize
const canScroll = maxScroll > 1
setIsScrollable(canScroll)
if (!canScroll) {
setFadeStart(0)
setFadeEnd(0)
return
}
const progress = maxScroll > 0 ? effectiveScrollPos / maxScroll : 0
const startProgress = Math.min(progress / 0.1, 1)
setFadeStart(startProgress * fadeStartSize())
const endProgress = progress > 0.9 ? (1 - progress) / 0.1 : 1
setFadeEnd(Math.max(0, endProgress) * fadeEndSize())
}
onMount(() => {
if (!containerRef) return
updateFade()
let rafId: number | undefined
let isPolling = false
let pollTimeout: ReturnType<typeof setTimeout> | undefined
const startPolling = () => {
if (isPolling) return
isPolling = true
const pollScroll = () => {
updateFade()
rafId = requestAnimationFrame(pollScroll)
}
rafId = requestAnimationFrame(pollScroll)
}
const stopPolling = () => {
if (!isPolling) return
isPolling = false
if (rafId !== undefined) {
cancelAnimationFrame(rafId)
rafId = undefined
}
}
const schedulePollingStop = () => {
if (pollTimeout !== undefined) clearTimeout(pollTimeout)
pollTimeout = setTimeout(stopPolling, 1000)
}
const onActivity = () => {
updateFade()
if (local.trackTransformSelector) {
startPolling()
schedulePollingStop()
}
}
containerRef.addEventListener("scroll", onActivity, { passive: true })
const resizeObserver = new ResizeObserver(() => {
lastScrollSize = 0
lastClientSize = 0
onActivity()
})
resizeObserver.observe(containerRef)
const mutationObserver = new MutationObserver(() => {
lastScrollSize = 0
lastClientSize = 0
requestAnimationFrame(onActivity)
})
mutationObserver.observe(containerRef, {
childList: true,
subtree: true,
characterData: true,
})
onCleanup(() => {
containerRef?.removeEventListener("scroll", onActivity)
resizeObserver.disconnect()
mutationObserver.disconnect()
stopPolling()
if (pollTimeout !== undefined) clearTimeout(pollTimeout)
})
})
createEffect(() => {
local.children
requestAnimationFrame(updateFade)
})
return (
<div
ref={(el) => {
containerRef = el
local.ref?.(el)
}}
data-component="scroll-fade"
data-direction={direction()}
data-scrollable={isScrollable() || undefined}
data-fade-start={fadeStart() > 0 || undefined}
data-fade-end={fadeEnd() > 0 || undefined}
class={local.class}
style={{
...(typeof local.style === "object" ? local.style : {}),
"--scroll-fade-start": `${fadeStart()}px`,
"--scroll-fade-end": `${fadeEnd()}px`,
}}
{...others}
>
{local.children}
</div>
)
}

View File

@@ -0,0 +1,141 @@
import { type JSX, onCleanup, splitProps } from "solid-js"
import { ScrollFade, type ScrollFadeProps } from './scroll-fade'
const SCROLL_SPEED = 60
const PAUSE_DURATION = 800
type ScrollAnimationState = {
rafId: number | null
startTime: number
running: boolean
}
const startScrollAnimation = (containerEl: HTMLElement): ScrollAnimationState | null => {
containerEl.offsetHeight
const extraWidth = containerEl.scrollWidth - containerEl.clientWidth
if (extraWidth <= 0) {
return null
}
const scrollDuration = (extraWidth / SCROLL_SPEED) * 1000
const totalDuration = PAUSE_DURATION + scrollDuration + PAUSE_DURATION + scrollDuration + PAUSE_DURATION
const state: ScrollAnimationState = {
rafId: null,
startTime: performance.now(),
running: true,
}
const animate = (currentTime: number) => {
if (!state.running) return
const elapsed = currentTime - state.startTime
const progress = (elapsed % totalDuration) / totalDuration
const pausePercent = PAUSE_DURATION / totalDuration
const scrollPercent = scrollDuration / totalDuration
const pauseEnd1 = pausePercent
const scrollEnd1 = pauseEnd1 + scrollPercent
const pauseEnd2 = scrollEnd1 + pausePercent
const scrollEnd2 = pauseEnd2 + scrollPercent
let scrollPos = 0
if (progress < pauseEnd1) {
scrollPos = 0
} else if (progress < scrollEnd1) {
const scrollProgress = (progress - pauseEnd1) / scrollPercent
scrollPos = scrollProgress * extraWidth
} else if (progress < pauseEnd2) {
scrollPos = extraWidth
} else if (progress < scrollEnd2) {
const scrollProgress = (progress - pauseEnd2) / scrollPercent
scrollPos = extraWidth * (1 - scrollProgress)
} else {
scrollPos = 0
}
containerEl.scrollLeft = scrollPos
state.rafId = requestAnimationFrame(animate)
}
state.rafId = requestAnimationFrame(animate)
return state
}
const stopScrollAnimation = (state: ScrollAnimationState | null, containerEl?: HTMLElement) => {
if (state) {
state.running = false
if (state.rafId !== null) {
cancelAnimationFrame(state.rafId)
}
}
if (containerEl) {
containerEl.scrollLeft = 0
}
}
export interface ScrollRevealProps extends Omit<ScrollFadeProps, "direction"> {
hoverDelay?: number
}
export function ScrollReveal(props: ScrollRevealProps) {
const [local, others] = splitProps(props, ["children", "hoverDelay", "ref"])
const hoverDelay = () => local.hoverDelay ?? 300
let containerRef: HTMLDivElement | undefined
let hoverTimeout: ReturnType<typeof setTimeout> | undefined
let scrollAnimationState: ScrollAnimationState | null = null
const handleMouseEnter: JSX.EventHandler<HTMLDivElement, MouseEvent> = () => {
hoverTimeout = setTimeout(() => {
if (!containerRef) return
containerRef.offsetHeight
const isScrollable = containerRef.scrollWidth > containerRef.clientWidth + 1
if (isScrollable) {
stopScrollAnimation(scrollAnimationState, containerRef)
scrollAnimationState = startScrollAnimation(containerRef)
}
}, hoverDelay())
}
const handleMouseLeave: JSX.EventHandler<HTMLDivElement, MouseEvent> = () => {
if (hoverTimeout) {
clearTimeout(hoverTimeout)
hoverTimeout = undefined
}
stopScrollAnimation(scrollAnimationState, containerRef)
scrollAnimationState = null
}
onCleanup(() => {
if (hoverTimeout) {
clearTimeout(hoverTimeout)
}
stopScrollAnimation(scrollAnimationState, containerRef)
})
return (
<ScrollFade
ref={(el) => {
containerRef = el
local.ref?.(el)
}}
fadeStartSize={8}
fadeEndSize={8}
direction="horizontal"
onMouseEnter={handleMouseEnter}
onMouseLeave={handleMouseLeave}
{...others}
>
{local.children}
</ScrollFade>
)
}

View File

@@ -1,202 +1,165 @@
[data-component="select"] {
[data-slot="select-select-trigger"] {
padding: 0 4px 0 8px;
box-shadow: none;
[data-slot="select-select-trigger"] {
display: flex;
padding: 4px 8px !important;
align-items: center;
justify-content: space-between;
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;
text-overflow: ellipsis;
white-space: nowrap;
}
[data-slot="select-select-trigger-icon"] {
width: 16px;
height: 16px;
display: flex;
align-items: center;
justify-content: center;
flex-shrink: 0;
color: var(--text-weak);
transition: transform 0.1s ease-in-out;
}
[data-slot="select-select-trigger-value"] {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
[data-slot="select-select-trigger-icon"] {
width: 16px;
height: 16px;
display: flex;
align-items: center;
justify-content: center;
flex-shrink: 0;
color: var(--icon-base);
}
&[data-expanded] {
&[data-variant="secondary"] {
background-color: var(--button-secondary-hover);
}
&[data-variant="ghost"] {
background-color: var(--surface-raised-base-active);
}
&[data-variant="primary"] {
background-color: var(--icon-strong-active);
}
}
&:not([data-expanded]):focus-visible {
&[data-variant="secondary"] {
background-color: var(--button-secondary-base);
}
&[data-variant="ghost"] {
background-color: var(--surface-raised-base-hover);
}
&[data-variant="primary"] {
background-color: var(--icon-strong-base);
}
}
}
&[data-trigger-style="settings"] {
[data-slot="select-select-trigger"] {
padding: 6px 6px 6px 12px;
box-shadow: none;
border-radius: 6px;
min-width: 160px;
height: 32px;
justify-content: flex-end;
gap: 12px;
background-color: transparent;
[data-slot="select-select-trigger-value"] {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
font-size: var(--font-size-base);
font-weight: var(--font-weight-regular);
}
[data-slot="select-select-trigger-icon"] {
width: 16px;
height: 20px;
display: flex;
align-items: center;
justify-content: center;
flex-shrink: 0;
color: var(--text-weak);
background-color: var(--surface-raised-base);
border-radius: 4px;
transition: transform 0.1s ease-in-out;
}
&[data-slot="select-select-trigger"]:hover:not(:disabled),
&[data-slot="select-select-trigger"][data-expanded],
&[data-slot="select-select-trigger"][data-expanded]:hover:not(:disabled) {
background-color: var(--input-base);
box-shadow: var(--shadow-xs-border-base);
}
&:not([data-expanded]):focus {
background-color: transparent;
box-shadow: none;
}
}
}
&:hover,
&[data-expanded] {
&[data-variant="secondary"] {
background-color: var(--button-secondary-hover);
}
&[data-variant="ghost"] {
background-color: var(--surface-raised-base-active);
}
&[data-variant="primary"] {
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;
}
&[data-variant="primary"] {
background-color: var(--icon-strong-base);
}
}
}
}
[data-component="select-content"] {
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: 60;
min-width: 8rem;
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;
&[data-expanded] {
animation: select-open 0.15s ease-out;
}
animation: selectContentHide var(--transition-duration)
var(--transition-easing) forwards;
[data-slot="select-select-content-list"] {
overflow-y: auto;
max-height: 12rem;
white-space: nowrap;
overflow-x: hidden;
display: flex;
flex-direction: column;
@starting-style {
animation: none;
}
&:focus {
outline: none;
}
&[data-expanded] {
pointer-events: auto;
animation: selectContentShow var(--transition-duration)
var(--transition-easing) forwards;
}
> *:not([role="presentation"]) + *:not([role="presentation"]) {
margin-top: 2px;
}
}
[data-slot="select-select-content-list"] {
overflow-y: auto;
max-height: 12rem;
white-space: nowrap;
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;
gap: 12px;
border-radius: var(--radius-sm);
[data-slot="select-select-item"] {
position: relative;
display: flex;
align-items: center;
padding: 2px 8px;
gap: 12px;
border-radius: 4px;
cursor: default;
/* text-12-medium */
font-family: var(--font-family-sans);
font-size: var(--font-size-base);
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);
/* text-12-medium */
font-family: var(--font-family-sans);
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);
transition-property: background-color, color;
transition-duration: var(--transition-duration);
transition-timing-function: var(--transition-easing);
outline: none;
user-select: none;
color: var(--text-strong);
&:hover {
background-color: var(--surface-raised-base-hover);
}
&[data-disabled] {
background-color: var(--surface-raised-base);
pointer-events: none;
}
[data-slot="select-select-item-indicator"] {
display: flex;
align-items: center;
justify-content: center;
margin-left: auto;
width: 16px;
height: 16px;
color: var(--icon-strong-base);
transition:
background-color 0.2s ease-in-out,
color 0.2s ease-in-out;
outline: none;
user-select: none;
&[data-highlighted] {
background: var(--surface-raised-base-hover);
}
&[data-disabled] {
background-color: var(--surface-raised-base);
pointer-events: none;
}
[data-slot="select-select-item-indicator"] {
display: flex;
align-items: center;
justify-content: center;
margin-left: auto;
width: 16px;
height: 16px;
}
&:focus {
outline: none;
}
&:hover {
background: var(--surface-raised-base-hover);
}
}
svg {
color: var(--icon-strong-base);
}
}
&:focus {
outline: none;
}
&:hover {
background: var(--surface-raised-base-hover);
}
}
}
[data-component="select-content"][data-trigger-style="settings"] {
min-width: 160px;
border-radius: 8px;
padding: 0;
[data-slot="select-select-content-list"] {
padding: 4px;
}
[data-slot="select-select-item"] {
/* text-14-regular */
font-family: var(--font-family-sans);
font-size: var(--font-size-base);
font-style: normal;
font-weight: var(--font-weight-regular);
line-height: var(--line-height-large);
letter-spacing: var(--letter-spacing-normal);
}
@keyframes selectContentShow {
from {
opacity: 0;
transform: scaleY(0.95);
}
to {
opacity: 1;
transform: scaleY(1);
}
}
@keyframes select-open {
from {
opacity: 0;
transform: scale(0.95);
}
to {
opacity: 1;
transform: scale(1);
}
@keyframes selectContentHide {
from {
opacity: 1;
transform: scaleY(1);
}
to {
opacity: 0;
transform: scaleY(0.95);
}
}

View File

@@ -1,8 +1,10 @@
import { Select as Kobalte } from "@kobalte/core/select"
import { createMemo, onCleanup, splitProps, type ComponentProps, type JSX } from "solid-js"
import { createMemo, createSignal, 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
@@ -38,6 +40,8 @@ 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,
@@ -85,7 +89,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={4}
gutter={8}
value={local.current}
options={grouped()}
optionValue={(x) => (local.value ? local.value(x) : (x as string))}
@@ -115,7 +119,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-small" size="small" />
<Icon name="check" size="small" />
</Kobalte.ItemIndicator>
</Kobalte.Item>
)}
@@ -124,6 +128,7 @@ export function Select<T>(props: SelectProps<T> & Omit<ButtonProps, "children">)
stop()
}}
onOpenChange={(open) => {
setIsOpen(open)
local.onOpenChange?.(open)
if (!open) stop()
}}
@@ -149,7 +154,12 @@ export function Select<T>(props: SelectProps<T> & Omit<ButtonProps, "children">)
}}
</Kobalte.Value>
<Kobalte.Icon data-slot="select-select-trigger-icon">
<Icon name={local.triggerVariant === "settings" ? "selector" : "chevron-down"} size="small" />
<Show when={local.triggerVariant === "settings"}>
<Icon name="selector" size="small" />
</Show>
<Show when={local.triggerVariant !== "settings"}>
<MorphChevron expanded={isOpen()} />
</Show>
</Kobalte.Icon>
</Kobalte.Trigger>
<Kobalte.Portal>

View File

@@ -1,217 +1,216 @@
[data-component="session-review"] {
display: flex;
flex-direction: column;
gap: 8px;
height: 100%;
overflow-y: auto;
scrollbar-width: none;
contain: strict;
&::-webkit-scrollbar {
display: none;
}
display: flex;
flex-direction: column;
gap: 8px;
height: 100%;
overflow-y: auto;
scrollbar-width: none;
contain: strict;
&::-webkit-scrollbar {
display: none;
}
/* [data-slot="session-review-container"] { */
/* height: 100%; */
/* } */
/* [data-slot="session-review-container"] { */
/* height: 100%; */
/* } */
[data-slot="session-review-header"] {
position: sticky;
top: 0;
z-index: 20;
background-color: var(--background-stronger);
height: 32px;
flex-shrink: 0;
display: flex;
justify-content: space-between;
align-items: center;
align-self: stretch;
}
[data-slot="session-review-header"] {
position: sticky;
top: 0;
z-index: 20;
background-color: var(--background-stronger);
height: 32px;
flex-shrink: 0;
display: flex;
justify-content: space-between;
align-items: center;
align-self: stretch;
}
[data-slot="session-review-title"] {
font-family: var(--font-family-sans);
font-size: var(--font-size-large);
font-weight: var(--font-weight-medium);
line-height: var(--line-height-large);
color: var(--text-strong);
}
[data-slot="session-review-title"] {
font-family: var(--font-family-sans);
font-size: var(--font-size-large);
font-weight: var(--font-weight-medium);
line-height: var(--line-height-large);
color: var(--text-strong);
}
[data-slot="session-review-actions"] {
display: flex;
align-items: center;
column-gap: 16px;
padding-right: 1px;
}
[data-slot="session-review-actions"] {
display: flex;
align-items: center;
column-gap: 16px;
padding-right: 1px;
}
[data-component="sticky-accordion-header"] {
top: 40px;
[data-component="sticky-accordion-header"] {
top: 40px;
&[data-expanded]::before {
top: -40px;
}
}
&[data-expanded]::before {
top: -40px;
}
}
[data-slot="accordion-trigger"] {
background-color: var(--background-stronger) !important;
}
[data-slot="accordion-trigger"] {
background-color: var(--background-stronger) !important;
}
[data-slot="session-review-accordion-item"][data-selected] {
[data-slot="session-review-accordion-content"] {
box-shadow: var(--shadow-xs-border-select);
border-radius: var(--radius-lg);
}
}
[data-slot="session-review-accordion-item"][data-selected] {
[data-slot="session-review-accordion-content"] {
box-shadow: var(--shadow-xs-border-select);
border-radius: var(--radius-lg);
}
}
[data-slot="accordion-item"] {
[data-slot="accordion-content"] {
display: none;
}
&[data-expanded] {
[data-slot="accordion-content"] {
display: block;
}
}
}
[data-slot="accordion-item"] {
[data-slot="accordion-content"] {
/* Use grid-template-rows for smooth height transition */
display: grid;
}
}
[data-slot="accordion-content"] {
-webkit-user-select: text;
user-select: text;
}
[data-slot="accordion-content"] {
-webkit-user-select: text;
user-select: text;
}
[data-slot="session-review-accordion-content"] {
position: relative;
overflow: hidden;
}
[data-slot="session-review-accordion-content"] {
position: relative;
overflow: hidden;
}
[data-slot="session-review-trigger-content"] {
display: flex;
align-items: center;
justify-content: space-between;
width: 100%;
gap: 20px;
}
[data-slot="session-review-trigger-content"] {
display: flex;
align-items: center;
justify-content: space-between;
width: 100%;
gap: 20px;
}
[data-slot="session-review-file-info"] {
flex-grow: 1;
display: flex;
align-items: center;
gap: 20px;
min-width: 0;
}
[data-slot="session-review-file-info"] {
flex-grow: 1;
display: flex;
align-items: center;
gap: 20px;
min-width: 0;
}
[data-slot="session-review-file-name-container"] {
display: flex;
flex-grow: 1;
min-width: 0;
}
[data-slot="session-review-file-name-container"] {
display: flex;
flex-grow: 1;
min-width: 0;
}
[data-slot="session-review-directory"] {
color: var(--text-base);
text-overflow: ellipsis;
overflow: hidden;
white-space: nowrap;
direction: rtl;
text-align: left;
}
[data-slot="session-review-directory"] {
color: var(--text-base);
text-overflow: ellipsis;
overflow: hidden;
white-space: nowrap;
direction: rtl;
text-align: left;
}
[data-slot="session-review-filename"] {
color: var(--text-strong);
flex-shrink: 0;
}
[data-slot="session-review-filename"] {
color: var(--text-strong);
flex-shrink: 0;
}
[data-slot="session-review-view-button"] {
display: flex;
align-items: center;
justify-content: center;
padding: 2px;
margin-left: 8px;
border: none;
background: transparent;
color: var(--text-base);
cursor: pointer;
border-radius: 4px;
opacity: 0;
transition: opacity 0.15s ease;
[data-slot="session-review-view-button"] {
display: flex;
align-items: center;
justify-content: center;
padding: 2px;
margin-left: 8px;
border: none;
background: transparent;
color: var(--text-base);
cursor: pointer;
border-radius: 4px;
opacity: 0;
transition-property: opacity, background-color, color;
transition-duration: var(--transition-duration);
transition-timing-function: var(--transition-easing);
&:hover {
color: var(--text-strong);
background: var(--surface-base);
}
}
&:hover {
color: var(--text-strong);
background: var(--surface-base);
}
}
[data-slot="accordion-trigger"]:hover [data-slot="session-review-view-button"] {
opacity: 1;
}
[data-slot="accordion-trigger"]:hover
[data-slot="session-review-view-button"] {
opacity: 1;
}
[data-slot="session-review-trigger-actions"] {
flex-shrink: 0;
display: flex;
gap: 16px;
align-items: center;
justify-content: flex-end;
}
[data-slot="session-review-trigger-actions"] {
flex-shrink: 0;
display: flex;
gap: 16px;
align-items: center;
justify-content: flex-end;
}
[data-slot="session-review-change"] {
font-family: var(--font-family-sans);
font-size: var(--font-size-small);
font-weight: var(--font-weight-medium);
}
[data-slot="session-review-change"] {
font-family: var(--font-family-sans);
font-size: var(--font-size-small);
font-weight: var(--font-weight-medium);
}
[data-slot="session-review-change"][data-type="added"] {
color: var(--icon-diff-add-base);
}
[data-slot="session-review-change"][data-type="added"] {
color: var(--icon-diff-add-base);
}
[data-slot="session-review-change"][data-type="removed"] {
color: var(--icon-diff-delete-base);
}
[data-slot="session-review-change"][data-type="removed"] {
color: var(--icon-diff-delete-base);
}
[data-slot="session-review-file-container"] {
padding: 0;
}
[data-slot="session-review-file-container"] {
padding: 0;
}
[data-slot="session-review-image-container"] {
padding: 12px;
display: flex;
justify-content: center;
background: var(--background-stronger);
}
[data-slot="session-review-image-container"] {
padding: 12px;
display: flex;
justify-content: center;
background: var(--background-stronger);
}
[data-slot="session-review-image"] {
max-width: 100%;
max-height: 60vh;
object-fit: contain;
border-radius: 8px;
border: 1px solid var(--border-weak-base);
background: var(--background-base);
}
[data-slot="session-review-image"] {
max-width: 100%;
max-height: 60vh;
object-fit: contain;
border-radius: 8px;
border: 1px solid var(--border-weak-base);
background: var(--background-base);
}
[data-slot="session-review-image-placeholder"] {
font-family: var(--font-family-sans);
font-size: var(--font-size-small);
color: var(--text-weak);
}
[data-slot="session-review-image-placeholder"] {
font-family: var(--font-family-sans);
font-size: var(--font-size-small);
color: var(--text-weak);
}
[data-slot="session-review-audio-container"] {
padding: 12px;
display: flex;
justify-content: center;
background: var(--background-stronger);
}
[data-slot="session-review-audio-container"] {
padding: 12px;
display: flex;
justify-content: center;
background: var(--background-stronger);
}
[data-slot="session-review-audio"] {
width: 100%;
max-width: 560px;
}
[data-slot="session-review-audio"] {
width: 100%;
max-width: 560px;
}
[data-slot="session-review-audio-placeholder"] {
font-family: var(--font-family-sans);
font-size: var(--font-size-small);
color: var(--text-weak);
}
[data-slot="session-review-audio-placeholder"] {
font-family: var(--font-family-sans);
font-size: var(--font-size-small);
color: var(--text-weak);
}
[data-slot="session-review-diff-wrapper"] {
position: relative;
overflow: hidden;
--line-comment-z: 5;
--line-comment-popover-z: 30;
}
[data-slot="session-review-diff-wrapper"] {
position: relative;
overflow: hidden;
--line-comment-z: 5;
--line-comment-popover-z: 30;
}
}

View File

@@ -290,8 +290,8 @@ export const SessionReview = (props: SessionReviewProps) => {
<div data-slot="session-review-title">{i18n.t("ui.sessionReview.title")}</div>
<div data-slot="session-review-actions">
<Show when={props.onDiffStyleChange}>
<RadioGroup
options={["unified", "split"] as const}
<RadioGroup<SessionReviewDiffStyle>
options={["unified", "split"]}
current={diffStyle()}
value={(style) => style}
label={(style) =>
@@ -501,6 +501,7 @@ export const SessionReview = (props: SessionReviewProps) => {
value={diff.file}
id={diffId(diff.file)}
data-file={diff.file}
expanded={open().includes(diff.file)}
data-slot="session-review-accordion-item"
data-selected={props.focusedFile === diff.file ? "" : undefined}
>

File diff suppressed because it is too large Load Diff

View File

@@ -553,7 +553,7 @@ export function SessionTurn(
data-slot="session-turn-collapsible-trigger-content"
variant="ghost"
size="small"
onClick={props.onStepsExpandedToggle ?? (() => {})}
onClick={props.onStepsExpandedToggle ?? (() => { })}
aria-expanded={props.stepsExpanded}
>
<Switch>

View File

@@ -1,6 +1,6 @@
[data-component="spinner"] {
color: inherit;
flex-shrink: 0;
width: 18px;
aspect-ratio: 1;
color: inherit;
flex-shrink: 0;
width: 18px;
aspect-ratio: 1;
}

View File

@@ -1,16 +1,16 @@
[data-component="sticky-accordion-header"] {
position: sticky;
top: 0px;
position: sticky;
top: 0px;
&[data-expanded] {
z-index: 10;
&[data-expanded] {
z-index: 10;
&::before {
content: "";
z-index: -10;
position: absolute;
inset: 0;
background-color: var(--background-stronger);
}
}
&::before {
content: "";
z-index: -10;
position: absolute;
inset: 0;
background-color: var(--background-stronger);
}
}
}

View File

@@ -1,132 +1,133 @@
[data-component="switch"] {
position: relative;
display: flex;
align-items: center;
gap: 8px;
cursor: default;
position: relative;
display: flex;
align-items: center;
gap: 8px;
cursor: default;
[data-slot="switch-input"] {
position: absolute;
width: 1px;
height: 1px;
padding: 0;
margin: -1px;
overflow: hidden;
clip: rect(0, 0, 0, 0);
white-space: nowrap;
border-width: 0;
}
[data-slot="switch-input"] {
position: absolute;
width: 1px;
height: 1px;
padding: 0;
margin: -1px;
overflow: hidden;
clip: rect(0, 0, 0, 0);
white-space: nowrap;
border-width: 0;
}
[data-slot="switch-control"] {
display: inline-flex;
align-items: center;
width: 28px;
height: 16px;
flex-shrink: 0;
border-radius: 3px;
border: 1px solid var(--border-weak-base);
background: var(--surface-base);
transition:
background-color 150ms,
border-color 150ms;
}
[data-slot="switch-control"] {
display: inline-flex;
align-items: center;
width: 28px;
height: 16px;
flex-shrink: 0;
border-radius: 3px;
border: 1px solid var(--border-weak-base);
background: var(--surface-base);
transition-property: background-color, border-color, box-shadow;
transition-duration: var(--transition-duration);
transition-timing-function: var(--transition-easing);
}
[data-slot="switch-thumb"] {
width: 14px;
height: 14px;
box-sizing: content-box;
[data-slot="switch-thumb"] {
width: 14px;
height: 14px;
box-sizing: content-box;
border-radius: 2px;
border: 1px solid var(--border-base);
background: var(--icon-invert-base);
border-radius: 2px;
border: 1px solid var(--border-base);
background: var(--icon-invert-base);
/* shadows/shadow-xs */
box-shadow:
0 1px 2px -1px rgba(19, 16, 16, 0.04),
0 1px 2px 0 rgba(19, 16, 16, 0.06),
0 1px 3px 0 rgba(19, 16, 16, 0.08);
/* shadows/shadow-xs */
box-shadow:
0 1px 2px -1px rgba(19, 16, 16, 0.04),
0 1px 2px 0 rgba(19, 16, 16, 0.06),
0 1px 3px 0 rgba(19, 16, 16, 0.08);
transform: translateX(-1px);
transition:
transform 150ms,
background-color 150ms;
}
transform: translateX(-1px);
transition-property: transform, background-color, border-color;
transition-duration: var(--transition-duration);
transition-timing-function: var(--transition-easing);
}
[data-slot="switch-label"] {
user-select: none;
color: var(--text-base);
font-family: var(--font-family-sans);
font-size: var(--font-size-small);
font-style: normal;
font-weight: var(--font-weight-regular);
line-height: var(--line-height-large);
letter-spacing: var(--letter-spacing-normal);
}
[data-slot="switch-label"] {
user-select: none;
color: var(--text-base);
font-family: var(--font-family-sans);
font-size: var(--font-size-small);
font-style: normal;
font-weight: var(--font-weight-regular);
line-height: var(--line-height-large);
letter-spacing: var(--letter-spacing-normal);
}
[data-slot="switch-description"] {
color: var(--text-base);
font-family: var(--font-family-sans);
font-size: 12px;
font-weight: var(--font-weight-regular);
line-height: var(--line-height-normal);
letter-spacing: var(--letter-spacing-normal);
}
[data-slot="switch-description"] {
color: var(--text-base);
font-family: var(--font-family-sans);
font-size: 12px;
font-weight: var(--font-weight-regular);
line-height: var(--line-height-normal);
letter-spacing: var(--letter-spacing-normal);
}
[data-slot="switch-error"] {
color: var(--text-error);
font-family: var(--font-family-sans);
font-size: 12px;
font-weight: var(--font-weight-regular);
line-height: var(--line-height-normal);
letter-spacing: var(--letter-spacing-normal);
}
[data-slot="switch-error"] {
color: var(--text-error);
font-family: var(--font-family-sans);
font-size: 12px;
font-weight: var(--font-weight-regular);
line-height: var(--line-height-normal);
letter-spacing: var(--letter-spacing-normal);
}
&:hover:not([data-disabled], [data-readonly]) [data-slot="switch-control"] {
border-color: var(--border-hover);
background-color: var(--surface-hover);
}
&:hover:not([data-disabled], [data-readonly]) [data-slot="switch-control"] {
border-color: var(--border-hover);
background-color: var(--surface-hover);
}
&:focus-within:not([data-readonly]) [data-slot="switch-control"] {
border-color: var(--border-focus);
box-shadow: 0 0 0 2px var(--surface-focus);
}
&:focus-within:not([data-readonly]) [data-slot="switch-control"] {
border-color: var(--border-focus);
box-shadow: 0 0 0 2px var(--surface-focus);
}
&[data-checked] [data-slot="switch-control"] {
box-sizing: border-box;
border-color: var(--icon-strong-base);
background-color: var(--icon-strong-base);
}
&[data-checked] [data-slot="switch-control"] {
box-sizing: border-box;
border-color: var(--icon-strong-base);
background-color: var(--icon-strong-base);
}
&[data-checked] [data-slot="switch-thumb"] {
border: none;
transform: translateX(12px);
background-color: var(--icon-invert-base);
}
&[data-checked] [data-slot="switch-thumb"] {
border: none;
transform: translateX(12px);
background-color: var(--icon-invert-base);
}
&[data-checked]:hover:not([data-disabled], [data-readonly]) [data-slot="switch-control"] {
border-color: var(--border-hover);
background-color: var(--surface-hover);
}
&[data-checked]:hover:not([data-disabled], [data-readonly])
[data-slot="switch-control"] {
border-color: var(--border-hover);
background-color: var(--surface-hover);
}
&[data-disabled] {
cursor: not-allowed;
}
&[data-disabled] {
cursor: not-allowed;
}
&[data-disabled] [data-slot="switch-control"] {
border-color: var(--border-disabled);
background-color: var(--surface-disabled);
}
&[data-disabled] [data-slot="switch-control"] {
border-color: var(--border-disabled);
background-color: var(--surface-disabled);
}
&[data-disabled] [data-slot="switch-thumb"] {
background-color: var(--icon-disabled);
}
&[data-disabled] [data-slot="switch-thumb"] {
background-color: var(--icon-disabled);
}
&[data-invalid] [data-slot="switch-control"] {
border-color: var(--border-error);
}
&[data-invalid] [data-slot="switch-control"] {
border-color: var(--border-error);
}
&[data-readonly] {
cursor: default;
pointer-events: none;
}
&[data-readonly] {
cursor: default;
pointer-events: none;
}
}

View File

@@ -1,451 +1,454 @@
[data-component="tabs"] {
width: 100%;
height: 100%;
display: flex;
flex-direction: column;
background-color: var(--background-stronger);
overflow: clip;
[data-slot="tabs-list"] {
height: 48px;
width: 100%;
position: relative;
display: flex;
align-items: center;
overflow-x: auto;
/* Hide scrollbar */
scrollbar-width: none;
-ms-overflow-style: none;
&::-webkit-scrollbar {
display: none;
}
/* After element to fill remaining space */
&::after {
content: "";
display: block;
flex-grow: 1;
height: 100%;
border-bottom: 1px solid var(--border-weak-base);
background-color: var(--background-base);
}
&:empty::after {
display: none;
}
}
[data-slot="tabs-trigger-wrapper"] {
position: relative;
height: 100%;
display: flex;
align-items: center;
gap: 12px;
color: var(--text-base);
/* text-14-medium */
font-family: var(--font-family-sans);
font-size: 14px;
font-style: normal;
font-weight: var(--font-weight-medium);
line-height: var(--line-height-large); /* 142.857% */
letter-spacing: var(--letter-spacing-normal);
white-space: nowrap;
flex-shrink: 0;
max-width: 280px;
border-bottom: 1px solid var(--border-weak-base);
border-right: 1px solid var(--border-weak-base);
background-color: var(--background-base);
[data-slot="tabs-trigger"] {
display: flex;
align-items: center;
justify-content: center;
padding: 14px 24px 14px 12px;
outline: none;
min-width: 0;
overflow: hidden;
text-overflow: ellipsis;
&:focus-visible {
outline: none;
box-shadow: none;
}
}
[data-slot="tabs-trigger-close-button"] {
display: flex;
align-items: center;
justify-content: center;
}
[data-component="icon-button"] {
margin: -0.25rem;
}
&:disabled {
pointer-events: none;
color: var(--text-weaker);
}
&:focus-visible {
outline: none;
box-shadow: none;
}
&:has([data-hidden]) {
[data-slot="tabs-trigger-close-button"] {
opacity: 0;
}
&:hover {
[data-slot="tabs-trigger-close-button"] {
opacity: 1;
}
}
}
&:has([data-selected]) {
color: var(--text-strong);
background-color: transparent;
border-bottom-color: transparent;
[data-slot="tabs-trigger-close-button"] {
opacity: 1;
}
}
&:hover:not(:disabled):not([data-selected]) {
color: var(--text-strong);
}
&:has([data-slot="tabs-trigger-close-button"]) {
padding-right: 12px;
[data-slot="tabs-trigger"] {
padding-right: 0;
}
}
}
[data-slot="tabs-content"] {
overflow-y: auto;
flex: 1;
/* Hide scrollbar */
scrollbar-width: none;
-ms-overflow-style: none;
&::-webkit-scrollbar {
display: none;
}
&:focus-visible {
outline: none;
}
}
&[data-variant="alt"] {
[data-slot="tabs-list"] {
padding-left: 24px;
padding-right: 24px;
gap: 12px;
border-bottom: 1px solid var(--border-weak-base);
background-color: transparent;
&::after {
border: none;
background-color: transparent;
}
&:empty::after {
display: none;
}
}
[data-slot="tabs-trigger-wrapper"] {
border: none;
color: var(--text-base);
background-color: transparent;
border-bottom-width: 2px;
border-bottom-style: solid;
border-bottom-color: transparent;
gap: 4px;
/* text-14-regular */
font-family: var(--font-family-sans);
font-size: var(--font-size-base);
font-style: normal;
font-weight: var(--font-weight-regular);
line-height: var(--line-height-x-large); /* 171.429% */
letter-spacing: var(--letter-spacing-normal);
[data-slot="tabs-trigger"] {
height: 100%;
padding: 4px;
background-color: transparent;
border-bottom-width: 2px;
border-bottom-color: transparent;
}
[data-slot="tabs-trigger-close-button"] {
display: flex;
align-items: center;
justify-content: center;
}
[data-component="icon-button"] {
width: 16px;
height: 16px;
margin: 0;
}
&:has([data-selected]) {
color: var(--text-strong);
background-color: transparent;
border-bottom-color: var(--icon-strong-base);
}
&:hover:not(:disabled):not([data-selected]) {
color: var(--text-strong);
}
&:has([data-slot="tabs-trigger-close-button"]) {
padding-right: 0;
[data-slot="tabs-trigger"] {
padding-right: 0;
}
}
}
/* [data-slot="tabs-content"] { */
/* } */
}
&[data-variant="pill"][data-orientation="horizontal"] {
background-color: transparent;
[data-slot="tabs-list"] {
height: auto;
padding: 6px 0;
gap: 4px;
background-color: var(--background-base);
&::after {
display: none;
}
}
[data-slot="tabs-trigger-wrapper"] {
height: 32px;
border: none;
border-radius: var(--radius-sm);
background-color: transparent;
gap: 0;
/* text-13-medium */
font-family: var(--font-family-sans);
font-size: var(--font-size-small);
font-style: normal;
font-weight: var(--font-weight-medium);
line-height: var(--line-height-large);
letter-spacing: var(--letter-spacing-normal);
[data-slot="tabs-trigger"] {
height: 100%;
width: 100%;
padding: 0 12px;
background-color: transparent;
}
&:hover:not(:disabled) {
background-color: var(--surface-raised-base-hover);
color: var(--text-strong);
}
&:has([data-selected]) {
background-color: var(--surface-raised-base-active);
color: var(--text-strong);
&:hover:not(:disabled) {
background-color: var(--surface-raised-base-active);
}
}
}
}
&[data-variant="pill"][data-orientation="horizontal"][data-scope="filetree"] {
[data-slot="tabs-list"] {
height: 48px;
padding-inline: 12px;
gap: 8px;
align-items: center;
}
[data-slot="tabs-trigger-wrapper"] {
height: 26px;
border-radius: 6px;
color: var(--text-weak);
&:not(:has([data-selected])):hover:not(:disabled) {
color: var(--text-base);
}
&:has([data-selected]) {
color: var(--text-strong);
}
}
}
&[data-orientation="vertical"] {
flex-direction: row;
[data-slot="tabs-list"] {
flex-direction: column;
width: auto;
height: 100%;
overflow-x: hidden;
overflow-y: auto;
padding: 8px;
gap: 4px;
background-color: var(--background-base);
border-right: 1px solid var(--border-weak-base);
&::after {
display: none;
}
}
[data-slot="tabs-trigger-wrapper"] {
width: 100%;
height: 32px;
border: none;
border-radius: 8px;
background-color: transparent;
[data-slot="tabs-trigger"] {
height: 100%;
padding: 0 8px;
gap: 8px;
justify-content: flex-start;
}
&:hover:not(:disabled) {
background-color: var(--surface-raised-base-hover);
}
&:has([data-selected]) {
background-color: var(--surface-raised-base-active);
color: var(--text-strong);
}
}
[data-slot="tabs-content"] {
overflow-x: auto;
overflow-y: auto;
}
&[data-variant="alt"] {
[data-slot="tabs-list"] {
padding: 8px;
gap: 4px;
border: none;
&::after {
display: none;
}
}
[data-slot="tabs-trigger-wrapper"] {
height: 32px;
border: none;
border-radius: 8px;
[data-slot="tabs-trigger"] {
border: none;
padding: 0 8px;
gap: 8px;
justify-content: flex-start;
}
&:hover:not(:disabled) {
background-color: var(--surface-raised-base-hover);
}
&:has([data-selected]) {
background-color: var(--surface-raised-base-hover);
color: var(--text-strong);
}
}
}
&[data-variant="settings"] {
[data-slot="tabs-list"] {
width: 150px;
min-width: 150px;
@media (min-width: 640px) {
width: 200px;
min-width: 200px;
}
padding: 12px;
gap: 0;
background-color: var(--background-base);
border-right: 1px solid var(--border-weak-base);
&::after {
display: none;
}
}
[data-slot="tabs-section-title"] {
width: 100%;
padding: 0 0 0 4px;
font-family: var(--font-family-sans);
font-size: var(--font-size-small);
font-weight: var(--font-weight-medium);
color: var(--text-weak);
}
[data-slot="tabs-trigger-wrapper"] {
height: 32px;
border: none;
border-radius: var(--radius-md);
/* text-14-medium */
font-family: var(--font-family-sans);
font-size: var(--font-size-base);
font-weight: var(--font-weight-medium);
line-height: var(--line-height-large);
[data-slot="tabs-trigger"] {
border: none;
padding: 0 8px;
gap: 12px;
justify-content: flex-start;
width: 100%;
height: 100%;
}
[data-component="icon"] {
color: var(--icon-base);
}
&:hover:not(:disabled) {
background-color: var(--surface-raised-base-hover);
}
&:has([data-selected]) {
background-color: var(--surface-raised-base-active);
color: var(--text-strong);
[data-component="icon"] {
color: var(--icon-strong-base);
}
&:hover:not(:disabled) {
background-color: var(--surface-raised-base-active);
}
}
}
[data-slot="tabs-content"] {
background-color: var(--surface-raised-stronger-non-alpha);
}
}
}
width: 100%;
height: 100%;
display: flex;
flex-direction: column;
background-color: var(--background-stronger);
overflow: clip;
[data-slot="tabs-list"] {
height: 48px;
width: 100%;
position: relative;
display: flex;
align-items: center;
overflow-x: auto;
/* Hide scrollbar */
scrollbar-width: none;
-ms-overflow-style: none;
&::-webkit-scrollbar {
display: none;
}
/* After element to fill remaining space */
&::after {
content: "";
display: block;
flex-grow: 1;
height: 100%;
border-bottom: 1px solid var(--border-weak-base);
background-color: var(--background-base);
}
&:empty::after {
display: none;
}
}
[data-slot="tabs-trigger-wrapper"] {
position: relative;
height: 100%;
display: flex;
align-items: center;
gap: 12px;
color: var(--text-base);
/* text-14-medium */
font-family: var(--font-family-sans);
font-size: 14px;
font-style: normal;
font-weight: var(--font-weight-medium);
line-height: var(--line-height-large); /* 142.857% */
letter-spacing: var(--letter-spacing-normal);
white-space: nowrap;
flex-shrink: 0;
max-width: 280px;
border-bottom: 1px solid var(--border-weak-base);
border-right: 1px solid var(--border-weak-base);
background-color: var(--background-base);
transition-property: background-color, border-color, color;
transition-duration: var(--transition-duration);
transition-timing-function: var(--transition-easing);
[data-slot="tabs-trigger"] {
display: flex;
align-items: center;
justify-content: center;
padding: 14px 24px 14px 12px;
outline: none;
min-width: 0;
overflow: hidden;
text-overflow: ellipsis;
&:focus-visible {
outline: none;
box-shadow: none;
}
}
[data-slot="tabs-trigger-close-button"] {
display: flex;
align-items: center;
justify-content: center;
}
[data-component="icon-button"] {
margin: -0.25rem;
}
&:disabled {
pointer-events: none;
color: var(--text-weaker);
}
&:focus-visible {
outline: none;
box-shadow: none;
}
&:has([data-hidden]) {
[data-slot="tabs-trigger-close-button"] {
opacity: 0;
}
&:hover {
[data-slot="tabs-trigger-close-button"] {
opacity: 1;
}
}
}
&:has([data-selected]) {
color: var(--text-strong);
background-color: transparent;
border-bottom-color: transparent;
[data-slot="tabs-trigger-close-button"] {
opacity: 1;
}
}
&:hover:not(:disabled):not([data-selected]) {
color: var(--text-strong);
}
&:has([data-slot="tabs-trigger-close-button"]) {
padding-right: 12px;
[data-slot="tabs-trigger"] {
padding-right: 0;
}
}
}
[data-slot="tabs-content"] {
overflow-y: auto;
flex: 1;
/* Hide scrollbar */
scrollbar-width: none;
-ms-overflow-style: none;
&::-webkit-scrollbar {
display: none;
}
&:focus-visible {
outline: none;
}
}
&[data-variant="alt"] {
[data-slot="tabs-list"] {
padding-left: 24px;
padding-right: 24px;
gap: 12px;
border-bottom: 1px solid var(--border-weak-base);
background-color: transparent;
&::after {
border: none;
background-color: transparent;
}
&:empty::after {
display: none;
}
}
[data-slot="tabs-trigger-wrapper"] {
border: none;
color: var(--text-base);
background-color: transparent;
border-bottom-width: 2px;
border-bottom-style: solid;
border-bottom-color: transparent;
gap: 4px;
/* text-14-regular */
font-family: var(--font-family-sans);
font-size: var(--font-size-base);
font-style: normal;
font-weight: var(--font-weight-regular);
line-height: var(--line-height-x-large); /* 171.429% */
letter-spacing: var(--letter-spacing-normal);
[data-slot="tabs-trigger"] {
height: 100%;
padding: 4px;
background-color: transparent;
border-bottom-width: 2px;
border-bottom-color: transparent;
}
[data-slot="tabs-trigger-close-button"] {
display: flex;
align-items: center;
justify-content: center;
}
[data-component="icon-button"] {
width: 16px;
height: 16px;
margin: 0;
}
&:has([data-selected]) {
color: var(--text-strong);
background-color: transparent;
border-bottom-color: var(--icon-strong-base);
}
&:hover:not(:disabled):not([data-selected]) {
color: var(--text-strong);
}
&:has([data-slot="tabs-trigger-close-button"]) {
padding-right: 0;
[data-slot="tabs-trigger"] {
padding-right: 0;
}
}
}
/* [data-slot="tabs-content"] { */
/* } */
}
&[data-variant="pill"][data-orientation="horizontal"] {
background-color: transparent;
[data-slot="tabs-list"] {
height: auto;
padding: 6px 0;
gap: 4px;
background-color: var(--background-base);
&::after {
display: none;
}
}
[data-slot="tabs-trigger-wrapper"] {
height: 32px;
border: none;
border-radius: var(--radius-sm);
background-color: transparent;
gap: 0;
/* text-13-medium */
font-family: var(--font-family-sans);
font-size: var(--font-size-small);
font-style: normal;
font-weight: var(--font-weight-medium);
line-height: var(--line-height-large);
letter-spacing: var(--letter-spacing-normal);
[data-slot="tabs-trigger"] {
height: 100%;
width: 100%;
padding: 0 12px;
background-color: transparent;
}
&:hover:not(:disabled) {
background-color: var(--surface-raised-base-hover);
color: var(--text-strong);
}
&:has([data-selected]) {
background-color: var(--surface-raised-base-active);
color: var(--text-strong);
&:hover:not(:disabled) {
background-color: var(--surface-raised-base-active);
}
}
}
}
&[data-variant="pill"][data-orientation="horizontal"][data-scope="filetree"] {
[data-slot="tabs-list"] {
height: 48px;
padding-inline: 12px;
gap: 8px;
align-items: center;
}
[data-slot="tabs-trigger-wrapper"] {
height: 26px;
border-radius: 6px;
color: var(--text-weak);
&:not(:has([data-selected])):hover:not(:disabled) {
color: var(--text-base);
}
&:has([data-selected]) {
color: var(--text-strong);
}
}
}
&[data-orientation="vertical"] {
flex-direction: row;
[data-slot="tabs-list"] {
flex-direction: column;
width: auto;
height: 100%;
overflow-x: hidden;
overflow-y: auto;
padding: 8px;
gap: 4px;
background-color: var(--background-base);
border-right: 1px solid var(--border-weak-base);
&::after {
display: none;
}
}
[data-slot="tabs-trigger-wrapper"] {
width: 100%;
height: 32px;
border: none;
border-radius: 8px;
background-color: transparent;
[data-slot="tabs-trigger"] {
height: 100%;
padding: 0 8px;
gap: 8px;
justify-content: flex-start;
}
&:hover:not(:disabled) {
background-color: var(--surface-raised-base-hover);
}
&:has([data-selected]) {
background-color: var(--surface-raised-base-active);
color: var(--text-strong);
}
}
[data-slot="tabs-content"] {
overflow-x: auto;
overflow-y: auto;
}
&[data-variant="alt"] {
[data-slot="tabs-list"] {
padding: 8px;
gap: 4px;
border: none;
&::after {
display: none;
}
}
[data-slot="tabs-trigger-wrapper"] {
height: 32px;
border: none;
border-radius: 8px;
[data-slot="tabs-trigger"] {
border: none;
padding: 0 8px;
gap: 8px;
justify-content: flex-start;
}
&:hover:not(:disabled) {
background-color: var(--surface-raised-base-hover);
}
&:has([data-selected]) {
background-color: var(--surface-raised-base-hover);
color: var(--text-strong);
}
}
}
&[data-variant="settings"] {
[data-slot="tabs-list"] {
width: 150px;
min-width: 150px;
@media (min-width: 640px) {
width: 200px;
min-width: 200px;
}
padding: 12px;
gap: 0;
background-color: var(--background-base);
border-right: 1px solid var(--border-weak-base);
&::after {
display: none;
}
}
[data-slot="tabs-section-title"] {
width: 100%;
padding: 0 0 0 4px;
font-family: var(--font-family-sans);
font-size: var(--font-size-small);
font-weight: var(--font-weight-medium);
color: var(--text-weak);
}
[data-slot="tabs-trigger-wrapper"] {
height: 32px;
border: none;
border-radius: var(--radius-md);
/* text-14-medium */
font-family: var(--font-family-sans);
font-size: var(--font-size-base);
font-weight: var(--font-weight-medium);
line-height: var(--line-height-large);
[data-slot="tabs-trigger"] {
border: none;
padding: 0 8px;
gap: 12px;
justify-content: flex-start;
width: 100%;
height: 100%;
}
[data-component="icon"] {
color: var(--icon-base);
}
&:hover:not(:disabled) {
background-color: var(--surface-raised-base-hover);
}
&:has([data-selected]) {
background-color: var(--surface-raised-base-active);
color: var(--text-strong);
[data-component="icon"] {
color: var(--icon-strong-base);
}
&:hover:not(:disabled) {
background-color: var(--surface-raised-base-active);
}
}
}
[data-slot="tabs-content"] {
background-color: var(--surface-raised-stronger-non-alpha);
}
}
}
}

View File

@@ -1,37 +1,40 @@
[data-component="tag"] {
display: inline-flex;
align-items: center;
justify-content: center;
user-select: none;
display: inline-flex;
align-items: center;
justify-content: center;
user-select: none;
border-radius: var(--radius-xs);
border: 0.5px solid var(--border-weak-base);
background: var(--surface-raised-base);
color: var(--text-base);
border-radius: var(--radius-xs);
border: 0.5px solid var(--border-weak-base);
background: var(--surface-raised-base);
color: var(--text-base);
transition-property: background-color, border-color, color;
transition-duration: var(--transition-duration);
transition-timing-function: var(--transition-easing);
&[data-size="normal"] {
height: 18px;
padding: 0 6px;
&[data-size="normal"] {
height: 18px;
padding: 0 6px;
/* text-12-medium */
font-family: var(--font-family-sans);
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);
}
/* text-12-medium */
font-family: var(--font-family-sans);
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="large"] {
height: 22px;
padding: 0 8px;
&[data-size="large"] {
height: 22px;
padding: 0 8px;
/* text-14-medium */
font-family: var(--font-family-sans);
font-size: 14px;
font-style: normal;
font-weight: var(--font-weight-medium);
line-height: var(--line-height-large); /* 142.857% */
letter-spacing: var(--letter-spacing-normal);
}
/* text-14-medium */
font-family: var(--font-family-sans);
font-size: 14px;
font-style: normal;
font-weight: var(--font-weight-medium);
line-height: var(--line-height-large); /* 142.857% */
letter-spacing: var(--letter-spacing-normal);
}
}

View File

@@ -1,134 +1,134 @@
[data-component="input"] {
width: 100%;
width: 100%;
[data-slot="input-input"] {
width: 100%;
color: var(--text-strong);
[data-slot="input-input"] {
width: 100%;
color: var(--text-strong);
/* text-14-regular */
font-family: var(--font-family-sans);
font-size: 14px;
font-style: normal;
font-weight: var(--font-weight-regular);
line-height: var(--line-height-large); /* 142.857% */
letter-spacing: var(--letter-spacing-normal);
/* text-14-regular */
font-family: var(--font-family-sans);
font-size: 14px;
font-style: normal;
font-weight: var(--font-weight-regular);
line-height: var(--line-height-large); /* 142.857% */
letter-spacing: var(--letter-spacing-normal);
&:focus {
outline: none;
}
&:focus {
outline: none;
}
&::placeholder {
color: var(--text-weak);
}
}
&::placeholder {
color: var(--text-weak);
}
}
&[data-variant="normal"] {
display: flex;
flex-direction: column;
align-items: flex-start;
gap: 8px;
&[data-variant="normal"] {
display: flex;
flex-direction: column;
align-items: flex-start;
gap: 8px;
[data-slot="input-label"] {
color: var(--text-weak);
[data-slot="input-label"] {
color: var(--text-weak);
/* text-12-medium */
font-family: var(--font-family-sans);
font-size: var(--font-size-small);
font-style: normal;
font-weight: var(--font-weight-medium);
line-height: 18px; /* 150% */
letter-spacing: var(--letter-spacing-normal);
}
/* text-12-medium */
font-family: var(--font-family-sans);
font-size: var(--font-size-small);
font-style: normal;
font-weight: var(--font-weight-medium);
line-height: 18px; /* 150% */
letter-spacing: var(--letter-spacing-normal);
}
[data-slot="input-wrapper"] {
display: flex;
align-items: start;
justify-content: space-between;
width: 100%;
padding-right: 4px;
[data-slot="input-wrapper"] {
display: flex;
align-items: start;
justify-content: space-between;
width: 100%;
padding-right: 4px;
border-radius: var(--radius-md);
border: 1px solid var(--border-weak-base);
background: var(--input-base);
border-radius: var(--radius-md);
border: 1px solid var(--border-weak-base);
background: var(--input-base);
&:focus-within:not(:has([data-readonly])) {
border-color: transparent;
/* border/shadow-xs/select */
box-shadow:
0 0 0 3px var(--border-weak-selected),
0 0 0 1px var(--border-selected),
0 1px 2px -1px rgba(19, 16, 16, 0.25),
0 1px 2px 0 rgba(19, 16, 16, 0.08),
0 1px 3px 0 rgba(19, 16, 16, 0.12);
}
&:focus-within:not(:has([data-readonly])) {
border-color: transparent;
/* border/shadow-xs/select */
box-shadow:
0 0 0 3px var(--border-weak-selected),
0 0 0 1px var(--border-selected),
0 1px 2px -1px rgba(19, 16, 16, 0.25),
0 1px 2px 0 rgba(19, 16, 16, 0.08),
0 1px 3px 0 rgba(19, 16, 16, 0.12);
}
&:has([data-invalid]) {
background: var(--surface-critical-weak);
border: 1px solid var(--border-critical-selected);
}
&:has([data-invalid]) {
background: var(--surface-critical-weak);
border: 1px solid var(--border-critical-selected);
}
&:not(:has([data-slot="input-copy-button"])) {
padding-right: 0;
}
}
&:not(:has([data-slot="input-copy-button"])) {
padding-right: 0;
}
}
[data-slot="input-input"] {
color: var(--text-strong);
[data-slot="input-input"] {
color: var(--text-strong);
display: flex;
height: 32px;
padding: 2px 12px;
align-items: center;
flex: 1;
min-width: 0;
display: flex;
height: 32px;
padding: 2px 12px;
align-items: center;
flex: 1;
min-width: 0;
background: transparent;
border: none;
background: transparent;
border: none;
/* text-14-regular */
font-family: var(--font-family-sans);
font-size: 14px;
font-style: normal;
font-weight: var(--font-weight-regular);
line-height: var(--line-height-large); /* 142.857% */
letter-spacing: var(--letter-spacing-normal);
/* text-14-regular */
font-family: var(--font-family-sans);
font-size: 14px;
font-style: normal;
font-weight: var(--font-weight-regular);
line-height: var(--line-height-large); /* 142.857% */
letter-spacing: var(--letter-spacing-normal);
&:focus {
outline: none;
}
&:focus {
outline: none;
}
&::placeholder {
color: var(--text-weak);
}
}
&::placeholder {
color: var(--text-weak);
}
}
textarea[data-slot="input-input"] {
height: auto;
min-height: 32px;
padding: 6px 12px;
resize: none;
}
textarea[data-slot="input-input"] {
height: auto;
min-height: 32px;
padding: 6px 12px;
resize: none;
}
[data-slot="input-copy-button"] {
flex-shrink: 0;
margin-top: 4px;
color: var(--icon-base);
[data-slot="input-copy-button"] {
flex-shrink: 0;
margin-top: 4px;
color: var(--icon-base);
&:hover {
color: var(--icon-strong-base);
}
}
&:hover {
color: var(--icon-strong-base);
}
}
[data-slot="input-error"] {
color: var(--text-on-critical-base);
[data-slot="input-error"] {
color: var(--text-on-critical-base);
/* text-12-medium */
font-family: var(--font-family-sans);
font-size: var(--font-size-small);
font-style: normal;
font-weight: var(--font-weight-medium);
line-height: 18px; /* 150% */
letter-spacing: var(--letter-spacing-normal);
}
}
/* text-12-medium */
font-family: var(--font-family-sans);
font-size: var(--font-size-small);
font-style: normal;
font-weight: var(--font-weight-medium);
line-height: 18px; /* 150% */
letter-spacing: var(--letter-spacing-normal);
}
}
}

View File

@@ -1,205 +1,205 @@
[data-component="toast-region"] {
position: fixed;
bottom: 48px;
right: 32px;
z-index: 1000;
display: flex;
flex-direction: column;
gap: 8px;
max-width: 400px;
width: 100%;
pointer-events: none;
position: fixed;
bottom: 48px;
right: 32px;
z-index: 1000;
display: flex;
flex-direction: column;
gap: 8px;
max-width: 400px;
width: 100%;
pointer-events: none;
[data-slot="toast-list"] {
display: flex;
flex-direction: column;
gap: 8px;
list-style: none;
margin: 0;
padding: 0;
}
[data-slot="toast-list"] {
display: flex;
flex-direction: column;
gap: 8px;
list-style: none;
margin: 0;
padding: 0;
}
}
[data-component="toast"] {
display: flex;
align-items: flex-start;
gap: 20px;
padding: 16px 20px;
pointer-events: auto;
transition: all 150ms ease-out;
display: flex;
align-items: flex-start;
gap: 20px;
padding: 16px 20px;
pointer-events: auto;
transition: all 150ms ease-out;
border-radius: var(--radius-lg);
border: 1px solid var(--border-weak-base);
background: var(--surface-float-base);
color: var(--text-invert-base);
box-shadow: var(--shadow-md);
border-radius: var(--radius-lg);
border: 1px solid var(--border-weak-base);
background: var(--surface-float-base);
color: var(--text-invert-base);
box-shadow: var(--shadow-md);
[data-slot="toast-inner"] {
display: flex;
align-items: flex-start;
gap: 10px;
}
[data-slot="toast-inner"] {
display: flex;
align-items: flex-start;
gap: 10px;
}
&[data-opened] {
animation: toastPopIn 150ms ease-out;
}
&[data-opened] {
animation: toastPopIn 150ms ease-out;
}
&[data-closed] {
animation: toastPopOut 100ms ease-in forwards;
}
&[data-closed] {
animation: toastPopOut 100ms ease-in forwards;
}
&[data-swipe="move"] {
transform: translateX(var(--kb-toast-swipe-move-x));
}
&[data-swipe="move"] {
transform: translateX(var(--kb-toast-swipe-move-x));
}
&[data-swipe="cancel"] {
transform: translateX(0);
transition: transform 200ms ease-out;
}
&[data-swipe="cancel"] {
transform: translateX(0);
transition: transform 200ms ease-out;
}
&[data-swipe="end"] {
animation: toastSwipeOut 100ms ease-out forwards;
}
&[data-swipe="end"] {
animation: toastSwipeOut 100ms ease-out forwards;
}
/* &[data-variant="success"] { */
/* border-color: var(--color-semantic-positive); */
/* } */
/**/
/* &[data-variant="error"] { */
/* border-color: var(--color-semantic-danger); */
/* } */
/**/
/* &[data-variant="loading"] { */
/* border-color: var(--color-semantic-info); */
/* } */
/* &[data-variant="success"] { */
/* border-color: var(--color-semantic-positive); */
/* } */
/**/
/* &[data-variant="error"] { */
/* border-color: var(--color-semantic-danger); */
/* } */
/**/
/* &[data-variant="loading"] { */
/* border-color: var(--color-semantic-info); */
/* } */
[data-slot="toast-icon"] {
flex-shrink: 0;
display: flex;
align-items: center;
justify-content: center;
[data-slot="toast-icon"] {
flex-shrink: 0;
display: flex;
align-items: center;
justify-content: center;
[data-component="icon"] {
color: var(--text-invert-stronger);
/* color: var(--icon-invert-base); */
}
}
[data-component="icon"] {
color: var(--text-invert-stronger);
/* color: var(--icon-invert-base); */
}
}
[data-slot="toast-content"] {
flex: 1;
display: flex;
flex-direction: column;
gap: 2px;
min-width: 0;
}
[data-slot="toast-content"] {
flex: 1;
display: flex;
flex-direction: column;
gap: 2px;
min-width: 0;
}
[data-slot="toast-title"] {
color: var(--text-invert-strong);
[data-slot="toast-title"] {
color: var(--text-invert-strong);
/* text-14-medium */
font-family: var(--font-family-sans);
font-size: 14px;
font-style: normal;
font-weight: var(--font-weight-medium);
line-height: var(--line-height-large); /* 142.857% */
letter-spacing: var(--letter-spacing-normal);
/* text-14-medium */
font-family: var(--font-family-sans);
font-size: 14px;
font-style: normal;
font-weight: var(--font-weight-medium);
line-height: var(--line-height-large); /* 142.857% */
letter-spacing: var(--letter-spacing-normal);
margin: 0;
}
margin: 0;
}
[data-slot="toast-description"] {
color: var(--text-invert-base);
text-wrap-style: pretty;
[data-slot="toast-description"] {
color: var(--text-invert-base);
text-wrap-style: pretty;
/* text-14-regular */
font-family: var(--font-family-sans);
font-size: var(--font-size-base);
font-style: normal;
font-weight: var(--font-weight-regular);
line-height: var(--line-height-x-large); /* 171.429% */
letter-spacing: var(--letter-spacing-normal);
/* text-14-regular */
font-family: var(--font-family-sans);
font-size: var(--font-size-base);
font-style: normal;
font-weight: var(--font-weight-regular);
line-height: var(--line-height-x-large); /* 171.429% */
letter-spacing: var(--letter-spacing-normal);
margin: 0;
}
margin: 0;
}
[data-slot="toast-actions"] {
display: flex;
gap: 16px;
margin-top: 8px;
}
[data-slot="toast-actions"] {
display: flex;
gap: 16px;
margin-top: 8px;
}
[data-slot="toast-action"] {
background: none;
border: none;
padding: 0;
cursor: pointer;
[data-slot="toast-action"] {
background: none;
border: none;
padding: 0;
cursor: pointer;
color: var(--text-invert-weak);
font-family: var(--font-family-sans);
font-size: var(--font-size-base);
font-weight: var(--font-weight-medium);
line-height: var(--line-height-large);
letter-spacing: var(--letter-spacing-normal);
color: var(--text-invert-weak);
font-family: var(--font-family-sans);
font-size: var(--font-size-base);
font-weight: var(--font-weight-medium);
line-height: var(--line-height-large);
letter-spacing: var(--letter-spacing-normal);
&:hover {
text-decoration: underline;
}
&:hover {
text-decoration: underline;
}
&:first-child {
color: var(--text-invert-strong);
}
}
&:first-child {
color: var(--text-invert-strong);
}
}
[data-slot="toast-close-button"] {
flex-shrink: 0;
}
[data-slot="toast-close-button"] {
flex-shrink: 0;
}
[data-slot="toast-progress-track"] {
position: absolute;
bottom: 0;
left: 0;
right: 0;
height: 3px;
background-color: var(--surface-base);
border-radius: 0 0 var(--radius-lg) var(--radius-lg);
overflow: hidden;
}
[data-slot="toast-progress-track"] {
position: absolute;
bottom: 0;
left: 0;
right: 0;
height: 3px;
background-color: var(--surface-base);
border-radius: 0 0 var(--radius-lg) var(--radius-lg);
overflow: hidden;
}
[data-slot="toast-progress-fill"] {
height: 100%;
width: var(--kb-toast-progress-fill-width);
background-color: var(--color-primary);
transition: width 250ms linear;
}
[data-slot="toast-progress-fill"] {
height: 100%;
width: var(--kb-toast-progress-fill-width);
background-color: var(--color-primary);
transition: width 250ms linear;
}
}
@keyframes toastPopIn {
from {
opacity: 0;
transform: translateY(20px);
}
to {
opacity: 1;
transform: translateY(0);
}
from {
opacity: 0;
transform: translateY(20px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
@keyframes toastPopOut {
from {
opacity: 1;
transform: translateY(0);
}
to {
opacity: 0;
transform: translateY(20px);
}
from {
opacity: 1;
transform: translateY(0);
}
to {
opacity: 0;
transform: translateY(20px);
}
}
@keyframes toastSwipeOut {
from {
transform: translateX(var(--kb-toast-swipe-end-x));
}
to {
transform: translateX(100%);
}
from {
transform: translateX(var(--kb-toast-swipe-end-x));
}
to {
transform: translateX(100%);
}
}

View File

@@ -1,74 +1,74 @@
[data-component="tooltip-trigger"] {
display: flex;
display: flex;
}
[data-slot="tooltip-keybind"] {
display: flex;
align-items: center;
gap: 12px;
display: flex;
align-items: center;
gap: 12px;
}
[data-slot="tooltip-keybind-key"] {
color: var(--text-invert-base);
font-size: var(--font-size-small);
font-weight: var(--font-weight-medium);
line-height: var(--line-height-large);
color: var(--text-invert-base);
font-size: var(--font-size-small);
font-weight: var(--font-weight-medium);
line-height: var(--line-height-large);
}
[data-component="tooltip"] {
z-index: 1000;
max-width: 320px;
border-radius: var(--radius-sm);
background-color: var(--surface-float-base);
color: var(--text-invert-strong);
background: var(--surface-float-base);
padding: 2px 8px;
border: 1px solid var(--border-weak-base, rgba(0, 0, 0, 0.07));
z-index: 1000;
max-width: 320px;
border-radius: var(--radius-sm);
background-color: var(--surface-float-base);
color: var(--text-invert-strong);
background: var(--surface-float-base);
padding: 2px 8px;
border: 1px solid var(--border-weak-base, rgba(0, 0, 0, 0.07));
box-shadow: var(--shadow-md);
pointer-events: none !important;
/* transition: all 150ms ease-out; */
/* transform: translate3d(0, 0, 0); */
/* transform-origin: var(--kb-tooltip-content-transform-origin); */
box-shadow: var(--shadow-md);
pointer-events: none !important;
/* transition: all 150ms ease-out; */
/* transform: translate3d(0, 0, 0); */
/* transform-origin: var(--kb-tooltip-content-transform-origin); */
/* text-12-medium */
font-family: var(--font-family-sans);
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);
/* text-12-medium */
font-family: var(--font-family-sans);
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-expanded] {
opacity: 1;
/* transform: translate3d(0, 0, 0); */
}
&[data-expanded] {
opacity: 1;
/* transform: translate3d(0, 0, 0); */
}
&[data-closed]:not([data-force-open="true"]) {
opacity: 0;
}
&[data-closed]:not([data-force-open="true"]) {
opacity: 0;
}
/* &[data-placement="top"] { */
/* &[data-closed] { */
/* transform: translate3d(0, 4px, 0); */
/* } */
/* } */
/**/
/* &[data-placement="bottom"] { */
/* &[data-closed] { */
/* transform: translate3d(0, -4px, 0); */
/* } */
/* } */
/**/
/* &[data-placement="left"] { */
/* &[data-closed] { */
/* transform: translate3d(4px, 0, 0); */
/* } */
/* } */
/**/
/* &[data-placement="right"] { */
/* &[data-closed] { */
/* transform: translate3d(-4px, 0, 0); */
/* } */
/* } */
/* &[data-placement="top"] { */
/* &[data-closed] { */
/* transform: translate3d(0, 4px, 0); */
/* } */
/* } */
/**/
/* &[data-placement="bottom"] { */
/* &[data-closed] { */
/* transform: translate3d(0, -4px, 0); */
/* } */
/* } */
/**/
/* &[data-placement="left"] { */
/* &[data-closed] { */
/* transform: translate3d(4px, 0, 0); */
/* } */
/* } */
/**/
/* &[data-placement="right"] { */
/* &[data-closed] { */
/* transform: translate3d(-4px, 0, 0); */
/* } */
/* } */
}

View File

@@ -1,14 +1,14 @@
@keyframes blink {
0%,
50% {
opacity: 1;
}
51%,
100% {
opacity: 0;
}
0%,
50% {
opacity: 1;
}
51%,
100% {
opacity: 0;
}
}
.blinking-cursor {
animation: blink 1s step-end infinite;
animation: blink 1s step-end infinite;
}

View File

@@ -28,6 +28,7 @@ const Context = createContext<ReturnType<typeof init>>()
function init() {
const [active, setActive] = createSignal<Active | undefined>()
const [renders, setRenders] = createSignal<Record<string, JSX.Element>>({})
const timer = { current: undefined as ReturnType<typeof setTimeout> | undefined }
const lock = { value: false }
@@ -118,12 +119,28 @@ function init() {
setActive({ id, node, dispose, owner, onClose, setClosing })
}
const render = (element: JSX.Element, id: string, owner: Owner) => {
setRenders((renders) => ({ ...renders, [id]: element }))
show(() => element, owner, () => {
setRenders((renders) => {
const { [id]: _, ...rest } = renders
return rest
})
})
}
const isActive = (id: string) => {
return renders()[id] !== undefined
}
return {
get active() {
return active()
},
isActive,
close,
show,
render,
}
}
@@ -152,10 +169,17 @@ export function useDialog() {
get active() {
return ctx.active
},
isActive(id: string) {
return ctx.isActive(id)
},
show(element: DialogElement, onClose?: () => void) {
const base = ctx.active?.owner ?? owner
ctx.show(element, base, onClose)
},
render(element: JSX.Element, id: string) {
const base = ctx.active?.owner ?? owner
ctx.render(element, id, base)
},
close() {
ctx.close()
},

View File

@@ -33,8 +33,10 @@
@import "../components/markdown.css" layer(components);
@import "../components/message-part.css" layer(components);
@import "../components/message-nav.css" layer(components);
@import "../components/morph-chevron.css" layer(components);
@import "../components/popover.css" layer(components);
@import "../components/progress-circle.css" layer(components);
@import "../components/reasoning-icon.css" layer(components);
@import "../components/radio-group.css" layer(components);
@import "../components/resize-handle.css" layer(components);
@import "../components/select.css" layer(components);

View File

@@ -1,131 +1,174 @@
:root {
interpolate-size: allow-keywords;
interpolate-size: allow-keywords;
[data-popper-positioner] {
pointer-events: none;
}
/* Transition tokens */
--transition-duration: 200ms;
--transition-easing: cubic-bezier(0.25, 0, 0.5, 1);
--transition-fast: 150ms;
--transition-slow: 300ms;
/* ::selection { */
/* background-color: color-mix(in srgb, var(--color-primary) 33%, transparent); */
/* background-color: var(--color-primary); */
/* color: var(--color-background); */
/* } */
/* Allow height transitions from 0 to auto */
@supports (interpolate-size: allow-keywords) {
interpolate-size: allow-keywords;
}
::-webkit-scrollbar-track {
background: transparent;
}
[data-popper-positioner] {
pointer-events: none;
}
::-webkit-scrollbar-thumb {
background-color: var(--surface-float-base);
border-radius: var(--radius-md);
}
/* ::selection { */
/* background-color: color-mix(in srgb, var(--color-primary) 33%, transparent); */
/* background-color: var(--color-primary); */
/* color: var(--color-background); */
/* } */
* {
scrollbar-color: var(--surface-float-base) transparent;
}
::-webkit-scrollbar-track {
background: transparent;
}
::-webkit-scrollbar-thumb {
background-color: var(--surface-float-base);
border-radius: var(--radius-md);
}
* {
scrollbar-color: var(--surface-float-base) transparent;
}
}
.no-scrollbar {
&::-webkit-scrollbar {
display: none;
}
/* Hide scrollbar for IE, Edge and Firefox */
& {
-ms-overflow-style: none; /* IE and Edge */
scrollbar-width: none; /* Firefox */
}
&::-webkit-scrollbar {
display: none;
}
/* Hide scrollbar for IE, Edge and Firefox */
& {
-ms-overflow-style: none; /* IE and Edge */
scrollbar-width: none; /* Firefox */
}
}
.sr-only {
position: absolute;
width: 1px;
height: 1px;
padding: 0;
margin: -1px;
overflow: hidden;
clip: rect(0, 0, 0, 0);
white-space: nowrap;
border-width: 0;
position: absolute;
width: 1px;
height: 1px;
padding: 0;
margin: -1px;
overflow: hidden;
clip: rect(0, 0, 0, 0);
white-space: nowrap;
border-width: 0;
}
.truncate-start {
text-overflow: ellipsis;
overflow: hidden;
white-space: nowrap;
direction: rtl;
text-align: left;
text-overflow: ellipsis;
overflow: hidden;
white-space: nowrap;
direction: rtl;
text-align: left;
}
.text-12-regular {
font-family: var(--font-family-sans);
font-size: var(--font-size-small);
font-style: normal;
font-weight: var(--font-weight-regular);
line-height: var(--line-height-large); /* 166.667% */
letter-spacing: var(--letter-spacing-normal);
font-family: var(--font-family-sans);
font-size: var(--font-size-small);
font-style: normal;
font-weight: var(--font-weight-regular);
line-height: var(--line-height-large); /* 166.667% */
letter-spacing: var(--letter-spacing-normal);
}
.text-12-medium {
font-family: var(--font-family-sans);
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);
font-family: var(--font-family-sans);
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);
}
.text-12-mono {
font-family: var(--font-family-mono);
font-feature-settings: var(--font-feature-settings-mono);
font-size: var(--font-size-small);
font-style: normal;
font-weight: var(--font-weight-regular);
line-height: var(--line-height-large); /* 166.667% */
letter-spacing: var(--letter-spacing-normal);
font-family: var(--font-family-mono);
font-feature-settings: var(--font-feature-settings-mono);
font-size: var(--font-size-small);
font-style: normal;
font-weight: var(--font-weight-regular);
line-height: var(--line-height-large); /* 166.667% */
letter-spacing: var(--letter-spacing-normal);
}
.text-14-regular {
font-family: var(--font-family-sans);
font-size: var(--font-size-base);
font-style: normal;
font-weight: var(--font-weight-regular);
line-height: var(--line-height-x-large); /* 171.429% */
letter-spacing: var(--letter-spacing-normal);
font-family: var(--font-family-sans);
font-size: var(--font-size-base);
font-style: normal;
font-weight: var(--font-weight-regular);
line-height: var(--line-height-x-large); /* 171.429% */
letter-spacing: var(--letter-spacing-normal);
}
.text-14-medium {
font-family: var(--font-family-sans);
font-size: var(--font-size-base);
font-style: normal;
font-weight: var(--font-weight-medium);
line-height: var(--line-height-large); /* 171.429% */
letter-spacing: var(--letter-spacing-normal);
font-family: var(--font-family-sans);
font-size: var(--font-size-base);
font-style: normal;
font-weight: var(--font-weight-medium);
line-height: var(--line-height-large); /* 171.429% */
letter-spacing: var(--letter-spacing-normal);
}
.text-14-mono {
font-family: var(--font-family-mono);
font-feature-settings: var(--font-feature-settings-mono);
font-size: var(--font-size-base);
font-style: normal;
font-weight: var(--font-weight-regular);
line-height: var(--line-height-large); /* 171.429% */
letter-spacing: var(--letter-spacing-normal);
font-family: var(--font-family-mono);
font-feature-settings: var(--font-feature-settings-mono);
font-size: var(--font-size-base);
font-style: normal;
font-weight: var(--font-weight-regular);
line-height: var(--line-height-large); /* 171.429% */
letter-spacing: var(--letter-spacing-normal);
}
.text-16-medium {
font-family: var(--font-family-sans);
font-size: var(--font-size-large);
font-style: normal;
font-weight: var(--font-weight-medium);
line-height: var(--line-height-x-large); /* 150% */
letter-spacing: var(--letter-spacing-tight);
font-family: var(--font-family-sans);
font-size: var(--font-size-large);
font-style: normal;
font-weight: var(--font-weight-medium);
line-height: var(--line-height-x-large); /* 150% */
letter-spacing: var(--letter-spacing-tight);
}
.text-20-medium {
font-family: var(--font-family-sans);
font-size: var(--font-size-x-large);
font-style: normal;
font-weight: var(--font-weight-medium);
line-height: var(--line-height-x-large); /* 120% */
letter-spacing: var(--letter-spacing-tightest);
font-family: var(--font-family-sans);
font-size: var(--font-size-x-large);
font-style: normal;
font-weight: var(--font-weight-medium);
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);
}