@opencode-ai/ui 0.0.0-dev-202609030903 → 0.0.0-dev-18997

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.
Files changed (296) hide show
  1. package/dist/actions/button/button.d.ts +10 -0
  2. package/dist/actions/icon-button/icon-button.d.ts +11 -0
  3. package/dist/actions/split-button/split-button.d.ts +5 -0
  4. package/dist/components/card.d.ts +1 -1
  5. package/dist/components/list.d.ts +1 -1
  6. package/dist/components/scroll-view.d.ts +3 -3
  7. package/dist/context/i18n.d.ts +10 -7
  8. package/dist/context/marked-base.d.ts +3 -0
  9. package/dist/context/marked-parser.d.ts +1 -2
  10. package/dist/{components → data-display/accordion}/accordion.d.ts +6 -6
  11. package/dist/{v2/components/avatar-v2.d.ts → data-display/avatar/avatar.d.ts} +1 -1
  12. package/dist/data-display/badge/badge.d.ts +7 -0
  13. package/dist/{components → data-display/diff-changes}/diff-changes.d.ts +2 -1
  14. package/dist/data-display/keybind/keybind.d.ts +7 -0
  15. package/dist/{v2/components/line-comment-v2.d.ts → data-display/line-comment/line-comment.d.ts} +9 -9
  16. package/dist/{v2/components/project-avatar-v2.d.ts → data-display/project-avatar/project-avatar.d.ts} +1 -1
  17. package/dist/feedback/loader/loader.d.ts +3 -0
  18. package/dist/{components → feedback/progress-circle}/progress-circle.d.ts +2 -0
  19. package/dist/feedback/toast/toast.d.ts +57 -0
  20. package/dist/{components → forms/checkbox}/checkbox.d.ts +2 -2
  21. package/dist/{v2/components/field-v2.d.ts → forms/field/field.d.ts} +4 -10
  22. package/dist/forms/radio/radio.d.ts +16 -0
  23. package/dist/{v2/components/select-v2.d.ts → forms/select/select.d.ts} +4 -6
  24. package/dist/{components → forms/switch}/switch.d.ts +4 -2
  25. package/dist/{v2/components/text-input-v2.d.ts → forms/text-input/text-input.d.ts} +3 -3
  26. package/dist/forms/textarea/textarea.d.ts +7 -0
  27. package/dist/hooks/use-filtered-list.d.ts +9 -0
  28. package/dist/i18n/ar.d.ts +0 -2
  29. package/dist/i18n/bg.d.ts +0 -2
  30. package/dist/i18n/br.d.ts +0 -2
  31. package/dist/i18n/bs.d.ts +0 -2
  32. package/dist/i18n/da.d.ts +0 -2
  33. package/dist/i18n/de.d.ts +0 -2
  34. package/dist/i18n/en.d.ts +234 -1
  35. package/dist/i18n/es.d.ts +0 -2
  36. package/dist/i18n/fr.d.ts +0 -2
  37. package/dist/i18n/he.d.ts +197 -0
  38. package/dist/i18n/ja.d.ts +0 -2
  39. package/dist/i18n/km.d.ts +0 -2
  40. package/dist/i18n/ko.d.ts +0 -2
  41. package/dist/i18n/lo.d.ts +0 -2
  42. package/dist/i18n/mk.d.ts +0 -2
  43. package/dist/i18n/mn.d.ts +0 -2
  44. package/dist/i18n/my.d.ts +0 -2
  45. package/dist/i18n/pl.d.ts +0 -2
  46. package/dist/i18n/ru.d.ts +0 -2
  47. package/dist/i18n/sr.d.ts +0 -2
  48. package/dist/i18n/tg.d.ts +0 -2
  49. package/dist/i18n/th.d.ts +0 -2
  50. package/dist/i18n/tr.d.ts +0 -2
  51. package/dist/i18n/zh.d.ts +0 -2
  52. package/dist/i18n/zht.d.ts +0 -2
  53. package/dist/{components/icon.d.ts → icons/icon/additional-icons.d.ts} +8 -8
  54. package/dist/{v2/components → icons/icon}/icon.d.ts +24 -1
  55. package/dist/layout/divider/divider.d.ts +5 -0
  56. package/dist/navigation/menu/menu.d.ts +59 -0
  57. package/dist/{v2/components/segmented-control-v2.d.ts → navigation/segmented-control/segmented-control.d.ts} +5 -5
  58. package/dist/{components → navigation/tabs}/tabs.d.ts +15 -8
  59. package/dist/{v2/components/dialog-v2.d.ts → overlays/dialog/dialog.d.ts} +1 -2
  60. package/dist/overlays/tooltip/tooltip.d.ts +15 -0
  61. package/dist/{components → typography/text-shimmer}/text-shimmer.d.ts +1 -0
  62. package/dist/typography/wordmark/wordmark.d.ts +2 -0
  63. package/package.json +140 -34
  64. package/src/{components → actions/button}/button.tsx +10 -11
  65. package/src/actions/icon-button/icon-button.tsx +32 -0
  66. package/src/{v2/components/split-button-v2.css → actions/split-button/split-button.css} +1 -6
  67. package/src/{v2/components/split-button-v2.tsx → actions/split-button/split-button.tsx} +4 -4
  68. package/src/components/animated-number.css +29 -11
  69. package/src/components/animated-number.tsx +2 -2
  70. package/src/components/card.css +2 -23
  71. package/src/components/card.tsx +4 -4
  72. package/src/components/collapsible.tsx +2 -2
  73. package/src/components/dock-surface.css +2 -9
  74. package/src/components/image-preview.tsx +3 -2
  75. package/src/components/list.css +5 -5
  76. package/src/components/list.tsx +7 -5
  77. package/src/components/popover.tsx +3 -2
  78. package/src/components/scroll-view.tsx +5 -20
  79. package/src/components/sticky-accordion-header.tsx +1 -1
  80. package/src/components/text-field.tsx +12 -4
  81. package/src/context/dialog.tsx +1 -0
  82. package/src/context/i18n.tsx +17 -14
  83. package/src/context/marked-base.tsx +27 -0
  84. package/src/context/marked-parser.tsx +3 -13
  85. package/src/{components → data-display/accordion}/accordion.css +5 -31
  86. package/src/{components → data-display/accordion}/accordion.tsx +14 -14
  87. package/src/{v2/components/avatar-v2.tsx → data-display/avatar/avatar.tsx} +1 -1
  88. package/src/{v2/components/badge-v2.css → data-display/badge/badge.css} +19 -0
  89. package/src/{v2/components/badge-v2.tsx → data-display/badge/badge.tsx} +6 -4
  90. package/src/{components → data-display/diff-changes}/diff-changes.css +22 -19
  91. package/src/{v2/components/diff-changes-v2.tsx → data-display/diff-changes/diff-changes.tsx} +7 -2
  92. package/src/{v2/components/keybind-v2.css → data-display/keybind/keybind.css} +1 -1
  93. package/src/{v2/components/keybind-v2.tsx → data-display/keybind/keybind.tsx} +3 -3
  94. package/src/{v2/components/line-comment-v2.css → data-display/line-comment/line-comment.css} +4 -4
  95. package/src/{v2/components/line-comment-v2.tsx → data-display/line-comment/line-comment.tsx} +17 -15
  96. package/src/{v2/components/project-avatar-v2.tsx → data-display/project-avatar/project-avatar.tsx} +1 -1
  97. package/src/{v2/components/loader-v2.tsx → feedback/loader/loader.tsx} +2 -2
  98. package/src/feedback/progress-circle/progress-circle.css +28 -0
  99. package/src/feedback/progress-circle/progress-circle.tsx +64 -0
  100. package/src/{v2/components/toast-v2.tsx → feedback/toast/toast.tsx} +60 -58
  101. package/src/{components → forms/checkbox}/checkbox.css +1 -7
  102. package/src/{components → forms/checkbox}/checkbox.tsx +13 -13
  103. package/src/{v2/components/field-v2.css → forms/field/field.css} +1 -1
  104. package/src/{v2/components/field-v2.tsx → forms/field/field.tsx} +9 -11
  105. package/src/{v2/components/radio-v2.tsx → forms/radio/radio.tsx} +30 -20
  106. package/src/{v2/components/select-v2.css → forms/select/select.css} +2 -8
  107. package/src/{v2/components/select-v2.tsx → forms/select/select.tsx} +40 -32
  108. package/src/{v2/components/switch-v2.css → forms/switch/switch.css} +110 -0
  109. package/src/forms/switch/switch.tsx +34 -0
  110. package/src/{v2/components/text-input-v2.css → forms/text-input/text-input.css} +1 -1
  111. package/src/{v2/components/text-input-v2.tsx → forms/text-input/text-input.tsx} +4 -4
  112. package/src/{v2/components/textarea-v2.tsx → forms/textarea/textarea.tsx} +3 -3
  113. package/src/hooks/create-auto-scroll.tsx +20 -0
  114. package/src/i18n/am.ts +7 -9
  115. package/src/i18n/ar.ts +7 -9
  116. package/src/i18n/az.ts +7 -9
  117. package/src/i18n/bg.ts +7 -9
  118. package/src/i18n/bn.ts +7 -9
  119. package/src/i18n/br.ts +7 -9
  120. package/src/i18n/bs.ts +7 -9
  121. package/src/i18n/ca.ts +7 -9
  122. package/src/i18n/cs.ts +7 -9
  123. package/src/i18n/da.ts +7 -9
  124. package/src/i18n/de.ts +1 -3
  125. package/src/i18n/dv.ts +7 -9
  126. package/src/i18n/dz.ts +5 -7
  127. package/src/i18n/el.ts +7 -9
  128. package/src/i18n/en.ts +50 -11
  129. package/src/i18n/es.ts +6 -8
  130. package/src/i18n/et.ts +7 -9
  131. package/src/i18n/fa.ts +7 -9
  132. package/src/i18n/fi.ts +7 -9
  133. package/src/i18n/fo.ts +7 -9
  134. package/src/i18n/fr.ts +6 -8
  135. package/src/i18n/he.ts +199 -0
  136. package/src/i18n/hi.ts +7 -9
  137. package/src/i18n/hr.ts +7 -9
  138. package/src/i18n/hu.ts +7 -9
  139. package/src/i18n/hy.ts +7 -9
  140. package/src/i18n/id.ts +7 -9
  141. package/src/i18n/is.ts +7 -9
  142. package/src/i18n/it.ts +7 -9
  143. package/src/i18n/ja.ts +7 -9
  144. package/src/i18n/ka.ts +7 -9
  145. package/src/i18n/km.ts +7 -9
  146. package/src/i18n/ko.ts +7 -9
  147. package/src/i18n/lo.ts +7 -9
  148. package/src/i18n/lt.ts +7 -9
  149. package/src/i18n/lv.ts +7 -9
  150. package/src/i18n/mk.ts +7 -9
  151. package/src/i18n/mn.ts +7 -9
  152. package/src/i18n/ms.ts +7 -9
  153. package/src/i18n/my.ts +7 -9
  154. package/src/i18n/ne.ts +7 -9
  155. package/src/i18n/nl.ts +7 -9
  156. package/src/i18n/no.ts +7 -9
  157. package/src/i18n/pa.ts +7 -9
  158. package/src/i18n/pl.ts +7 -9
  159. package/src/i18n/ro.ts +7 -9
  160. package/src/i18n/ru.ts +7 -9
  161. package/src/i18n/si.ts +7 -9
  162. package/src/i18n/sk.ts +7 -9
  163. package/src/i18n/sl.ts +7 -9
  164. package/src/i18n/sq.ts +7 -9
  165. package/src/i18n/sr.ts +7 -9
  166. package/src/i18n/sv.ts +7 -9
  167. package/src/i18n/tg.ts +7 -9
  168. package/src/i18n/th.ts +7 -9
  169. package/src/i18n/tk.ts +7 -9
  170. package/src/i18n/tr.ts +7 -9
  171. package/src/i18n/uk.ts +7 -9
  172. package/src/i18n/ur.ts +7 -9
  173. package/src/i18n/uz.ts +7 -9
  174. package/src/i18n/vi.ts +7 -9
  175. package/src/i18n/zh.ts +7 -9
  176. package/src/i18n/zht.ts +7 -9
  177. package/src/{components/icon.tsx → icons/icon/additional-icons.ts} +8 -74
  178. package/src/icons/icon/icon.css +3 -0
  179. package/src/{v2/components → icons/icon}/icon.tsx +51 -10
  180. package/src/{v2/components/divider-v2.tsx → layout/divider/divider.tsx} +3 -3
  181. package/src/{v2/components/menu-v2.css → navigation/menu/menu.css} +123 -2
  182. package/src/{v2/components/menu-v2.tsx → navigation/menu/menu.tsx} +96 -32
  183. package/src/{v2/components/segmented-control-v2.css → navigation/segmented-control/segmented-control.css} +1 -1
  184. package/src/{v2/components/segmented-control-v2.tsx → navigation/segmented-control/segmented-control.tsx} +9 -8
  185. package/src/{v2/components/tabs-v2.css → navigation/tabs/tabs-current.css} +25 -10
  186. package/src/{components → navigation/tabs}/tabs.css +39 -229
  187. package/src/navigation/tabs/tabs.tsx +194 -0
  188. package/src/{v2/components/dialog-v2.css → overlays/dialog/dialog.css} +3 -0
  189. package/src/{v2/components/dialog-v2.tsx → overlays/dialog/dialog.tsx} +11 -13
  190. package/src/{v2/components/tooltip-v2.css → overlays/tooltip/tooltip.css} +26 -0
  191. package/src/{v2/components/tooltip-v2.tsx → overlays/tooltip/tooltip.tsx} +24 -17
  192. package/src/styles/base.css +5 -0
  193. package/src/styles/index.css +4 -20
  194. package/src/styles/tailwind/colors.css +1 -0
  195. package/src/styles/tailwind/index.css +18 -1
  196. package/src/styles/theme.css +2 -2
  197. package/src/{v2/styles → styles/tokens}/theme.css +18 -14
  198. package/src/theme/context.tsx +19 -11
  199. package/src/theme/themes/oc-2.json +3 -1
  200. package/src/theme/v2/foreground.ts +1 -0
  201. package/src/theme/v2/mapping.ts +4 -0
  202. package/src/{components → typography/text-shimmer}/text-shimmer.css +2 -1
  203. package/src/{components → typography/text-shimmer}/text-shimmer.tsx +1 -0
  204. package/src/{v2/components/wordmark-v2.tsx → typography/wordmark/wordmark.tsx} +2 -2
  205. package/dist/components/avatar.d.ts +0 -9
  206. package/dist/components/button.d.ts +0 -9
  207. package/dist/components/dialog.d.ts +0 -12
  208. package/dist/components/dropdown-menu.d.ts +0 -80
  209. package/dist/components/icon-button.d.ts +0 -10
  210. package/dist/components/keybind.d.ts +0 -6
  211. package/dist/components/radio-group.d.ts +0 -16
  212. package/dist/components/select.d.ts +0 -21
  213. package/dist/components/tag.d.ts +0 -5
  214. package/dist/components/toast.d.ts +0 -56
  215. package/dist/components/tooltip.d.ts +0 -17
  216. package/dist/v2/components/accordion-v2.d.ts +0 -26
  217. package/dist/v2/components/badge-v2.d.ts +0 -6
  218. package/dist/v2/components/button-v2.d.ts +0 -10
  219. package/dist/v2/components/checkbox-v2.d.ts +0 -10
  220. package/dist/v2/components/diff-changes-v2.d.ts +0 -11
  221. package/dist/v2/components/divider-v2.d.ts +0 -5
  222. package/dist/v2/components/icon-button-v2.d.ts +0 -11
  223. package/dist/v2/components/inline-input-v2.d.ts +0 -21
  224. package/dist/v2/components/keybind-v2.d.ts +0 -7
  225. package/dist/v2/components/loader-v2.d.ts +0 -3
  226. package/dist/v2/components/menu-v2.d.ts +0 -52
  227. package/dist/v2/components/progress-circle-v2.d.ts +0 -8
  228. package/dist/v2/components/radio-v2.d.ts +0 -16
  229. package/dist/v2/components/split-button-v2.d.ts +0 -5
  230. package/dist/v2/components/switch-v2.d.ts +0 -7
  231. package/dist/v2/components/tabs-v2.d.ts +0 -34
  232. package/dist/v2/components/text-shimmer-v2.d.ts +0 -9
  233. package/dist/v2/components/textarea-v2.d.ts +0 -7
  234. package/dist/v2/components/toast-v2.d.ts +0 -57
  235. package/dist/v2/components/tooltip-v2.d.ts +0 -13
  236. package/dist/v2/components/wordmark-v2.d.ts +0 -2
  237. package/src/components/avatar.css +0 -49
  238. package/src/components/avatar.tsx +0 -55
  239. package/src/components/button.css +0 -194
  240. package/src/components/dialog.css +0 -181
  241. package/src/components/dialog.tsx +0 -72
  242. package/src/components/diff-changes.tsx +0 -115
  243. package/src/components/dropdown-menu.css +0 -135
  244. package/src/components/dropdown-menu.tsx +0 -308
  245. package/src/components/icon-button.css +0 -181
  246. package/src/components/icon-button.tsx +0 -29
  247. package/src/components/icon.css +0 -39
  248. package/src/components/keybind.css +0 -18
  249. package/src/components/keybind.tsx +0 -20
  250. package/src/components/progress-circle.css +0 -16
  251. package/src/components/progress-circle.tsx +0 -64
  252. package/src/components/radio-group.css +0 -187
  253. package/src/components/radio-group.tsx +0 -83
  254. package/src/components/select.css +0 -201
  255. package/src/components/select.tsx +0 -174
  256. package/src/components/switch.css +0 -136
  257. package/src/components/switch.tsx +0 -29
  258. package/src/components/tabs.tsx +0 -126
  259. package/src/components/tag.css +0 -37
  260. package/src/components/tag.tsx +0 -22
  261. package/src/components/toast.css +0 -236
  262. package/src/components/toast.tsx +0 -185
  263. package/src/components/tooltip.css +0 -74
  264. package/src/components/tooltip.tsx +0 -163
  265. package/src/v2/components/accordion-v2.css +0 -139
  266. package/src/v2/components/accordion-v2.tsx +0 -86
  267. package/src/v2/components/button-v2.tsx +0 -35
  268. package/src/v2/components/checkbox-v2.css +0 -184
  269. package/src/v2/components/checkbox-v2.tsx +0 -65
  270. package/src/v2/components/diff-changes-v2.css +0 -26
  271. package/src/v2/components/icon-button-v2.tsx +0 -37
  272. package/src/v2/components/inline-input-v2.css +0 -225
  273. package/src/v2/components/inline-input-v2.tsx +0 -107
  274. package/src/v2/components/progress-circle-v2.css +0 -13
  275. package/src/v2/components/progress-circle-v2.tsx +0 -52
  276. package/src/v2/components/switch-v2.tsx +0 -28
  277. package/src/v2/components/tabs-v2.tsx +0 -149
  278. package/src/v2/components/text-shimmer-v2.css +0 -125
  279. package/src/v2/components/text-shimmer-v2.tsx +0 -63
  280. /package/dist/{components → forms/inline-input}/inline-input.d.ts +0 -0
  281. /package/dist/{v2/components → navigation}/tab-state-indicator.d.ts +0 -0
  282. /package/src/{v2/components/button-v2.css → actions/button/button.css} +0 -0
  283. /package/src/{v2/components/icon-button-v2.css → actions/icon-button/icon-button.css} +0 -0
  284. /package/src/{v2/components/avatar-v2.css → data-display/avatar/avatar.css} +0 -0
  285. /package/src/{v2/components/project-avatar-v2.css → data-display/project-avatar/project-avatar.css} +0 -0
  286. /package/src/{v2/components/loader-v2.css → feedback/loader/loader.css} +0 -0
  287. /package/src/{v2/components/toast-v2.css → feedback/toast/toast.css} +0 -0
  288. /package/src/{components → forms/inline-input}/inline-input.css +0 -0
  289. /package/src/{components → forms/inline-input}/inline-input.tsx +0 -0
  290. /package/src/{v2/components/radio-v2.css → forms/radio/radio.css} +0 -0
  291. /package/src/{v2/components/textarea-v2.css → forms/textarea/textarea.css} +0 -0
  292. /package/src/{v2/components/divider-v2.css → layout/divider/divider.css} +0 -0
  293. /package/src/{v2/components → navigation}/tab-state-indicator.tsx +0 -0
  294. /package/src/{v2/components/file-tree-v2.css → styles/file-tree.css} +0 -0
  295. /package/src/{v2/styles → styles/tokens}/colors.css +0 -0
  296. /package/src/{v2/styles/tailwind.css → styles/tokens/index.css} +0 -0
