@opencode/ui 2.0.22 → 2.0.24

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 (82) hide show
  1. package/dist/data-display/accordion/accordion.d.ts +3 -1
  2. package/dist/feedback/toast/toast.d.ts +3 -2
  3. package/dist/i18n/en.d.ts +5 -0
  4. package/dist/icons/catalog.d.ts +257 -0
  5. package/dist/icons/icon/additional-icons.d.ts +1 -0
  6. package/dist/icons/icon/icon.d.ts +1 -237
  7. package/package.json +5 -1
  8. package/src/actions/button/button.tsx +1 -0
  9. package/src/actions/icon-button/icon-button.tsx +1 -0
  10. package/src/actions/split-button/split-button.tsx +3 -0
  11. package/src/components/animated-number.tsx +13 -0
  12. package/src/components/app-icon.tsx +2 -0
  13. package/src/components/card.tsx +21 -0
  14. package/src/components/collapsible.tsx +1 -0
  15. package/src/components/context-menu.tsx +34 -0
  16. package/src/components/dock-surface.tsx +3 -0
  17. package/src/components/file-icon.tsx +12 -0
  18. package/src/components/image-preview.tsx +1 -0
  19. package/src/components/list.tsx +32 -0
  20. package/src/components/motion-spring.tsx +5 -0
  21. package/src/components/popover.tsx +12 -0
  22. package/src/components/provider-icon.tsx +1 -0
  23. package/src/components/resize-handle.tsx +8 -0
  24. package/src/components/scroll-view.tsx +39 -0
  25. package/src/components/spinner.tsx +2 -0
  26. package/src/components/text-field.tsx +6 -0
  27. package/src/components/text-reveal.tsx +19 -0
  28. package/src/components/text-strikethrough.tsx +8 -0
  29. package/src/components/typewriter.tsx +4 -0
  30. package/src/context/dialog.tsx +12 -0
  31. package/src/context/file.tsx +1 -0
  32. package/src/context/helper.tsx +4 -0
  33. package/src/context/i18n.tsx +20 -0
  34. package/src/context/index.ts +3 -0
  35. package/src/context/marked-base.tsx +7 -0
  36. package/src/context/marked-parser.tsx +7 -0
  37. package/src/context/marked.tsx +3 -0
  38. package/src/context/worker-pool.tsx +2 -0
  39. package/src/data-display/accordion/accordion.tsx +16 -2
  40. package/src/data-display/avatar/avatar.tsx +4 -0
  41. package/src/data-display/badge/badge.tsx +1 -0
  42. package/src/data-display/diff-changes/diff-changes.tsx +2 -0
  43. package/src/data-display/keybind/keybind.tsx +1 -0
  44. package/src/data-display/line-comment/line-comment.tsx +22 -0
  45. package/src/data-display/project-avatar/project-avatar.tsx +10 -0
  46. package/src/feedback/loader/loader.tsx +1 -0
  47. package/src/feedback/toast/description.ts +1 -0
  48. package/src/feedback/toast/toast.tsx +32 -6
  49. package/src/forms/checkbox/checkbox.tsx +1 -0
  50. package/src/forms/field/field.tsx +8 -0
  51. package/src/forms/inline-input/inline-input.tsx +4 -0
  52. package/src/forms/radio/radio.tsx +2 -0
  53. package/src/forms/select/select.tsx +11 -0
  54. package/src/forms/switch/switch.tsx +1 -0
  55. package/src/forms/text-input/text-input.tsx +3 -0
  56. package/src/hooks/create-auto-scroll.tsx +34 -0
  57. package/src/hooks/index.ts +1 -0
  58. package/src/hooks/use-filtered-list.tsx +14 -0
  59. package/src/i18n/en.ts +10 -0
  60. package/src/i18n/no.ts +1 -0
  61. package/src/icons/catalog.ts +273 -0
  62. package/src/icons/icon/additional-icons.ts +1 -0
  63. package/src/icons/icon/icon.tsx +10 -250
  64. package/src/layout/divider/divider.tsx +1 -0
  65. package/src/navigation/menu/menu.tsx +13 -0
  66. package/src/navigation/segmented-control/segmented-control.tsx +16 -0
  67. package/src/navigation/tab-state-indicator.tsx +1 -0
  68. package/src/navigation/tabs/tabs.css +6 -72
  69. package/src/navigation/tabs/tabs.tsx +18 -0
  70. package/src/overlays/dialog/dialog.tsx +3 -0
  71. package/src/overlays/tooltip/tooltip.tsx +15 -0
  72. package/src/storybook/scaffold.tsx +3 -0
  73. package/src/styles/theme.css +1 -1
  74. package/src/theme/color.ts +27 -0
  75. package/src/theme/context.tsx +58 -0
  76. package/src/theme/default-themes.ts +35 -0
  77. package/src/theme/index.ts +3 -0
  78. package/src/theme/loader.ts +11 -0
  79. package/src/theme/resolve.ts +28 -0
  80. package/src/theme/v2/foreground.ts +8 -0
  81. package/src/theme/v2/resolve.ts +10 -0
  82. package/src/typography/text-shimmer/text-shimmer.tsx +1 -0
