@adea-ai/ui 0.85.0 → 0.88.0
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/README.md +17 -1
- package/dist/NOTICE +34 -0
- package/dist/components/composites/action-button/action-button.d.ts.map +1 -1
- package/dist/components/composites/action-button/action-button.js +2 -2
- package/dist/components/composites/action-button/action-button.js.map +1 -1
- package/dist/components/composites/list-row/list-row.d.ts +6 -3
- package/dist/components/composites/list-row/list-row.d.ts.map +1 -1
- package/dist/components/composites/list-row/list-row.js +69 -7
- package/dist/components/composites/list-row/list-row.js.map +1 -1
- package/dist/components/composites/settings/settings.d.ts +9 -11
- package/dist/components/composites/settings/settings.d.ts.map +1 -1
- package/dist/components/composites/settings/settings.js +48 -33
- package/dist/components/composites/settings/settings.js.map +1 -1
- package/dist/components/conversation/message-composer.js +1 -1
- package/dist/components/conversation/scroll-follow.d.ts.map +1 -1
- package/dist/components/conversation/scroll-follow.js +95 -15
- package/dist/components/conversation/scroll-follow.js.map +1 -1
- package/dist/components/layout/app-shell/index.d.ts +1 -0
- package/dist/components/layout/app-shell/index.d.ts.map +1 -1
- package/dist/components/layout/app-shell/index.js +2 -1
- package/dist/components/layout/app-shell/skip-link.d.ts +11 -0
- package/dist/components/layout/app-shell/skip-link.d.ts.map +1 -0
- package/dist/components/layout/app-shell/skip-link.js +44 -0
- package/dist/components/layout/app-shell/skip-link.js.map +1 -0
- package/dist/components/layout/floating-preview/floating-preview.d.ts +12 -0
- package/dist/components/layout/floating-preview/floating-preview.d.ts.map +1 -0
- package/dist/components/layout/floating-preview/floating-preview.js +283 -0
- package/dist/components/layout/floating-preview/floating-preview.js.map +1 -0
- package/dist/components/layout/floating-preview/index.d.ts +3 -0
- package/dist/components/layout/floating-preview/index.d.ts.map +1 -0
- package/dist/components/layout/floating-preview/index.js +3 -0
- package/dist/components/layout/floating-preview/model.d.ts +74 -0
- package/dist/components/layout/floating-preview/model.d.ts.map +1 -0
- package/dist/components/layout/floating-preview/model.js +146 -0
- package/dist/components/layout/floating-preview/model.js.map +1 -0
- package/dist/components/layout/sidebar-nav/index.d.ts +1 -1
- package/dist/components/layout/sidebar-nav/index.d.ts.map +1 -1
- package/dist/components/layout/sidebar-nav/sidebar-nav.d.ts +18 -2
- package/dist/components/layout/sidebar-nav/sidebar-nav.d.ts.map +1 -1
- package/dist/components/layout/sidebar-nav/sidebar-nav.js +42 -11
- package/dist/components/layout/sidebar-nav/sidebar-nav.js.map +1 -1
- package/dist/components/theme/index.d.ts +1 -0
- package/dist/components/theme/index.d.ts.map +1 -1
- package/dist/components/theme/index.js +2 -1
- package/dist/components/theme/theme-mode-toggle.d.ts +10 -0
- package/dist/components/theme/theme-mode-toggle.d.ts.map +1 -0
- package/dist/components/theme/theme-mode-toggle.js +82 -0
- package/dist/components/theme/theme-mode-toggle.js.map +1 -0
- package/dist/components/ui/checkbox/checkbox.d.ts +2 -0
- package/dist/components/ui/checkbox/checkbox.d.ts.map +1 -1
- package/dist/components/ui/checkbox/checkbox.js +24 -3
- package/dist/components/ui/checkbox/checkbox.js.map +1 -1
- package/dist/components/ui/combobox/combobox.d.ts.map +1 -1
- package/dist/components/ui/combobox/combobox.js +41 -4
- package/dist/components/ui/combobox/combobox.js.map +1 -1
- package/dist/components/ui/combobox/index.d.ts +1 -0
- package/dist/components/ui/combobox/index.d.ts.map +1 -1
- package/dist/components/ui/combobox/index.js +2 -1
- package/dist/components/ui/combobox/value-combobox.d.ts +19 -0
- package/dist/components/ui/combobox/value-combobox.d.ts.map +1 -0
- package/dist/components/ui/combobox/value-combobox.js +42 -0
- package/dist/components/ui/combobox/value-combobox.js.map +1 -0
- package/dist/components/ui/empty/empty-state.d.ts +15 -0
- package/dist/components/ui/empty/empty-state.d.ts.map +1 -0
- package/dist/components/ui/empty/empty-state.js +96 -0
- package/dist/components/ui/empty/empty-state.js.map +1 -0
- package/dist/components/ui/empty/index.d.ts +1 -0
- package/dist/components/ui/empty/index.d.ts.map +1 -1
- package/dist/components/ui/empty/index.js +2 -1
- package/dist/components/ui/entity-icon/entity-icon.d.ts +4 -1
- package/dist/components/ui/entity-icon/entity-icon.d.ts.map +1 -1
- package/dist/components/ui/entity-icon/entity-icon.js +37 -13
- package/dist/components/ui/entity-icon/entity-icon.js.map +1 -1
- package/dist/components/ui/field/field.d.ts +36 -13
- package/dist/components/ui/field/field.d.ts.map +1 -1
- package/dist/components/ui/field/field.js +146 -24
- package/dist/components/ui/field/field.js.map +1 -1
- package/dist/components/ui/field/index.d.ts +3 -1
- package/dist/components/ui/field/index.d.ts.map +1 -1
- package/dist/components/ui/field/index.js +3 -2
- package/dist/components/ui/field/number-field.d.ts +19 -0
- package/dist/components/ui/field/number-field.d.ts.map +1 -0
- package/dist/components/ui/field/number-field.js +76 -0
- package/dist/components/ui/field/number-field.js.map +1 -0
- package/dist/components/ui/input/index.d.ts +1 -0
- package/dist/components/ui/input/index.d.ts.map +1 -1
- package/dist/components/ui/input/index.js +2 -1
- package/dist/components/ui/input/input-control.d.ts +11 -0
- package/dist/components/ui/input/input-control.d.ts.map +1 -0
- package/dist/components/ui/input/input-control.js +24 -0
- package/dist/components/ui/input/input-control.js.map +1 -0
- package/dist/components/ui/input/input.d.ts.map +1 -1
- package/dist/components/ui/input/input.js +56 -28
- package/dist/components/ui/input/input.js.map +1 -1
- package/dist/components/ui/input-group/index.d.ts +1 -0
- package/dist/components/ui/input-group/index.d.ts.map +1 -1
- package/dist/components/ui/input-group/index.js +2 -1
- package/dist/components/ui/input-group/input-group.d.ts.map +1 -1
- package/dist/components/ui/input-group/input-group.js +42 -5
- package/dist/components/ui/input-group/input-group.js.map +1 -1
- package/dist/components/ui/input-group/secret-input-group.d.ts +11 -0
- package/dist/components/ui/input-group/secret-input-group.d.ts.map +1 -0
- package/dist/components/ui/input-group/secret-input-group.js +67 -0
- package/dist/components/ui/input-group/secret-input-group.js.map +1 -0
- package/dist/components/ui/native-select/native-select.d.ts.map +1 -1
- package/dist/components/ui/native-select/native-select.js +39 -4
- package/dist/components/ui/native-select/native-select.js.map +1 -1
- package/dist/components/ui/progress/progress.d.ts.map +1 -1
- package/dist/components/ui/progress/progress.js +30 -18
- package/dist/components/ui/progress/progress.js.map +1 -1
- package/dist/components/ui/radio-group/radio-group.d.ts.map +1 -1
- package/dist/components/ui/radio-group/radio-group.js +41 -4
- package/dist/components/ui/radio-group/radio-group.js.map +1 -1
- package/dist/components/ui/switch/switch.d.ts +2 -0
- package/dist/components/ui/switch/switch.d.ts.map +1 -1
- package/dist/components/ui/switch/switch.js +24 -3
- package/dist/components/ui/switch/switch.js.map +1 -1
- package/dist/components/ui/tabs/tabs.js +1 -1
- package/dist/components/ui/tabs/tabs.js.map +1 -1
- package/dist/components/ui/text-link/index.d.ts +2 -0
- package/dist/components/ui/text-link/index.d.ts.map +1 -0
- package/dist/components/ui/text-link/index.js +2 -0
- package/dist/components/ui/text-link/text-link.d.ts +9 -0
- package/dist/components/ui/text-link/text-link.d.ts.map +1 -0
- package/dist/components/ui/text-link/text-link.js +30 -0
- package/dist/components/ui/text-link/text-link.js.map +1 -0
- package/dist/components/ui/textarea/textarea.d.ts.map +1 -1
- package/dist/components/ui/textarea/textarea.js +41 -4
- package/dist/components/ui/textarea/textarea.js.map +1 -1
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +18 -7
- package/dist/lib/clipboard.d.ts +3 -0
- package/dist/lib/clipboard.d.ts.map +1 -0
- package/dist/lib/clipboard.js +35 -0
- package/dist/lib/clipboard.js.map +1 -0
- package/dist/lib/download.d.ts +3 -0
- package/dist/lib/download.d.ts.map +1 -0
- package/dist/lib/download.js +31 -0
- package/dist/lib/download.js.map +1 -0
- package/dist/lib/form-field.d.ts +37 -0
- package/dist/lib/form-field.d.ts.map +1 -0
- package/dist/lib/form-field.js +47 -0
- package/dist/lib/form-field.js.map +1 -0
- package/dist/r/app-shell.json +5 -0
- package/dist/r/combobox.json +5 -0
- package/dist/r/empty.json +10 -1
- package/dist/r/field.json +7 -0
- package/dist/r/floating-preview.json +30 -0
- package/dist/r/input-group.json +6 -0
- package/dist/r/input.json +5 -0
- package/dist/r/lib.json +15 -0
- package/dist/r/list-row.json +1 -0
- package/dist/r/registry.json +112 -1
- package/dist/r/src/components/composites/action-button/action-button.tsx +5 -1
- package/dist/r/src/components/composites/list-row/list-row.tsx +81 -8
- package/dist/r/src/components/composites/settings/settings.tsx +67 -37
- package/dist/r/src/components/conversation/scroll-follow.ts +109 -15
- package/dist/r/src/components/layout/app-shell/index.ts +1 -0
- package/dist/r/src/components/layout/app-shell/skip-link.tsx +35 -0
- package/dist/r/src/components/layout/floating-preview/floating-preview.tsx +260 -0
- package/dist/r/src/components/layout/floating-preview/index.ts +2 -0
- package/dist/r/src/components/layout/floating-preview/model.ts +285 -0
- package/dist/r/src/components/layout/sidebar-nav/index.ts +2 -0
- package/dist/r/src/components/layout/sidebar-nav/sidebar-nav.tsx +71 -16
- package/dist/r/src/components/theme/index.ts +1 -0
- package/dist/r/src/components/theme/theme-mode-toggle.tsx +56 -0
- package/dist/r/src/components/ui/checkbox/checkbox.tsx +20 -3
- package/dist/r/src/components/ui/combobox/combobox.tsx +24 -1
- package/dist/r/src/components/ui/combobox/index.ts +1 -0
- package/dist/r/src/components/ui/combobox/value-combobox.tsx +38 -0
- package/dist/r/src/components/ui/empty/empty-state.tsx +71 -0
- package/dist/r/src/components/ui/empty/index.ts +1 -0
- package/dist/r/src/components/ui/entity-icon/entity-icon.tsx +33 -2
- package/dist/r/src/components/ui/field/field.tsx +102 -5
- package/dist/r/src/components/ui/field/index.ts +5 -0
- package/dist/r/src/components/ui/field/number-field.tsx +71 -0
- package/dist/r/src/components/ui/input/index.ts +1 -0
- package/dist/r/src/components/ui/input/input-control.tsx +38 -0
- package/dist/r/src/components/ui/input/input.tsx +32 -20
- package/dist/r/src/components/ui/input-group/index.ts +1 -0
- package/dist/r/src/components/ui/input-group/input-group.tsx +25 -2
- package/dist/r/src/components/ui/input-group/secret-input-group.tsx +58 -0
- package/dist/r/src/components/ui/native-select/native-select.tsx +27 -1
- package/dist/r/src/components/ui/progress/progress.tsx +12 -8
- package/dist/r/src/components/ui/radio-group/radio-group.tsx +30 -2
- package/dist/r/src/components/ui/switch/switch.tsx +20 -3
- package/dist/r/src/components/ui/tabs/tabs.tsx +1 -1
- package/dist/r/src/components/ui/text-link/index.ts +2 -0
- package/dist/r/src/components/ui/text-link/text-link.tsx +28 -0
- package/dist/r/src/components/ui/textarea/textarea.tsx +24 -1
- package/dist/r/src/lib/clipboard.ts +41 -0
- package/dist/r/src/lib/download.ts +29 -0
- package/dist/r/src/lib/form-field.ts +93 -0
- package/dist/r/text-link.json +22 -0
- package/dist/r/theming.json +6 -0
- package/package.json +1 -1
- package/registry.json +112 -1
- package/src/components/composites/action-button/action-button.tsx +5 -1
- package/src/components/composites/list-row/list-row.tsx +81 -8
- package/src/components/composites/settings/settings.tsx +67 -37
- package/src/components/conversation/scroll-follow.ts +109 -15
- package/src/components/layout/app-shell/index.ts +1 -0
- package/src/components/layout/app-shell/skip-link.tsx +35 -0
- package/src/components/layout/floating-preview/floating-preview.tsx +260 -0
- package/src/components/layout/floating-preview/index.ts +2 -0
- package/src/components/layout/floating-preview/model.ts +285 -0
- package/src/components/layout/sidebar-nav/index.ts +2 -0
- package/src/components/layout/sidebar-nav/sidebar-nav.tsx +71 -16
- package/src/components/theme/index.ts +1 -0
- package/src/components/theme/theme-mode-toggle.tsx +56 -0
- package/src/components/ui/checkbox/checkbox.tsx +20 -3
- package/src/components/ui/combobox/combobox.tsx +24 -1
- package/src/components/ui/combobox/index.ts +1 -0
- package/src/components/ui/combobox/value-combobox.tsx +38 -0
- package/src/components/ui/empty/empty-state.tsx +71 -0
- package/src/components/ui/empty/index.ts +1 -0
- package/src/components/ui/entity-icon/entity-icon.tsx +33 -2
- package/src/components/ui/field/field.tsx +102 -5
- package/src/components/ui/field/index.ts +5 -0
- package/src/components/ui/field/number-field.tsx +71 -0
- package/src/components/ui/input/index.ts +1 -0
- package/src/components/ui/input/input-control.tsx +38 -0
- package/src/components/ui/input/input.tsx +32 -20
- package/src/components/ui/input-group/index.ts +1 -0
- package/src/components/ui/input-group/input-group.tsx +25 -2
- package/src/components/ui/input-group/secret-input-group.tsx +58 -0
- package/src/components/ui/native-select/native-select.tsx +27 -1
- package/src/components/ui/progress/progress.tsx +12 -8
- package/src/components/ui/radio-group/radio-group.tsx +30 -2
- package/src/components/ui/switch/switch.tsx +20 -3
- package/src/components/ui/tabs/tabs.tsx +1 -1
- package/src/components/ui/text-link/index.ts +2 -0
- package/src/components/ui/text-link/text-link.tsx +28 -0
- package/src/components/ui/textarea/textarea.tsx +24 -1
- package/src/index.ts +3 -0
- package/src/lib/clipboard.ts +41 -0
- package/src/lib/download.ts +29 -0
- package/src/lib/form-field.ts +93 -0
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import type { ComponentProps } from 'solid-js'
|
|
2
|
+
import { splitProps } from 'solid-js'
|
|
3
|
+
import { cn } from '../../../lib/utils'
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* A keyboard-first link to the main content region.
|
|
7
|
+
*
|
|
8
|
+
* Place it before the shell's navigation and set the destination element's
|
|
9
|
+
* `id` to match `href`. The link stays translated above the viewport until it
|
|
10
|
+
* receives focus, then moves into view. Its text remains available to assistive
|
|
11
|
+
* technology while it is visually hidden.
|
|
12
|
+
*/
|
|
13
|
+
export function SkipLink(props: ComponentProps<'a'>) {
|
|
14
|
+
const [local, rest] = splitProps(props, ['class', 'children', 'href', 'tabIndex'])
|
|
15
|
+
|
|
16
|
+
return (
|
|
17
|
+
<a
|
|
18
|
+
data-slot="skip-link"
|
|
19
|
+
class={cn(
|
|
20
|
+
'fixed top-0 start-2 z-(--z-toast) -translate-y-full',
|
|
21
|
+
'inline-flex items-center rounded-md border border-border bg-background',
|
|
22
|
+
'px-control-md py-2 text-sm font-medium text-foreground shadow-lg',
|
|
23
|
+
'underline decoration-2 underline-offset-2 outline-none transition-transform duration-150',
|
|
24
|
+
'focus:translate-y-0 focus-visible:border-ring focus-visible:ring-3 focus-visible:ring-primary-subtle',
|
|
25
|
+
'motion-reduce:transition-none',
|
|
26
|
+
local.class
|
|
27
|
+
)}
|
|
28
|
+
href={local.href ?? '#main-content'}
|
|
29
|
+
tabIndex={local.tabIndex ?? 0}
|
|
30
|
+
{...rest}
|
|
31
|
+
>
|
|
32
|
+
{local.children === undefined ? 'Skip to main content' : local.children}
|
|
33
|
+
</a>
|
|
34
|
+
)
|
|
35
|
+
}
|
|
@@ -0,0 +1,260 @@
|
|
|
1
|
+
import { createEffect, createSignal, onCleanup, onMount, on, type JSX } from 'solid-js'
|
|
2
|
+
import { Move, X } from 'lucide-solid'
|
|
3
|
+
import { ActionButton } from '../../composites/action-button'
|
|
4
|
+
import { ScrollArea } from '../../ui/scroll-area'
|
|
5
|
+
import {
|
|
6
|
+
type FloatingPreviewFrame,
|
|
7
|
+
type FloatingPreviewResizeDirection,
|
|
8
|
+
type FloatingPreviewSize,
|
|
9
|
+
resolveFloatingPreviewFrame,
|
|
10
|
+
resizeFloatingPreview,
|
|
11
|
+
} from './model'
|
|
12
|
+
|
|
13
|
+
const directions: readonly {
|
|
14
|
+
direction: FloatingPreviewResizeDirection
|
|
15
|
+
class: string
|
|
16
|
+
glyph: string
|
|
17
|
+
}[] = [
|
|
18
|
+
{
|
|
19
|
+
direction: 'north',
|
|
20
|
+
class: 'absolute -top-3 right-6 left-6 h-control-xs w-auto cursor-ns-resize touch-none',
|
|
21
|
+
glyph: '↕',
|
|
22
|
+
},
|
|
23
|
+
{
|
|
24
|
+
direction: 'south',
|
|
25
|
+
class: 'absolute -bottom-3 right-6 left-6 h-control-xs w-auto cursor-ns-resize touch-none',
|
|
26
|
+
glyph: '↕',
|
|
27
|
+
},
|
|
28
|
+
{
|
|
29
|
+
direction: 'east',
|
|
30
|
+
class: 'absolute -right-3 top-6 bottom-6 w-6 h-auto cursor-ew-resize touch-none',
|
|
31
|
+
glyph: '↔',
|
|
32
|
+
},
|
|
33
|
+
{
|
|
34
|
+
direction: 'west',
|
|
35
|
+
class: 'absolute -left-3 top-6 bottom-6 w-6 h-auto cursor-ew-resize touch-none',
|
|
36
|
+
glyph: '↔',
|
|
37
|
+
},
|
|
38
|
+
{
|
|
39
|
+
direction: 'northwest',
|
|
40
|
+
class: 'absolute -top-3 -left-3 size-control-xs cursor-nwse-resize touch-none',
|
|
41
|
+
glyph: '↖',
|
|
42
|
+
},
|
|
43
|
+
{
|
|
44
|
+
direction: 'northeast',
|
|
45
|
+
class: 'absolute -top-3 -right-3 size-control-xs cursor-nesw-resize touch-none',
|
|
46
|
+
glyph: '↗',
|
|
47
|
+
},
|
|
48
|
+
{
|
|
49
|
+
direction: 'southwest',
|
|
50
|
+
class: 'absolute -bottom-3 -left-3 size-control-xs cursor-nesw-resize touch-none',
|
|
51
|
+
glyph: '↙',
|
|
52
|
+
},
|
|
53
|
+
{
|
|
54
|
+
direction: 'southeast',
|
|
55
|
+
class: 'absolute -bottom-3 -right-3 size-control-xs cursor-nwse-resize touch-none',
|
|
56
|
+
glyph: '↘',
|
|
57
|
+
},
|
|
58
|
+
]
|
|
59
|
+
|
|
60
|
+
export type FloatingPreviewProps = {
|
|
61
|
+
label: string
|
|
62
|
+
source: FloatingPreviewSize
|
|
63
|
+
onClose?: () => void
|
|
64
|
+
actions?: JSX.Element
|
|
65
|
+
children: JSX.Element
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/** A host-bounded movable preview frame. Content and actions remain caller-owned. */
|
|
69
|
+
export function FloatingPreview(props: FloatingPreviewProps) {
|
|
70
|
+
const [frame, setFrame] = createSignal<FloatingPreviewFrame>({ x: 0, y: 0, width: 1, height: 1 })
|
|
71
|
+
// oxlint-disable-next-line no-unassigned-vars -- assigned through Solid's ref callback.
|
|
72
|
+
let bounds: HTMLDivElement | undefined
|
|
73
|
+
let observer: ResizeObserver | undefined
|
|
74
|
+
let gesture:
|
|
75
|
+
| {
|
|
76
|
+
id: number
|
|
77
|
+
x: number
|
|
78
|
+
y: number
|
|
79
|
+
start: FloatingPreviewFrame
|
|
80
|
+
direction: FloatingPreviewResizeDirection | null
|
|
81
|
+
}
|
|
82
|
+
| undefined
|
|
83
|
+
|
|
84
|
+
const measure = () => {
|
|
85
|
+
const rect = bounds?.getBoundingClientRect()
|
|
86
|
+
if (!rect) return
|
|
87
|
+
setFrame((current) =>
|
|
88
|
+
resolveFloatingPreviewFrame({
|
|
89
|
+
width: current.width > 1 ? current.width : null,
|
|
90
|
+
position: current.width > 1 ? { x: current.x, y: current.y } : null,
|
|
91
|
+
source: props.source,
|
|
92
|
+
container: { width: rect.width, height: rect.height },
|
|
93
|
+
})
|
|
94
|
+
)
|
|
95
|
+
}
|
|
96
|
+
createEffect(
|
|
97
|
+
on(
|
|
98
|
+
() => [props.source.width, props.source.height] as const,
|
|
99
|
+
() => measure(),
|
|
100
|
+
{ defer: true }
|
|
101
|
+
)
|
|
102
|
+
)
|
|
103
|
+
onMount(() => {
|
|
104
|
+
if (bounds) {
|
|
105
|
+
observer = new ResizeObserver(measure)
|
|
106
|
+
observer.observe(bounds)
|
|
107
|
+
measure()
|
|
108
|
+
}
|
|
109
|
+
})
|
|
110
|
+
onCleanup(() => observer?.disconnect())
|
|
111
|
+
|
|
112
|
+
function start(event: PointerEvent, direction: FloatingPreviewResizeDirection | null) {
|
|
113
|
+
if (event.button !== 0 || gesture) return
|
|
114
|
+
event.preventDefault()
|
|
115
|
+
event.stopPropagation()
|
|
116
|
+
gesture = { id: event.pointerId, x: event.clientX, y: event.clientY, start: frame(), direction }
|
|
117
|
+
;(event.currentTarget as HTMLElement).setPointerCapture(event.pointerId)
|
|
118
|
+
}
|
|
119
|
+
function move(event: PointerEvent) {
|
|
120
|
+
if (!gesture || gesture.id !== event.pointerId) return
|
|
121
|
+
const rect = bounds?.getBoundingClientRect()
|
|
122
|
+
if (!rect) return
|
|
123
|
+
const container = { width: rect.width, height: rect.height }
|
|
124
|
+
const delta = { x: event.clientX - gesture.x, y: event.clientY - gesture.y }
|
|
125
|
+
setFrame(
|
|
126
|
+
gesture.direction
|
|
127
|
+
? resizeFloatingPreview({
|
|
128
|
+
start: gesture.start,
|
|
129
|
+
direction: gesture.direction,
|
|
130
|
+
delta,
|
|
131
|
+
source: props.source,
|
|
132
|
+
container,
|
|
133
|
+
})
|
|
134
|
+
: resolveFloatingPreviewFrame({
|
|
135
|
+
width: gesture.start.width,
|
|
136
|
+
position: { x: gesture.start.x + delta.x, y: gesture.start.y + delta.y },
|
|
137
|
+
source: props.source,
|
|
138
|
+
container,
|
|
139
|
+
})
|
|
140
|
+
)
|
|
141
|
+
}
|
|
142
|
+
function end(event: PointerEvent) {
|
|
143
|
+
if (gesture?.id === event.pointerId) gesture = undefined
|
|
144
|
+
}
|
|
145
|
+
function keyboardMove(event: KeyboardEvent) {
|
|
146
|
+
const delta = { x: 0, y: 0 }
|
|
147
|
+
if (event.key === 'ArrowLeft') delta.x = -10
|
|
148
|
+
else if (event.key === 'ArrowRight') delta.x = 10
|
|
149
|
+
else if (event.key === 'ArrowUp') delta.y = -10
|
|
150
|
+
else if (event.key === 'ArrowDown') delta.y = 10
|
|
151
|
+
else return
|
|
152
|
+
event.preventDefault()
|
|
153
|
+
const rect = bounds?.getBoundingClientRect()
|
|
154
|
+
if (!rect) return
|
|
155
|
+
const current = frame()
|
|
156
|
+
setFrame(
|
|
157
|
+
resolveFloatingPreviewFrame({
|
|
158
|
+
width: current.width,
|
|
159
|
+
position: { x: current.x + delta.x, y: current.y + delta.y },
|
|
160
|
+
source: props.source,
|
|
161
|
+
container: { width: rect.width, height: rect.height },
|
|
162
|
+
})
|
|
163
|
+
)
|
|
164
|
+
}
|
|
165
|
+
function keyboardResize(event: KeyboardEvent, direction: FloatingPreviewResizeDirection) {
|
|
166
|
+
if (!event.key.startsWith('Arrow')) return
|
|
167
|
+
event.preventDefault()
|
|
168
|
+
const rect = bounds?.getBoundingClientRect()
|
|
169
|
+
if (!rect) return
|
|
170
|
+
const delta = {
|
|
171
|
+
x: event.key === 'ArrowRight' ? 10 : event.key === 'ArrowLeft' ? -10 : 0,
|
|
172
|
+
y: event.key === 'ArrowDown' ? 10 : event.key === 'ArrowUp' ? -10 : 0,
|
|
173
|
+
}
|
|
174
|
+
setFrame(
|
|
175
|
+
resizeFloatingPreview({
|
|
176
|
+
start: frame(),
|
|
177
|
+
direction,
|
|
178
|
+
delta,
|
|
179
|
+
source: props.source,
|
|
180
|
+
container: { width: rect.width, height: rect.height },
|
|
181
|
+
})
|
|
182
|
+
)
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
return (
|
|
186
|
+
<div
|
|
187
|
+
ref={bounds}
|
|
188
|
+
class="pointer-events-none absolute inset-0 z-(--z-sticky) overflow-hidden"
|
|
189
|
+
aria-label={props.label}
|
|
190
|
+
>
|
|
191
|
+
<section
|
|
192
|
+
class="pointer-events-auto absolute flex flex-col overflow-visible rounded-lg border border-border bg-card text-card-foreground shadow-lg"
|
|
193
|
+
aria-label={props.label}
|
|
194
|
+
style={{
|
|
195
|
+
left: `${frame().x}px`,
|
|
196
|
+
top: `${frame().y}px`,
|
|
197
|
+
width: `${frame().width}px`,
|
|
198
|
+
height: `${frame().height}px`,
|
|
199
|
+
}}
|
|
200
|
+
>
|
|
201
|
+
<header class="flex h-control-sm items-center gap-1 border-b border-border p-1">
|
|
202
|
+
<ActionButton
|
|
203
|
+
type="button"
|
|
204
|
+
variant="ghost"
|
|
205
|
+
size="sm"
|
|
206
|
+
class="flex-1 cursor-move touch-none"
|
|
207
|
+
aria-label={`Move ${props.label}`}
|
|
208
|
+
tooltip={`Move ${props.label}. Use arrow keys to adjust its position.`}
|
|
209
|
+
onPointerDown={(event) => start(event, null)}
|
|
210
|
+
onPointerMove={move}
|
|
211
|
+
onPointerUp={end}
|
|
212
|
+
onPointerCancel={end}
|
|
213
|
+
onLostPointerCapture={end}
|
|
214
|
+
onKeyDown={keyboardMove}
|
|
215
|
+
>
|
|
216
|
+
<>
|
|
217
|
+
<Move aria-hidden="true" />
|
|
218
|
+
Move
|
|
219
|
+
</>
|
|
220
|
+
</ActionButton>
|
|
221
|
+
<div class="flex items-center gap-1">{props.actions}</div>
|
|
222
|
+
{props.onClose && (
|
|
223
|
+
<ActionButton
|
|
224
|
+
type="button"
|
|
225
|
+
variant="ghost"
|
|
226
|
+
size="icon-sm"
|
|
227
|
+
aria-label={`Close ${props.label}`}
|
|
228
|
+
tooltip={`Close ${props.label}.`}
|
|
229
|
+
onClick={props.onClose}
|
|
230
|
+
>
|
|
231
|
+
<X aria-hidden="true" />
|
|
232
|
+
</ActionButton>
|
|
233
|
+
)}
|
|
234
|
+
</header>
|
|
235
|
+
<ScrollArea role="region" aria-label={`${props.label} content`} class="flex-1" tabIndex={0}>
|
|
236
|
+
{props.children}
|
|
237
|
+
</ScrollArea>
|
|
238
|
+
{directions.map(({ direction, class: className, glyph }) => (
|
|
239
|
+
<ActionButton
|
|
240
|
+
type="button"
|
|
241
|
+
variant="ghost"
|
|
242
|
+
size="icon-sm"
|
|
243
|
+
class={className}
|
|
244
|
+
data-direction={direction}
|
|
245
|
+
aria-label={`Resize ${props.label} ${direction}`}
|
|
246
|
+
tooltip={`Resize ${props.label} from the ${direction} edge. Use arrow keys to resize.`}
|
|
247
|
+
onPointerDown={(event) => start(event, direction)}
|
|
248
|
+
onPointerMove={move}
|
|
249
|
+
onPointerUp={end}
|
|
250
|
+
onPointerCancel={end}
|
|
251
|
+
onLostPointerCapture={end}
|
|
252
|
+
onKeyDown={(event) => keyboardResize(event, direction)}
|
|
253
|
+
>
|
|
254
|
+
<span aria-hidden="true">{glyph}</span>
|
|
255
|
+
</ActionButton>
|
|
256
|
+
))}
|
|
257
|
+
</section>
|
|
258
|
+
</div>
|
|
259
|
+
)
|
|
260
|
+
}
|
|
@@ -0,0 +1,285 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright (c) 2026 Adea contributors
|
|
3
|
+
* SPDX-License-Identifier: MIT
|
|
4
|
+
* Geometry translated from t3code apps/web/src/components/preview/
|
|
5
|
+
* previewMiniPlayerLayout.ts, issue #422, revision
|
|
6
|
+
* 77bca8b2d76a1f42552e5eee7d277fcb1160347a (MIT). Runtime and device
|
|
7
|
+
* behavior are excluded. See NOTICE.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
export const PREVIEW_MINI_PLAYER_EDGE_GAP = 12
|
|
11
|
+
export const PREVIEW_MINI_PLAYER_CORNER_RADIUS = 12
|
|
12
|
+
export interface PreviewMiniPlayerSize {
|
|
13
|
+
readonly width: number
|
|
14
|
+
readonly height: number
|
|
15
|
+
}
|
|
16
|
+
export interface PreviewMiniPlayerPosition {
|
|
17
|
+
readonly x: number
|
|
18
|
+
readonly y: number
|
|
19
|
+
}
|
|
20
|
+
export interface PreviewMiniPlayerFrame extends PreviewMiniPlayerPosition, PreviewMiniPlayerSize {}
|
|
21
|
+
|
|
22
|
+
export type BrowserViewportResizeDirection =
|
|
23
|
+
| 'north'
|
|
24
|
+
| 'south'
|
|
25
|
+
| 'east'
|
|
26
|
+
| 'west'
|
|
27
|
+
| 'northwest'
|
|
28
|
+
| 'northeast'
|
|
29
|
+
| 'southwest'
|
|
30
|
+
| 'southeast'
|
|
31
|
+
|
|
32
|
+
const PREVIEW_MINI_PLAYER_DEFAULT_BOX = { width: 320, height: 320 } as const
|
|
33
|
+
const PREVIEW_MINI_PLAYER_MIN_SIZE = { width: 240, height: 150 } as const
|
|
34
|
+
|
|
35
|
+
interface HorizontalSpan {
|
|
36
|
+
readonly left: number
|
|
37
|
+
readonly right: number
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* The composer stack docked to the bottom edge, in container coordinates. It
|
|
42
|
+
* only reserves the columns it covers, so the margins beside it stay open all
|
|
43
|
+
* the way down.
|
|
44
|
+
*/
|
|
45
|
+
export interface PreviewMiniPlayerObstacles {
|
|
46
|
+
readonly composer: (HorizontalSpan & { readonly height: number }) | null
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export const NO_PREVIEW_MINI_PLAYER_OBSTACLES: PreviewMiniPlayerObstacles = { composer: null }
|
|
50
|
+
|
|
51
|
+
const spanOf = (x: number, width: number): HorizontalSpan => ({ left: x, right: x + width })
|
|
52
|
+
|
|
53
|
+
const spansOverlap = (a: HorizontalSpan, b: HorizontalSpan) => a.left < b.right && a.right > b.left
|
|
54
|
+
|
|
55
|
+
/** The lowest row (before the edge gap) open to a player covering these columns. */
|
|
56
|
+
function floorFor(
|
|
57
|
+
span: HorizontalSpan,
|
|
58
|
+
container: PreviewMiniPlayerSize,
|
|
59
|
+
obstacles: PreviewMiniPlayerObstacles
|
|
60
|
+
): number {
|
|
61
|
+
const { composer } = obstacles
|
|
62
|
+
return composer && spansOverlap(span, composer)
|
|
63
|
+
? container.height - Math.max(0, composer.height)
|
|
64
|
+
: container.height
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* The box a stored size is fitted into. A player with a position keeps the
|
|
69
|
+
* rows its own columns have, so a tall frame parked beside the composer
|
|
70
|
+
* survives the next layout pass; without one it takes the rows above the
|
|
71
|
+
* composer, which every column has.
|
|
72
|
+
*/
|
|
73
|
+
const availableArea = (
|
|
74
|
+
container: PreviewMiniPlayerSize,
|
|
75
|
+
obstacles: PreviewMiniPlayerObstacles,
|
|
76
|
+
span: HorizontalSpan | null
|
|
77
|
+
): PreviewMiniPlayerSize => ({
|
|
78
|
+
width: container.width - PREVIEW_MINI_PLAYER_EDGE_GAP * 2,
|
|
79
|
+
height:
|
|
80
|
+
(span
|
|
81
|
+
? floorFor(span, container, obstacles)
|
|
82
|
+
: container.height - Math.max(0, obstacles.composer?.height ?? 0)) -
|
|
83
|
+
PREVIEW_MINI_PLAYER_EDGE_GAP * 2,
|
|
84
|
+
})
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* Width is the player's only free dimension; height always follows the source
|
|
88
|
+
* aspect ratio so the content fills the box without letterboxing. The player
|
|
89
|
+
* never grows past the source's own size, and a tight container wins over the
|
|
90
|
+
* minimum.
|
|
91
|
+
*/
|
|
92
|
+
function fitPreviewMiniPlayerWidth(
|
|
93
|
+
desiredWidth: number,
|
|
94
|
+
source: PreviewMiniPlayerSize,
|
|
95
|
+
max: PreviewMiniPlayerSize
|
|
96
|
+
): PreviewMiniPlayerSize {
|
|
97
|
+
const aspectRatio = source.width / source.height
|
|
98
|
+
const width = Math.min(
|
|
99
|
+
Math.max(
|
|
100
|
+
desiredWidth,
|
|
101
|
+
PREVIEW_MINI_PLAYER_MIN_SIZE.width,
|
|
102
|
+
PREVIEW_MINI_PLAYER_MIN_SIZE.height * aspectRatio
|
|
103
|
+
),
|
|
104
|
+
source.width,
|
|
105
|
+
Math.max(1, max.width),
|
|
106
|
+
Math.max(1, max.height * aspectRatio)
|
|
107
|
+
)
|
|
108
|
+
return { width: Math.round(width), height: Math.round(width / aspectRatio) }
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
function defaultPreviewMiniPlayerWidth(source: PreviewMiniPlayerSize): number {
|
|
112
|
+
return Math.min(
|
|
113
|
+
PREVIEW_MINI_PLAYER_DEFAULT_BOX.width,
|
|
114
|
+
(PREVIEW_MINI_PLAYER_DEFAULT_BOX.height * source.width) / source.height
|
|
115
|
+
)
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
const clampToContainer = (
|
|
119
|
+
position: PreviewMiniPlayerPosition,
|
|
120
|
+
container: PreviewMiniPlayerSize,
|
|
121
|
+
player: PreviewMiniPlayerSize,
|
|
122
|
+
bottom = container.height
|
|
123
|
+
): PreviewMiniPlayerPosition => ({
|
|
124
|
+
x: Math.min(
|
|
125
|
+
Math.max(position.x, PREVIEW_MINI_PLAYER_EDGE_GAP),
|
|
126
|
+
Math.max(
|
|
127
|
+
PREVIEW_MINI_PLAYER_EDGE_GAP,
|
|
128
|
+
container.width - player.width - PREVIEW_MINI_PLAYER_EDGE_GAP
|
|
129
|
+
)
|
|
130
|
+
),
|
|
131
|
+
y: Math.min(
|
|
132
|
+
Math.max(position.y, PREVIEW_MINI_PLAYER_EDGE_GAP),
|
|
133
|
+
Math.max(PREVIEW_MINI_PLAYER_EDGE_GAP, bottom - player.height - PREVIEW_MINI_PLAYER_EDGE_GAP)
|
|
134
|
+
),
|
|
135
|
+
})
|
|
136
|
+
|
|
137
|
+
const overlapsObstacle = (
|
|
138
|
+
position: PreviewMiniPlayerPosition,
|
|
139
|
+
player: PreviewMiniPlayerSize,
|
|
140
|
+
container: PreviewMiniPlayerSize,
|
|
141
|
+
obstacles: PreviewMiniPlayerObstacles
|
|
142
|
+
): boolean =>
|
|
143
|
+
position.y + player.height > floorFor(spanOf(position.x, player.width), container, obstacles)
|
|
144
|
+
|
|
145
|
+
/**
|
|
146
|
+
* Keeps the player inside the container and off the composer. An overlapping
|
|
147
|
+
* player is pushed out along whichever side needs the smaller move, so a drag
|
|
148
|
+
* slides along the composer into the margin beside it instead of stopping at
|
|
149
|
+
* its top edge; when no side leaves it fully clear it sits above the composer.
|
|
150
|
+
*/
|
|
151
|
+
export function clampPreviewMiniPlayerPosition(
|
|
152
|
+
position: PreviewMiniPlayerPosition,
|
|
153
|
+
container: PreviewMiniPlayerSize,
|
|
154
|
+
player: PreviewMiniPlayerSize,
|
|
155
|
+
obstacles: PreviewMiniPlayerObstacles = NO_PREVIEW_MINI_PLAYER_OBSTACLES
|
|
156
|
+
): PreviewMiniPlayerPosition {
|
|
157
|
+
const inside = clampToContainer(position, container, player)
|
|
158
|
+
const { composer } = obstacles
|
|
159
|
+
if (!composer || !overlapsObstacle(inside, player, container, obstacles)) return inside
|
|
160
|
+
const gap = PREVIEW_MINI_PLAYER_EDGE_GAP
|
|
161
|
+
const above = { x: inside.x, y: container.height - composer.height - gap - player.height }
|
|
162
|
+
const beside = [
|
|
163
|
+
{ x: composer.left - gap - player.width, y: inside.y },
|
|
164
|
+
{ x: composer.right + gap, y: inside.y },
|
|
165
|
+
]
|
|
166
|
+
let best = clampToContainer(above, container, player)
|
|
167
|
+
let bestDistance = Math.abs(best.y - inside.y)
|
|
168
|
+
for (const candidate of beside) {
|
|
169
|
+
const clamped = clampToContainer(candidate, container, player)
|
|
170
|
+
if (clamped.x !== candidate.x || overlapsObstacle(candidate, player, container, obstacles)) {
|
|
171
|
+
continue
|
|
172
|
+
}
|
|
173
|
+
const distance = Math.abs(candidate.x - inside.x)
|
|
174
|
+
if (distance < bestDistance) {
|
|
175
|
+
best = candidate
|
|
176
|
+
bestDistance = distance
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
return best
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
/**
|
|
183
|
+
* Resolves the on-screen frame from the stored width and position. Clamping
|
|
184
|
+
* happens here on every layout pass instead of being written back to the
|
|
185
|
+
* store, so a temporarily narrow container never destroys the user's chosen
|
|
186
|
+
* width. A player without a position sits in the top-right corner.
|
|
187
|
+
*/
|
|
188
|
+
export function resolvePreviewMiniPlayerFrame(input: {
|
|
189
|
+
readonly width: number | null
|
|
190
|
+
readonly position: PreviewMiniPlayerPosition | null
|
|
191
|
+
readonly source: PreviewMiniPlayerSize
|
|
192
|
+
readonly container: PreviewMiniPlayerSize
|
|
193
|
+
readonly obstacles?: PreviewMiniPlayerObstacles
|
|
194
|
+
}): PreviewMiniPlayerFrame {
|
|
195
|
+
const { width, position, source, container, obstacles = NO_PREVIEW_MINI_PLAYER_OBSTACLES } = input
|
|
196
|
+
const size = fitPreviewMiniPlayerWidth(
|
|
197
|
+
width ?? defaultPreviewMiniPlayerWidth(source),
|
|
198
|
+
source,
|
|
199
|
+
availableArea(container, obstacles, position && width ? spanOf(position.x, width) : null)
|
|
200
|
+
)
|
|
201
|
+
const anchored = position ?? {
|
|
202
|
+
x: container.width - PREVIEW_MINI_PLAYER_EDGE_GAP - size.width,
|
|
203
|
+
y: PREVIEW_MINI_PLAYER_EDGE_GAP,
|
|
204
|
+
}
|
|
205
|
+
return { ...clampPreviewMiniPlayerPosition(anchored, container, size, obstacles), ...size }
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
/**
|
|
209
|
+
* Resizes from any edge or corner while holding the aspect ratio. The edge
|
|
210
|
+
* opposite the dragged one stays anchored, so growth stops at the container
|
|
211
|
+
* on that axis and the pointer keeps tracking the grabbed edge.
|
|
212
|
+
*/
|
|
213
|
+
export function resizePreviewMiniPlayer(input: {
|
|
214
|
+
readonly start: PreviewMiniPlayerFrame
|
|
215
|
+
readonly direction: BrowserViewportResizeDirection
|
|
216
|
+
readonly delta: PreviewMiniPlayerPosition
|
|
217
|
+
readonly source: PreviewMiniPlayerSize
|
|
218
|
+
readonly container: PreviewMiniPlayerSize
|
|
219
|
+
readonly obstacles?: PreviewMiniPlayerObstacles
|
|
220
|
+
}): PreviewMiniPlayerFrame {
|
|
221
|
+
const {
|
|
222
|
+
start,
|
|
223
|
+
direction,
|
|
224
|
+
delta,
|
|
225
|
+
source,
|
|
226
|
+
container,
|
|
227
|
+
obstacles = NO_PREVIEW_MINI_PLAYER_OBSTACLES,
|
|
228
|
+
} = input
|
|
229
|
+
const east = direction.includes('east')
|
|
230
|
+
const west = direction.includes('west')
|
|
231
|
+
const north = direction.includes('north')
|
|
232
|
+
const south = direction.includes('south')
|
|
233
|
+
const right = start.x + start.width
|
|
234
|
+
const bottom = start.y + start.height
|
|
235
|
+
const floor = floorFor(spanOf(start.x, start.width), container, obstacles)
|
|
236
|
+
const max = {
|
|
237
|
+
width: west
|
|
238
|
+
? right - PREVIEW_MINI_PLAYER_EDGE_GAP
|
|
239
|
+
: east
|
|
240
|
+
? container.width - PREVIEW_MINI_PLAYER_EDGE_GAP - start.x
|
|
241
|
+
: container.width - PREVIEW_MINI_PLAYER_EDGE_GAP * 2,
|
|
242
|
+
height: north
|
|
243
|
+
? bottom - PREVIEW_MINI_PLAYER_EDGE_GAP
|
|
244
|
+
: south
|
|
245
|
+
? floor - PREVIEW_MINI_PLAYER_EDGE_GAP - start.y
|
|
246
|
+
: floor - PREVIEW_MINI_PLAYER_EDGE_GAP * 2,
|
|
247
|
+
}
|
|
248
|
+
const desiredWidth = start.width + (east ? delta.x : west ? -delta.x : 0)
|
|
249
|
+
const desiredHeight = start.height + (south ? delta.y : north ? -delta.y : 0)
|
|
250
|
+
const horizontal = east || west
|
|
251
|
+
const vertical = north || south
|
|
252
|
+
const widthLeads =
|
|
253
|
+
horizontal && !vertical
|
|
254
|
+
? true
|
|
255
|
+
: vertical && !horizontal
|
|
256
|
+
? false
|
|
257
|
+
: Math.abs(desiredWidth - start.width) / start.width >=
|
|
258
|
+
Math.abs(desiredHeight - start.height) / start.height
|
|
259
|
+
const size = fitPreviewMiniPlayerWidth(
|
|
260
|
+
widthLeads ? desiredWidth : (desiredHeight * source.width) / source.height,
|
|
261
|
+
source,
|
|
262
|
+
max
|
|
263
|
+
)
|
|
264
|
+
const position = clampPreviewMiniPlayerPosition(
|
|
265
|
+
{ x: west ? right - size.width : start.x, y: north ? bottom - size.height : start.y },
|
|
266
|
+
container,
|
|
267
|
+
size,
|
|
268
|
+
obstacles
|
|
269
|
+
)
|
|
270
|
+
return { ...position, ...size }
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
// Product-neutral names for new consumers. The PreviewMiniPlayer names stay
|
|
274
|
+
// exported for Adea Dev Runtime's existing browser model API.
|
|
275
|
+
export type FloatingPreviewSize = PreviewMiniPlayerSize
|
|
276
|
+
export type FloatingPreviewPosition = PreviewMiniPlayerPosition
|
|
277
|
+
export type FloatingPreviewFrame = PreviewMiniPlayerFrame
|
|
278
|
+
export type FloatingPreviewResizeDirection = BrowserViewportResizeDirection
|
|
279
|
+
export type FloatingPreviewObstacles = PreviewMiniPlayerObstacles
|
|
280
|
+
export const FLOATING_PREVIEW_EDGE_GAP = PREVIEW_MINI_PLAYER_EDGE_GAP
|
|
281
|
+
export const FLOATING_PREVIEW_CORNER_RADIUS = PREVIEW_MINI_PLAYER_CORNER_RADIUS
|
|
282
|
+
export const NO_FLOATING_PREVIEW_OBSTACLES = NO_PREVIEW_MINI_PLAYER_OBSTACLES
|
|
283
|
+
export const resolveFloatingPreviewFrame = resolvePreviewMiniPlayerFrame
|
|
284
|
+
export const resizeFloatingPreview = resizePreviewMiniPlayer
|
|
285
|
+
export const clampFloatingPreviewPosition = clampPreviewMiniPlayerPosition
|