@@ -43,10 +43,10 @@ function Digit(props: { value: number; direction: 1 | -1 }) {
43
43
  )
44
44
 
45
45
  return (
46
- <span data-slot="animated-number-digit">
46
+ <span data-slot="animated-number-digit" data-animating={animating() ? "true" : "false"}>
47
+ <span data-slot="animated-number-static">{props.value}</span>
47
48
  <span
48
49
  data-slot="animated-number-strip"
49
- data-animating={animating() ? "true" : "false"}
50
50
  onTransitionEnd={() => {
51
51
  setState("animating", false)
52
52
  setState("step", (value) => normalize(value) + 10)
@@ -58,7 +58,7 @@
58
58
  gap: var(--card-gap);
59
59
  }
60
60
 
61
- :where([data-slot="card-title"]) [data-component="icon"] {
61
+ :where([data-slot="card-title"]) [data-slot="icon-svg"] {
62
62
  color: var(--card-accent);
63
63
  }
64
64
 
@@ -71,7 +71,7 @@
71
71
  flex: 0 0 auto;
72
72
  }
73
73
 
74
- :where([data-slot="card-title-icon"][data-placeholder]) [data-component="icon"] {
74
+ :where([data-slot="card-title-icon"][data-placeholder]) [data-slot="icon-svg"] {
75
75
  color: var(--v2-text-text-faint);
76
76
  }
77
77
 
@@ -92,24 +92,3 @@
92
92
  padding-left: var(--card-indent);
93
93
  }
94
94
  }
95
-
96
- body:not([data-new-layout]) [data-component="card"] {
97
- color: var(--text-strong);
98
- --card-accent: var(--icon-active);
99
-
100
- :where([data-card="title"], [data-slot="card-title"]) {
101
- color: var(--text-strong);
102
- }
103
-
104
- :where([data-slot="card-title-icon"][data-placeholder]) [data-component="icon"] {
105
- color: var(--text-weak);
106
- }
107
-
108
- :where([data-card="description"], [data-slot="card-description"]) {
109
- color: var(--text-base);
110
- }
111
-
112
- &[data-variant="error"] {
113
- --card-accent: var(--icon-critical-base) !important;
114
- }
115
- }
@@ -1,5 +1,5 @@
1
- import { type ComponentProps, splitProps } from "solid-js"
2
- import { Icon, type IconProps } from "./icon"
1
+ import { type ComponentProps, Show, splitProps } from "solid-js"
2
+ import { Icon, type IconProps } from "@opencode-ai/ui/icon"
3
3
 
4
4
  type Variant = "normal" | "error" | "warning" | "success" | "info"
5
5
 
@@ -80,11 +80,11 @@ export function CardTitle(props: CardTitleProps) {
80
80
  [split.class ?? ""]: !!split.class,
81
81
  }}