@@ -47,7 +47,9 @@ const MenuAppearanceContext = createContext<{ appearance: Accessor<MenuAppearanc
47
47
 
48
48
  function useMenuContext() {
49
49
  const ctx = useContext(MenuAppearanceContext)
50
+
50
51
  if (!ctx) throw new Error("Menu components must be used inside Menu or Menu.Context")
52
+
51
53
  return ctx
52
54
  }
53
55
 
@@ -76,6 +78,7 @@ export interface MenuItemProps extends ComponentProps<typeof DropdownMenu.Item>
76
78
  function MenuItem(props: ParentProps<MenuItemProps>) {
77
79
  const ctx = useMenuContext()
78
80
  const [s, r] = splitProps(props, ["class", "classList", "children", "shortcut", "badge"])
81
+
79
82
  return (
80
83
  <DropdownMenu.Item
81
84
  {...r}
@@ -98,6 +101,7 @@ export interface MenuCheckboxItemProps extends ComponentProps<typeof DropdownMen
98
101
  function MenuCheckboxItem(props: ParentProps<MenuCheckboxItemProps>) {
99
102
  const ctx = useMenuContext()
100
103
  const [s, r] = splitProps(props, ["class", "classList", "children", "shortcut", "badge"])
104
+
101
105
  return (
102
106
  <DropdownMenu.CheckboxItem
103
107
  {...r}
@@ -128,6 +132,7 @@ export interface MenuRadioItemProps extends ComponentProps<typeof DropdownMenu.R
128
132
  function MenuRadioItem(props: ParentProps<MenuRadioItemProps>) {
129
133
  const ctx = useMenuContext()
130
134
  const [s, r] = splitProps(props, ["class", "classList", "children", "shortcut", "badge"])
135
+
131
136
  return (
132
137
  <DropdownMenu.RadioItem
133
138
  {...r}
@@ -178,6 +183,7 @@ function MenuSub(props: MenuSubProps) {
178
183
  function MenuSubTrigger(props: ParentProps<MenuSubTriggerProps>) {
179
184
  const ctx = useMenuContext()
180
185
  const [s, r] = splitProps(props, ["class", "classList", "children", "shortcut", "badge"])
186
+
181
187
  return (
182
188
  <DropdownMenu.SubTrigger
183
189
  {...r}
@@ -195,6 +201,7 @@ function MenuSubTrigger(props: ParentProps<MenuSubTriggerProps>) {
195
201
  function MenuSubContent(props: ComponentProps<typeof DropdownMenu.SubContent>) {
196
202
  const ctx = useMenuContext()
197
203
  const [s, r] = splitProps(props, ["class", "classList"])
204
+
198
205
  return (
199
206
  <DropdownMenu.SubContent
200
207
  {...r}
@@ -208,6 +215,7 @@ function MenuSubContent(props: ComponentProps<typeof DropdownMenu.SubContent>) {
208
215
  function MenuGroupLabel(props: ComponentProps<typeof DropdownMenu.GroupLabel>) {
209
216
  const ctx = useMenuContext()
210
217
  const [s, r] = splitProps(props, ["class", "classList"])
218
+
211
219
  return (
212
220
  <DropdownMenu.GroupLabel
213
221
  {...r}
@@ -221,6 +229,7 @@ function MenuGroupLabel(props: ComponentProps<typeof DropdownMenu.GroupLabel>) {
221
229
  function MenuSeparator(props: ComponentProps<typeof DropdownMenu.Separator>) {
222
230
  const ctx = useMenuContext()
223
231
  const [s, r] = splitProps(props, ["class", "classList"])
232
+
224
233
  return (
225
234
  <DropdownMenu.Separator
226
235
  {...r}
@@ -234,6 +243,7 @@ function MenuSeparator(props: ComponentProps<typeof DropdownMenu.Separator>) {
234
243
  function MenuContent(props: ComponentProps<typeof DropdownMenu.Content>) {
235
244
  const ctx = useMenuContext()
236
245
  const [s, r] = splitProps(props, ["class", "classList"])
246
+
237
247
  return (
238
248
  <DropdownMenu.Content
239
249
  {...r}
@@ -251,6 +261,7 @@ export interface MenuProps extends ComponentProps<typeof DropdownMenu> {
251
261
  function MenuRoot(props: MenuProps) {
252
262
  const [local, rest] = splitProps(props, ["appearance", "children"])
253
263
  const appearance = () => local.appearance ?? "compact"
264
+
254
265
  return (
255
266
  <MenuAppearanceContext.Provider value={{ appearance }}>
256
267
  <DropdownMenu {...rest}>{local.children}</DropdownMenu>
@@ -265,6 +276,7 @@ export interface MenuContextProps extends ComponentProps<typeof ContextMenu> {
265
276
  function MenuContextRoot(props: MenuContextProps) {
266
277
  const [local, rest] = splitProps(props, ["appearance", "children"])
267
278
  const appearance = () => local.appearance ?? "compact"
279
+
268
280
  return (
269
281
  <MenuAppearanceContext.Provider value={{ appearance }}>
270
282
  <ContextMenu {...rest}>{local.children}</ContextMenu>
@@ -275,6 +287,7 @@ function MenuContextRoot(props: MenuContextProps) {
275
287
  function MenuContextContent(props: ComponentProps<typeof ContextMenu.Content>) {
276
288
  const ctx = useMenuContext()
277
289
  const [s, r] = splitProps(props, ["class", "classList"])
290
+
278
291
  return (
279
292
  <ContextMenu.Content
280
293
  {...r}
@@ -26,7 +26,9 @@ const SegmentedControlContext = createContext<SegmentedControlContextValue>()
26
26
 
27
27
  function useSegmentedControlContext() {
28
28
  const ctx = useContext(SegmentedControlContext)
29
+
29
30
  if (!ctx) throw new Error("SegmentedControlItem must be used inside SegmentedControl")
31
+
30
32
  return ctx
31
33
  }
32
34
 
@@ -45,6 +47,7 @@ export type SegmentedControlProps = Omit<ComponentProps<"div">, "onChange"> &
45
47
  export function SegmentedControl(props: SegmentedControlProps) {
46
48
  const isControlled = createMemo(() => Object.hasOwn(props as object, "value"))
47
49
  const merged = mergeProps({ allowDeselect: false, disabled: false }, props)
50
+
48
51
  const [local, rest] = splitProps(merged, [
49
52
  "class",
50
53
  "classList",
@@ -77,10 +80,13 @@ export function SegmentedControl(props: SegmentedControlProps) {
77
80
 
78
81
  const focusNext = (from: HTMLButtonElement, direction: 1 | -1) => {
79
82
  const root = from.closest(`[data-slot="segmented-control-v2"]`)
83
+
80
84
  if (!root) return
85
+
81
86
  const buttons = Array.from(
82
87
  root.querySelectorAll<HTMLButtonElement>(`button[data-slot="segmented-control-v2-item"]`),
83
88
  ).filter((b) => !b.disabled)
89
+
84
90
  const i = buttons.indexOf(from)
85
91
  const next = buttons[i + direction]
86
92
  next?.focus()
@@ -96,6 +102,7 @@ export function SegmentedControl(props: SegmentedControlProps) {
96
102
 
97
103
  const assignRef = (el: HTMLDivElement | undefined) => {
98
104
  const r = local.ref
105
+
99
106
  if (typeof r === "function") (r as (el: HTMLDivElement | undefined) => void)(el)
100
107
  else if (r != null && typeof r === "object" && "value" in r) (r as { value: HTMLDivElement | undefined }).value = el
101
108
  }
@@ -134,6 +141,7 @@ function invokeButtonHandler<E extends Event>(
134
141
 
135
142
  export function SegmentedControlItem(props: SegmentedControlItemProps) {
136
143
  const merged = mergeProps({ disabled: false }, props)
144
+
137
145
  const [local, rest] = splitProps(merged, [
138
146
  "class",
139
147
  "classList",
@@ -143,6 +151,7 @@ export function SegmentedControlItem(props: SegmentedControlItemProps) {
143
151
  "onClick",
144
152
  "onKeyDown",
145
153
  ])
154
+
146
155
  const ctx = useSegmentedControlContext()
147
156
 
148
157
  const pressed = createMemo(() => ctx.selected() === local.value)
@@ -150,13 +159,16 @@ export function SegmentedControlItem(props: SegmentedControlItemProps) {
150
159
 
151
160
  const onClick: JSX.EventHandlerUnion<HTMLButtonElement, MouseEvent> = (e) => {
152
161
  invokeButtonHandler(local.onClick, e)
162
+
153
163
  if (e.defaultPrevented || disabled()) return
164
+
154
165
  if (pressed()) ctx.clearIfAllowed(local.value)
155
166
  else ctx.select(local.value)
156
167
  }
157
168
 
158
169
  const onKeyDown: JSX.EventHandlerUnion<HTMLButtonElement, KeyboardEvent> = (e) => {
159
170
  invokeButtonHandler(local.onKeyDown, e)
171
+
160
172
  if (e.defaultPrevented || disabled()) return
161
173
  const t = e.currentTarget
162
174
  const horizontal = t.closest(`[data-slot="segmented-control-v2"]`)?.matches(":dir(rtl)") ? -1 : 1
@@ -173,16 +185,20 @@ export function SegmentedControlItem(props: SegmentedControlItemProps) {
173
185
  else if (e.key === "Home") {
174
186
  e.preventDefault()
175
187
  const root = t.closest(`[data-slot="segmented-control-v2"]`)
188
+
176
189
  const first = root?.querySelector<HTMLButtonElement>(
177
190
  `button[data-slot="segmented-control-v2-item"]:not(:disabled)`,
178
191
  )
192
+
179
193
  first?.focus()
180
194
  } else if (e.key === "End") {
181
195
  e.preventDefault()
182
196
  const root = t.closest(`[data-slot="segmented-control-v2"]`)
197
+
183
198
  const buttons = root?.querySelectorAll<HTMLButtonElement>(
184
199
  `button[data-slot="segmented-control-v2-item"]:not(:disabled)`,
185
200
  )
201
+
186
202
  const last = buttons?.[buttons.length - 1]
187
203
  last?.focus()
188
204
  }
@@ -2,6 +2,7 @@ import { splitProps, type ComponentProps } from "solid-js"
2
2
 
3
3
  export function TabStateIndicator(props: ComponentProps<"svg">) {
4
4
  const [local, rest] = splitProps(props, ["class", "classList", "width", "height"])
5
+
5
6
  return (
6
7
  <svg
7
8
  {...rest}
@@ -568,11 +568,6 @@
568
568
  color: var(--v2-text-text-base);
569
569
  }
570
570
 
571
- .tab-fileicon-color,
572
- .tab-fileicon-mono {
573
- margin-inline-start: -2px;
574
- }
575
-
576
571
  .italic {
577
572
  font-style: italic !important;
578
573
  font-variation-settings: "slnt" -10 !important;
@@ -600,27 +595,15 @@
600
595
  flex: 1 1 0;
601
596
  min-width: 0;
602
597
  width: auto;
598
+ height: var(--tabs-bar-height);
599
+ padding-inline-end: 0;
603
600
  border-bottom: none;
604
601
  }
605
602
 
603
+ /* The end gap lives inside the sticky "+" box. Sticky offsets respect the strip's padding, so padding there
604
+ would leave a gap after the "+" where scrolled tabs show through. */
606
605
  :root body #review-panel [data-component="tabs"] .session-review-v2-tabs-bar [data-slot="tabs-list"] > .sticky {
607
- padding-inline-end: 0;
608
-
609
- [data-component="icon-button-v2"] {
610
- position: relative;
611
-
612
- &::after {
613
- content: "";
614
- position: absolute;
615
- inset-inline-start: 100%;
616
- top: 50%;
617
- transform: translateY(-50%);
618
- width: 20px;
619
- height: 28px;
620
- background-color: var(--v2-background-bg-base);
621
- pointer-events: none;
622
- }
623
- }
606
+ padding-inline-end: 12px;
624
607
  }
625
608
 
626
609
  :root
@@ -629,61 +612,12 @@
629
612
  [data-component="tabs"]
630
613
  .session-review-v2-tabs-bar
631
614
  [data-slot="tabs-list"]
632
- > .sticky:not(.session-review-v2-sidebar-toggle-slot) {
615
+ > .sticky {
633
616
  left: auto;
634
617
  right: auto;
635
618
  inset-inline-end: 0;
636
619
  }
637
620
 
638
- :root
639
- body
640
- #review-panel
641
- [data-component="tabs"]
642
- .session-review-v2-tabs-bar
643
- [data-slot="tabs-list"]
644
- > .session-review-v2-sidebar-toggle-slot.sticky {
645
- left: auto;
646
- right: auto;
647
- inset-inline-start: 0;
648
- padding-inline-end: 0;
649
-
650
- &::before {
651
- content: "";
652
- position: absolute;
653
- top: 50%;
654
- bottom: auto;
655
- inset-inline-start: auto;
656
- inset-inline-end: 100%;
657
- transform: translateY(-50%);
658
- width: 12px;
659
- height: 28px;
660
- background-color: var(--v2-background-bg-base);
661
- background-image: none;
662
- pointer-events: none;
663
- }
664
-
665
- &::after {
666
- content: "";
667
- position: absolute;
668
- top: 50%;
669
- inset-inline-start: 100%;
670
- inset-inline-end: auto;
671
- transform: translateY(-50%);
672
- width: 8px;
673
- height: 28px;
674
- pointer-events: none;
675
- background: linear-gradient(90deg, var(--v2-background-bg-base), transparent);
676
- }
677
-
678
- &:dir(rtl)::after {
679
- background: linear-gradient(270deg, var(--v2-background-bg-base), transparent);
680
- }
681
-
682
- [data-component="icon-button-v2"]::after {
683
- display: none;
684
- }
685
- }
686
-
687
621
  :root body #review-panel [data-component="tabs"] .session-review-v2-open-in-app-slot {
688
622
  flex-shrink: 0;
689
623
  margin-inline-start: auto;
@@ -10,7 +10,9 @@ export interface TabsProps extends ComponentProps<typeof Root> {
10
10
  variant?: TabsVariant
11
11
  orientation?: "horizontal" | "vertical"
12
12
  }
13
+
13
14
  export interface TabsListProps extends ComponentProps<typeof List> {}
15
+
14
16
  export interface TabsTriggerProps extends ComponentProps<typeof Trigger> {
15
17
  classes?: { button?: string }
16
18
  closeButton?: JSX.Element
@@ -18,7 +20,9 @@ export interface TabsTriggerProps extends ComponentProps<typeof Trigger> {
18
20
  onMiddleClick?: () => void
19
21
  subtext?: JSX.Element | string
20
22
  }
23
+
21
24
  export interface TabsCloseButtonProps extends ComponentProps<"button"> {}
25
+
22
26
  export interface TabsContentProps extends ComponentProps<typeof Content> {}
23
27
 
24
28
  const TabsContext = createContext<{ current: () => boolean }>({ current: () => false })
@@ -27,12 +31,17 @@ function TabsRoot(props: TabsProps) {
27
31
  const [local, rest] = splitProps(props, ["class", "classList", "variant", "orientation", "children"])
28
32
  const variant = () => local.variant ?? "panel"
29
33
  const current = () => variant() === "line" || variant() === "pill" || variant() === "settings"
34
+
30
35
  const dataVariant = () => {
31
36
  if (variant() === "panel" || variant() === "line") return "normal"
37
+
32
38
  if (variant() === "underline") return "alt"
39
+
33
40
  if (variant() === "surface") return "pill"
41
+
34
42
  return variant()
35
43
  }
44
+
36
45
  return (
37
46
  <TabsContext.Provider value={{ current }}>
38
47
  <Root
@@ -55,6 +64,7 @@ function TabsRoot(props: TabsProps) {
55
64
  function TabsList(props: TabsListProps) {
56
65
  const ctx = useContext(TabsContext)
57
66
  const [local, rest] = splitProps(props, ["class", "classList"])
67
+
58
68
  return (
59
69
  <List
60
70
  {...rest}
@@ -69,6 +79,7 @@ function TabsList(props: TabsListProps) {
69
79
 
70
80
  function TabsTrigger(props: ParentProps<TabsTriggerProps>) {
71
81
  const ctx = useContext(TabsContext)
82
+
72
83
  const [local, rest] = splitProps(props, [
73
84
  "class",
74
85
  "classList",
@@ -80,9 +91,11 @@ function TabsTrigger(props: ParentProps<TabsTriggerProps>) {
80
91
  "subtext",
81
92
  "dir",
82
93
  ])
94
+
83
95
  const wrapperSlot = () => (ctx.current() ? "tabs-v2-trigger-wrapper" : "tabs-trigger-wrapper")
84
96
  const triggerSlot = () => (ctx.current() ? "tabs-v2-trigger" : "tabs-trigger")
85
97
  const closeSlot = () => (ctx.current() ? "tabs-v2-trigger-close-button" : "tabs-trigger-close-button")
98
+
86
99
  return (
87
100
  <div
88
101
  data-slot={wrapperSlot()}
@@ -135,6 +148,7 @@ function TabsTrigger(props: ParentProps<TabsTriggerProps>) {
135
148
  function TabsCloseButton(props: TabsCloseButtonProps) {
136
149
  const i18n = useI18n()
137
150
  const [local, rest] = splitProps(props, ["class", "classList", "onClick", "onPointerDown", "aria-label"])
151
+
138
152
  return (
139
153
  <button
140
154
  type="button"
@@ -147,11 +161,13 @@ function TabsCloseButton(props: TabsCloseButtonProps) {
147
161
  }}
148
162
  onPointerDown={(event) => {
149
163
  event.stopPropagation()
164
+
150
165
  if (typeof local.onPointerDown === "function") local.onPointerDown(event)
151
166
  }}
152
167
  onClick={(event) => {
153
168
  event.preventDefault()
154
169
  event.stopPropagation()
170
+
155
171
  if (typeof local.onClick === "function") local.onClick(event)
156
172
  }}
157
173
  >
@@ -166,6 +182,7 @@ function TabsCloseButton(props: TabsCloseButtonProps) {
166
182
  function TabsContent(props: ParentProps<TabsContentProps>) {
167
183
  const ctx = useContext(TabsContext)
168
184
  const [local, rest] = splitProps(props, ["class", "classList", "children"])
185
+
169
186
  return (
170
187
  <Content
171
188
  {...rest}
@@ -182,6 +199,7 @@ function TabsContent(props: ParentProps<TabsContentProps>) {
182
199
 
183
200
  const TabsSectionTitle: Component<ParentProps> = (props) => {
184
201
  const ctx = useContext(TabsContext)
202
+
185
203
  return <div data-slot={ctx.current() ? "tabs-v2-section-title" : "tabs-section-title"}>{props.children}</div>
186
204
  }
187
205
 
@@ -31,6 +31,7 @@ export function DialogFooter(props: ParentProps) {
31
31
 
32
32
  export function DialogBody(props: ParentProps & { class?: ComponentProps<"div">["class"] }) {
33
33
  const [local] = splitProps(props, ["class", "children"])
34
+
34
35
  return (
35
36
  <div data-slot="dialog-body" class={local.class}>
36
37
  {local.children}
@@ -96,6 +97,7 @@ export function Dialog(props: DialogProps) {
96
97
  "onCloseAutoFocus",
97
98
  "preventBackdropDismiss",
98
99
  ])
100
+
99
101
  const layer = useDialogLayer()
100
102
  createEffect(() => layer?.setBackdropDismiss(!local.preventBackdropDismiss))
101
103
 
@@ -120,6 +122,7 @@ export function Dialog(props: DialogProps) {
120
122
  onOpenAutoFocus={(e) => {
121
123
  const target = e.currentTarget as HTMLElement | null
122
124
  const autofocusEl = target?.querySelector("[autofocus]") as HTMLElement | null
125
+
123
126
  if (autofocusEl) {
124
127
  e.preventDefault()
125
128
  autofocusEl.focus({ preventScroll: true })
@@ -17,11 +17,13 @@ export interface TooltipProps extends ComponentProps<typeof Root> {
17
17
 
18
18
  export function Tooltip(props: TooltipProps) {
19
19
  let ref: HTMLDivElement | undefined
20
+
20
21
  const [state, setState] = createStore({
21
22
  open: false,
22
23
  block: false,
23
24
  expand: false,
24
25
  })
26
+
25
27
  const [local, others] = splitProps(props, [
26
28
  "children",
27
29
  "appearance",
@@ -40,13 +42,17 @@ export function Tooltip(props: TooltipProps) {
40
42
 
41
43
  const inside = () => {
42
44
  const active = document.activeElement
45
+
43
46
  if (!ref || !active) return false
47
+
44
48
  return ref.contains(active)
45
49
  }
46
50
 
47
51
  const drop = (expand = state.expand) => {
48
52
  if (expand || !state.block) return
53
+
49
54
  if (ref?.matches(":hover")) return
55
+
50
56
  if (inside()) return
51
57
  setState("block", false)
52
58
  }
@@ -54,11 +60,14 @@ export function Tooltip(props: TooltipProps) {
54
60
  const sync = () => {
55
61
  const expand = !!ref?.querySelector('[aria-expanded="true"], [data-expanded]')
56
62
  setState("expand", expand)
63
+
57
64
  if (expand) {
58
65
  setState("block", true)
59
66
  close()
67
+
60
68
  return
61
69
  }
70
+
62
71
  drop(expand)
63
72
  }
64
73
 
@@ -101,11 +110,15 @@ export function Tooltip(props: TooltipProps) {
101
110
  open={controlled() ? local.forceOpen : state.open}
102
111
  onOpenChange={(open) => {
103
112
  if (controlled()) return
113
+
104
114
  if (state.block && open) return
115
+
105
116
  if (justClickedTrigger) {
106
117
  justClickedTrigger = false
118
+
107
119
  return
108
120
  }
121
+
109
122
  setState("open", open)
110
123
  }}
111
124
  >
@@ -129,6 +142,7 @@ export function Tooltip(props: TooltipProps) {
129
142
  <Content
130
143
  ref={(el) => {
131
144
  const theme = ref?.closest("[data-theme]")?.getAttribute("data-theme")
145
+
132
146
  if (theme) el.setAttribute("data-theme", theme)
133
147
  }}
134
148
  data-component="tooltip-v2"
@@ -141,6 +155,7 @@ export function Tooltip(props: TooltipProps) {
141
155
  if (ref === e.target || (e.target instanceof Node && ref?.contains(e.target))) {
142
156
  justClickedTrigger = true
143
157
  }
158
+
144
159
  e.preventDefault()
145
160
  }}
146
161
  >
@@ -7,14 +7,17 @@ function fn(value: unknown): value is (...args: never[]) => unknown {
7
7
 
8
8
  function pick(mod: Record<string, unknown>, name?: string) {
9
9
  if (name && fn(mod[name])) return mod[name]
10
+
10
11
  if (fn(mod.default)) return mod.default
11
12
 
12
13
  const preferred = Object.keys(mod)
13
14
  .filter((k) => k[0] && k[0] === k[0].toUpperCase())
14
15
  .find((k) => fn(mod[k]))
16
+
15
17
  if (preferred) return mod[preferred]
16
18
 
17
19
  const first = Object.keys(mod).find((k) => fn(mod[k]))
20
+
18
21
  if (first) return mod[first]
19
22
 
20
23
  return () => {
@@ -11,7 +11,7 @@
11
11
  --font-size-x-large: 20px;
12
12
  --font-weight-regular: 400;
13
13
  --font-weight-medium: 500;
14
- --font-weight-bold: 700;
14
+ --font-weight-bold: 670;
15
15
  --line-height-normal: 130%;
16
16
  --line-height-large: 150%;
17
17
  --line-height-x-large: 180%;