@opencode/ui 2.0.23 → 2.0.25
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/context/marked-parser.d.ts +2 -0
- package/dist/i18n/en.d.ts +1 -0
- package/dist/icons/catalog.d.ts +36 -0
- package/dist/navigation/segmented-control/segmented-control.d.ts +21 -2
- package/package.json +2 -1
- package/src/actions/button/button.css +11 -9
- package/src/actions/button/button.tsx +1 -0
- package/src/actions/icon-button/icon-button.css +1 -5
- package/src/actions/icon-button/icon-button.tsx +1 -0
- package/src/actions/split-button/split-button.tsx +3 -0
- package/src/actions/submit.css +14 -12
- package/src/components/animated-number.tsx +13 -0
- package/src/components/app-icon.tsx +2 -0
- package/src/components/card.tsx +21 -0
- package/src/components/collapsible.tsx +1 -0
- package/src/components/context-menu.tsx +34 -0
- package/src/components/dock-surface.tsx +3 -0
- package/src/components/file-icon.tsx +12 -0
- package/src/components/image-preview.tsx +1 -0
- package/src/components/list.tsx +32 -0
- package/src/components/motion-spring.tsx +5 -0
- package/src/components/popover.tsx +12 -0
- package/src/components/provider-icon.tsx +1 -0
- package/src/components/resize-handle.tsx +8 -0
- package/src/components/scroll-view.tsx +39 -0
- package/src/components/spinner.tsx +2 -0
- package/src/components/text-field.tsx +6 -0
- package/src/components/text-reveal.tsx +19 -0
- package/src/components/text-strikethrough.tsx +8 -0
- package/src/components/typewriter.tsx +4 -0
- package/src/context/dialog.tsx +12 -0
- package/src/context/file.tsx +1 -0
- package/src/context/helper.tsx +4 -0
- package/src/context/i18n.tsx +20 -0
- package/src/context/index.ts +3 -0
- package/src/context/marked-base.tsx +9 -1
- package/src/context/marked-parser.tsx +57 -18
- package/src/context/marked.tsx +3 -0
- package/src/context/worker-pool.tsx +2 -0
- package/src/data-display/avatar/avatar.tsx +4 -0
- package/src/data-display/badge/badge.tsx +1 -0
- package/src/data-display/diff-changes/diff-changes.tsx +2 -0
- package/src/data-display/keybind/keybind.tsx +1 -0
- package/src/data-display/line-comment/line-comment.tsx +22 -0
- package/src/data-display/project-avatar/project-avatar.tsx +10 -0
- package/src/feedback/loader/loader.tsx +1 -0
- package/src/feedback/toast/description.ts +1 -0
- package/src/forms/checkbox/checkbox.tsx +1 -0
- package/src/forms/field/field.tsx +8 -0
- package/src/forms/inline-input/inline-input.tsx +4 -0
- package/src/forms/radio/radio.tsx +2 -0
- package/src/forms/select/select.tsx +11 -0
- package/src/forms/switch/switch.tsx +1 -0
- package/src/forms/text-input/text-input.tsx +3 -0
- package/src/hooks/create-auto-scroll.tsx +34 -0
- package/src/hooks/index.ts +1 -0
- package/src/hooks/use-filtered-list.tsx +14 -0
- package/src/i18n/en.ts +1 -0
- package/src/i18n/no.ts +1 -0
- package/src/icons/catalog.ts +36 -0
- package/src/icons/icon/icon.tsx +2 -0
- package/src/layout/divider/divider.tsx +1 -0
- package/src/navigation/menu/menu.tsx +13 -0
- package/src/navigation/segmented-control/segmented-control.css +37 -4
- package/src/navigation/segmented-control/segmented-control.tsx +210 -14
- package/src/navigation/tab-state-indicator.tsx +1 -0
- package/src/navigation/tabs/tabs-current.css +1 -5
- package/src/navigation/tabs/tabs.css +5 -22
- package/src/navigation/tabs/tabs.tsx +18 -0
- package/src/overlays/dialog/dialog.tsx +3 -0
- package/src/overlays/tooltip/tooltip.tsx +15 -0
- package/src/storybook/scaffold.tsx +3 -0
- package/src/styles/theme.css +1 -1
- package/src/theme/color.ts +27 -0
- package/src/theme/context.tsx +58 -0
- package/src/theme/default-themes.ts +35 -0
- package/src/theme/index.ts +3 -0
- package/src/theme/loader.ts +11 -0
- package/src/theme/resolve.ts +28 -0
- package/src/theme/v2/foreground.ts +8 -0
- package/src/theme/v2/resolve.ts +10 -0
- package/src/typography/text-shimmer/text-shimmer.tsx +1 -0
|
@@ -8,7 +8,9 @@ const segmenter =
|
|
|
8
8
|
|
|
9
9
|
function first(value: string) {
|
|
10
10
|
if (!value) return ""
|
|
11
|
+
|
|
11
12
|
if (!segmenter) return Array.from(value)[0] ?? ""
|
|
13
|
+
|
|
12
14
|
return segmenter.segment(value)[Symbol.iterator]().next().value?.segment ?? Array.from(value)[0] ?? ""
|
|
13
15
|
}
|
|
14
16
|
|
|
@@ -33,14 +35,19 @@ const OPENCODE_PROJECT_ID = "4b0ea68d7af9a6031a7ffda7ad66e0cb83315750"
|
|
|
33
35
|
|
|
34
36
|
export function getProjectAvatarSource(id?: string, icon?: { color?: string; url?: string; override?: string }) {
|
|
35
37
|
if (id === OPENCODE_PROJECT_ID) return "https://opencode.ai/favicon.svg"
|
|
38
|
+
|
|
36
39
|
if (icon?.override) return icon.override
|
|
40
|
+
|
|
37
41
|
if (icon?.color) return undefined
|
|
42
|
+
|
|
38
43
|
return icon?.url
|
|
39
44
|
}
|
|
40
45
|
|
|
41
46
|
export function getProjectAvatarVariant(key?: string): ProjectAvatarVariant {
|
|
42
47
|
if (key === "mint") return "cyan"
|
|
48
|
+
|
|
43
49
|
if (key === "lime") return "green"
|
|
50
|
+
|
|
44
51
|
if (
|
|
45
52
|
key === "orange" ||
|
|
46
53
|
key === "yellow" ||
|
|
@@ -53,12 +60,14 @@ export function getProjectAvatarVariant(key?: string): ProjectAvatarVariant {
|
|
|
53
60
|
key === "gray"
|
|
54
61
|
)
|
|
55
62
|
return key
|
|
63
|
+
|
|
56
64
|
return "gray"
|
|
57
65
|
}
|
|
58
66
|
|
|
59
67
|
export const displayName = (project: { name?: string; worktree: string }) => {
|
|
60
68
|
const trimmed = project.worktree.replace(/[/\\]+$/, "")
|
|
61
69
|
const filename = trimmed.slice(Math.max(trimmed.lastIndexOf("/"), trimmed.lastIndexOf("\\")) + 1)
|
|
70
|
+
|
|
62
71
|
return project.name || filename || project.worktree
|
|
63
72
|
}
|
|
64
73
|
|
|
@@ -71,6 +80,7 @@ export interface ProjectAvatarProps extends ComponentProps<"div"> {
|
|
|
71
80
|
|
|
72
81
|
export function ProjectAvatar(props: ProjectAvatarProps) {
|
|
73
82
|
const [split, rest] = splitProps(props, ["fallback", "src", "variant", "unread", "class", "classList", "style"])
|
|
83
|
+
|
|
74
84
|
return (
|
|
75
85
|
<div
|
|
76
86
|
{...rest}
|
|
@@ -5,5 +5,6 @@ export const toastDescriptionLimit = 2000
|
|
|
5
5
|
|
|
6
6
|
export function boundToastDescription<T extends { description?: string }>(options: T): T {
|
|
7
7
|
if (!options.description || options.description.length <= toastDescriptionLimit) return options
|
|
8
|
+
|
|
8
9
|
return { ...options, description: `${options.description.slice(0, toastDescriptionLimit)}…` }
|
|
9
10
|
}
|
|
@@ -10,6 +10,7 @@ export interface CheckboxProps extends ParentProps<ComponentProps<typeof Root>>
|
|
|
10
10
|
|
|
11
11
|
export function Checkbox(props: CheckboxProps) {
|
|
12
12
|
const [local, others] = splitProps(props, ["children", "class", "label", "hideLabel", "description", "icon"])
|
|
13
|
+
|
|
13
14
|
return (
|
|
14
15
|
<Root {...others} data-component="checkbox">
|
|
15
16
|
<Input data-slot="checkbox-checkbox-input" />
|
|
@@ -31,9 +31,11 @@ const FieldContext = createContext<FieldContextValue>()
|
|
|
31
31
|
|
|
32
32
|
function useField() {
|
|
33
33
|
const ctx = useContext(FieldContext)
|
|
34
|
+
|
|
34
35
|
if (!ctx) {
|
|
35
36
|
throw new Error("Field subcomponents must be used within <Field>")
|
|
36
37
|
}
|
|
38
|
+
|
|
37
39
|
return ctx
|
|
38
40
|
}
|
|
39
41
|
|
|
@@ -72,17 +74,22 @@ function FieldRoot(props: ParentProps<FieldProps>) {
|
|
|
72
74
|
unregisterSuffix: () => setSuffixCount((n) => Math.max(0, n - 1)),
|
|
73
75
|
getDescribedBy: () => {
|
|
74
76
|
const ids: string[] = []
|
|
77
|
+
|
|
75
78
|
if (prefixCount() > 0) ids.push(prefixId)
|
|
79
|
+
|
|
76
80
|
if (suffixCount() > 0) ids.push(suffixId)
|
|
81
|
+
|
|
77
82
|
return ids.length > 0 ? ids.join(" ") : undefined
|
|
78
83
|
},
|
|
79
84
|
}
|
|
80
85
|
|
|
81
86
|
const syncControlA11y = () => {
|
|
82
87
|
const root = rootRef
|
|
88
|
+
|
|
83
89
|
if (!root) return
|
|
84
90
|
|
|
85
91
|
const control = root.querySelector(CONTROL_SELECTOR) as HTMLInputElement | HTMLTextAreaElement | null
|
|
92
|
+
|
|
86
93
|
if (!control) return
|
|
87
94
|
|
|
88
95
|
const shell = control.closest(
|
|
@@ -93,6 +100,7 @@ function FieldRoot(props: ParentProps<FieldProps>) {
|
|
|
93
100
|
control.setAttribute("aria-labelledby", labelId)
|
|
94
101
|
|
|
95
102
|
const describedBy = ctx.getDescribedBy()
|
|
103
|
+
|
|
96
104
|
if (describedBy) {
|
|
97
105
|
control.setAttribute("aria-describedby", describedBy)
|
|
98
106
|
} else {
|
|
@@ -10,11 +10,15 @@ export function InlineInput(props: InlineInputProps) {
|
|
|
10
10
|
|
|
11
11
|
const style = () => {
|
|
12
12
|
if (!local.style) return { width: local.width }
|
|
13
|
+
|
|
13
14
|
if (typeof local.style === "string") {
|
|
14
15
|
if (!local.width) return local.style
|
|
16
|
+
|
|
15
17
|
return `${local.style};width:${local.width}`
|
|
16
18
|
}
|
|
19
|
+
|
|
17
20
|
if (!local.width) return local.style
|
|
21
|
+
|
|
18
22
|
return { ...local.style, width: local.width }
|
|
19
23
|
}
|
|
20
24
|
|
|
@@ -21,6 +21,7 @@ export interface RadioGroupProps extends ParentProps<ComponentProps<typeof Root>
|
|
|
21
21
|
|
|
22
22
|
export function RadioGroup(props: RadioGroupProps) {
|
|
23
23
|
const [local, others] = splitProps(props, ["class", "classList", "children", "label", "description", "hideLabel"])
|
|
24
|
+
|
|
24
25
|
return (
|
|
25
26
|
<Root
|
|
26
27
|
{...others}
|
|
@@ -54,6 +55,7 @@ export interface RadioItemProps extends ComponentProps<typeof Item> {
|
|
|
54
55
|
|
|
55
56
|
export function RadioItem(props: RadioItemProps) {
|
|
56
57
|
const [local, others] = splitProps(props, ["class", "classList", "label", "description", "hideLabel"])
|
|
58
|
+
|
|
57
59
|
return (
|
|
58
60
|
<Item
|
|
59
61
|
{...others}
|
|
@@ -17,13 +17,17 @@ function groupOptions<T>(options: T[], groupBy?: (x: T) => string): { category:
|
|
|
17
17
|
if (!groupBy) {
|
|
18
18
|
return [{ category: "", options }]
|
|
19
19
|
}
|
|
20
|
+
|
|
20
21
|
const map = new Map<string, T[]>()
|
|
22
|
+
|
|
21
23
|
for (const opt of options) {
|
|
22
24
|
const key = groupBy(opt)
|
|
23
25
|
const arr = map.get(key)
|
|
26
|
+
|
|
24
27
|
if (arr) arr.push(opt)
|
|
25
28
|
else map.set(key, [opt])
|
|
26
29
|
}
|
|
30
|
+
|
|
27
31
|
return [...map.entries()].map(([category, opts]) => ({ category, options: opts }))
|
|
28
32
|
}
|
|
29
33
|
|
|
@@ -110,11 +114,15 @@ export function Select<T>(props: SelectProps<T>) {
|
|
|
110
114
|
|
|
111
115
|
const move = (item: T | undefined) => {
|
|
112
116
|
if (!local.onHighlight) return
|
|
117
|
+
|
|
113
118
|
if (!item) {
|
|
114
119
|
stop()
|
|
120
|
+
|
|
115
121
|
return
|
|
116
122
|
}
|
|
123
|
+
|
|
117
124
|
const key = keyFor(item)
|
|
125
|
+
|
|
118
126
|
if (state.key === key) return
|
|
119
127
|
state.cleanup?.()
|
|
120
128
|
state.cleanup = local.onHighlight(item)
|
|
@@ -178,6 +186,7 @@ export function Select<T>(props: SelectProps<T>) {
|
|
|
178
186
|
}}
|
|
179
187
|
onOpenChange={(open) => {
|
|
180
188
|
local.onOpenChange?.(open)
|
|
189
|
+
|
|
181
190
|
if (!open) stop()
|
|
182
191
|
}}
|
|
183
192
|
>
|
|
@@ -200,7 +209,9 @@ export function Select<T>(props: SelectProps<T>) {
|
|
|
200
209
|
<Value<T> data-slot="select-v2-value-text" class={local.valueClass}>
|
|
201
210
|
{(st) => {
|
|
202
211
|
const selected = st.selectedOption()
|
|
212
|
+
|
|
203
213
|
if (local.label && selected != null) return local.label(selected)
|
|
214
|
+
|
|
204
215
|
return selected != null ? (selected as string) : ""
|
|
205
216
|
}}
|
|
206
217
|
</Value>
|
|
@@ -12,6 +12,7 @@ export interface SwitchProps extends ParentProps<ComponentProps<typeof Root>> {
|
|
|
12
12
|
|
|
13
13
|
export function Switch(props: SwitchProps) {
|
|
14
14
|
const [local, others] = splitProps(props, ["children", "class", "appearance", "hideLabel", "description"])
|
|
15
|
+
|
|
15
16
|
return (
|
|
16
17
|
<Root {...others} class={local.class} data-component="switch" data-appearance={local.appearance ?? "compact"}>
|
|
17
18
|
<Input data-slot="switch-input" />
|
|
@@ -29,6 +29,7 @@ export interface TextInputProps extends Omit<ComponentProps<"input">, "type"> {
|
|
|
29
29
|
|
|
30
30
|
export function TextInput(props: TextInputProps) {
|
|
31
31
|
const i18n = useI18n()
|
|
32
|
+
|
|
32
33
|
const [local, inputProps] = splitProps(props, [
|
|
33
34
|
"class",
|
|
34
35
|
"classList",
|
|
@@ -89,8 +90,10 @@ export function TextInput(props: TextInputProps) {
|
|
|
89
90
|
onClick={(event) => {
|
|
90
91
|
if (local.showClearButton) {
|
|
91
92
|
local.onClearClick?.(event)
|
|
93
|
+
|
|
92
94
|
return
|
|
93
95
|
}
|
|
96
|
+
|
|
94
97
|
local.onCopyClick?.(event)
|
|
95
98
|
}}
|
|
96
99
|
>
|
|
@@ -53,10 +53,12 @@ export function createAutoScroll(options: AutoScrollOptions) {
|
|
|
53
53
|
|
|
54
54
|
const isAuto = (el: HTMLElement) => {
|
|
55
55
|
const a = auto
|
|
56
|
+
|
|
56
57
|
if (!a) return false
|
|
57
58
|
|
|
58
59
|
if (Date.now() - a.time > 1500) {
|
|
59
60
|
auto = undefined
|
|
61
|
+
|
|
60
62
|
return false
|
|
61
63
|
}
|
|
62
64
|
|
|
@@ -65,10 +67,13 @@ export function createAutoScroll(options: AutoScrollOptions) {
|
|
|
65
67
|
|
|
66
68
|
const scrollToBottomNow = (behavior: ScrollBehavior) => {
|
|
67
69
|
const el = store.scrollRef
|
|
70
|
+
|
|
68
71
|
if (!el) return
|
|
69
72
|
markAuto(el)
|
|
73
|
+
|
|
70
74
|
if (behavior === "smooth") {
|
|
71
75
|
el.scrollTo({ top: el.scrollHeight, behavior })
|
|
76
|
+
|
|
72
77
|
return
|
|
73
78
|
}
|
|
74
79
|
|
|
@@ -82,13 +87,16 @@ export function createAutoScroll(options: AutoScrollOptions) {
|
|
|
82
87
|
if (force && store.userScrolled) setStore("userScrolled", false)
|
|
83
88
|
|
|
84
89
|
const el = store.scrollRef
|
|
90
|
+
|
|
85
91
|
if (!el) return
|
|
86
92
|
|
|
87
93
|
if (!force && store.userScrolled) return
|
|
88
94
|
|
|
89
95
|
const distance = distanceFromBottom(el)
|
|
96
|
+
|
|
90
97
|
if (distance < 2) {
|
|
91
98
|
markAuto(el)
|
|
99
|
+
|
|
92
100
|
return
|
|
93
101
|
}
|
|
94
102
|
|
|
@@ -99,11 +107,15 @@ export function createAutoScroll(options: AutoScrollOptions) {
|
|
|
99
107
|
|
|
100
108
|
const stop = () => {
|
|
101
109
|
const el = store.scrollRef
|
|
110
|
+
|
|
102
111
|
if (!el) return
|
|
112
|
+
|
|
103
113
|
if (!canScroll(el)) {
|
|
104
114
|
if (store.userScrolled) setStore("userScrolled", false)
|
|
115
|
+
|
|
105
116
|
return
|
|
106
117
|
}
|
|
118
|
+
|
|
107
119
|
if (store.userScrolled) return
|
|
108
120
|
|
|
109
121
|
setStore("userScrolled", true)
|
|
@@ -118,27 +130,32 @@ export function createAutoScroll(options: AutoScrollOptions) {
|
|
|
118
130
|
const el = store.scrollRef
|
|
119
131
|
const target = e.target instanceof Element ? e.target : undefined
|
|
120
132
|
const nested = target?.closest("[data-scrollable]")
|
|
133
|
+
|
|
121
134
|
if (el && nested && nested !== el) return
|
|
122
135
|
stop()
|
|
123
136
|
}
|
|
124
137
|
|
|
125
138
|
const handleScroll = () => {
|
|
126
139
|
const el = store.scrollRef
|
|
140
|
+
|
|
127
141
|
if (!el) return
|
|
128
142
|
|
|
129
143
|
if (!canScroll(el)) {
|
|
130
144
|
if (store.userScrolled) setStore("userScrolled", false)
|
|
145
|
+
|
|
131
146
|
return
|
|
132
147
|
}
|
|
133
148
|
|
|
134
149
|
if (distanceFromBottom(el) < threshold()) {
|
|
135
150
|
if (store.userScrolled) setStore("userScrolled", false)
|
|
151
|
+
|
|
136
152
|
return
|
|
137
153
|
}
|
|
138
154
|
|
|
139
155
|
// Ignore scroll events triggered by our own scrollToBottom calls.
|
|
140
156
|
if (!store.userScrolled && isAuto(el)) {
|
|
141
157
|
scrollToBottom(false)
|
|
158
|
+
|
|
142
159
|
return
|
|
143
160
|
}
|
|
144
161
|
|
|
@@ -148,6 +165,7 @@ export function createAutoScroll(options: AutoScrollOptions) {
|
|
|
148
165
|
const handleInteraction = () => {
|
|
149
166
|
if (!active()) return
|
|
150
167
|
const selection = window.getSelection()
|
|
168
|
+
|
|
151
169
|
if (selection && selection.toString().length > 0) {
|
|
152
170
|
stop()
|
|
153
171
|
}
|
|
@@ -158,11 +176,13 @@ export function createAutoScroll(options: AutoScrollOptions) {
|
|
|
158
176
|
|
|
159
177
|
if (mode === "none") {
|
|
160
178
|
el.style.overflowAnchor = "none"
|
|
179
|
+
|
|
161
180
|
return
|
|
162
181
|
}
|
|
163
182
|
|
|
164
183
|
if (mode === "auto") {
|
|
165
184
|
el.style.overflowAnchor = "auto"
|
|
185
|
+
|
|
166
186
|
return
|
|
167
187
|
}
|
|
168
188
|
|
|
@@ -173,11 +193,15 @@ export function createAutoScroll(options: AutoScrollOptions) {
|
|
|
173
193
|
() => store.contentRef,
|
|
174
194
|
() => {
|
|
175
195
|
const el = store.scrollRef
|
|
196
|
+
|
|
176
197
|
if (el && !canScroll(el)) {
|
|
177
198
|
if (store.userScrolled) setStore("userScrolled", false)
|
|
199
|
+
|
|
178
200
|
return
|
|
179
201
|
}
|
|
202
|
+
|
|
180
203
|
if (!active()) return
|
|
204
|
+
|
|
181
205
|
if (store.userScrolled) return
|
|
182
206
|
// ResizeObserver fires after layout, before paint.
|
|
183
207
|
// Keep the bottom locked in the same frame to avoid visible
|
|
@@ -188,20 +212,26 @@ export function createAutoScroll(options: AutoScrollOptions) {
|
|
|
188
212
|
|
|
189
213
|
createEffect(() => {
|
|
190
214
|
const el = store.scrollRef
|
|
215
|
+
|
|
191
216
|
if (!el) return
|
|
192
217
|
const root = el.closest("main")
|
|
218
|
+
|
|
193
219
|
if (!root) return
|
|
194
220
|
let connected = el.isConnected
|
|
195
221
|
const contains = (node: Node) => node === el || (node instanceof Element && node.contains(el))
|
|
222
|
+
|
|
196
223
|
const observer = new MutationObserver((records) => {
|
|
197
224
|
records.forEach((record) => {
|
|
198
225
|
if ([...record.removedNodes].some(contains)) connected = false
|
|
226
|
+
|
|
199
227
|
if (!record.addedNodes.length || ![...record.addedNodes].some(contains)) return
|
|
200
228
|
const reattached = !connected
|
|
201
229
|
connected = true
|
|
230
|
+
|
|
202
231
|
if (reattached) scrollToBottom(false)
|
|
203
232
|
})
|
|
204
233
|
})
|
|
234
|
+
|
|
205
235
|
observer.observe(root, { childList: true })
|
|
206
236
|
onCleanup(() => observer.disconnect())
|
|
207
237
|
})
|
|
@@ -209,11 +239,13 @@ export function createAutoScroll(options: AutoScrollOptions) {
|
|
|
209
239
|
createEffect(
|
|
210
240
|
on(options.working, (working: boolean) => {
|
|
211
241
|
settling = false
|
|
242
|
+
|
|
212
243
|
if (settleTimer) clearTimeout(settleTimer)
|
|
213
244
|
settleTimer = undefined
|
|
214
245
|
|
|
215
246
|
if (working) {
|
|
216
247
|
if (!store.userScrolled) scrollToBottom(true)
|
|
248
|
+
|
|
217
249
|
return
|
|
218
250
|
}
|
|
219
251
|
|
|
@@ -229,6 +261,7 @@ export function createAutoScroll(options: AutoScrollOptions) {
|
|
|
229
261
|
// update overflow anchoring once the element exists.
|
|
230
262
|
store.userScrolled
|
|
231
263
|
const el = store.scrollRef
|
|
264
|
+
|
|
232
265
|
if (!el) return
|
|
233
266
|
updateOverflowAnchor(el)
|
|
234
267
|
})
|
|
@@ -237,6 +270,7 @@ export function createAutoScroll(options: AutoScrollOptions) {
|
|
|
237
270
|
|
|
238
271
|
onCleanup(() => {
|
|
239
272
|
if (settleTimer) clearTimeout(settleTimer)
|
|
273
|
+
|
|
240
274
|
if (autoTimer) clearTimeout(autoTimer)
|
|
241
275
|
})
|
|
242
276
|
|
package/src/hooks/index.ts
CHANGED
|
@@ -21,6 +21,7 @@ export function useFilteredList<T>(props: FilteredListProps<T>) {
|
|
|
21
21
|
const [store, setStore] = createStore<{ filter: string }>({ filter: "" })
|
|
22
22
|
|
|
23
23
|
type Group = { category: string; items: [T, ...T[]] }
|
|
24
|
+
|
|
24
25
|
const empty: Group[] = []
|
|
25
26
|
|
|
26
27
|
const [grouped, { refetch }] = createResource(
|
|
@@ -32,6 +33,7 @@ export function useFilteredList<T>(props: FilteredListProps<T>) {
|
|
|
32
33
|
const query = filter ?? ""
|
|
33
34
|
const needle = query.toLowerCase()
|
|
34
35
|
const all = (await Promise.resolve(items)) || []
|
|
36
|
+
|
|
35
37
|
const result = pipe(
|
|
36
38
|
all,
|
|
37
39
|
(x) => {
|
|
@@ -39,10 +41,12 @@ export function useFilteredList<T>(props: FilteredListProps<T>) {
|
|
|
39
41
|
const skipFilter = props.skipFilter
|
|
40
42
|
const filterable = skipFilter ? x.filter((item) => !skipFilter(item)) : x
|
|
41
43
|
const skipped = skipFilter ? x.filter(skipFilter) : []
|
|
44
|
+
|
|
42
45
|
const filtered =
|
|
43
46
|
!props.filterKeys && Array.isArray(filterable) && filterable.every((e) => typeof e === "string")
|
|
44
47
|
? (fuzzysort.go(needle, filterable).map((x) => x.target) as T[])
|
|
45
48
|
: fuzzysort.go(needle, filterable, { keys: props.filterKeys! }).map((x) => x.obj)
|
|
49
|
+
|
|
46
50
|
return skipped.length ? [...filtered, ...skipped] : filtered
|
|
47
51
|
},
|
|
48
52
|
groupBy((x) => (props.groupBy ? props.groupBy(x) : "")),
|
|
@@ -50,6 +54,7 @@ export function useFilteredList<T>(props: FilteredListProps<T>) {
|
|
|
50
54
|
map(([k, v]) => ({ category: k, items: props.sortBy ? v.sort(props.sortBy) : v })),
|
|
51
55
|
(groups) => (props.sortGroupsBy ? groups.sort(props.sortGroupsBy) : groups),
|
|
52
56
|
)
|
|
57
|
+
|
|
53
58
|
return result
|
|
54
59
|
},
|
|
55
60
|
{ initialValue: empty },
|
|
@@ -64,10 +69,13 @@ export function useFilteredList<T>(props: FilteredListProps<T>) {
|
|
|
64
69
|
|
|
65
70
|
function initialActive() {
|
|
66
71
|
if (props.noInitialSelection) return ""
|
|
72
|
+
|
|
67
73
|
if (props.current) return props.key(props.current)
|
|
68
74
|
|
|
69
75
|
const items = flat()
|
|
76
|
+
|
|
70
77
|
if (items.length === 0) return ""
|
|
78
|
+
|
|
71
79
|
return props.key(items[0])
|
|
72
80
|
}
|
|
73
81
|
|
|
@@ -80,9 +88,12 @@ export function useFilteredList<T>(props: FilteredListProps<T>) {
|
|
|
80
88
|
const reset = () => {
|
|
81
89
|
if (props.noInitialSelection) {
|
|
82
90
|
list.setActive("")
|
|
91
|
+
|
|
83
92
|
return
|
|
84
93
|
}
|
|
94
|
+
|
|
85
95
|
const all = flat()
|
|
96
|
+
|
|
86
97
|
if (all.length === 0) return
|
|
87
98
|
list.setActive(props.key(all[0]))
|
|
88
99
|
}
|
|
@@ -92,14 +103,17 @@ export function useFilteredList<T>(props: FilteredListProps<T>) {
|
|
|
92
103
|
event.preventDefault()
|
|
93
104
|
const selectedIndex = flat().findIndex((x) => props.key(x) === list.active())
|
|
94
105
|
const selected = flat()[selectedIndex]
|
|
106
|
+
|
|
95
107
|
if (selected) props.onSelect?.(selected, selectedIndex)
|
|
96
108
|
} else if (event.ctrlKey && !event.metaKey && !event.altKey && !event.shiftKey) {
|
|
97
109
|
if (event.key === "n" || event.key === "p") {
|
|
98
110
|
event.preventDefault()
|
|
111
|
+
|
|
99
112
|
const navEvent = new KeyboardEvent("keydown", {
|
|
100
113
|
key: event.key === "n" ? "ArrowDown" : "ArrowUp",
|
|
101
114
|
bubbles: true,
|
|
102
115
|
})
|
|
116
|
+
|
|
103
117
|
list.onKeyDown(navEvent)
|
|
104
118
|
}
|
|
105
119
|
} else {
|
package/src/i18n/en.ts
CHANGED
|
@@ -244,6 +244,7 @@ const source = {
|
|
|
244
244
|
"ui.message.forkMessage": "Fork to new session",
|
|
245
245
|
"ui.message.revertMessage": "Revert message",
|
|
246
246
|
"ui.message.moveToQueue": "Move to queue",
|
|
247
|
+
"ui.message.pending": "Pending",
|
|
247
248
|
"ui.message.deletePending": "Delete",
|
|
248
249
|
"ui.message.copyResponse": "Copy response",
|
|
249
250
|
"ui.message.copied": "Copied",
|
package/src/i18n/no.ts
CHANGED
package/src/icons/catalog.ts
CHANGED
|
@@ -186,6 +186,38 @@ const icons = {
|
|
|
186
186
|
viewBox: "0 0 16 16",
|
|
187
187
|
body: `<path d="M4.14908 11.0081H1.76282V1.51758H9.1038V2.55588M14.2225 4.99681H6.75397V14.4873H14.2225V4.99681Z" stroke="currentColor"/>`,
|
|
188
188
|
},
|
|
189
|
+
"outline-arrow-left": {
|
|
190
|
+
viewBox: "0 0 16 16",
|
|
191
|
+
body: `<path d="M2.44442 7.99999H13.5555M6.22221 4.22222L2.44442 7.99999L6.22221 11.7778" stroke="currentColor"/>`,
|
|
192
|
+
},
|
|
193
|
+
"outline-arrow-right": {
|
|
194
|
+
viewBox: "0 0 16 16",
|
|
195
|
+
body: `<path d="M13.5555 7.99999H2.4444M9.77773 11.7778L13.5555 7.99999L9.77773 4.22222" stroke="currentColor"/>`,
|
|
196
|
+
},
|
|
197
|
+
"outline-arrow-up-right": {
|
|
198
|
+
viewBox: "0 0 16 16",
|
|
199
|
+
body: `<path d="M12.5 3.5L3.5 12.5M12.5 9.62L12.5 3.5L6.38 3.5" stroke="currentColor"/>`,
|
|
200
|
+
},
|
|
201
|
+
"outline-rotate-clockwise": {
|
|
202
|
+
viewBox: "0 0 16 16",
|
|
203
|
+
body: `<path d="M14.1992 8C14.1992 9.18669 13.8473 10.3467 13.188 11.3334C12.5288 12.3201 11.5917 13.0892 10.4953 13.5433C9.39897 13.9974 8.19257 14.1162 7.02868 13.8847C5.86479 13.6532 4.7957 13.0818 3.95658 12.2426C3.11747 11.4035 2.54602 10.3344 2.31451 9.17054C2.083 8.00666 2.20182 6.80026 2.65594 5.7039C3.11007 4.60754 3.87911 3.67047 4.8658 3.01118C5.85249 2.35189 7.01253 2 8.19922 2C9.87922 2 11.4859 2.66667 12.6926 3.82667L14.1992 5.33333M10.866 5.33333L14.1992 5.33333L14.1993 2" stroke="currentColor" stroke-linecap="square" stroke-linejoin="round"/>`,
|
|
204
|
+
},
|
|
205
|
+
"outline-globe": {
|
|
206
|
+
viewBox: "0 0 16 16",
|
|
207
|
+
body: `<path d="M8.00001 14.4445C9.47277 14.4445 10.6667 11.5592 10.6667 8.00001C10.6667 4.44085 9.47277 1.55557 8.00001 1.55557M8.00001 14.4445C6.52725 14.4445 5.33335 11.5592 5.33335 8.00001C5.33335 4.44085 6.52725 1.55557 8.00001 1.55557M8.00001 14.4445C11.5592 14.4445 14.4444 11.5592 14.4444 8C14.4444 4.44083 11.5592 1.55557 8.00001 1.55557M8.00001 14.4445C4.44085 14.4445 1.55556 11.5592 1.55556 8C1.55556 4.44083 4.44085 1.55557 8.00001 1.55557M1.87203 6.00001H14.128M2.03555 10.4445H13.9644" stroke="currentColor"/>`,
|
|
208
|
+
},
|
|
209
|
+
"outline-globe-plus": {
|
|
210
|
+
viewBox: "0 0 16 16",
|
|
211
|
+
body: `<path d="M7 12.6667C5.71133 12.6667 4.66667 10.1296 4.66667 7C4.66667 3.87039 5.71133 1.33333 7 1.33333C8.2426 1.33333 9.25833 3.69221 9.32933 6.66667" stroke="currentColor" stroke-miterlimit="10"/><path d="M12.6667 6.66667H1.33333" stroke="currentColor"/><path d="M12.6667 7.72825V7C12.6667 3.87039 10.1296 1.33333 7 1.33333C3.8704 1.33333 1.33333 3.87039 1.33333 7C1.33333 10.1296 3.8704 12.6667 7 12.6667H7.58694" stroke="currentColor" stroke-miterlimit="10"/><path d="M9.5 11.5H13.5M11.5 9.5V13.5" stroke="currentColor" stroke-miterlimit="10" stroke-linecap="square"/>`,
|
|
212
|
+
},
|
|
213
|
+
"outline-cookie": {
|
|
214
|
+
viewBox: "0 0 16 16",
|
|
215
|
+
body: `<path d="M14 8.5A6 6 0 1 1 7.5 2a2 2 0 0 0 2.5 2.5 2 2 0 0 0 2.5 2.5c.4.6.9 1.1 1.5 1.5Z" stroke="currentColor" stroke-linejoin="round"/><path d="M5.5 6.5h.01M5.5 10h.01M8.5 9h.01M10.5 11.5h.01" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"/>`,
|
|
216
|
+
},
|
|
217
|
+
"outline-browser-annotate": {
|
|
218
|
+
viewBox: "0 0 16 16",
|
|
219
|
+
body: `<path d="M10.6667 2H14V5.33333M2 5.33333V2H5.33333M2 10.6667V14H5.33333" stroke="currentColor" stroke-linecap="square"/><path d="M11.8571 11.8572L14 14M6.50008 6.50033L14.0001 9.00033L9.00008 14.0003L6.50008 6.50033Z" stroke="currentColor" stroke-linecap="square"/>`,
|
|
220
|
+
},
|
|
189
221
|
"arrow-up-right": {
|
|
190
222
|
viewBox: "0 0 16 16",
|
|
191
223
|
body: `<path d="M11 9.56V5H6.44M11 5L5 11" stroke="currentColor"/>`,
|
|
@@ -222,6 +254,10 @@ const icons = {
|
|
|
222
254
|
viewBox: "0 0 20 20",
|
|
223
255
|
body: `<path d="M5.83333 4.16406L2.5 7.4974L5.83333 10.8307M3.33333 7.4974H17.9167V15.4141H10" stroke="currentColor" stroke-linecap="square"/>`,
|
|
224
256
|
},
|
|
257
|
+
"outline-undo": {
|
|
258
|
+
viewBox: "0 0 16 16",
|
|
259
|
+
body: `<path d="M2 10L4.25193 7.76999C7.29213 4.7594 12.4119 5.77372 14.0747 9.71606" stroke="currentColor"/><path d="M2 6V10H6" stroke="currentColor" stroke-linecap="square"/>`,
|
|
260
|
+
},
|
|
225
261
|
"outline-reset": {
|
|
226
262
|
viewBox: "0 0 20 20",
|
|
227
263
|
body: `<path d="M5.83333 4.16406L2.5 7.4974L5.83333 10.8307M3.33333 7.4974H17.9167V15.4141H10" stroke="currentColor" stroke-linecap="square"/>`,
|
package/src/icons/icon/icon.tsx
CHANGED
|
@@ -63,6 +63,8 @@ export function Icon(props: IconProps) {
|
|
|
63
63
|
data-directional={
|
|
64
64
|
iconName() === "arrow-left" ||
|
|
65
65
|
iconName() === "arrow-right" ||
|
|
66
|
+
iconName() === "outline-arrow-left" ||
|
|
67
|
+
iconName() === "outline-arrow-right" ||
|
|
66
68
|
iconName() === "chevron-left" ||
|
|
67
69
|
iconName() === "chevron-right"
|
|
68
70
|
? ""
|