82
82
  >
83
- {show() ? (
83
+ <Show when={show()}>
84
84
  <span data-slot="card-title-icon" data-placeholder={placeholder() || undefined}>
85
85
  <Icon name={name() ?? "dash"} size="small" />
86
86
  </span>
87
- ) : null}
87
+ </Show>
88
88
  {split.children}
89
89
  </div>
90
90
  )
@@ -1,6 +1,6 @@
1
1
  import { Collapsible as Kobalte, CollapsibleRootProps } from "@kobalte/core/collapsible"
2
2
  import { ComponentProps, ParentProps, splitProps } from "solid-js"
3
- import { Icon } from "./icon"
3
+ import { Icon } from "@opencode-ai/ui/icon"
4
4
 
5
5
  export interface CollapsibleProps extends ParentProps<CollapsibleRootProps> {
6
6
  class?: string
@@ -35,7 +35,7 @@ function CollapsibleArrow(props?: ComponentProps<"div">) {
35
35
  return (
36
36
  <div data-slot="collapsible-arrow" {...(props || {})}>
37
37
  <span data-slot="collapsible-arrow-icon">
38
- <Icon name="chevron-down" size="small" />
38
+ <Icon name="fill-triangle-down" size="small" />
39
39
  </span>
40
40
  </div>
41
41
  )
@@ -10,15 +10,8 @@
10
10
  [data-dock-border-underlay] {
11
11
  /* Later shadows paint underneath, so this solid ring masks overlapping surfaces without changing border geometry. */
12
12
  box-shadow:
13
- var(--dock-shell-visual-shadow, var(--shadow-xs-border)),
14
- 0 0 0 var(--dock-shell-border-underlay-width, 1px)
15
- var(--dock-shell-border-underlay-background, var(--surface-raised-stronger-non-alpha));
16
- }
17
-
18
- [data-dock-border-underlay="v2"] {
19
- --dock-shell-visual-shadow: var(--v2-elevation-raised);
20
- --dock-shell-border-underlay-width: 0.5px;
21
- --dock-shell-border-underlay-background: var(--v2-background-bg-base);
13
+ var(--v2-elevation-raised),
14
+ 0 0 0 0.5px var(--v2-background-bg-base);
22
15
  }
23
16
 
24
17
  [data-dock-surface="tray"] {
@@ -1,6 +1,7 @@
1
1
  import { Dialog as Kobalte } from "@kobalte/core/dialog"
2
2
  import { useI18n } from "../context/i18n"
3
- import { IconButton } from "./icon-button"
3
+ import { Icon } from "@opencode-ai/ui/icon"
4
+ import { IconButton } from "@opencode-ai/ui/icon-button"
4
5
 
5
6
  export interface ImagePreviewProps {
6
7
  src: string
@@ -17,7 +18,7 @@ export function ImagePreview(props: ImagePreviewProps) {
17
18
  <Kobalte.CloseButton
18
19
  data-slot="image-preview-close"
19
20
  as={IconButton}
20
- icon="close"
21
+ icon={<Icon name="close" />}
21
22
  variant="ghost"
22
23
  aria-label={i18n.t("ui.common.close")}
23
24
  />
@@ -31,7 +31,7 @@
31
31
  align-self: stretch;
32
32
  margin-bottom: 4px;
33
33
 
34
- > [data-component="icon-button"] {
34
+ > [data-component="icon-button-v2"] {
35
35
  width: 24px;
36
36
  height: 24px;
37
37
  flex-shrink: 0;
@@ -83,7 +83,7 @@
83
83
  }
84
84
  }
85
85
 
86
- > [data-component="icon-button"] {
86
+ > [data-component="icon-button-v2"] {
87
87
  width: 20px;
88
88
  height: 20px;
89
89
  background-color: transparent;
@@ -106,7 +106,7 @@
106
106
  }
107
107
  }
108
108
 
109
- > [data-component="icon-button"] {
109
+ > [data-component="icon-button-v2"] {
110
110
  background-color: transparent;
111
111
 
112
112
  &:hover:not(:disabled),
@@ -252,7 +252,7 @@
252
252
  justify-content: center;
253
253
  flex-shrink: 0;
254
254
  aspect-ratio: 1/1;
255
- [data-component="icon"] {
255
+ [data-slot="icon-svg"] {
256
256
  color: var(--icon-strong-base);
257
257
  }
258
258
  }
@@ -262,7 +262,7 @@
262
262
  justify-content: center;
263
263
  flex-shrink: 0;
264
264
  aspect-ratio: 1/1;
265
- [data-component="icon"] {
265
+ [data-slot="icon-svg"] {
266
266
  color: var(--icon-strong-base);
267
267
  }
268
268
  }
@@ -3,8 +3,8 @@ import { createEffect, For, type JSX, on, Show } from "solid-js"
3
3
  import { createStore } from "solid-js/store"
4
4
  import { makeEventListener } from "@solid-primitives/event-listener"
5
5
  import { useI18n } from "../context/i18n"
6
- import { Icon, type IconProps } from "./icon"
7
- import { IconButton } from "./icon-button"
6
+ import { Icon, type IconProps } from "@opencode-ai/ui/icon"
7
+ import { IconButton } from "@opencode-ai/ui/icon-button"
8
8
  import { TextField } from "./text-field"
9
9
 
10
10
  function findByKey(container: HTMLElement, key: string) {
@@ -302,7 +302,7 @@ export function List<T>(props: ListProps<T> & { ref?: (ref: ListRef) => void })
302
302
  </div>
303
303
  <Show when={internalFilter()}>
304
304
  <IconButton
305
- icon="circle-x"
305
+ icon={<Icon name="circle-x" />}
306
306
  variant="ghost"
307
307
  onClick={() => {
308
308
  setInternalFilter("")
@@ -367,9 +367,11 @@ export function List<T>(props: ListProps<T> & { ref?: (ref: ListRef) => void })
367
367
  </span>
368
368
  )}
369
369
  </Show>
370
- {props.divider && (i() !== group.items.length - 1 || (showAdd() && isLastGroup())) && (
370
+ <Show
371
+ when={props.divider && (i() !== group.items.length - 1 || (showAdd() && isLastGroup()))}
372
+ >
371
373
  <span data-slot="list-item-divider" />
372
- )}
374
+ </Show>
373
375
  </button>
374
376
  )
375
377
  if (props.itemWrapper) return props.itemWrapper(item, node)
@@ -3,7 +3,8 @@ import { ComponentProps, JSXElement, ParentProps, Show, createEffect, splitProps
3
3
  import { createStore } from "solid-js/store"
4
4
  import { makeEventListener } from "@solid-primitives/event-listener"
5
5
  import { useI18n } from "../context/i18n"
6
- import { IconButton } from "./icon-button"
6
+ import { Icon } from "@opencode-ai/ui/icon"
7
+ import { IconButton } from "@opencode-ai/ui/icon-button"
7
8
 
8
9
  export interface PopoverProps<T extends ValidComponent = "div">
9
10
  extends ParentProps,
@@ -122,7 +123,7 @@ export function Popover<T extends ValidComponent = "div">(props: PopoverProps<T>
122
123
  <Kobalte.CloseButton
123
124
  data-slot="popover-close-button"
124
125
  as={IconButton}
125
- icon="close"
126
+ icon={<Icon name="close" />}
126
127
  variant="ghost"
127
128
  aria-label={i18n.t("ui.common.close")}
128
129
  />
@@ -1,14 +1,4 @@
1
- import {
2
- createEffect,
3
- createMemo,
4
- mergeProps,
5
- onCleanup,
6
- onMount,
7
- Show,
8
- splitProps,
9
- type Accessor,
10
- type ComponentProps,
11
- } from "solid-js"
1
+ import { createEffect, mergeProps, onCleanup, onMount, Show, splitProps, type ComponentProps } from "solid-js"
12
2
  import { Portal } from "solid-js/web"
13
3
  import { createResizeObserver } from "@solid-primitives/resize-observer"
14
4
  import { createStore } from "solid-js/store"
@@ -27,9 +17,9 @@ export interface ScrollViewProps extends ComponentProps<"div"> {
27
17
  * */
28
18
  thumbVisibility?: ScrollViewThumbVisibility
29
19
  /** Mount the thumb into an external track. Scroll metrics still come from this ScrollView. */
30
- thumbContainer?: HTMLElement | Accessor<HTMLElement | undefined>
20
+ thumbContainer?: HTMLElement
31
21
  /** Element whose hover reveals the thumb. Defaults to the ScrollView root when unset. */
32
- thumbHoverTarget?: HTMLElement | Accessor<HTMLElement | undefined>
22
+ thumbHoverTarget?: HTMLElement
33
23
  }
34
24
 
35
25
  export const scrollKey = (event: Pick<KeyboardEvent, "key" | "altKey" | "ctrlKey" | "metaKey" | "shiftKey">) => {
@@ -128,13 +118,8 @@ export function ScrollView(props: ScrollViewProps) {
128
118
  let viewportRef!: HTMLDivElement
129
119
  let thumbRef!: HTMLDivElement
130
120
 
131
- const resolveEl = (value: HTMLElement | Accessor<HTMLElement | undefined> | undefined) => {
132
- if (typeof value === "function") return value()
133
- return value
134
- }
135
-
136
- const thumbMount = createMemo(() => resolveEl(local.thumbContainer))
137
- const thumbHover = createMemo(() => resolveEl(local.thumbHoverTarget))
121
+ const thumbMount = () => local.thumbContainer
122
+ const thumbHover = () => local.thumbHoverTarget
138
123
  const hoverRoot = () => !local.thumbHoverTarget && !local.thumbContainer
139
124
 
140
125
  const [state, setState] = createStore({
@@ -1,4 +1,4 @@
1
- import { Accordion } from "./accordion"
1
+ import { Accordion } from "@opencode-ai/ui/accordion"
2
2
  import { ParentProps } from "solid-js"
3
3
 
4
4
  export function StickyAccordionHeader(
@@ -2,8 +2,9 @@ import { TextField as Kobalte } from "@kobalte/core/text-field"
2
2
  import { createSignal, Show, splitProps } from "solid-js"
3
3
  import type { ComponentProps } from "solid-js"
4
4
  import { useI18n } from "../context/i18n"
5
- import { IconButton } from "./icon-button"
6
- import { Tooltip } from "./tooltip"
5
+ import { IconButton } from "@opencode-ai/ui/icon-button"
6
+ import { Icon } from "@opencode-ai/ui/icon"
7
+ import { Tooltip } from "@opencode-ai/ui/tooltip"
7
8
 
8
9
  export interface TextFieldProps
9
10
  extends ComponentProps<typeof Kobalte.Input>,
@@ -106,10 +107,17 @@ export function TextField(props: TextFieldProps) {
106
107
  <Kobalte.TextArea {...others} autoResize data-slot="input-input" class={local.class} />
107
108
  </Show>
108
109
  <Show when={local.copyable}>
109
- <Tooltip value={label()} placement="top" gutter={4} forceOpen={copied()} skipDelayDuration={0}>
110
+ <Tooltip
111
+ appearance="standard"
112
+ value={label()}
113
+ placement="top"
114
+ gutter={4}
115
+ forceOpen={copied() ? true : undefined}
116
+ skipDelayDuration={0}
117
+ >
110
118
  <IconButton
111
119
  type="button"
112
- icon={icon()}
120
+ icon={<Icon name={icon()} />}
113
121
  variant="ghost"
114
122
  onClick={handleCopy}
115
123
  tabIndex={-1}
@@ -81,6 +81,7 @@ function init() {
81
81
  let dispose: (() => void) | undefined
82
82
  let setClosing: ((closing: boolean) => void) | undefined
83
83
 
84
+ // Stacked dialogs render as sibling portals, so only the top layer may own the focus trap.
84
85
  const node = runWithOwner(owner, () =>
85
86
  createRoot((d: () => void) => {
86
87
  dispose = d
@@ -1,26 +1,24 @@
1
1
  import { createContext, useContext, type Accessor, type ParentProps } from "solid-js"
2
2
  import { I18nProvider } from "@kobalte/core/i18n"
3
3
  import { dict as en } from "../i18n/en"
4
+ import type { Key, LocaleKey, PluralCategory, PluralKey, PluralLookupKey } from "../i18n/en"
4
5
 
5
- export type UiI18nKey = keyof typeof en
6
-
7
- export const UI_PLURAL_KEYS = [
8
- "ui.sessionTurn.diffs.changed",
9
- "ui.messagePart.context.read",
10
- "ui.messagePart.context.search",
11
- "ui.messagePart.context.list",
12
- ] as const
13
- export type UiI18nPluralKey = (typeof UI_PLURAL_KEYS)[number]
14
- export type UiPluralCategory = "zero" | "one" | "two" | "few" | "many" | "other"
15
- export type UiI18nPluralLookupKey = `${UiI18nPluralKey}.${UiPluralCategory}`
6
+ export type UiI18nKey = Key
7
+ export type UiI18nPluralKey = PluralKey
8
+ export type UiPluralCategory = PluralCategory
9
+ export type UiI18nPluralLookupKey = PluralLookupKey
10
+ export type UiI18nLocaleKey = LocaleKey
11
+ type UiTranslationKey<Value extends string> = Value extends UiI18nPluralLookupKey ? never : Value
16
12
 
17
13
  export type UiI18nParams = Record<string, string | number | boolean>
14
+ export type UiTranslate = <Value extends string>(key: UiTranslationKey<Value>, params?: UiI18nParams) => string
18
15
 
19
16
  export type UiI18n = {
20
17
  locale: Accessor<string>
21
18
  layoutLocale?: Accessor<string>
22
- t: (key: UiI18nKey, params?: UiI18nParams) => string
19
+ t: UiTranslate
23
20
  plural: (key: UiI18nPluralKey, count: number, params?: UiI18nParams) => string
21
+ pluralForm?: (key: UiI18nPluralKey, category: UiPluralCategory, params?: UiI18nParams) => string
24
22
  }
25
23
 
26
24
  const rules = new Map<string, Intl.PluralRules>()
@@ -50,11 +48,16 @@ function resolveTemplate(text: string, params?: UiI18nParams) {
50
48
  const fallback: UiI18n = {
51
49
  locale: () => "en",
52
50
  t: (key, params) => {
53
- const value = en[key] ?? String(key)
51
+ const value = en[key as UiI18nKey] ?? String(key)
54
52
  return resolveTemplate(value, params)
55
53
  },
56
54
  plural: (key, count, params) =>
57
- fallback.t(pluralKey(key, pluralCategory(fallback.locale(), count)), { ...params, count }),
55
+ fallback.pluralForm!(key, pluralCategory(fallback.locale(), count), { ...params, count }),
56
+ pluralForm: (key, category, params) => {
57
+ const values = en as Partial<Record<UiI18nLocaleKey, string>>
58
+ const value = values[pluralKey(key, category)] ?? values[`${key}.other`] ?? `${key}.other`
59
+ return resolveTemplate(value, params)
60
+ },
58
61
  }
59
62
 
60
63
  const Context = createContext<UiI18n>(fallback)
@@ -0,0 +1,27 @@
1
+ import { Marked } from "marked"
2
+
3
+ export function createMarkdownBase() {
4
+ return new Marked({
5
+ renderer: {
6
+ link({ href, title, text }) {
7
+ const titleAttr = title ? ` title="${title}"` : ""
8
+ return `<a href="${href}"${titleAttr} class="external-link" target="_blank" rel="noopener noreferrer">${text}</a>`
9
+ },
10
+ },
11
+ })
12
+ }
13
+
14
+ let smallParser: Marked | undefined
15
+
16
+ export function parseSmallMarkdown(text: string) {
17
+ // Any possible KaTeX delimiter stays on the worker, including escaped ones.
18
+ if (text.length > 1024 || text.includes("\\(") || text.includes("$$")) return
19
+ const parser = (smallParser ??= createMarkdownBase())
20
+ const tokens = parser.lexer(text)
21
+ let code = false
22
+ parser.walkTokens(tokens, (token) => {
23
+ if (token.type === "code") code = true
24
+ })
25
+ if (code) return
26
+ return parser.parser(tokens)
27
+ }
@@ -1,20 +1,10 @@
1
1
  import katex from "katex"
2
- import { Marked, type MarkedExtension, type Tokens } from "marked"
2
+ import type { MarkedExtension, Tokens } from "marked"
3
3
  import markedShiki from "marked-shiki"
4
+ import { createMarkdownBase } from "./marked-base"
4
5
 
5
6
  export function createMarkdownParser(highlight: (code: string, language: string) => string | Promise<string>) {
6
- return new Marked(
7
- {
8
- renderer: {
9
- link({ href, title, text }) {
10
- const titleAttr = title ? ` title="${title}"` : ""
11
- return `<a href="${href}"${titleAttr} class="external-link" target="_blank" rel="noopener noreferrer">${text}</a>`
12
- },
13
- },
14
- },
15
- katexExtension,
16
- markedShiki({ highlight }),
17
- )
7
+ return createMarkdownBase().use(katexExtension, markedShiki({ highlight }))
18
8
  }
19
9
 
20
10
  const inlineMathRegex = /^\\\(((?:\\.|[^\\\n])*?)\\\)/
@@ -43,19 +43,17 @@
43
43
  color: var(--v2-text-text-base);
44
44
  transition: background-color 0.15s ease;
45
45
 
46
- /* text-12-regular */
47
46
  font-family: var(--font-family-sans);
48
47
  font-size: var(--font-size-small);
49
48
  font-style: normal;
50
49
  font-weight: var(--font-weight-regular);
51
- line-height: var(--line-height-large); /* 166.667% */
50
+ line-height: var(--line-height-large);
52
51
  letter-spacing: var(--letter-spacing-normal);
53
52
 
54
- &:hover:not([data-disabled]) {
55
- background-color: var(--v2-overlay-simple-overlay-hover);
56
- }
57
- &:active:not([data-disabled]) {
58
- background-color: var(--v2-overlay-simple-overlay-pressed);
53
+ @media (hover: hover) {
54
+ &:hover:not([data-disabled]) {
55
+ background-color: var(--v2-overlay-simple-overlay-hover);
56
+ }
59
57
  }
60
58
  &:focus-visible {
61
59
  outline: none;
@@ -104,30 +102,6 @@
104
102
  }
105
103
  }
106
104
 
107
- body:not([data-new-layout]) [data-component="accordion"] {
108
- [data-slot="accordion-item"] [data-slot="accordion-header"] [data-slot="accordion-trigger"] {
109
- background-color: var(--background-stronger);
110
- border-width: 1px;
111
- border-color: var(--border-weak-base);
112
- color: var(--text-strong);
113
-
114
- &:hover:not([data-disabled]) {
115
- background-color: var(--surface-base-hover);
116
- }
117
-
118
- &:active:not([data-disabled]) {
119
- background-color: var(--surface-base-active);
120
- }
121
- }
122
-
123
- [data-slot="accordion-item"][data-expanded] [data-slot="accordion-content"] {
124
- border-width: 1px;
125
- border-color: var(--border-weak-base);
126
- border-top: 0;
127
- background-color: var(--background-stronger);
128
- }
129
- }
130
-
131
105
  @keyframes slideDown {
132
106
  from {
133
107
  height: 0;
@@ -1,17 +1,17 @@
1
- import { Accordion as Kobalte } from "@kobalte/core/accordion"
1
+ import { Content, Header, Item, Root, Trigger } from "@kobalte/core/accordion"
2
2
  import { splitProps } from "solid-js"
3
3
  import type { ComponentProps, ParentProps } from "solid-js"
4
4
 
5
- export interface AccordionProps extends ComponentProps<typeof Kobalte> {}
6
- export interface AccordionItemProps extends ComponentProps<typeof Kobalte.Item> {}
7
- export interface AccordionHeaderProps extends ComponentProps<typeof Kobalte.Header> {}
8
- export interface AccordionTriggerProps extends ComponentProps<typeof Kobalte.Trigger> {}
9
- export interface AccordionContentProps extends ComponentProps<typeof Kobalte.Content> {}
5
+ export interface AccordionProps extends ComponentProps<typeof Root> {}
6
+ export interface AccordionItemProps extends ComponentProps<typeof Item> {}
7
+ export interface AccordionHeaderProps extends ComponentProps<typeof Header> {}
8
+ export interface AccordionTriggerProps extends ComponentProps<typeof Trigger> {}
9
+ export interface AccordionContentProps extends ComponentProps<typeof Content> {}
10
10
 
11
11
  function AccordionRoot(props: AccordionProps) {
12
12
  const [split, rest] = splitProps(props, ["class", "classList"])
13
13
  return (
14
- <Kobalte
14
+ <Root
15
15
  {...rest}
16
16
  data-component="accordion"
17
17
  classList={{
@@ -25,7 +25,7 @@ function AccordionRoot(props: AccordionProps) {
25
25
  function AccordionItem(props: AccordionItemProps) {
26
26
  const [split, rest] = splitProps(props, ["class", "classList"])
27
27
  return (
28
- <Kobalte.Item
28
+ <Item
29
29
  {...rest}
30
30
  data-slot="accordion-item"
31
31
  classList={{
@@ -39,7 +39,7 @@ function AccordionItem(props: AccordionItemProps) {
39
39
  function AccordionHeader(props: ParentProps<AccordionHeaderProps>) {
40
40
  const [split, rest] = splitProps(props, ["class", "classList", "children"])
41
41
  return (
42
- <Kobalte.Header
42
+ <Header
43
43
  {...rest}
44
44
  data-slot="accordion-header"
45
45
  classList={{
@@ -48,14 +48,14 @@ function AccordionHeader(props: ParentProps<AccordionHeaderProps>) {
48
48
  }}
49
49
  >
50
50
  {split.children}
51
- </Kobalte.Header>
51
+ </Header>
52
52
  )
53
53
  }
54
54
 
55
55
  function AccordionTrigger(props: ParentProps<AccordionTriggerProps>) {
56
56
  const [split, rest] = splitProps(props, ["class", "classList", "children"])
57
57
  return (
58
- <Kobalte.Trigger
58
+ <Trigger
59
59
  {...rest}
60
60
  data-slot="accordion-trigger"
61
61
  classList={{
@@ -64,14 +64,14 @@ function AccordionTrigger(props: ParentProps<AccordionTriggerProps>) {
64
64
  }}
65
65
  >
66
66
  {split.children}
67
- </Kobalte.Trigger>
67
+ </Trigger>
68
68
  )
69
69
  }
70
70
 
71
71
  function AccordionContent(props: ParentProps<AccordionContentProps>) {
72
72
  const [split, rest] = splitProps(props, ["class", "classList", "children"])
73
73
  return (
74
- <Kobalte.Content
74
+ <Content
75
75
  {...rest}
76
76
  data-slot="accordion-content"
77
77
  classList={{
@@ -80,7 +80,7 @@ function AccordionContent(props: ParentProps<AccordionContentProps>) {
80
80
  }}
81
81
  >
82
82
  {split.children}
83
- </Kobalte.Content>
83
+ </Content>
84
84
  )
85
85
  }
86
86
 
@@ -1,5 +1,5 @@
1
1
  import { type ComponentProps, splitProps, Show } from "solid-js"
2
- import "./avatar-v2.css"
2
+ import "./avatar.css"
3
3
 
4
4
  const segmenter =
5
5
  typeof Intl !== "undefined" && "Segmenter" in Intl
@@ -31,3 +31,22 @@
31
31
  background: var(--v2-background-bg-accent);
32
32
  color: var(--v2-text-text-contrast);
33
33
  }
34
+
35
+ [data-component="tag"][data-appearance="standard"] {
36
+ height: 18px;
37
+ padding: 0 6px;
38
+ border-radius: var(--radius-xs);
39
+ font-family: var(--font-family-sans);
40
+ font-size: var(--font-size-small);
41
+ font-style: normal;
42
+ font-weight: var(--font-weight-medium);
43
+ line-height: var(--line-height-large);
44
+ letter-spacing: var(--letter-spacing-normal);
45
+ font-variant-numeric: normal;
46
+ }
47
+
48
+ [data-component="tag"][data-appearance="standard"][data-variant="neutral"] {
49
+ border: 0.5px solid var(--border-weak-base);
50
+ background: var(--surface-raised-base);
51
+ color: var(--text-base);
52
+ }
@@ -1,16 +1,18 @@
1
1
  import { type ComponentProps, splitProps } from "solid-js"
2
- import "./badge-v2.css"
2
+ import "./badge.css"
3
3
 
4
- export interface TagProps extends ComponentProps<"span"> {
4
+ export interface BadgeProps extends ComponentProps<"span"> {
5
+ appearance?: "standard" | "compact"
5
6
  variant?: "neutral" | "accent"
6
7
  }
7
8
 
8
- export function Tag(props: TagProps) {
9
- const [split, rest] = splitProps(props, ["class", "classList", "children", "variant"])
9
+ export function Badge(props: BadgeProps) {
10
+ const [split, rest] = splitProps(props, ["class", "classList", "children", "appearance", "variant"])
10
11
  return (
11
12
  <span
12
13
  {...rest}
13
14
  data-component="tag"
15
+ data-appearance={split.appearance ?? "compact"}
14
16
  data-variant={split.variant ?? "neutral"}
15
17
  classList={{
16
18
  ...split.classList,