Skip to content

Commit c554672

Browse files
committed
chore: cleanup
1 parent 1038eb8 commit c554672

21 files changed

Lines changed: 478 additions & 310 deletions

packages/ui/src/components/animated-number.tsx

Lines changed: 22 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
import { For, Index, createEffect, createMemo, createSignal, on } from "solid-js"
1+
import { For, Index, createEffect, createMemo, on } from "solid-js"
2+
import { createStore } from "solid-js/store"
23

34
const TRACK = Array.from({ length: 30 }, (_, index) => index % 10)
45
const DURATION = 600
@@ -14,8 +15,12 @@ function spin(from: number, to: number, direction: 1 | -1) {
1415
}
1516

1617
function Digit(props: { value: number; direction: 1 | -1 }) {
17-
const [step, setStep] = createSignal(props.value + 10)
18-
const [animating, setAnimating] = createSignal(false)
18+
const [state, setState] = createStore({
19+
step: props.value + 10,
20+
animating: false,
21+
})
22+
const step = () => state.step
23+
const animating = () => state.animating
1924
let last = props.value
2025

2126
createEffect(
@@ -25,13 +30,13 @@ function Digit(props: { value: number; direction: 1 | -1 }) {
2530
const delta = spin(last, next, props.direction)
2631
last = next
2732
if (!delta) {
28-
setAnimating(false)
29-
setStep(next + 10)
33+
setState("animating", false)
34+
setState("step", next + 10)
3035
return
3136
}
3237

33-
setAnimating(true)
34-
setStep((value) => value + delta)
38+
setState("animating", true)
39+
setState("step", (value) => value + delta)
3540
},
3641
{ defer: true },
3742
),
@@ -43,8 +48,8 @@ function Digit(props: { value: number; direction: 1 | -1 }) {
4348
data-slot="animated-number-strip"
4449
data-animating={animating() ? "true" : "false"}
4550
onTransitionEnd={() => {
46-
setAnimating(false)
47-
setStep((value) => normalize(value) + 10)
51+
setState("animating", false)
52+
setState("step", (value) => normalize(value) + 10)
4853
}}
4954
style={{
5055
"--animated-number-offset": `${step()}`,
@@ -63,8 +68,12 @@ export function AnimatedNumber(props: { value: number; class?: string }) {
6368
return Math.max(0, Math.round(props.value))
6469
})
6570

66-
const [value, setValue] = createSignal(target())
67-
const [direction, setDirection] = createSignal<1 | -1>(1)
71+
const [state, setState] = createStore({
72+
value: target(),
73+
direction: 1 as 1 | -1,
74+
})
75+
const value = () => state.value
76+
const direction = () => state.direction
6877

6978
createEffect(
7079
on(
@@ -73,8 +82,8 @@ export function AnimatedNumber(props: { value: number; class?: string }) {
7382
const current = value()
7483
if (next === current) return
7584

76-
setDirection(next > current ? 1 : -1)
77-
setValue(next)
85+
setState("direction", next > current ? 1 : -1)
86+
setState("value", next)
7887
},
7988
{ defer: true },
8089
),

packages/ui/src/components/basic-tool.tsx

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
1-
import { createEffect, createSignal, For, Match, on, onCleanup, Show, Switch, type JSX } from "solid-js"
1+
import { createEffect, For, Match, on, onCleanup, Show, Switch, type JSX } from "solid-js"
22
import { animate, type AnimationPlaybackControls } from "motion"
3+
import { createStore } from "solid-js/store"
34
import { Collapsible } from "./collapsible"
45
import type { IconProps } from "./icon"
56
import { TextShimmer } from "./text-shimmer"
@@ -37,8 +38,12 @@ export interface BasicToolProps {
3738
const SPRING = { type: "spring" as const, visualDuration: 0.35, bounce: 0 }
3839

3940
export function BasicTool(props: BasicToolProps) {
40-
const [open, setOpen] = createSignal(props.defaultOpen ?? false)
41-
const [ready, setReady] = createSignal(open())
41+
const [state, setState] = createStore({
42+
open: props.defaultOpen ?? false,
43+
ready: props.defaultOpen ?? false,
44+
})
45+
const open = () => state.open
46+
const ready = () => state.ready
4247
const pending = () => props.status === "pending" || props.status === "running"
4348

4449
let frame: number | undefined
@@ -52,7 +57,7 @@ export function BasicTool(props: BasicToolProps) {
5257
onCleanup(cancel)
5358

5459
createEffect(() => {
55-
if (props.forceOpen) setOpen(true)
60+
if (props.forceOpen) setState("open", true)
5661
})
5762

5863
createEffect(
@@ -62,15 +67,15 @@ export function BasicTool(props: BasicToolProps) {
6267
if (!props.defer) return
6368
if (!value) {
6469
cancel()
65-
setReady(false)
70+
setState("ready", false)
6671
return
6772
}
6873

6974
cancel()
7075
frame = requestAnimationFrame(() => {
7176
frame = undefined
7277
if (!open()) return
73-
setReady(true)
78+
setState("ready", true)
7479
})
7580
},
7681
{ defer: true },
@@ -112,7 +117,7 @@ export function BasicTool(props: BasicToolProps) {
112117
const handleOpenChange = (value: boolean) => {
113118
if (pending()) return
114119
if (props.locked && !value) return
115-
setOpen(value)
120+
setState("open", value)
116121
}
117122

118123
return (

packages/ui/src/components/line-comment-annotations.tsx

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { type DiffLineAnnotation, type SelectedLineRange } from "@pierre/diffs"
22
import { createEffect, createMemo, createSignal, onCleanup, Show, type Accessor, type JSX } from "solid-js"
3+
import { createStore } from "solid-js/store"
34
import { render as renderSolid } from "solid-js/web"
45
import { createHoverCommentUtility } from "../pierre/comment-hover"
56
import { cloneSelectedLineRange, formatSelectedLineLabel, lineInSelectedRange } from "../pierre/selection-bridge"
@@ -200,8 +201,14 @@ export function createLineCommentAnnotationRenderer<T>(props: {
200201
}
201202

202203
export function createLineCommentState<T>(props: LineCommentStateProps<T>) {
203-
const [draft, setDraft] = createSignal("")
204-
const [editing, setEditing] = createSignal<T | null>(null)
204+
const [state, setState] = createStore({
205+
draft: "",
206+
editing: null as T | null,
207+
})
208+
const draft = () => state.draft
209+
const setDraft = (value: string) => setState("draft", value)
210+
const editing = () => state.editing
211+
const setEditing = (value: T | null) => setState("editing", typeof value === "function" ? () => value : value)
205212

206213
const toRange = (range: SelectedLineRange | null) => (range ? cloneSelectedLineRange(range) : null)
207214
const setSelected = (range: SelectedLineRange | null) => {
@@ -261,7 +268,7 @@ export function createLineCommentState<T>(props: LineCommentStateProps<T>) {
261268
closeComment()
262269
setSelected(range)
263270
props.setCommenting(null)
264-
setEditing(() => id)
271+
setEditing(id)
265272
setDraft(value)
266273
}
267274

packages/ui/src/components/list.tsx

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { type FilteredListProps, useFilteredList } from "@opencode-ai/ui/hooks"
2-
import { createEffect, createSignal, For, onCleanup, type JSX, on, Show } from "solid-js"
2+
import { createEffect, For, onCleanup, type JSX, on, Show } from "solid-js"
33
import { createStore } from "solid-js/store"
44
import { useI18n } from "../context/i18n"
55
import { Icon, type IconProps } from "./icon"
@@ -56,12 +56,16 @@ export interface ListRef {
5656

5757
export function List<T>(props: ListProps<T> & { ref?: (ref: ListRef) => void }) {
5858
const i18n = useI18n()
59-
const [scrollRef, setScrollRef] = createSignal<HTMLDivElement | undefined>(undefined)
60-
const [internalFilter, setInternalFilter] = createSignal("")
6159
let inputRef: HTMLInputElement | HTMLTextAreaElement | undefined
6260
const [store, setStore] = createStore({
6361
mouseActive: false,
62+
scrollRef: undefined as HTMLDivElement | undefined,
63+
internalFilter: "",
6464
})
65+
const scrollRef = () => store.scrollRef
66+
const setScrollRef = (el: HTMLDivElement | undefined) => setStore("scrollRef", el)
67+
const internalFilter = () => store.internalFilter
68+
const setInternalFilter = (value: string) => setStore("internalFilter", value)
6569

6670
const scrollIntoView = (container: HTMLDivElement, node: HTMLElement, block: "center" | "nearest") => {
6771
const containerRect = container.getBoundingClientRect()
@@ -208,18 +212,20 @@ export function List<T>(props: ListProps<T> & { ref?: (ref: ListRef) => void })
208212
}
209213

210214
function GroupHeader(groupProps: { group: { category: string; items: T[] } }): JSX.Element {
211-
const [stuck, setStuck] = createSignal(false)
212-
const [header, setHeader] = createSignal<HTMLDivElement | undefined>(undefined)
215+
const [state, setState] = createStore({
216+
stuck: false,
217+
header: undefined as HTMLDivElement | undefined,
218+
})
213219

214220
createEffect(() => {
215221
const scroll = scrollRef()
216-
const node = header()
222+
const node = state.header
217223
if (!scroll || !node) return
218224

219225
const handler = () => {
220226
const rect = node.getBoundingClientRect()
221227
const scrollRect = scroll.getBoundingClientRect()
222-
setStuck(rect.top <= scrollRect.top + 1 && scroll.scrollTop > 0)
228+
setState("stuck", rect.top <= scrollRect.top + 1 && scroll.scrollTop > 0)
223229
}
224230

225231
scroll.addEventListener("scroll", handler, { passive: true })
@@ -228,7 +234,7 @@ export function List<T>(props: ListProps<T> & { ref?: (ref: ListRef) => void })
228234
})
229235

230236
return (
231-
<div data-slot="list-header" data-stuck={stuck()} ref={setHeader}>
237+
<div data-slot="list-header" data-stuck={state.stuck} ref={(el) => setState("header", el)}>
232238
{props.groupHeader?.(groupProps.group) ?? groupProps.group.category}
233239
</div>
234240
)

packages/ui/src/components/message-part.tsx

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import {
1212
Index,
1313
type JSX,
1414
} from "solid-js"
15+
import { createStore } from "solid-js/store"
1516
import stripAnsi from "strip-ansi"
1617
import { Dynamic } from "solid-js/web"
1718
import {
@@ -885,8 +886,12 @@ export function UserMessageDisplay(props: { message: UserMessage; parts: PartTyp
885886
const data = useData()
886887
const dialog = useDialog()
887888
const i18n = useI18n()
888-
const [copied, setCopied] = createSignal(false)
889-
const [busy, setBusy] = createSignal<"fork" | "revert" | undefined>()
889+
const [state, setState] = createStore({
890+
copied: false,
891+
busy: undefined as "fork" | "revert" | undefined,
892+
})
893+
const copied = () => state.copied
894+
const busy = () => state.busy
890895

891896
const textPart = createMemo(
892897
() => props.parts?.find((p) => p.type === "text" && !(p as TextPart).synthetic) as TextPart | undefined,
@@ -946,14 +951,14 @@ export function UserMessageDisplay(props: { message: UserMessage; parts: PartTyp
946951
const content = text()
947952
if (!content) return
948953
await navigator.clipboard.writeText(content)
949-
setCopied(true)
950-
setTimeout(() => setCopied(false), 2000)
954+
setState("copied", true)
955+
setTimeout(() => setState("copied", false), 2000)
951956
}
952957

953958
const run = (kind: "fork" | "revert") => {
954959
const act = kind === "fork" ? props.actions?.fork : props.actions?.revert
955960
if (!act || busy()) return
956-
setBusy(kind)
961+
setState("busy", kind)
957962
void Promise.resolve()
958963
.then(() =>
959964
act({
@@ -962,7 +967,7 @@ export function UserMessageDisplay(props: { message: UserMessage; parts: PartTyp
962967
}),
963968
)
964969
.finally(() => {
965-
if (busy() === kind) setBusy(undefined)
970+
if (busy() === kind) setState("busy", undefined)
966971
})
967972
}
968973

packages/ui/src/components/popover.tsx

Lines changed: 17 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,11 @@ import {
55
ParentProps,
66
Show,
77
createEffect,
8-
createSignal,
98
onCleanup,
109
splitProps,
1110
ValidComponent,
1211
} from "solid-js"
12+
import { createStore } from "solid-js/store"
1313
import { useI18n } from "../context/i18n"
1414
import { IconButton } from "./icon-button"
1515

@@ -46,39 +46,40 @@ export function Popover<T extends ValidComponent = "div">(props: PopoverProps<T>
4646
"modal",
4747
])
4848

49-
const [contentRef, setContentRef] = createSignal<HTMLElement | undefined>(undefined)
50-
const [triggerRef, setTriggerRef] = createSignal<HTMLElement | undefined>(undefined)
51-
const [dismiss, setDismiss] = createSignal<"escape" | "outside" | null>(null)
52-
53-
const [uncontrolledOpen, setUncontrolledOpen] = createSignal<boolean>(local.defaultOpen ?? false)
49+
const [state, setState] = createStore({
50+
contentRef: undefined as HTMLElement | undefined,
51+
triggerRef: undefined as HTMLElement | undefined,
52+
dismiss: null as "escape" | "outside" | null,
53+
uncontrolledOpen: local.defaultOpen ?? false,
54+
})
5455

5556
const controlled = () => local.open !== undefined
5657
const opened = () => {
5758
if (controlled()) return local.open ?? false
58-
return uncontrolledOpen()
59+
return state.uncontrolledOpen
5960
}
6061

6162
const onOpenChange = (next: boolean) => {
62-
if (next) setDismiss(null)
63+
if (next) setState("dismiss", null)
6364
if (local.onOpenChange) local.onOpenChange(next)
6465
if (controlled()) return
65-
setUncontrolledOpen(next)
66+
setState("uncontrolledOpen", next)
6667
}
6768

6869
createEffect(() => {
6970
if (!opened()) return
7071

7172
const inside = (node: Node | null | undefined) => {
7273
if (!node) return false
73-
const content = contentRef()
74+
const content = state.contentRef
7475
if (content && content.contains(node)) return true
75-
const trigger = triggerRef()
76+
const trigger = state.triggerRef
7677
if (trigger && trigger.contains(node)) return true
7778
return false
7879
}
7980

8081
const close = (reason: "escape" | "outside") => {
81-
setDismiss(reason)
82+
setState("dismiss", reason)
8283
onOpenChange(false)
8384
}
8485

@@ -116,16 +117,16 @@ export function Popover<T extends ValidComponent = "div">(props: PopoverProps<T>
116117

117118
const content = () => (
118119
<Kobalte.Content
119-
ref={(el: HTMLElement | undefined) => setContentRef(el)}
120+
ref={(el: HTMLElement | undefined) => setState("contentRef", el)}
120121
data-component="popover-content"
121122
classList={{
122123
...(local.classList ?? {}),
123124
[local.class ?? ""]: !!local.class,
124125
}}
125126
style={local.style}
126127
onCloseAutoFocus={(event: Event) => {
127-
if (dismiss() === "outside") event.preventDefault()
128-
setDismiss(null)
128+
if (state.dismiss === "outside") event.preventDefault()
129+
setState("dismiss", null)
129130
}}
130131
>
131132
{/* <Kobalte.Arrow data-slot="popover-arrow" /> */}
@@ -151,7 +152,7 @@ export function Popover<T extends ValidComponent = "div">(props: PopoverProps<T>
151152
return (
152153
<Kobalte gutter={4} {...rest} open={opened()} onOpenChange={onOpenChange} modal={local.modal ?? false}>
153154
<Kobalte.Trigger
154-
ref={(el: HTMLElement) => setTriggerRef(el)}
155+
ref={(el: HTMLElement) => setState("triggerRef", el)}
155156
as={local.triggerAs ?? "div"}
156157
data-slot="popover-trigger"
157158
{...(local.triggerProps as any)}

0 commit comments

Comments
 (0)