@adea-ai/ui 0.98.0 → 0.99.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/components/composites/action-button/action-button.d.ts +1 -0
- package/dist/components/composites/action-button/action-button.d.ts.map +1 -1
- package/dist/components/composites/action-button/action-button.js +1 -1
- package/dist/components/composites/action-button/action-button.js.map +1 -1
- package/dist/components/composites/appearance-editor/appearance-choices.d.ts.map +1 -1
- package/dist/components/composites/appearance-editor/appearance-choices.js +32 -28
- package/dist/components/composites/appearance-editor/appearance-choices.js.map +1 -1
- package/dist/components/composites/appearance-editor/appearance-rows.d.ts.map +1 -1
- package/dist/components/composites/appearance-editor/appearance-rows.js +1 -1
- package/dist/components/composites/appearance-editor/appearance-rows.js.map +1 -1
- package/dist/components/layout/side-rail/side-rail.d.ts.map +1 -1
- package/dist/components/layout/side-rail/side-rail.js +10 -7
- package/dist/components/layout/side-rail/side-rail.js.map +1 -1
- package/dist/components/layout/top-bar/top-bar.d.ts +7 -0
- package/dist/components/layout/top-bar/top-bar.d.ts.map +1 -1
- package/dist/components/layout/top-bar/top-bar.js +11 -5
- package/dist/components/layout/top-bar/top-bar.js.map +1 -1
- package/dist/components/ui/dropdown-menu/dropdown-menu.d.ts.map +1 -1
- package/dist/components/ui/dropdown-menu/dropdown-menu.js +4 -2
- package/dist/components/ui/dropdown-menu/dropdown-menu.js.map +1 -1
- package/dist/components/ui/kbd/kbd.d.ts.map +1 -1
- package/dist/components/ui/kbd/kbd.js +1 -1
- package/dist/components/ui/kbd/kbd.js.map +1 -1
- package/dist/components/ui/status-chip/status-chip.d.ts.map +1 -1
- package/dist/components/ui/status-chip/status-chip.js +0 -1
- package/dist/components/ui/status-chip/status-chip.js.map +1 -1
- package/dist/components/ui/tooltip/tooltip.d.ts +1 -4
- package/dist/components/ui/tooltip/tooltip.d.ts.map +1 -1
- package/dist/components/ui/tooltip/tooltip.js +3 -3
- package/dist/components/ui/tooltip/tooltip.js.map +1 -1
- package/dist/lib/overlay.d.ts +7 -0
- package/dist/lib/overlay.d.ts.map +1 -1
- package/dist/lib/overlay.js +8 -1
- package/dist/lib/overlay.js.map +1 -1
- package/dist/lib/tokens.d.ts.map +1 -1
- package/dist/lib/tokens.js +5 -0
- package/dist/lib/tokens.js.map +1 -1
- package/dist/r/src/components/composites/action-button/action-button.tsx +2 -1
- package/dist/r/src/components/composites/appearance-editor/appearance-choices.tsx +35 -20
- package/dist/r/src/components/composites/appearance-editor/appearance-rows.tsx +6 -2
- package/dist/r/src/components/layout/side-rail/side-rail.tsx +7 -3
- package/dist/r/src/components/layout/top-bar/top-bar.tsx +13 -2
- package/dist/r/src/components/ui/dropdown-menu/dropdown-menu.tsx +10 -2
- package/dist/r/src/components/ui/kbd/kbd.tsx +0 -2
- package/dist/r/src/components/ui/status-chip/status-chip.tsx +1 -3
- package/dist/r/src/components/ui/tooltip/tooltip.tsx +7 -7
- package/dist/r/src/lib/overlay.ts +9 -0
- package/dist/r/src/lib/tokens.ts +6 -0
- package/dist/r/src/styles/theme.css +5 -0
- package/package.json +1 -1
- package/src/components/composites/action-button/action-button.tsx +2 -1
- package/src/components/composites/appearance-editor/appearance-choices.tsx +35 -20
- package/src/components/composites/appearance-editor/appearance-rows.tsx +6 -2
- package/src/components/layout/side-rail/side-rail.tsx +7 -3
- package/src/components/layout/top-bar/top-bar.tsx +13 -2
- package/src/components/ui/dropdown-menu/dropdown-menu.tsx +10 -2
- package/src/components/ui/kbd/kbd.tsx +0 -2
- package/src/components/ui/status-chip/status-chip.tsx +1 -3
- package/src/components/ui/tooltip/tooltip.tsx +7 -7
- package/src/lib/overlay.ts +9 -0
- package/src/lib/tokens.ts +6 -0
- package/src/styles/theme.css +5 -0
|
@@ -20,8 +20,6 @@ export function Kbd(props: ComponentProps<'kbd'>) {
|
|
|
20
20
|
data-slot="kbd"
|
|
21
21
|
class={cn(
|
|
22
22
|
'bg-muted text-muted-foreground pointer-events-none inline-flex h-5 min-w-5 items-center justify-center gap-1 rounded-sm border border-border px-1 font-mono text-2xs font-medium select-none',
|
|
23
|
-
/* Inside a hover/selected row the key needs to recede with the row. */
|
|
24
|
-
'in-data-[slot=br-tooltip-content]:bg-background/20 in-data-[slot=br-tooltip-content]:text-scrim-foreground in-data-[slot=br-tooltip-content]:border-transparent',
|
|
25
23
|
local.class
|
|
26
24
|
)}
|
|
27
25
|
{...rest}
|
|
@@ -99,9 +99,7 @@ export function StatusChip(props: StatusChipProps) {
|
|
|
99
99
|
<TooltipTrigger as="span" class="inline-flex">
|
|
100
100
|
{chip}
|
|
101
101
|
</TooltipTrigger>
|
|
102
|
-
<TooltipContent data-slot="tooltip-content"
|
|
103
|
-
{detail()}
|
|
104
|
-
</TooltipContent>
|
|
102
|
+
<TooltipContent data-slot="tooltip-content">{detail()}</TooltipContent>
|
|
105
103
|
</Tooltip>
|
|
106
104
|
)}
|
|
107
105
|
</Show>
|
|
@@ -10,6 +10,7 @@ import {
|
|
|
10
10
|
useContext,
|
|
11
11
|
} from 'solid-js'
|
|
12
12
|
import { isServer } from 'solid-js/web'
|
|
13
|
+
import { tooltipTip } from '../../../lib/overlay'
|
|
13
14
|
import { cn } from '../../../lib/utils'
|
|
14
15
|
|
|
15
16
|
/**
|
|
@@ -348,16 +349,12 @@ export function TooltipTrigger(props: ComponentProps<typeof KobalteTooltip.Trigg
|
|
|
348
349
|
)
|
|
349
350
|
}
|
|
350
351
|
|
|
351
|
-
export type TooltipContentProps = ComponentProps<typeof KobalteTooltip.Content>
|
|
352
|
-
/** Hide the caret pointing at the trigger. */
|
|
353
|
-
hideArrow?: boolean
|
|
354
|
-
}
|
|
352
|
+
export type TooltipContentProps = ComponentProps<typeof KobalteTooltip.Content>
|
|
355
353
|
|
|
356
354
|
export function TooltipContent(props: TooltipContentProps) {
|
|
357
355
|
const interaction = useContext(TooltipInteractionContext)
|
|
358
356
|
const [local, rest] = splitProps(props, [
|
|
359
357
|
'class',
|
|
360
|
-
'hideArrow',
|
|
361
358
|
'children',
|
|
362
359
|
'aria-hidden',
|
|
363
360
|
'onEscapeKeyDown',
|
|
@@ -371,7 +368,11 @@ export function TooltipContent(props: TooltipContentProps) {
|
|
|
371
368
|
<KobalteTooltip.Portal>
|
|
372
369
|
<KobalteTooltip.Content
|
|
373
370
|
class={cn(
|
|
374
|
-
|
|
371
|
+
tooltipTip,
|
|
372
|
+
// The max width is a token, not a fixed measure: it has to fall
|
|
373
|
+
// behind the viewport at large root font sizes or the tip — which
|
|
374
|
+
// Kobalte can shift but never shrink — forces a horizontal scroll.
|
|
375
|
+
'z-(--z-tooltip) w-fit max-w-(--tooltip-max-width) px-2 py-1',
|
|
375
376
|
'origin-(--kb-tooltip-content-transform-origin) text-balance',
|
|
376
377
|
'data-expanded:animate-in data-expanded:fade-in-0 data-expanded:zoom-in-95',
|
|
377
378
|
'data-closed:animate-out data-closed:fade-out-0 data-closed:zoom-out-95',
|
|
@@ -390,7 +391,6 @@ export function TooltipContent(props: TooltipContentProps) {
|
|
|
390
391
|
{...rest}
|
|
391
392
|
>
|
|
392
393
|
{local.children}
|
|
393
|
-
{!local.hideArrow && <KobalteTooltip.Arrow aria-hidden="true" />}
|
|
394
394
|
</KobalteTooltip.Content>
|
|
395
395
|
</KobalteTooltip.Portal>
|
|
396
396
|
)
|
|
@@ -21,6 +21,15 @@ export const overlayPositioner = 'fixed inset-0 z-(--z-dialog) grid place-items-
|
|
|
21
21
|
export const overlayScrim =
|
|
22
22
|
'fixed inset-0 z-(--z-dialog) bg-scrim/50 supports-[backdrop-filter]:backdrop-blur-xs'
|
|
23
23
|
|
|
24
|
+
/**
|
|
25
|
+
* The tip: the card-toned bubble an explanation shows in. The side rail draws
|
|
26
|
+
* it flush to a collapsed row and every floating tooltip composes the same
|
|
27
|
+
* fill, edge, and type, so a control never explains itself in two visual
|
|
28
|
+
* languages.
|
|
29
|
+
*/
|
|
30
|
+
export const tooltipTip =
|
|
31
|
+
'bg-card text-card-foreground rounded-md border border-border text-sm font-medium shadow-lg'
|
|
32
|
+
|
|
24
33
|
/**
|
|
25
34
|
* Entrance and exit motion, expressed as data-state classes.
|
|
26
35
|
*
|
package/dist/r/src/lib/tokens.ts
CHANGED
|
@@ -542,6 +542,12 @@ export const densityTokens: TokenDefinition[] = [
|
|
|
542
542
|
},
|
|
543
543
|
{ name: 'topbar-height', kind: 'dimension', description: '48px — the window title row.' },
|
|
544
544
|
{ name: 'statusbar-height', kind: 'dimension', description: '28px — the bottom readout strip.' },
|
|
545
|
+
{
|
|
546
|
+
name: 'tooltip-max-width',
|
|
547
|
+
kind: 'dimension',
|
|
548
|
+
description:
|
|
549
|
+
'The lesser of the 16rem readable measure and one viewport minus a gutter — a tip wraps before it can push its document wider than itself.',
|
|
550
|
+
},
|
|
545
551
|
]
|
|
546
552
|
|
|
547
553
|
export const elevationTokens: TokenDefinition[] = [
|
|
@@ -614,6 +614,11 @@
|
|
|
614
614
|
--sidebar-width-compact: 3rem;
|
|
615
615
|
--topbar-height: 3rem;
|
|
616
616
|
--statusbar-height: 1.75rem;
|
|
617
|
+
/* A tip wraps before it can overflow the window carrying it: the 16rem
|
|
618
|
+
readable measure governs on a desktop, but the measure scales with the root
|
|
619
|
+
font while the window does not, so at a 200% zoom the viewport term wins and
|
|
620
|
+
a tooltip can never push its document wider than itself. */
|
|
621
|
+
--tooltip-max-width: min(16rem, calc(100vw - 1.5rem));
|
|
617
622
|
|
|
618
623
|
/* Shadows. Two parts on purpose: a tinted spread that reads as elevation, plus a
|
|
619
624
|
hairline that keeps an edge visible when the surface behind a panel is the
|
package/package.json
CHANGED
|
@@ -27,6 +27,7 @@ import { Tooltip, TooltipContent, TooltipTrigger } from '../../ui/tooltip'
|
|
|
27
27
|
export type ActionButtonProps<T extends ValidComponent = 'button'> = ButtonProps<T> & {
|
|
28
28
|
/** A short explanation, also shown on keyboard focus. The Button still needs its own name. */
|
|
29
29
|
tooltip?: string
|
|
30
|
+
/** Placement of the explanation; icon actions live in bars, so it defaults below the control. */
|
|
30
31
|
tooltipSide?: 'top' | 'right' | 'bottom' | 'left'
|
|
31
32
|
/** Disables the action and announces the busy label through a polite status region. */
|
|
32
33
|
busy?: boolean
|
|
@@ -173,7 +174,7 @@ export function ActionButton<T extends ValidComponent = 'button'>(props: ActionB
|
|
|
173
174
|
>
|
|
174
175
|
{contents()}
|
|
175
176
|
</TooltipTrigger>
|
|
176
|
-
<TooltipContent side={local.tooltipSide}>{local.tooltip}</TooltipContent>
|
|
177
|
+
<TooltipContent side={local.tooltipSide ?? 'bottom'}>{local.tooltip}</TooltipContent>
|
|
177
178
|
</Tooltip>
|
|
178
179
|
</Show>
|
|
179
180
|
<Show when={busy()}>
|
|
@@ -83,6 +83,11 @@ export function ModeChoices(props: AppearanceEditorProps) {
|
|
|
83
83
|
}
|
|
84
84
|
|
|
85
85
|
export function AccentChoices(props: AppearanceEditorProps) {
|
|
86
|
+
// The resolved appearance decides which side of a preset pair — and which
|
|
87
|
+
// theme accent — the swatches paint, so the row previews each choice as the
|
|
88
|
+
// user will see it.
|
|
89
|
+
const resolvedAppearance = () =>
|
|
90
|
+
props.draft.mode === 'system' ? props.resolvedAppearance : props.draft.mode
|
|
86
91
|
const custom = () =>
|
|
87
92
|
props.draft.accent !== 'theme' &&
|
|
88
93
|
!props.accentOptions.some((option) => option.id === props.draft.accent)
|
|
@@ -93,9 +98,9 @@ export function AccentChoices(props: AppearanceEditorProps) {
|
|
|
93
98
|
disabled={props.saving}
|
|
94
99
|
orientation="horizontal"
|
|
95
100
|
aria-label="Accent"
|
|
96
|
-
//
|
|
97
|
-
//
|
|
98
|
-
//
|
|
101
|
+
// One chip (custom) beside a capped swatch grid: a chip-per-state column
|
|
102
|
+
// beside a full-width swatch line overflowed the settings sidebar's
|
|
103
|
+
// control column, so the pair stays a narrow chip plus a wrapped grid.
|
|
99
104
|
class="flex items-center gap-3"
|
|
100
105
|
onChange={(accent) =>
|
|
101
106
|
props.onChange({
|
|
@@ -103,21 +108,29 @@ export function AccentChoices(props: AppearanceEditorProps) {
|
|
|
103
108
|
})
|
|
104
109
|
}
|
|
105
110
|
>
|
|
106
|
-
<div class="
|
|
107
|
-
|
|
111
|
+
<div class="grid grid-cols-4 gap-2">
|
|
112
|
+
{/* The theme's own accent is the first swatch. Picking it is the same
|
|
113
|
+
act the old dedicated "Theme default" chip performed, without a
|
|
114
|
+
second control for the state the row starts in. */}
|
|
115
|
+
<Radio.Item
|
|
116
|
+
value="theme"
|
|
117
|
+
class="rounded-full focus-within:ring-3 focus-within:ring-ring/50"
|
|
118
|
+
>
|
|
108
119
|
<Radio.ItemInput />
|
|
109
|
-
<Radio.ItemLabel class="
|
|
110
|
-
|
|
120
|
+
<Radio.ItemLabel class="block size-7 cursor-pointer rounded-full border p-0.5 data-[checked]:border-primary data-[checked]:ring-1 data-[checked]:ring-primary">
|
|
121
|
+
<span
|
|
122
|
+
class="block size-full rounded-full"
|
|
123
|
+
aria-hidden="true"
|
|
124
|
+
style={{
|
|
125
|
+
'background-color':
|
|
126
|
+
resolvedAppearance() === 'light'
|
|
127
|
+
? props.lightTheme.colors.accent
|
|
128
|
+
: props.darkTheme.colors.accent,
|
|
129
|
+
}}
|
|
130
|
+
/>
|
|
131
|
+
<span class="sr-only">Theme default</span>
|
|
111
132
|
</Radio.ItemLabel>
|
|
112
133
|
</Radio.Item>
|
|
113
|
-
<Radio.Item value="custom">
|
|
114
|
-
<Radio.ItemInput />
|
|
115
|
-
<Radio.ItemLabel class="flex h-7 cursor-pointer items-center rounded-md border px-2 text-xs whitespace-nowrap data-[checked]:border-primary data-[checked]:ring-1 data-[checked]:ring-primary">
|
|
116
|
-
Custom
|
|
117
|
-
</Radio.ItemLabel>
|
|
118
|
-
</Radio.Item>
|
|
119
|
-
</div>
|
|
120
|
-
<div class="grid grid-cols-3 gap-2">
|
|
121
134
|
<For each={props.accentOptions}>
|
|
122
135
|
{(option) => (
|
|
123
136
|
<Radio.Item
|
|
@@ -131,11 +144,7 @@ export function AccentChoices(props: AppearanceEditorProps) {
|
|
|
131
144
|
aria-hidden="true"
|
|
132
145
|
style={{
|
|
133
146
|
'background-color':
|
|
134
|
-
(
|
|
135
|
-
? props.resolvedAppearance
|
|
136
|
-
: props.draft.mode) === 'light'
|
|
137
|
-
? option.light
|
|
138
|
-
: option.dark,
|
|
147
|
+
resolvedAppearance() === 'light' ? option.light : option.dark,
|
|
139
148
|
}}
|
|
140
149
|
/>
|
|
141
150
|
<span class="sr-only">{option.label}</span>
|
|
@@ -144,6 +153,12 @@ export function AccentChoices(props: AppearanceEditorProps) {
|
|
|
144
153
|
)}
|
|
145
154
|
</For>
|
|
146
155
|
</div>
|
|
156
|
+
<Radio.Item value="custom">
|
|
157
|
+
<Radio.ItemInput />
|
|
158
|
+
<Radio.ItemLabel class="flex h-7 cursor-pointer items-center rounded-md border px-2 text-xs whitespace-nowrap data-[checked]:border-primary data-[checked]:ring-1 data-[checked]:ring-primary">
|
|
159
|
+
Custom
|
|
160
|
+
</Radio.ItemLabel>
|
|
161
|
+
</Radio.Item>
|
|
147
162
|
</Radio>
|
|
148
163
|
)
|
|
149
164
|
}
|
|
@@ -210,10 +210,14 @@ function ThemeSelectMenu(props: {
|
|
|
210
210
|
</DropdownMenuTrigger>
|
|
211
211
|
<DropdownMenuContent
|
|
212
212
|
portalMount={portalMount()}
|
|
213
|
-
//
|
|
213
|
+
// A fixed height with its own scroll: an adaptive cap measured the
|
|
214
|
+
// host panel instead, and opening a long theme list scrolled the
|
|
215
|
+
// sidebar to reveal the menu. The content scrolls internally at the
|
|
216
|
+
// cap, so the panel around the trigger never moves. Width still
|
|
217
|
+
// follows content (at least the trigger width, never wider than the
|
|
214
218
|
// popper allows) so long theme names render in full with padding for
|
|
215
219
|
// the selection indicator instead of truncating at the anchor width.
|
|
216
|
-
class="max-h-
|
|
220
|
+
class="max-h-80 w-max min-w-(--kb-popper-anchor-width) max-w-(--kb-popper-content-available-width) overflow-x-hidden overflow-y-auto"
|
|
217
221
|
onInteractOutside={(event) => {
|
|
218
222
|
if (event.detail.originalEvent.type !== 'pointerdown') return
|
|
219
223
|
const parentDialog = portalMount()?.closest<HTMLElement>('[role="dialog"]')
|
|
@@ -2,6 +2,7 @@ import { Polymorphic, type PolymorphicProps } from '@kobalte/core/polymorphic'
|
|
|
2
2
|
import type { ComponentProps, JSX, ValidComponent } from 'solid-js'
|
|
3
3
|
import { Show, createMemo, createSignal, splitProps } from 'solid-js'
|
|
4
4
|
import { Portal } from 'solid-js/web'
|
|
5
|
+
import { tooltipTip } from '#lib/overlay'
|
|
5
6
|
import { cn } from '#lib/utils'
|
|
6
7
|
import { SideRailContext, createSideRailValue } from './side-rail-context'
|
|
7
8
|
|
|
@@ -305,8 +306,8 @@ export function SideRailItem<T extends ValidComponent = 'a'>(props: SideRailItem
|
|
|
305
306
|
aria-hidden="true"
|
|
306
307
|
data-slot="side-rail-tip"
|
|
307
308
|
class={cn(
|
|
308
|
-
|
|
309
|
-
'flex items-center gap-2.5
|
|
309
|
+
tooltipTip,
|
|
310
|
+
'pointer-events-none fixed z-(--z-tooltip) flex items-center gap-2.5 ps-3 pe-3 whitespace-nowrap'
|
|
310
311
|
)}
|
|
311
312
|
style={{
|
|
312
313
|
top: `${position().top}px`,
|
|
@@ -398,7 +399,10 @@ export function SideRailButton(
|
|
|
398
399
|
<div
|
|
399
400
|
aria-hidden="true"
|
|
400
401
|
data-slot="side-rail-tip"
|
|
401
|
-
class=
|
|
402
|
+
class={cn(
|
|
403
|
+
tooltipTip,
|
|
404
|
+
'pointer-events-none fixed z-(--z-tooltip) flex items-center gap-2.5 ps-3 pe-3 whitespace-nowrap'
|
|
405
|
+
)}
|
|
402
406
|
style={{
|
|
403
407
|
top: `${position().top}px`,
|
|
404
408
|
left: `${position().left}px`,
|
|
@@ -125,6 +125,13 @@ export type TopBarSearchProps = ComponentProps<'button'> & {
|
|
|
125
125
|
placeholder?: string
|
|
126
126
|
/** The shortcut chip drawn at the trailing edge, e.g. "⌘K". */
|
|
127
127
|
shortcut?: string
|
|
128
|
+
/**
|
|
129
|
+
* The parseable chord behind `shortcut`, e.g. `Meta+K`. The chip is
|
|
130
|
+
* `aria-hidden` — reading it out would pollute the button's accessible
|
|
131
|
+
* name — so this is what assistive technology announces instead. Supply it
|
|
132
|
+
* whenever `shortcut` is drawn.
|
|
133
|
+
*/
|
|
134
|
+
keyshortcuts?: string
|
|
128
135
|
}
|
|
129
136
|
|
|
130
137
|
/**
|
|
@@ -137,7 +144,7 @@ export type TopBarSearchProps = ComponentProps<'button'> & {
|
|
|
137
144
|
* like from the user's side.
|
|
138
145
|
*/
|
|
139
146
|
export function TopBarSearch(props: TopBarSearchProps) {
|
|
140
|
-
const [local, rest] = splitProps(props, ['class', 'placeholder', 'shortcut'])
|
|
147
|
+
const [local, rest] = splitProps(props, ['class', 'placeholder', 'shortcut', 'keyshortcuts'])
|
|
141
148
|
|
|
142
149
|
return (
|
|
143
150
|
<button
|
|
@@ -151,12 +158,16 @@ export function TopBarSearch(props: TopBarSearchProps) {
|
|
|
151
158
|
'window-no-drag',
|
|
152
159
|
local.class
|
|
153
160
|
)}
|
|
161
|
+
aria-keyshortcuts={local.keyshortcuts}
|
|
154
162
|
{...rest}
|
|
155
163
|
>
|
|
156
164
|
<Search aria-hidden="true" class="size-4 shrink-0 sm:hidden" />
|
|
157
165
|
<span class="sr-only sm:not-sr-only sm:truncate">{local.placeholder ?? 'Search'}</span>
|
|
158
166
|
<Show when={local.shortcut}>
|
|
159
|
-
<kbd
|
|
167
|
+
<kbd
|
|
168
|
+
aria-hidden="true"
|
|
169
|
+
class="bg-muted ms-auto hidden h-5 shrink-0 items-center rounded-sm border border-border px-1.5 font-mono text-2xs sm:flex"
|
|
170
|
+
>
|
|
160
171
|
{local.shortcut}
|
|
161
172
|
</kbd>
|
|
162
173
|
</Show>
|
|
@@ -153,7 +153,10 @@ export function DropdownMenuCheckboxItem(
|
|
|
153
153
|
return (
|
|
154
154
|
<KobalteDropdownMenu.CheckboxItem class={cn(menuItem, 'pe-8', local.class)} {...rest}>
|
|
155
155
|
{local.children}
|
|
156
|
-
<KobalteDropdownMenu.ItemIndicator
|
|
156
|
+
<KobalteDropdownMenu.ItemIndicator
|
|
157
|
+
data-slot="dropdown-menu-indicator"
|
|
158
|
+
class="absolute end-2 flex size-4 items-center justify-center text-primary"
|
|
159
|
+
>
|
|
157
160
|
<Check class="size-4" />
|
|
158
161
|
</KobalteDropdownMenu.ItemIndicator>
|
|
159
162
|
</KobalteDropdownMenu.CheckboxItem>
|
|
@@ -172,7 +175,12 @@ export function DropdownMenuRadioItem(props: ComponentProps<typeof KobalteDropdo
|
|
|
172
175
|
return (
|
|
173
176
|
<KobalteDropdownMenu.RadioItem class={cn(menuItem, 'pe-8', local.class)} {...rest}>
|
|
174
177
|
{local.children}
|
|
175
|
-
|
|
178
|
+
{/* The indicator reads in the accent, like every other selected state in
|
|
179
|
+
the system — a canvas-colored dot on a checked row reads as decoration. */}
|
|
180
|
+
<KobalteDropdownMenu.ItemIndicator
|
|
181
|
+
data-slot="dropdown-menu-indicator"
|
|
182
|
+
class="absolute end-2 flex size-4 items-center justify-center text-primary"
|
|
183
|
+
>
|
|
176
184
|
<Circle class="size-2 fill-current" />
|
|
177
185
|
</KobalteDropdownMenu.ItemIndicator>
|
|
178
186
|
</KobalteDropdownMenu.RadioItem>
|
|
@@ -20,8 +20,6 @@ export function Kbd(props: ComponentProps<'kbd'>) {
|
|
|
20
20
|
data-slot="kbd"
|
|
21
21
|
class={cn(
|
|
22
22
|
'bg-muted text-muted-foreground pointer-events-none inline-flex h-5 min-w-5 items-center justify-center gap-1 rounded-sm border border-border px-1 font-mono text-2xs font-medium select-none',
|
|
23
|
-
/* Inside a hover/selected row the key needs to recede with the row. */
|
|
24
|
-
'in-data-[slot=br-tooltip-content]:bg-background/20 in-data-[slot=br-tooltip-content]:text-scrim-foreground in-data-[slot=br-tooltip-content]:border-transparent',
|
|
25
23
|
local.class
|
|
26
24
|
)}
|
|
27
25
|
{...rest}
|
|
@@ -99,9 +99,7 @@ export function StatusChip(props: StatusChipProps) {
|
|
|
99
99
|
<TooltipTrigger as="span" class="inline-flex">
|
|
100
100
|
{chip}
|
|
101
101
|
</TooltipTrigger>
|
|
102
|
-
<TooltipContent data-slot="tooltip-content"
|
|
103
|
-
{detail()}
|
|
104
|
-
</TooltipContent>
|
|
102
|
+
<TooltipContent data-slot="tooltip-content">{detail()}</TooltipContent>
|
|
105
103
|
</Tooltip>
|
|
106
104
|
)}
|
|
107
105
|
</Show>
|
|
@@ -10,6 +10,7 @@ import {
|
|
|
10
10
|
useContext,
|
|
11
11
|
} from 'solid-js'
|
|
12
12
|
import { isServer } from 'solid-js/web'
|
|
13
|
+
import { tooltipTip } from '#lib/overlay'
|
|
13
14
|
import { cn } from '#lib/utils'
|
|
14
15
|
|
|
15
16
|
/**
|
|
@@ -348,16 +349,12 @@ export function TooltipTrigger(props: ComponentProps<typeof KobalteTooltip.Trigg
|
|
|
348
349
|
)
|
|
349
350
|
}
|
|
350
351
|
|
|
351
|
-
export type TooltipContentProps = ComponentProps<typeof KobalteTooltip.Content>
|
|
352
|
-
/** Hide the caret pointing at the trigger. */
|
|
353
|
-
hideArrow?: boolean
|
|
354
|
-
}
|
|
352
|
+
export type TooltipContentProps = ComponentProps<typeof KobalteTooltip.Content>
|
|
355
353
|
|
|
356
354
|
export function TooltipContent(props: TooltipContentProps) {
|
|
357
355
|
const interaction = useContext(TooltipInteractionContext)
|
|
358
356
|
const [local, rest] = splitProps(props, [
|
|
359
357
|
'class',
|
|
360
|
-
'hideArrow',
|
|
361
358
|
'children',
|
|
362
359
|
'aria-hidden',
|
|
363
360
|
'onEscapeKeyDown',
|
|
@@ -371,7 +368,11 @@ export function TooltipContent(props: TooltipContentProps) {
|
|
|
371
368
|
<KobalteTooltip.Portal>
|
|
372
369
|
<KobalteTooltip.Content
|
|
373
370
|
class={cn(
|
|
374
|
-
|
|
371
|
+
tooltipTip,
|
|
372
|
+
// The max width is a token, not a fixed measure: it has to fall
|
|
373
|
+
// behind the viewport at large root font sizes or the tip — which
|
|
374
|
+
// Kobalte can shift but never shrink — forces a horizontal scroll.
|
|
375
|
+
'z-(--z-tooltip) w-fit max-w-(--tooltip-max-width) px-2 py-1',
|
|
375
376
|
'origin-(--kb-tooltip-content-transform-origin) text-balance',
|
|
376
377
|
'data-expanded:animate-in data-expanded:fade-in-0 data-expanded:zoom-in-95',
|
|
377
378
|
'data-closed:animate-out data-closed:fade-out-0 data-closed:zoom-out-95',
|
|
@@ -390,7 +391,6 @@ export function TooltipContent(props: TooltipContentProps) {
|
|
|
390
391
|
{...rest}
|
|
391
392
|
>
|
|
392
393
|
{local.children}
|
|
393
|
-
{!local.hideArrow && <KobalteTooltip.Arrow aria-hidden="true" />}
|
|
394
394
|
</KobalteTooltip.Content>
|
|
395
395
|
</KobalteTooltip.Portal>
|
|
396
396
|
)
|
package/src/lib/overlay.ts
CHANGED
|
@@ -21,6 +21,15 @@ export const overlayPositioner = 'fixed inset-0 z-(--z-dialog) grid place-items-
|
|
|
21
21
|
export const overlayScrim =
|
|
22
22
|
'fixed inset-0 z-(--z-dialog) bg-scrim/50 supports-[backdrop-filter]:backdrop-blur-xs'
|
|
23
23
|
|
|
24
|
+
/**
|
|
25
|
+
* The tip: the card-toned bubble an explanation shows in. The side rail draws
|
|
26
|
+
* it flush to a collapsed row and every floating tooltip composes the same
|
|
27
|
+
* fill, edge, and type, so a control never explains itself in two visual
|
|
28
|
+
* languages.
|
|
29
|
+
*/
|
|
30
|
+
export const tooltipTip =
|
|
31
|
+
'bg-card text-card-foreground rounded-md border border-border text-sm font-medium shadow-lg'
|
|
32
|
+
|
|
24
33
|
/**
|
|
25
34
|
* Entrance and exit motion, expressed as data-state classes.
|
|
26
35
|
*
|
package/src/lib/tokens.ts
CHANGED
|
@@ -542,6 +542,12 @@ export const densityTokens: TokenDefinition[] = [
|
|
|
542
542
|
},
|
|
543
543
|
{ name: 'topbar-height', kind: 'dimension', description: '48px — the window title row.' },
|
|
544
544
|
{ name: 'statusbar-height', kind: 'dimension', description: '28px — the bottom readout strip.' },
|
|
545
|
+
{
|
|
546
|
+
name: 'tooltip-max-width',
|
|
547
|
+
kind: 'dimension',
|
|
548
|
+
description:
|
|
549
|
+
'The lesser of the 16rem readable measure and one viewport minus a gutter — a tip wraps before it can push its document wider than itself.',
|
|
550
|
+
},
|
|
545
551
|
]
|
|
546
552
|
|
|
547
553
|
export const elevationTokens: TokenDefinition[] = [
|
package/src/styles/theme.css
CHANGED
|
@@ -614,6 +614,11 @@
|
|
|
614
614
|
--sidebar-width-compact: 3rem;
|
|
615
615
|
--topbar-height: 3rem;
|
|
616
616
|
--statusbar-height: 1.75rem;
|
|
617
|
+
/* A tip wraps before it can overflow the window carrying it: the 16rem
|
|
618
|
+
readable measure governs on a desktop, but the measure scales with the root
|
|
619
|
+
font while the window does not, so at a 200% zoom the viewport term wins and
|
|
620
|
+
a tooltip can never push its document wider than itself. */
|
|
621
|
+
--tooltip-max-width: min(16rem, calc(100vw - 1.5rem));
|
|
617
622
|
|
|
618
623
|
/* Shadows. Two parts on purpose: a tinted spread that reads as elevation, plus a
|
|
619
624
|
hairline that keeps an edge visible when the surface behind a panel is the
|