@opencode/ui 0.0.0-dev-20607 → 0.0.0-dev-20610
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/package.json +1 -1
- package/src/actions/button/button.tsx +1 -0
- package/src/actions/icon-button/icon-button.tsx +1 -0
- package/src/actions/split-button/split-button.tsx +3 -0
- 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 +7 -0
- package/src/context/marked-parser.tsx +7 -0
- 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/no.ts +1 -0
- package/src/layout/divider/divider.tsx +1 -0
- package/src/navigation/menu/menu.tsx +13 -0
- package/src/navigation/segmented-control/segmented-control.tsx +16 -0
- package/src/navigation/tab-state-indicator.tsx +1 -0
- 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/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
package/package.json
CHANGED
|
@@ -3,6 +3,7 @@ import "./split-button.css"
|
|
|
3
3
|
|
|
4
4
|
export function SplitButton(props: ParentProps<ComponentProps<"div">>) {
|
|
5
5
|
const [split, rest] = splitProps(props, ["class", "classList", "children"])
|
|
6
|
+
|
|
6
7
|
return (
|
|
7
8
|
<div
|
|
8
9
|
data-component="split-button-v2"
|
|
@@ -19,6 +20,7 @@ export function SplitButton(props: ParentProps<ComponentProps<"div">>) {
|
|
|
19
20
|
|
|
20
21
|
export function SplitButtonAction(props: ComponentProps<"button">) {
|
|
21
22
|
const [split, rest] = splitProps(props, ["class", "classList"])
|
|
23
|
+
|
|
22
24
|
return (
|
|
23
25
|
<button
|
|
24
26
|
type="button"
|
|
@@ -34,6 +36,7 @@ export function SplitButtonAction(props: ComponentProps<"button">) {
|
|
|
34
36
|
|
|
35
37
|
export function SplitButtonMenuTrigger(props: ComponentProps<"button">) {
|
|
36
38
|
const [split, rest] = splitProps(props, ["class", "classList"])
|
|
39
|
+
|
|
37
40
|
return (
|
|
38
41
|
<button
|
|
39
42
|
type="button"
|
|
@@ -2,6 +2,7 @@ import { For, Index, createEffect, createMemo, on } from "solid-js"
|
|
|
2
2
|
import { createStore } from "solid-js/store"
|
|
3
3
|
|
|
4
4
|
const TRACK = Array.from({ length: 30 }, (_, index) => index % 10)
|
|
5
|
+
|
|
5
6
|
const DURATION = 600
|
|
6
7
|
|
|
7
8
|
function normalize(value: number) {
|
|
@@ -10,7 +11,9 @@ function normalize(value: number) {
|
|
|
10
11
|
|
|
11
12
|
function spin(from: number, to: number, direction: 1 | -1) {
|
|
12
13
|
if (from === to) return 0
|
|
14
|
+
|
|
13
15
|
if (direction > 0) return (to - from + 10) % 10
|
|
16
|
+
|
|
14
17
|
return -((from - to + 10) % 10)
|
|
15
18
|
}
|
|
16
19
|
|
|
@@ -19,6 +22,7 @@ function Digit(props: { value: number; direction: 1 | -1 }) {
|
|
|
19
22
|
step: props.value + 10,
|
|
20
23
|
animating: false,
|
|
21
24
|
})
|
|
25
|
+
|
|
22
26
|
const step = () => state.step
|
|
23
27
|
const animating = () => state.animating
|
|
24
28
|
let last = props.value
|
|
@@ -29,9 +33,11 @@ function Digit(props: { value: number; direction: 1 | -1 }) {
|
|
|
29
33
|
(next) => {
|
|
30
34
|
const delta = spin(last, next, props.direction)
|
|
31
35
|
last = next
|
|
36
|
+
|
|
32
37
|
if (!delta) {
|
|
33
38
|
setState("animating", false)
|
|
34
39
|
setState("step", next + 10)
|
|
40
|
+
|
|
35
41
|
return
|
|
36
42
|
}
|
|
37
43
|
|
|
@@ -65,6 +71,7 @@ function Digit(props: { value: number; direction: 1 | -1 }) {
|
|
|
65
71
|
export function AnimatedNumber(props: { value: number; class?: string }) {
|
|
66
72
|
const target = createMemo(() => {
|
|
67
73
|
if (!Number.isFinite(props.value)) return 0
|
|
74
|
+
|
|
68
75
|
return Math.max(0, Math.round(props.value))
|
|
69
76
|
})
|
|
70
77
|
|
|
@@ -72,6 +79,7 @@ export function AnimatedNumber(props: { value: number; class?: string }) {
|
|
|
72
79
|
value: target(),
|
|
73
80
|
direction: 1 as 1 | -1,
|
|
74
81
|
})
|
|
82
|
+
|
|
75
83
|
const value = () => state.value
|
|
76
84
|
const direction = () => state.direction
|
|
77
85
|
|
|
@@ -80,6 +88,7 @@ export function AnimatedNumber(props: { value: number; class?: string }) {
|
|
|
80
88
|
target,
|
|
81
89
|
(next) => {
|
|
82
90
|
const current = value()
|
|
91
|
+
|
|
83
92
|
if (next === current) return
|
|
84
93
|
|
|
85
94
|
setState("direction", next > current ? 1 : -1)
|
|
@@ -90,13 +99,17 @@ export function AnimatedNumber(props: { value: number; class?: string }) {
|
|
|
90
99
|
)
|
|
91
100
|
|
|
92
101
|
const label = createMemo(() => value().toString())
|
|
102
|
+
|
|
93
103
|
const digits = createMemo(() =>
|
|
94
104
|
Array.from(label(), (char) => {
|
|
95
105
|
const code = char.charCodeAt(0) - 48
|
|
106
|
+
|
|
96
107
|
if (code < 0 || code > 9) return 0
|
|
108
|
+
|
|
97
109
|
return code
|
|
98
110
|
}).reverse(),
|
|
99
111
|
)
|
|
112
|
+
|
|
100
113
|
const width = createMemo(() => `${digits().length}ch`)
|
|
101
114
|
|
|
102
115
|
return (
|
|
@@ -46,7 +46,9 @@ const themed: Partial<Record<IconName, { light: string; dark: string }>> = {
|
|
|
46
46
|
|
|
47
47
|
const scheme = () => {
|
|
48
48
|
if (typeof document !== "object") return "light" as const
|
|
49
|
+
|
|
49
50
|
if (document.documentElement.dataset.colorScheme === "dark") return "dark" as const
|
|
51
|
+
|
|
50
52
|
return "light" as const
|
|
51
53
|
}
|
|
52
54
|
|
package/src/components/card.tsx
CHANGED
|
@@ -22,30 +22,44 @@ export interface CardTitleProps extends ComponentProps<"div"> {
|
|
|
22
22
|
|
|
23
23
|
function pick(variant: Variant) {
|
|
24
24
|
if (variant === "error") return "circle-ban-sign" as const
|
|
25
|
+
|
|
25
26
|
if (variant === "warning") return "warning" as const
|
|
27
|
+
|
|
26
28
|
if (variant === "success") return "circle-check" as const
|
|
29
|
+
|
|
27
30
|
if (variant === "info") return "help" as const
|
|
31
|
+
|
|
28
32
|
return
|
|
29
33
|
}
|
|
30
34
|
|
|
31
35
|
function mix(style: ComponentProps<"div">["style"], value?: string) {
|
|
32
36
|
if (!value) return style
|
|
37
|
+
|
|
33
38
|
if (!style) return { "--card-accent": value }
|
|
39
|
+
|
|
34
40
|
if (typeof style === "string") return `${style};--card-accent:${value};`
|
|
41
|
+
|
|
35
42
|
return { ...(style as Record<string, string | number>), "--card-accent": value }
|
|
36
43
|
}
|
|
37
44
|
|
|
38
45
|
export function Card(props: CardProps) {
|
|
39
46
|
const [split, rest] = splitProps(props, ["variant", "style", "class", "classList"])
|
|
40
47
|
const variant = () => split.variant ?? "normal"
|
|
48
|
+
|
|
41
49
|
const accent = () => {
|
|
42
50
|
const v = variant()
|
|
51
|
+
|
|
43
52
|
if (v === "error") return "var(--v2-state-fg-danger)"
|
|
53
|
+
|
|
44
54
|
if (v === "warning") return "var(--icon-warning-active)"
|
|
55
|
+
|
|
45
56
|
if (v === "success") return "var(--icon-success-active)"
|
|
57
|
+
|
|
46
58
|
if (v === "info") return "var(--icon-info-active)"
|
|
59
|
+
|
|
47
60
|
return
|
|
48
61
|
}
|
|
62
|
+
|
|
49
63
|
return (
|
|
50
64
|
<div
|
|
51
65
|
{...rest}
|
|
@@ -65,12 +79,17 @@ export function Card(props: CardProps) {
|
|
|
65
79
|
export function CardTitle(props: CardTitleProps) {
|
|
66
80
|
const [split, rest] = splitProps(props, ["variant", "icon", "class", "classList", "children"])
|
|
67
81
|
const show = () => split.icon !== false && split.icon !== null
|
|
82
|
+
|
|
68
83
|
const name = () => {
|
|
69
84
|
if (split.icon === false || split.icon === null) return
|
|
85
|
+
|
|
70
86
|
if (typeof split.icon === "string") return split.icon
|
|
87
|
+
|
|
71
88
|
return pick(split.variant ?? "normal")
|
|
72
89
|
}
|
|
90
|
+
|
|
73
91
|
const placeholder = () => !name()
|
|
92
|
+
|
|
74
93
|
return (
|
|
75
94
|
<div
|
|
76
95
|
{...rest}
|
|
@@ -92,6 +111,7 @@ export function CardTitle(props: CardTitleProps) {
|
|
|
92
111
|
|
|
93
112
|
export function CardDescription(props: ComponentProps<"div">) {
|
|
94
113
|
const [split, rest] = splitProps(props, ["class", "classList", "children"])
|
|
114
|
+
|
|
95
115
|
return (
|
|
96
116
|
<div
|
|
97
117
|
{...rest}
|
|
@@ -108,6 +128,7 @@ export function CardDescription(props: ComponentProps<"div">) {
|
|
|
108
128
|
|
|
109
129
|
export function CardActions(props: ComponentProps<"div">) {
|
|
110
130
|
const [split, rest] = splitProps(props, ["class", "classList", "children"])
|
|
131
|
+
|
|
111
132
|
return (
|
|
112
133
|
<div
|
|
113
134
|
{...rest}
|
|
@@ -10,6 +10,7 @@ export interface CollapsibleProps extends ParentProps<CollapsibleRootProps> {
|
|
|
10
10
|
|
|
11
11
|
function CollapsibleRoot(props: CollapsibleProps) {
|
|
12
12
|
const [local, others] = splitProps(props, ["class", "classList", "variant"])
|
|
13
|
+
|
|
13
14
|
return (
|
|
14
15
|
<Kobalte
|
|
15
16
|
data-component="collapsible"
|
|
@@ -3,23 +3,41 @@ import { splitProps } from "solid-js"
|
|
|
3
3
|
import type { ComponentProps, ParentProps } from "solid-js"
|
|
4
4
|
|
|
5
5
|
export interface ContextMenuProps extends ComponentProps<typeof Kobalte> {}
|
|
6
|
+
|
|
6
7
|
export interface ContextMenuTriggerProps extends ComponentProps<typeof Kobalte.Trigger> {}
|
|
8
|
+
|
|
7
9
|
export interface ContextMenuIconProps extends ComponentProps<typeof Kobalte.Icon> {}
|
|
10
|
+
|
|
8
11
|
export interface ContextMenuPortalProps extends ComponentProps<typeof Kobalte.Portal> {}
|
|
12
|
+
|
|
9
13
|
export interface ContextMenuContentProps extends ComponentProps<typeof Kobalte.Content> {}
|
|
14
|
+
|
|
10
15
|
export interface ContextMenuArrowProps extends ComponentProps<typeof Kobalte.Arrow> {}
|
|
16
|
+
|
|
11
17
|
export interface ContextMenuSeparatorProps extends ComponentProps<typeof Kobalte.Separator> {}
|
|
18
|
+
|
|
12
19
|
export interface ContextMenuGroupProps extends ComponentProps<typeof Kobalte.Group> {}
|
|
20
|
+
|
|
13
21
|
export interface ContextMenuGroupLabelProps extends ComponentProps<typeof Kobalte.GroupLabel> {}
|
|
22
|
+
|
|
14
23
|
export interface ContextMenuItemProps extends ComponentProps<typeof Kobalte.Item> {}
|
|
24
|
+
|
|
15
25
|
export interface ContextMenuItemLabelProps extends ComponentProps<typeof Kobalte.ItemLabel> {}
|
|
26
|
+
|
|
16
27
|
export interface ContextMenuItemDescriptionProps extends ComponentProps<typeof Kobalte.ItemDescription> {}
|
|
28
|
+
|
|
17
29
|
export interface ContextMenuItemIndicatorProps extends ComponentProps<typeof Kobalte.ItemIndicator> {}
|
|
30
|
+
|
|
18
31
|
export interface ContextMenuRadioGroupProps extends ComponentProps<typeof Kobalte.RadioGroup> {}
|
|
32
|
+
|
|
19
33
|
export interface ContextMenuRadioItemProps extends ComponentProps<typeof Kobalte.RadioItem> {}
|
|
34
|
+
|
|
20
35
|
export interface ContextMenuCheckboxItemProps extends ComponentProps<typeof Kobalte.CheckboxItem> {}
|
|
36
|
+
|
|
21
37
|
export interface ContextMenuSubProps extends ComponentProps<typeof Kobalte.Sub> {}
|
|
38
|
+
|
|
22
39
|
export interface ContextMenuSubTriggerProps extends ComponentProps<typeof Kobalte.SubTrigger> {}
|
|
40
|
+
|
|
23
41
|
export interface ContextMenuSubContentProps extends ComponentProps<typeof Kobalte.SubContent> {}
|
|
24
42
|
|
|
25
43
|
function ContextMenuRoot(props: ContextMenuProps) {
|
|
@@ -28,6 +46,7 @@ function ContextMenuRoot(props: ContextMenuProps) {
|
|
|
28
46
|
|
|
29
47
|
function ContextMenuTrigger(props: ParentProps<ContextMenuTriggerProps>) {
|
|
30
48
|
const [local, rest] = splitProps(props, ["class", "classList", "children"])
|
|
49
|
+
|
|
31
50
|
return (
|
|
32
51
|
<Kobalte.Trigger
|
|
33
52
|
{...rest}
|
|
@@ -44,6 +63,7 @@ function ContextMenuTrigger(props: ParentProps<ContextMenuTriggerProps>) {
|
|
|
44
63
|
|
|
45
64
|
function ContextMenuIcon(props: ParentProps<ContextMenuIconProps>) {
|
|
46
65
|
const [local, rest] = splitProps(props, ["class", "classList", "children"])
|
|
66
|
+
|
|
47
67
|
return (
|
|
48
68
|
<Kobalte.Icon
|
|
49
69
|
{...rest}
|
|
@@ -64,6 +84,7 @@ function ContextMenuPortal(props: ContextMenuPortalProps) {
|
|
|
64
84
|
|
|
65
85
|
function ContextMenuContent(props: ParentProps<ContextMenuContentProps>) {
|
|
66
86
|
const [local, rest] = splitProps(props, ["class", "classList", "children"])
|
|
87
|
+
|
|
67
88
|
return (
|
|
68
89
|
<Kobalte.Content
|
|
69
90
|
{...rest}
|
|
@@ -80,6 +101,7 @@ function ContextMenuContent(props: ParentProps<ContextMenuContentProps>) {
|
|
|
80
101
|
|
|
81
102
|
function ContextMenuArrow(props: ContextMenuArrowProps) {
|
|
82
103
|
const [local, rest] = splitProps(props, ["class", "classList"])
|
|
104
|
+
|
|
83
105
|
return (
|
|
84
106
|
<Kobalte.Arrow
|
|
85
107
|
{...rest}
|
|
@@ -94,6 +116,7 @@ function ContextMenuArrow(props: ContextMenuArrowProps) {
|
|
|
94
116
|
|
|
95
117
|
function ContextMenuSeparator(props: ContextMenuSeparatorProps) {
|
|
96
118
|
const [local, rest] = splitProps(props, ["class", "classList"])
|
|
119
|
+
|
|
97
120
|
return (
|
|
98
121
|
<Kobalte.Separator
|
|
99
122
|
{...rest}
|
|
@@ -108,6 +131,7 @@ function ContextMenuSeparator(props: ContextMenuSeparatorProps) {
|
|
|
108
131
|
|
|
109
132
|
function ContextMenuGroup(props: ParentProps<ContextMenuGroupProps>) {
|
|
110
133
|
const [local, rest] = splitProps(props, ["class", "classList", "children"])
|
|
134
|
+
|
|
111
135
|
return (
|
|
112
136
|
<Kobalte.Group
|
|
113
137
|
{...rest}
|
|
@@ -124,6 +148,7 @@ function ContextMenuGroup(props: ParentProps<ContextMenuGroupProps>) {
|
|
|
124
148
|
|
|
125
149
|
function ContextMenuGroupLabel(props: ParentProps<ContextMenuGroupLabelProps>) {
|
|
126
150
|
const [local, rest] = splitProps(props, ["class", "classList", "children"])
|
|
151
|
+
|
|
127
152
|
return (
|
|
128
153
|
<Kobalte.GroupLabel
|
|
129
154
|
{...rest}
|
|
@@ -140,6 +165,7 @@ function ContextMenuGroupLabel(props: ParentProps<ContextMenuGroupLabelProps>) {
|
|
|
140
165
|
|
|
141
166
|
function ContextMenuItem(props: ParentProps<ContextMenuItemProps>) {
|
|
142
167
|
const [local, rest] = splitProps(props, ["class", "classList", "children"])
|
|
168
|
+
|
|
143
169
|
return (
|
|
144
170
|
<Kobalte.Item
|
|
145
171
|
{...rest}
|
|
@@ -156,6 +182,7 @@ function ContextMenuItem(props: ParentProps<ContextMenuItemProps>) {
|
|
|
156
182
|
|
|
157
183
|
function ContextMenuItemLabel(props: ParentProps<ContextMenuItemLabelProps>) {
|
|
158
184
|
const [local, rest] = splitProps(props, ["class", "classList", "children"])
|
|
185
|
+
|
|
159
186
|
return (
|
|
160
187
|
<Kobalte.ItemLabel
|
|
161
188
|
{...rest}
|
|
@@ -172,6 +199,7 @@ function ContextMenuItemLabel(props: ParentProps<ContextMenuItemLabelProps>) {
|
|
|
172
199
|
|
|
173
200
|
function ContextMenuItemDescription(props: ParentProps<ContextMenuItemDescriptionProps>) {
|
|
174
201
|
const [local, rest] = splitProps(props, ["class", "classList", "children"])
|
|
202
|
+
|
|
175
203
|
return (
|
|
176
204
|
<Kobalte.ItemDescription
|
|
177
205
|
{...rest}
|
|
@@ -188,6 +216,7 @@ function ContextMenuItemDescription(props: ParentProps<ContextMenuItemDescriptio
|
|
|
188
216
|
|
|
189
217
|
function ContextMenuItemIndicator(props: ParentProps<ContextMenuItemIndicatorProps>) {
|
|
190
218
|
const [local, rest] = splitProps(props, ["class", "classList", "children"])
|
|
219
|
+
|
|
191
220
|
return (
|
|
192
221
|
<Kobalte.ItemIndicator
|
|
193
222
|
{...rest}
|
|
@@ -204,6 +233,7 @@ function ContextMenuItemIndicator(props: ParentProps<ContextMenuItemIndicatorPro
|
|
|
204
233
|
|
|
205
234
|
function ContextMenuRadioGroup(props: ParentProps<ContextMenuRadioGroupProps>) {
|
|
206
235
|
const [local, rest] = splitProps(props, ["class", "classList", "children"])
|
|
236
|
+
|
|
207
237
|
return (
|
|
208
238
|
<Kobalte.RadioGroup
|
|
209
239
|
{...rest}
|
|
@@ -220,6 +250,7 @@ function ContextMenuRadioGroup(props: ParentProps<ContextMenuRadioGroupProps>) {
|
|
|
220
250
|
|
|
221
251
|
function ContextMenuRadioItem(props: ParentProps<ContextMenuRadioItemProps>) {
|
|
222
252
|
const [local, rest] = splitProps(props, ["class", "classList", "children"])
|
|
253
|
+
|
|
223
254
|
return (
|
|
224
255
|
<Kobalte.RadioItem
|
|
225
256
|
{...rest}
|
|
@@ -236,6 +267,7 @@ function ContextMenuRadioItem(props: ParentProps<ContextMenuRadioItemProps>) {
|
|
|
236
267
|
|
|
237
268
|
function ContextMenuCheckboxItem(props: ParentProps<ContextMenuCheckboxItemProps>) {
|
|
238
269
|
const [local, rest] = splitProps(props, ["class", "classList", "children"])
|
|
270
|
+
|
|
239
271
|
return (
|
|
240
272
|
<Kobalte.CheckboxItem
|
|
241
273
|
{...rest}
|
|
@@ -256,6 +288,7 @@ function ContextMenuSub(props: ContextMenuSubProps) {
|
|
|
256
288
|
|
|
257
289
|
function ContextMenuSubTrigger(props: ParentProps<ContextMenuSubTriggerProps>) {
|
|
258
290
|
const [local, rest] = splitProps(props, ["class", "classList", "children"])
|
|
291
|
+
|
|
259
292
|
return (
|
|
260
293
|
<Kobalte.SubTrigger
|
|
261
294
|
{...rest}
|
|
@@ -272,6 +305,7 @@ function ContextMenuSubTrigger(props: ParentProps<ContextMenuSubTriggerProps>) {
|
|
|
272
305
|
|
|
273
306
|
function ContextMenuSubContent(props: ParentProps<ContextMenuSubContentProps>) {
|
|
274
307
|
const [local, rest] = splitProps(props, ["class", "classList", "children"])
|
|
308
|
+
|
|
275
309
|
return (
|
|
276
310
|
<Kobalte.SubContent
|
|
277
311
|
{...rest}
|
|
@@ -6,6 +6,7 @@ export interface DockTrayProps extends ComponentProps<"div"> {
|
|
|
6
6
|
|
|
7
7
|
export function DockShell(props: ComponentProps<"div">) {
|
|
8
8
|
const [split, rest] = splitProps(props, ["children", "class", "classList"])
|
|
9
|
+
|
|
9
10
|
return (
|
|
10
11
|
<div
|
|
11
12
|
{...rest}
|
|
@@ -22,6 +23,7 @@ export function DockShell(props: ComponentProps<"div">) {
|
|
|
22
23
|
|
|
23
24
|
export function DockShellForm(props: ComponentProps<"form">) {
|
|
24
25
|
const [split, rest] = splitProps(props, ["children", "class", "classList"])
|
|
26
|
+
|
|
25
27
|
return (
|
|
26
28
|
<form
|
|
27
29
|
{...rest}
|
|
@@ -38,6 +40,7 @@ export function DockShellForm(props: ComponentProps<"form">) {
|
|
|
38
40
|
|
|
39
41
|
export function DockTray(props: DockTrayProps) {
|
|
40
42
|
const [split, rest] = splitProps(props, ["attach", "children", "class", "classList"])
|
|
43
|
+
|
|
41
44
|
return (
|
|
42
45
|
<div
|
|
43
46
|
{...rest}
|
|
@@ -13,6 +13,7 @@ export const FileIcon: Component<FileIconProps> = (props) => {
|
|
|
13
13
|
const [local, rest] = splitProps(props, ["node", "class", "classList", "expanded", "mono"])
|
|
14
14
|
const name = createMemo(() => chooseIconName(local.node.path, local.node.type, local.expanded || false))
|
|
15
15
|
const id = `file-icon-mono-${createUniqueId()}`
|
|
16
|
+
|
|
16
17
|
return (
|
|
17
18
|
<svg
|
|
18
19
|
data-component="file-icon"
|
|
@@ -542,8 +543,11 @@ const ICON_MAPS: IconMaps = {
|
|
|
542
543
|
|
|
543
544
|
const toOpenVariant = (icon: IconName): IconName => {
|
|
544
545
|
if (!icon.startsWith("Folder")) return icon
|
|
546
|
+
|
|
545
547
|
if (icon.endsWith("_light")) return icon.replace("_light", "Open_light") as IconName
|
|
548
|
+
|
|
546
549
|
if (!icon.endsWith("Open")) return (icon + "Open") as IconName
|
|
550
|
+
|
|
547
551
|
return icon
|
|
548
552
|
}
|
|
549
553
|
|
|
@@ -551,16 +555,20 @@ const basenameOf = (p: string) => p.split("\\").join("/").split("/").filter(Bool
|
|
|
551
555
|
|
|
552
556
|
const folderNameVariants = (name: string) => {
|
|
553
557
|
const n = name.toLowerCase()
|
|
558
|
+
|
|
554
559
|
return [n, `.${n}`, `_${n}`, `__${n}__`]
|
|
555
560
|
}
|
|
556
561
|
|
|
557
562
|
const dottedSuffixesDesc = (name: string) => {
|
|
558
563
|
const n = name.toLowerCase()
|
|
559
564
|
const idxs: number[] = []
|
|
565
|
+
|
|
560
566
|
for (let i = 0; i < n.length; i++) if (n[i] === ".") idxs.push(i)
|
|
561
567
|
const out = new Set<string>()
|
|
562
568
|
out.add(n) // allow exact whole-name "extensions" like "dockerfile"
|
|
569
|
+
|
|
563
570
|
for (const i of idxs) if (i + 1 < n.length) out.add(n.slice(i + 1))
|
|
571
|
+
|
|
564
572
|
return Array.from(out).sort((a, b) => b.length - a.length) // longest first
|
|
565
573
|
}
|
|
566
574
|
|
|
@@ -571,16 +579,20 @@ export function chooseIconName(path: string, type: "directory" | "file", expande
|
|
|
571
579
|
if (type === "directory") {
|
|
572
580
|
for (const cand of folderNameVariants(baseLower)) {
|
|
573
581
|
const icon = ICON_MAPS.folderNames[cand]
|
|
582
|
+
|
|
574
583
|
if (icon) return expanded ? toOpenVariant(icon) : icon
|
|
575
584
|
}
|
|
585
|
+
|
|
576
586
|
return expanded ? ICON_MAPS.defaults.folderOpen : ICON_MAPS.defaults.folder
|
|
577
587
|
}
|
|
578
588
|
|
|
579
589
|
const byName = ICON_MAPS.fileNames[baseLower]
|
|
590
|
+
|
|
580
591
|
if (byName) return byName
|
|
581
592
|
|
|
582
593
|
for (const ext of dottedSuffixesDesc(baseLower)) {
|
|
583
594
|
const icon = ICON_MAPS.fileExtensions[ext]
|
|
595
|
+
|
|
584
596
|
if (icon) return icon
|
|
585
597
|
}
|
|
586
598
|
|
package/src/components/list.tsx
CHANGED
|
@@ -9,6 +9,7 @@ import { TextField } from "./text-field"
|
|
|
9
9
|
|
|
10
10
|
function findByKey(container: HTMLElement, key: string) {
|
|
11
11
|
const nodes = container.querySelectorAll<HTMLElement>('[data-slot="list-item"][data-key]')
|
|
12
|
+
|
|
12
13
|
for (const node of nodes) {
|
|
13
14
|
if (node.getAttribute("data-key") === key) return node
|
|
14
15
|
}
|
|
@@ -58,11 +59,13 @@ export interface ListRef {
|
|
|
58
59
|
export function List<T>(props: ListProps<T> & { ref?: (ref: ListRef) => void }) {
|
|
59
60
|
const i18n = useI18n()
|
|
60
61
|
let inputRef: HTMLInputElement | HTMLTextAreaElement | undefined
|
|
62
|
+
|
|
61
63
|
const [store, setStore] = createStore({
|
|
62
64
|
mouseActive: false,
|
|
63
65
|
scrollRef: undefined as HTMLDivElement | undefined,
|
|
64
66
|
internalFilter: "",
|
|
65
67
|
})
|
|
68
|
+
|
|
66
69
|
const scrollRef = () => store.scrollRef
|
|
67
70
|
const setScrollRef = (el: HTMLDivElement | undefined) => setStore("scrollRef", el)
|
|
68
71
|
const internalFilter = () => store.internalFilter
|
|
@@ -75,6 +78,7 @@ export function List<T>(props: ListProps<T> & { ref?: (ref: ListRef) => void })
|
|
|
75
78
|
const bottom = top + nodeRect.height
|
|
76
79
|
const viewTop = container.scrollTop
|
|
77
80
|
const viewBottom = viewTop + container.clientHeight
|
|
81
|
+
|
|
78
82
|
const target =
|
|
79
83
|
block === "center"
|
|
80
84
|
? top - container.clientHeight / 2 + nodeRect.height / 2
|
|
@@ -83,6 +87,7 @@ export function List<T>(props: ListProps<T> & { ref?: (ref: ListRef) => void })
|
|
|
83
87
|
: bottom > viewBottom
|
|
84
88
|
? bottom - container.clientHeight
|
|
85
89
|
: viewTop
|
|
90
|
+
|
|
86
91
|
const max = Math.max(0, container.scrollHeight - container.clientHeight)
|
|
87
92
|
container.scrollTop = Math.max(0, Math.min(target, max))
|
|
88
93
|
}
|
|
@@ -108,13 +113,16 @@ export function List<T>(props: ListProps<T> & { ref?: (ref: ListRef) => void })
|
|
|
108
113
|
// This is important for programmatic changes like Tab completion.
|
|
109
114
|
if (prev === value) {
|
|
110
115
|
void refetch()
|
|
116
|
+
|
|
111
117
|
return
|
|
112
118
|
}
|
|
119
|
+
|
|
113
120
|
queueMicrotask(() => refetch())
|
|
114
121
|
}
|
|
115
122
|
|
|
116
123
|
createEffect(() => {
|
|
117
124
|
if (props.filter === undefined) return
|
|
125
|
+
|
|
118
126
|
if (props.filter === internalFilter()) return
|
|
119
127
|
setInternalFilter(props.filter)
|
|
120
128
|
onInput(props.filter)
|
|
@@ -132,11 +140,14 @@ export function List<T>(props: ListProps<T> & { ref?: (ref: ListRef) => void })
|
|
|
132
140
|
|
|
133
141
|
createEffect(() => {
|
|
134
142
|
const scroll = scrollRef()
|
|
143
|
+
|
|
135
144
|
if (!scroll) return
|
|
145
|
+
|
|
136
146
|
if (!props.current) return
|
|
137
147
|
const key = props.key(props.current)
|
|
138
148
|
requestAnimationFrame(() => {
|
|
139
149
|
const element = findByKey(scroll, key)
|
|
150
|
+
|
|
140
151
|
if (!element) return
|
|
141
152
|
scrollIntoView(scroll, element, "center")
|
|
142
153
|
})
|
|
@@ -144,16 +155,23 @@ export function List<T>(props: ListProps<T> & { ref?: (ref: ListRef) => void })
|
|
|
144
155
|
|
|
145
156
|
createEffect(() => {
|
|
146
157
|
const all = flat()
|
|
158
|
+
|
|
147
159
|
if (store.mouseActive || all.length === 0) return
|
|
148
160
|
const scroll = scrollRef()
|
|
161
|
+
|
|
149
162
|
if (!scroll) return
|
|
163
|
+
|
|
150
164
|
if (active() === props.key(all[0])) {
|
|
151
165
|
scroll.scrollTo(0, 0)
|
|
166
|
+
|
|
152
167
|
return
|
|
153
168
|
}
|
|
169
|
+
|
|
154
170
|
const key = active()
|
|
171
|
+
|
|
155
172
|
if (!key) return
|
|
156
173
|
const element = findByKey(scroll, key)
|
|
174
|
+
|
|
157
175
|
if (!element) return
|
|
158
176
|
scrollIntoView(scroll, element, "center")
|
|
159
177
|
})
|
|
@@ -171,6 +189,7 @@ export function List<T>(props: ListProps<T> & { ref?: (ref: ListRef) => void })
|
|
|
171
189
|
|
|
172
190
|
const handleKey = (e: KeyboardEvent) => {
|
|
173
191
|
setStore("mouseActive", false)
|
|
192
|
+
|
|
174
193
|
if (e.key === "Escape") return
|
|
175
194
|
|
|
176
195
|
const all = flat()
|
|
@@ -182,12 +201,15 @@ export function List<T>(props: ListProps<T> & { ref?: (ref: ListRef) => void })
|
|
|
182
201
|
|
|
183
202
|
if (e.key === "Enter" && !e.isComposing) {
|
|
184
203
|
e.preventDefault()
|
|
204
|
+
|
|
185
205
|
if (selected) handleSelect(selected, index)
|
|
186
206
|
} else if (props.search) {
|
|
187
207
|
if (e.ctrlKey && !e.metaKey && !e.altKey && !e.shiftKey && (e.key === "n" || e.key === "p")) {
|
|
188
208
|
onKeyDown(e)
|
|
209
|
+
|
|
189
210
|
return
|
|
190
211
|
}
|
|
212
|
+
|
|
191
213
|
if (e.key === "ArrowDown" || e.key === "ArrowUp") {
|
|
192
214
|
onKeyDown(e)
|
|
193
215
|
}
|
|
@@ -204,7 +226,9 @@ export function List<T>(props: ListProps<T> & { ref?: (ref: ListRef) => void })
|
|
|
204
226
|
|
|
205
227
|
const renderAdd = () => {
|
|
206
228
|
const add = addProps()
|
|
229
|
+
|
|
207
230
|
if (!add) return null
|
|
231
|
+
|
|
208
232
|
return (
|
|
209
233
|
<div data-slot="list-item-add" classList={{ [add.class ?? ""]: !!add.class }}>
|
|
210
234
|
{add.render()}
|
|
@@ -221,6 +245,7 @@ export function List<T>(props: ListProps<T> & { ref?: (ref: ListRef) => void })
|
|
|
221
245
|
createEffect(() => {
|
|
222
246
|
const scroll = scrollRef()
|
|
223
247
|
const node = state.header
|
|
248
|
+
|
|
224
249
|
if (!scroll || !node) return
|
|
225
250
|
|
|
226
251
|
const handler = () => {
|
|
@@ -242,12 +267,15 @@ export function List<T>(props: ListProps<T> & { ref?: (ref: ListRef) => void })
|
|
|
242
267
|
|
|
243
268
|
const emptyMessage = () => {
|
|
244
269
|
if (grouped.loading) return props.loadingMessage ?? i18n.t("ui.list.loading")
|
|
270
|
+
|
|
245
271
|
if (props.emptyMessage) return props.emptyMessage
|
|
246
272
|
|
|
247
273
|
const query = filter()
|
|
274
|
+
|
|
248
275
|
if (!query) return i18n.t("ui.list.empty")
|
|
249
276
|
|
|
250
277
|
const suffix = i18n.t("ui.list.emptyWithFilter.suffix")
|
|
278
|
+
|
|
251
279
|
return (
|
|
252
280
|
<>
|
|
253
281
|
<span>{i18n.t("ui.list.emptyWithFilter.prefix")}</span>
|
|
@@ -268,6 +296,7 @@ export function List<T>(props: ListProps<T> & { ref?: (ref: ListRef) => void })
|
|
|
268
296
|
classList={{ [searchProps().class ?? ""]: !!searchProps().class }}
|
|
269
297
|
onPointerDown={(event) => {
|
|
270
298
|
const container = event.currentTarget
|
|
299
|
+
|
|
271
300
|
if (!(container instanceof HTMLElement)) return
|
|
272
301
|
|
|
273
302
|
const node = container.querySelector("input, textarea")
|
|
@@ -327,6 +356,7 @@ export function List<T>(props: ListProps<T> & { ref?: (ref: ListRef) => void })
|
|
|
327
356
|
<For each={grouped.latest}>
|
|
328
357
|
{(group, groupIndex) => {
|
|
329
358
|
const isLastGroup = () => groupIndex() === grouped.latest.length - 1
|
|
359
|
+
|
|
330
360
|
return (
|
|
331
361
|
<div data-slot="list-group">
|
|
332
362
|
<Show when={group.category}>
|
|
@@ -374,7 +404,9 @@ export function List<T>(props: ListProps<T> & { ref?: (ref: ListRef) => void })
|
|
|
374
404
|
</Show>
|
|
375
405
|
</button>
|
|
376
406
|
)
|
|
407
|
+
|
|
377
408
|
if (props.itemWrapper) return props.itemWrapper(item, node)
|
|
409
|
+
|
|
378
410
|
return node
|
|
379
411
|
}}
|
|
380
412
|
</For>
|