@opencode/ui 0.0.0-dev-21832 → 0.0.0-dev-21843

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.
@@ -2,26 +2,29 @@ import { type ComponentProps, type JSX } from "solid-js";
2
2
  import "./line-comment.css";
3
3
  /** Horizontal “more” glyph for the display-card overflow control (Figma outline-dots). */
4
4
  export declare function LineCommentOverflowIcon(props: ComponentProps<"svg">): JSX.Element;
5
- export interface LineCommentProps extends ComponentProps<"div"> {
5
+ export interface LineCommentProps extends Omit<ComponentProps<"div">, "onClick"> {
6
6
  /** Main comment body (text or rich content). */
7
7
  comment: JSX.Element;
8
- /** Line / selection context (e.g. “Comment on line 40”). */
9
- selection: JSX.Element;
8
+ /** Optional context under the comment, e.g. the page or element it is about. */
9
+ selection?: JSX.Element;
10
10
  /** Typically an overflow menu trigger; use `LineCommentOverflowIcon` inside `line-comment-v2-overflow`. */
11
11
  actions?: JSX.Element;
12
+ /** Opens the comment, e.g. its editor, from a click anywhere on the card. Keep a keyboard path in `actions`. */
13
+ onOpen?: VoidFunction;
12
14
  }
13
15
  export declare function LineComment(props: LineCommentProps): JSX.Element;
14
16
  export type LineCommentEditorMention = {
15
17
  items: (query: string) => string[] | Promise<string[]>;
16
18
  };
17
19
  export interface LineCommentEditorProps extends Omit<ComponentProps<"div">, "children" | "onInput" | "onSubmit"> {
18
- /** Visible field label above the textarea (default: “Comment”). */
19
- heading?: JSX.Element | string;
20
+ /** Accessible name of the text field (default: “Comment”). */
21
+ label?: string;
20
22
  value: string;
21
23
  onInput: (value: string) => void;
22
24
  onCancel: () => void;
23
25
  onSubmit: (value: string) => void;
24
- selection: JSX.Element;
26
+ /** Optional context in the footer, e.g. the page or element being commented on. */
27
+ selection?: JSX.Element;
25
28
  placeholder?: string;
26
29
  rows?: number;
27
30
  cancelLabel?: string;
package/dist/i18n/en.d.ts CHANGED
@@ -229,6 +229,7 @@ declare const source: {
229
229
  "ui.message.voice": string;
230
230
  "ui.message.deletePending": string;
231
231
  "ui.message.copyResponse": string;
232
+ "ui.message.copyOutput": string;
232
233
  "ui.message.copied": string;
233
234
  "ui.message.thought": string;
234
235
  "ui.message.duration.seconds": string;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@opencode/ui",
3
- "version": "0.0.0-dev-21832",
3
+ "version": "0.0.0-dev-21843",
4
4
  "type": "module",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -43,6 +43,16 @@
43
43
  min-width: 0;
44
44
  }
45
45
 
46
+ [data-component="line-comment-v2"][data-variant="display"][data-clickable] {
47
+ cursor: pointer;
48
+ }
49
+
50
+ [data-component="line-comment-v2"][data-variant="display"][data-clickable]:hover [data-slot="line-comment-v2-shell"] {
51
+ background:
52
+ linear-gradient(var(--v2-overlay-simple-overlay-hover), var(--v2-overlay-simple-overlay-hover)),
53
+ var(--v2-background-bg-layer-01);
54
+ }
55
+
46
56
  [data-component="line-comment-v2"][data-variant="display"] [data-slot="line-comment-v2-text"] {
47
57
  margin: 0;
48
58
  width: 100%;
@@ -53,6 +63,8 @@
53
63
  letter-spacing: -0.04px;
54
64
  color: var(--v2-text-text-base);
55
65
  font-variation-settings: "slnt" 0;
66
+ white-space: pre-wrap;
67
+ overflow-wrap: anywhere;
56
68
  }
57
69
 
58
70
  [data-component="line-comment-v2"][data-variant="display"] [data-slot="line-comment-v2-meta"] {
@@ -130,36 +142,19 @@
130
142
  min-width: 0;
131
143
  }
132
144
 
133
- [data-component="line-comment-v2"][data-variant="editor"] [data-slot="line-comment-v2-label"] {
134
- display: flex;
135
- flex-direction: row;
136
- align-items: center;
137
- width: 100%;
138
- font-size: 13px;
139
- font-style: normal;
140
- font-weight: 530;
141
- line-height: var(--line-height-compact);
142
- letter-spacing: -0.04px;
143
- color: var(--v2-text-text-base);
144
- user-select: none;
145
- }
146
-
147
145
  [data-component="line-comment-v2"][data-variant="editor"] [data-slot="line-comment-v2-textarea"] {
148
146
  display: block;
149
147
  width: 100%;
150
148
  min-width: 0;
151
- min-height: 80px;
152
- padding: 8px;
149
+ padding: 0;
153
150
  margin: 0;
154
- resize: vertical;
155
- border: 1px solid var(--v2-border-border-base);
156
- border-radius: 6px;
157
- background:
158
- linear-gradient(180deg, var(--v2-alpha-light-2) 0%, var(--v2-alpha-light-0) 100%), var(--v2-background-bg-base);
151
+ resize: none;
152
+ border: none;
153
+ background: transparent;
159
154
  font-size: 13px;
160
155
  font-style: normal;
161
156
  font-weight: 440;
162
- line-height: 1.35;
157
+ line-height: var(--line-height-compact);
163
158
  letter-spacing: -0.04px;
164
159
  color: var(--v2-text-text-base);
165
160
  font-variation-settings: "slnt" 0;
@@ -171,10 +166,6 @@
171
166
  user-select: none;
172
167
  }
173
168
 
174
- [data-component="line-comment-v2"][data-variant="editor"] [data-slot="line-comment-v2-textarea"]:focus {
175
- border-color: var(--v2-border-border-focus);
176
- }
177
-
178
169
  [data-component="line-comment-v2"][data-variant="editor"] [data-slot="line-comment-v2-footer"] {
179
170
  display: flex;
180
171
  flex-direction: row;
@@ -202,6 +193,7 @@
202
193
  align-items: center;
203
194
  gap: 8px;
204
195
  flex-shrink: 0;
196
+ margin-inline-start: auto;
205
197
  }
206
198
 
207
199
  [data-component="line-comment-v2"][data-variant="editor"] [data-slot="line-comment-v2-mention-list"] {
@@ -24,23 +24,27 @@ export function LineCommentOverflowIcon(props: ComponentProps<"svg">) {
24
24
  )
25
25
  }
26
26
 
27
- export interface LineCommentProps extends ComponentProps<"div"> {
27
+ export interface LineCommentProps extends Omit<ComponentProps<"div">, "onClick"> {
28
28
  /** Main comment body (text or rich content). */
29
29
  comment: JSX.Element
30
- /** Line / selection context (e.g. “Comment on line 40”). */
31
- selection: JSX.Element
30
+ /** Optional context under the comment, e.g. the page or element it is about. */
31
+ selection?: JSX.Element
32
32
  /** Typically an overflow menu trigger; use `LineCommentOverflowIcon` inside `line-comment-v2-overflow`. */
33
33
  actions?: JSX.Element
34
+ /** Opens the comment, e.g. its editor, from a click anywhere on the card. Keep a keyboard path in `actions`. */
35
+ onOpen?: VoidFunction
34
36
  }
35
37
 
36
38
  export function LineComment(props: LineCommentProps) {
37
- const [local, rest] = splitProps(props, ["comment", "selection", "actions", "class", "classList"])
39
+ const [local, rest] = splitProps(props, ["comment", "selection", "actions", "onOpen", "class", "classList"])
38
40
 
39
41
  return (
40
42
  <div
41
43
  {...rest}
42
44
  data-component="line-comment-v2"
43
45
  data-variant="display"
46
+ data-clickable={local.onOpen ? "" : undefined}
47
+ onClick={() => local.onOpen?.()}
44
48
  classList={{
45
49
  ...local.classList,
46
50
  [local.class ?? ""]: !!local.class,
@@ -49,7 +53,7 @@ export function LineComment(props: LineCommentProps) {
49
53
  <div data-slot="line-comment-v2-shell">
50
54
  <div data-slot="line-comment-v2-column">
51
55
  <div data-slot="line-comment-v2-text">{local.comment}</div>
52
- <div data-slot="line-comment-v2-meta">{local.selection}</div>
56
+ <Show when={local.selection}>{(selection) => <div data-slot="line-comment-v2-meta">{selection()}</div>}</Show>
53
57
  </div>
54
58
  <Show when={local.actions}>{(actions) => <div data-slot="line-comment-v2-tools">{actions()}</div>}</Show>
55
59
  </div>
@@ -62,13 +66,14 @@ export type LineCommentEditorMention = {
62
66
  }
63
67
 
64
68
  export interface LineCommentEditorProps extends Omit<ComponentProps<"div">, "children" | "onInput" | "onSubmit"> {
65
- /** Visible field label above the textarea (default: “Comment”). */
66
- heading?: JSX.Element | string
69
+ /** Accessible name of the text field (default: “Comment”). */
70
+ label?: string
67
71
  value: string
68
72
  onInput: (value: string) => void
69
73
  onCancel: () => void
70
74
  onSubmit: (value: string) => void
71
- selection: JSX.Element
75
+ /** Optional context in the footer, e.g. the page or element being commented on. */
76
+ selection?: JSX.Element
72
77
  placeholder?: string
73
78
  rows?: number
74
79
  cancelLabel?: string
@@ -95,7 +100,7 @@ export function LineCommentEditor(props: LineCommentEditorProps) {
95
100
  const [mentionOpen, setMentionOpen] = createSignal(false)
96
101
 
97
102
  const [local, rest] = splitProps(props, [
98
- "heading",
103
+ "label",
99
104
  "value",
100
105
  "onInput",
101
106
  "onCancel",
@@ -111,7 +116,6 @@ export function LineCommentEditor(props: LineCommentEditorProps) {
111
116
  "classList",
112
117
  ])
113
118
 
114
- const heading = () => local.heading ?? i18n.t("ui.lineComment.submit")
115
119
  const canSubmit = () => local.value.trim().length > 0
116
120
 
117
121
  const closeMention = () => {
@@ -220,14 +224,14 @@ export function LineCommentEditor(props: LineCommentEditorProps) {
220
224
  >
221
225
  <div data-slot="line-comment-v2-shell">
222
226
  <div data-slot="line-comment-v2-field">
223
- <div data-slot="line-comment-v2-label">{heading()}</div>
224
227
  <textarea
225
228
  ref={(el) => {
226
229
  textareaRef = el
227
230
  }}
228
231
  data-slot="line-comment-v2-textarea"
232
+ aria-label={local.label ?? i18n.t("ui.lineComment.submit")}
229
233
  dir="auto"
230
- rows={local.rows ?? 3}
234
+ rows={local.rows ?? 4}
231
235
  placeholder={local.placeholder ?? i18n.t("ui.lineComment.contextPlaceholder")}
232
236
  value={local.value}
233
237
  style={{ "unicode-bidi": "plaintext", "text-align": "start" }}
@@ -314,12 +318,14 @@ export function LineCommentEditor(props: LineCommentEditorProps) {
314
318
  </Show>
315
319
  </div>
316
320
  <div data-slot="line-comment-v2-footer">
317
- <div data-slot="line-comment-v2-footer-meta">{local.selection}</div>
321
+ <Show when={local.selection}>
322
+ {(selection) => <div data-slot="line-comment-v2-footer-meta">{selection()}</div>}
323
+ </Show>
318
324
  <div data-slot="line-comment-v2-footer-actions">
319
- <Button type="button" size="normal" variant="ghost" onClick={() => local.onCancel()}>
325
+ <Button type="button" size="small" variant="ghost" onClick={() => local.onCancel()}>
320
326
  {local.cancelLabel ?? i18n.t("ui.lineComment.cancel")}
321
327
  </Button>
322
- <Button type="button" size="normal" variant="contrast" disabled={!canSubmit()} onClick={submit}>
328
+ <Button type="button" size="small" variant="contrast" disabled={!canSubmit()} onClick={submit}>
323
329
  {local.submitLabel ?? i18n.t("ui.lineComment.submit")}
324
330
  </Button>
325
331
  </div>
package/src/i18n/en.ts CHANGED
@@ -252,6 +252,7 @@ const source = {
252
252
  "ui.message.voice": "Voice",
253
253
  "ui.message.deletePending": "Delete",
254
254
  "ui.message.copyResponse": "Copy response",
255
+ "ui.message.copyOutput": "Copy output",
255
256
  "ui.message.copied": "Copied",
256
257
  "ui.message.thought": "Thought",
257
258
  "ui.message.duration.seconds": "{{count}}s",
@@ -77,8 +77,12 @@ export function Tooltip(props: TooltipProps) {
77
77
  }
78
78
 
79
79
  const leave = () => {
80
- if (!inside()) close()
81
- drop()
80
+ // Kobalte's own pointerleave handler runs after this one and only starts the
81
+ // skip-delay window for neighbouring tooltips if it still sees this one open.
82
+ queueMicrotask(() => {
83
+ if (!inside()) close()
84
+ drop()
85
+ })
82
86
  }
83
87
 
84
88
  createEffect(() => {