@passui/react 0.1.21 → 0.1.23
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/types/src/components/context-menu/menu-reveal.d.ts +9 -0
- package/dist/types/src/icons/icons.d.ts +4 -0
- package/package.json +1 -1
- package/src/components/context-menu/context-menu-host.tsx +9 -4
- package/src/components/context-menu/menu-reveal.ts +5 -0
- package/src/components/locale-switcher/locale-switcher.tsx +106 -65
- package/src/components/popover/anchored-surface.tsx +23 -6
- package/src/components/popover/popover.tsx +13 -4
- package/src/icons/icons.tsx +2 -0
- package/src/styles/motion-controls.css +4 -1
|
@@ -4,6 +4,15 @@ export type MenuRect = {
|
|
|
4
4
|
width: number;
|
|
5
5
|
height: number;
|
|
6
6
|
};
|
|
7
|
+
/** Return toward the source while handing its material back to the real trigger. */
|
|
8
|
+
export declare function menuSurfaceExit(source: ReturnType<typeof menuSurfaceReveal>): {
|
|
9
|
+
opacity: number;
|
|
10
|
+
x: number;
|
|
11
|
+
y: number;
|
|
12
|
+
width: number;
|
|
13
|
+
height: number;
|
|
14
|
+
borderRadius: number;
|
|
15
|
+
};
|
|
7
16
|
/** Animate the material's bounds independently so menu text never stretches. */
|
|
8
17
|
export declare function menuSurfaceReveal(source: MenuRect | undefined, target: MenuRect & {
|
|
9
18
|
radius?: number;
|
|
@@ -152,6 +152,10 @@ export declare const LanguageIcon: {
|
|
|
152
152
|
({ size, strokeWidth, ...props }: IconProps): import("react").JSX.Element;
|
|
153
153
|
displayName: string;
|
|
154
154
|
};
|
|
155
|
+
export declare const LoadingIcon: {
|
|
156
|
+
({ size, strokeWidth, ...props }: IconProps): import("react").JSX.Element;
|
|
157
|
+
displayName: string;
|
|
158
|
+
};
|
|
155
159
|
export declare const SignOutIcon: {
|
|
156
160
|
({ size, strokeWidth, ...props }: IconProps): import("react").JSX.Element;
|
|
157
161
|
displayName: string;
|
package/package.json
CHANGED
|
@@ -9,7 +9,7 @@ import { spring } from "../../motion/transitions"
|
|
|
9
9
|
import { concealMenuSource } from "./conceal-menu-source"
|
|
10
10
|
import { findMenuTypeaheadIndex, isMenuNavigationKey, nextMenuIndex } from "./menu-navigation"
|
|
11
11
|
import { menuPosition } from "./menu-position"
|
|
12
|
-
import { menuSurfaceReveal } from "./menu-reveal"
|
|
12
|
+
import { menuSurfaceExit, menuSurfaceReveal } from "./menu-reveal"
|
|
13
13
|
import {
|
|
14
14
|
closeContextMenu,
|
|
15
15
|
getContextMenu,
|
|
@@ -44,6 +44,7 @@ function Menu({ menu }: { menu: OpenMenu }) {
|
|
|
44
44
|
|
|
45
45
|
useLayoutEffect(() => {
|
|
46
46
|
if (
|
|
47
|
+
!present ||
|
|
47
48
|
(!menu.source && !menu.toolbar) ||
|
|
48
49
|
!position.ready ||
|
|
49
50
|
!(menu.anchor instanceof HTMLElement)
|
|
@@ -64,7 +65,7 @@ function Menu({ menu }: { menu: OpenMenu }) {
|
|
|
64
65
|
)
|
|
65
66
|
menu.anchor.focus({ preventScroll: true })
|
|
66
67
|
}
|
|
67
|
-
}, [menu, position.ready])
|
|
68
|
+
}, [menu, position.ready, present])
|
|
68
69
|
|
|
69
70
|
useLayoutEffect(() => {
|
|
70
71
|
const surface = ref.current
|
|
@@ -283,8 +284,12 @@ function Menu({ menu }: { menu: OpenMenu }) {
|
|
|
283
284
|
}
|
|
284
285
|
: undefined
|
|
285
286
|
}
|
|
286
|
-
exit={reducedMotion ? { opacity: 0 } : source}
|
|
287
|
-
transition={
|
|
287
|
+
exit={reducedMotion ? { opacity: 0 } : menuSurfaceExit(source)}
|
|
288
|
+
transition={
|
|
289
|
+
reducedMotion
|
|
290
|
+
? { duration: 0 }
|
|
291
|
+
: { ...spring.smooth, opacity: { duration: 0.16 } }
|
|
292
|
+
}
|
|
288
293
|
/>
|
|
289
294
|
)}
|
|
290
295
|
<motion.div
|
|
@@ -5,6 +5,11 @@ export type MenuRect = {
|
|
|
5
5
|
height: number
|
|
6
6
|
}
|
|
7
7
|
|
|
8
|
+
/** Return toward the source while handing its material back to the real trigger. */
|
|
9
|
+
export function menuSurfaceExit(source: ReturnType<typeof menuSurfaceReveal>) {
|
|
10
|
+
return { ...source, opacity: 0 }
|
|
11
|
+
}
|
|
12
|
+
|
|
8
13
|
/** Animate the material's bounds independently so menu text never stretches. */
|
|
9
14
|
export function menuSurfaceReveal(
|
|
10
15
|
source: MenuRect | undefined,
|
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
import { getNativeLanguageName } from "../../lib/language"
|
|
2
2
|
import { cn } from "../../lib/class-names"
|
|
3
|
-
import {
|
|
3
|
+
import { motion, useDragControls, useMotionValue } from "motion/react"
|
|
4
4
|
import { useEffect, useRef, useState } from "react"
|
|
5
|
+
import { useDismiss } from "../../hooks/use-dismiss"
|
|
6
|
+
import { CheckIcon, GlobeIcon } from "../../icons/icons"
|
|
7
|
+
import { Popover } from "../popover/popover"
|
|
5
8
|
|
|
6
9
|
type Side = "left" | "right"
|
|
7
10
|
type Edge = "top" | "bottom"
|
|
@@ -66,6 +69,7 @@ export function LocaleSwitcher<L extends string>({
|
|
|
66
69
|
label,
|
|
67
70
|
}: LocaleSwitcherProps<L>) {
|
|
68
71
|
const containerRef = useRef<HTMLDivElement>(null)
|
|
72
|
+
const triggerRef = useRef<HTMLButtonElement>(null)
|
|
69
73
|
const dragControls = useDragControls()
|
|
70
74
|
const x = useMotionValue(0)
|
|
71
75
|
const y = useMotionValue(0)
|
|
@@ -82,15 +86,12 @@ export function LocaleSwitcher<L extends string>({
|
|
|
82
86
|
if (stored) setAnchor(stored)
|
|
83
87
|
}, [storageKey])
|
|
84
88
|
|
|
89
|
+
useDismiss(containerRef, open, () => setOpen(false))
|
|
85
90
|
useEffect(() => {
|
|
86
|
-
if (
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
}
|
|
91
|
-
}
|
|
92
|
-
document.addEventListener("pointerdown", handlePointerDown)
|
|
93
|
-
return () => document.removeEventListener("pointerdown", handlePointerDown)
|
|
91
|
+
if (open)
|
|
92
|
+
containerRef.current
|
|
93
|
+
?.querySelector<HTMLButtonElement>('[role="menuitemradio"][aria-checked="true"]')
|
|
94
|
+
?.focus()
|
|
94
95
|
}, [open])
|
|
95
96
|
|
|
96
97
|
function commitDraggedPosition() {
|
|
@@ -129,74 +130,114 @@ export function LocaleSwitcher<L extends string>({
|
|
|
129
130
|
...(anchor.edge === "top" ? { top: anchor.y } : { bottom: anchor.y }),
|
|
130
131
|
}}
|
|
131
132
|
onDragEnd={commitDraggedPosition}
|
|
132
|
-
|
|
133
|
+
onDragStart={() => setOpen(false)}
|
|
134
|
+
onKeyDown={(event) => {
|
|
135
|
+
if (!open) return
|
|
136
|
+
if (event.key === "Escape") {
|
|
137
|
+
event.preventDefault()
|
|
138
|
+
setOpen(false)
|
|
139
|
+
triggerRef.current?.focus()
|
|
140
|
+
return
|
|
141
|
+
}
|
|
142
|
+
if (event.key === "Tab") {
|
|
143
|
+
setOpen(false)
|
|
144
|
+
return
|
|
145
|
+
}
|
|
146
|
+
if (!["ArrowDown", "ArrowUp", "Home", "End"].includes(event.key)) return
|
|
147
|
+
const options = Array.from(
|
|
148
|
+
containerRef.current?.querySelectorAll<HTMLButtonElement>(
|
|
149
|
+
'[role="menuitemradio"]'
|
|
150
|
+
) ?? []
|
|
151
|
+
)
|
|
152
|
+
if (!options.length) return
|
|
153
|
+
event.preventDefault()
|
|
154
|
+
const current = options.indexOf(document.activeElement as HTMLButtonElement)
|
|
155
|
+
const next =
|
|
156
|
+
event.key === "Home"
|
|
157
|
+
? 0
|
|
158
|
+
: event.key === "End"
|
|
159
|
+
? options.length - 1
|
|
160
|
+
: (current + (event.key === "ArrowDown" ? 1 : -1) + options.length) %
|
|
161
|
+
options.length
|
|
162
|
+
options[next]?.focus()
|
|
163
|
+
}}
|
|
133
164
|
className="z-60"
|
|
134
165
|
>
|
|
135
|
-
<
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
166
|
+
<button
|
|
167
|
+
ref={triggerRef}
|
|
168
|
+
type="button"
|
|
169
|
+
aria-label={label}
|
|
170
|
+
aria-haspopup="menu"
|
|
171
|
+
aria-expanded={open}
|
|
172
|
+
onPointerDown={(e) => dragControls.start(e)}
|
|
173
|
+
onClick={() => setOpen((prev) => !prev)}
|
|
174
|
+
onKeyDown={(event) => {
|
|
175
|
+
if (!open && (event.key === "ArrowDown" || event.key === "ArrowUp")) {
|
|
176
|
+
event.preventDefault()
|
|
177
|
+
setOpen(true)
|
|
178
|
+
}
|
|
141
179
|
}}
|
|
180
|
+
className="glass-menu flex h-12 min-w-20 touch-none cursor-grab items-center justify-center gap-2 rounded-full px-4 text-caption font-semibold text-label active:cursor-grabbing"
|
|
181
|
+
>
|
|
182
|
+
<GlobeIcon aria-hidden="true" className="size-5" />
|
|
183
|
+
{locale.toUpperCase()}
|
|
184
|
+
</button>
|
|
185
|
+
<Popover
|
|
186
|
+
open={open}
|
|
187
|
+
anchorRef={triggerRef}
|
|
188
|
+
origin={anchor.side === "right" ? "top-right" : "top-left"}
|
|
189
|
+
role="menu"
|
|
190
|
+
aria-label={label}
|
|
142
191
|
className={cn(
|
|
143
|
-
"
|
|
144
|
-
"
|
|
145
|
-
"flex"
|
|
146
|
-
growsUp ? "flex-col-reverse" : "flex-col",
|
|
147
|
-
open ? "w-40 gap-px p-1" : "size-10"
|
|
192
|
+
"top-0 flex w-52 max-w-[calc(100vw-2.5rem)] gap-2 p-2",
|
|
193
|
+
anchor.side === "right" ? "right-0" : "left-0",
|
|
194
|
+
growsUp ? "flex-col-reverse" : "flex-col"
|
|
148
195
|
)}
|
|
149
196
|
>
|
|
150
197
|
<button
|
|
151
198
|
type="button"
|
|
152
199
|
aria-label={label}
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
"active:cursor-grabbing text-xs font-semibold",
|
|
159
|
-
open ? "h-9 w-full rounded-lg hover:bg-accent" : "size-10 rounded-2xl"
|
|
160
|
-
)}
|
|
200
|
+
onClick={() => {
|
|
201
|
+
setOpen(false)
|
|
202
|
+
triggerRef.current?.focus()
|
|
203
|
+
}}
|
|
204
|
+
className="flex min-h-12 w-full items-center justify-center gap-2 rounded-4xl bg-fill/50 text-caption font-semibold text-label"
|
|
161
205
|
>
|
|
206
|
+
<GlobeIcon aria-hidden="true" className="size-5" />
|
|
162
207
|
{locale.toUpperCase()}
|
|
163
208
|
</button>
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
</motion.div>
|
|
197
|
-
)}
|
|
198
|
-
</AnimatePresence>
|
|
199
|
-
</motion.div>
|
|
209
|
+
<div className="flex flex-col gap-1">
|
|
210
|
+
{langs.map((item) => {
|
|
211
|
+
const active = item.value === locale
|
|
212
|
+
return (
|
|
213
|
+
<button
|
|
214
|
+
key={item.value}
|
|
215
|
+
type="button"
|
|
216
|
+
role="menuitemradio"
|
|
217
|
+
aria-checked={active}
|
|
218
|
+
tabIndex={-1}
|
|
219
|
+
onClick={() => {
|
|
220
|
+
setOpen(false)
|
|
221
|
+
triggerRef.current?.focus()
|
|
222
|
+
if (!active) {
|
|
223
|
+
onSelect(item.value)
|
|
224
|
+
}
|
|
225
|
+
}}
|
|
226
|
+
className={cn(
|
|
227
|
+
"flex min-h-11 items-center justify-between gap-3 rounded-4xl px-3.5 py-2.5 text-left text-footnote text-label outline-none",
|
|
228
|
+
"hover:bg-fill/65 focus-visible:bg-fill/65 transition-colors",
|
|
229
|
+
active && "bg-accent/12 font-medium"
|
|
230
|
+
)}
|
|
231
|
+
>
|
|
232
|
+
{item.label}
|
|
233
|
+
{active && (
|
|
234
|
+
<CheckIcon aria-hidden="true" className="size-4 shrink-0" />
|
|
235
|
+
)}
|
|
236
|
+
</button>
|
|
237
|
+
)
|
|
238
|
+
})}
|
|
239
|
+
</div>
|
|
240
|
+
</Popover>
|
|
200
241
|
</motion.div>
|
|
201
242
|
)
|
|
202
243
|
}
|
|
@@ -40,9 +40,12 @@ export const AnchoredSurface = forwardRef<HTMLDivElement, AnchoredSurfaceProps>(
|
|
|
40
40
|
const reducedMotion = useMediaQuery("(prefers-reduced-motion: reduce)")
|
|
41
41
|
const material = useRef<HTMLDivElement>(null)
|
|
42
42
|
const content = useRef<HTMLDivElement>(null)
|
|
43
|
-
const animated = useRef<{
|
|
44
|
-
|
|
45
|
-
|
|
43
|
+
const animated = useRef<{
|
|
44
|
+
values: number[]
|
|
45
|
+
velocities: number[]
|
|
46
|
+
opacity: number
|
|
47
|
+
materialOpacity: number
|
|
48
|
+
} | null>(null)
|
|
46
49
|
const placement = useAnchoredPlacement(anchor, width, needed, true)
|
|
47
50
|
const [geometry, setGeometry] = useState<{
|
|
48
51
|
source: ReturnType<typeof menuSurfaceReveal>
|
|
@@ -82,12 +85,16 @@ export const AnchoredSurface = forwardRef<HTMLDivElement, AnchoredSurfaceProps>(
|
|
|
82
85
|
useLayoutEffect(() => {
|
|
83
86
|
if (!root.current) return
|
|
84
87
|
const unregister = registerFloatingLayer(root.current, anchor)
|
|
88
|
+
return unregister
|
|
89
|
+
}, [anchor])
|
|
90
|
+
|
|
91
|
+
useLayoutEffect(() => {
|
|
92
|
+
if (!present) return
|
|
85
93
|
const restore = concealMenuSource(anchor, false)
|
|
86
94
|
return () => {
|
|
87
|
-
unregister()
|
|
88
95
|
restore()
|
|
89
96
|
}
|
|
90
|
-
}, [anchor])
|
|
97
|
+
}, [anchor, present])
|
|
91
98
|
|
|
92
99
|
useLayoutEffect(() => {
|
|
93
100
|
if (!geometry || !material.current || !content.current) {
|
|
@@ -110,6 +117,7 @@ export const AnchoredSurface = forwardRef<HTMLDivElement, AnchoredSurfaceProps>(
|
|
|
110
117
|
values: [...source],
|
|
111
118
|
velocities: source.map(() => 0),
|
|
112
119
|
opacity: 0,
|
|
120
|
+
materialOpacity: 1,
|
|
113
121
|
}
|
|
114
122
|
animated.current = state
|
|
115
123
|
let frame = 0,
|
|
@@ -120,6 +128,7 @@ export const AnchoredSurface = forwardRef<HTMLDivElement, AnchoredSurfaceProps>(
|
|
|
120
128
|
pane.style.width = `${Math.max(0, width)}px`
|
|
121
129
|
pane.style.height = `${Math.max(0, height)}px`
|
|
122
130
|
pane.style.borderRadius = `${Math.max(0, radius)}px`
|
|
131
|
+
pane.style.opacity = String(state.materialOpacity)
|
|
123
132
|
body.style.opacity = String(state.opacity)
|
|
124
133
|
}
|
|
125
134
|
const tick = (now: number) => {
|
|
@@ -151,11 +160,18 @@ export const AnchoredSurface = forwardRef<HTMLDivElement, AnchoredSurfaceProps>(
|
|
|
151
160
|
)
|
|
152
161
|
const opacity = present ? Math.max(0, (progress - 0.25) / 0.75) : 0
|
|
153
162
|
state.opacity += (opacity - state.opacity) * (1 - Math.exp(-dt / 0.04))
|
|
163
|
+
state.materialOpacity +=
|
|
164
|
+
((present ? 1 : 0) - state.materialOpacity) * (1 - Math.exp(-dt / 0.04))
|
|
154
165
|
paint()
|
|
155
|
-
if (
|
|
166
|
+
if (
|
|
167
|
+
resting &&
|
|
168
|
+
Math.abs(opacity - state.opacity) < 0.01 &&
|
|
169
|
+
Math.abs((present ? 1 : 0) - state.materialOpacity) < 0.01
|
|
170
|
+
) {
|
|
156
171
|
state.values = [...target]
|
|
157
172
|
state.velocities.fill(0)
|
|
158
173
|
state.opacity = present ? 1 : 0
|
|
174
|
+
state.materialOpacity = present ? 1 : 0
|
|
159
175
|
paint()
|
|
160
176
|
if (!present) remove?.()
|
|
161
177
|
return
|
|
@@ -166,6 +182,7 @@ export const AnchoredSurface = forwardRef<HTMLDivElement, AnchoredSurfaceProps>(
|
|
|
166
182
|
state.values = [...target]
|
|
167
183
|
state.velocities.fill(0)
|
|
168
184
|
state.opacity = present ? 1 : 0
|
|
185
|
+
state.materialOpacity = present ? 1 : 0
|
|
169
186
|
paint()
|
|
170
187
|
if (!present) remove?.()
|
|
171
188
|
} else {
|
|
@@ -7,7 +7,7 @@ import {
|
|
|
7
7
|
} from "motion/react"
|
|
8
8
|
import { type ReactNode, type RefObject, useLayoutEffect, useRef, useState } from "react"
|
|
9
9
|
import { concealMenuSource } from "../context-menu/conceal-menu-source"
|
|
10
|
-
import { menuSurfaceReveal } from "../context-menu/menu-reveal"
|
|
10
|
+
import { menuSurfaceExit, menuSurfaceReveal } from "../context-menu/menu-reveal"
|
|
11
11
|
import { cn } from "../../lib/class-names"
|
|
12
12
|
import { screenEdges } from "../../lib/screen-edges"
|
|
13
13
|
import { floatingPanelMotion, spring } from "../../motion/transitions"
|
|
@@ -183,11 +183,16 @@ function OpenPopover({
|
|
|
183
183
|
}
|
|
184
184
|
)
|
|
185
185
|
)
|
|
186
|
+
}, [anchorRef, fit])
|
|
187
|
+
|
|
188
|
+
useLayoutEffect(() => {
|
|
189
|
+
const source = anchorRef?.current
|
|
190
|
+
if (!source || !present) return
|
|
186
191
|
const restoreSource = concealMenuSource(source, false)
|
|
187
192
|
return () => {
|
|
188
193
|
restoreSource()
|
|
189
194
|
}
|
|
190
|
-
}, [anchorRef,
|
|
195
|
+
}, [anchorRef, present])
|
|
191
196
|
|
|
192
197
|
return (
|
|
193
198
|
<motion.div
|
|
@@ -274,8 +279,12 @@ function OpenPopover({
|
|
|
274
279
|
}
|
|
275
280
|
: undefined
|
|
276
281
|
}
|
|
277
|
-
exit={reducedMotion ? { opacity: 0 } : (reveal
|
|
278
|
-
transition={
|
|
282
|
+
exit={reducedMotion || !reveal ? { opacity: 0 } : menuSurfaceExit(reveal)}
|
|
283
|
+
transition={
|
|
284
|
+
reducedMotion
|
|
285
|
+
? { duration: 0 }
|
|
286
|
+
: { ...spring.smooth, opacity: { duration: 0.16 } }
|
|
287
|
+
}
|
|
279
288
|
/>
|
|
280
289
|
)}
|
|
281
290
|
{children}
|
package/src/icons/icons.tsx
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
LanguagesIcon,
|
|
3
|
+
Loading03Icon,
|
|
3
4
|
Logout01Icon,
|
|
4
5
|
MoreVertical,
|
|
5
6
|
SentIcon,
|
|
@@ -227,6 +228,7 @@ export const catalogIcons = {
|
|
|
227
228
|
|
|
228
229
|
export const NoteIcon = /* @__PURE__ */ icon(Note01Icon, "NoteIcon")
|
|
229
230
|
export const LanguageIcon = /* @__PURE__ */ icon(LanguagesIcon, "LanguageIcon")
|
|
231
|
+
export const LoadingIcon = /* @__PURE__ */ icon(Loading03Icon, "LoadingIcon")
|
|
230
232
|
export const SignOutIcon = /* @__PURE__ */ icon(Logout01Icon, "SignOutIcon")
|
|
231
233
|
export const MoreVerticalIcon = /* @__PURE__ */ icon(MoreVertical, "MoreVerticalIcon")
|
|
232
234
|
export const SendIcon = /* @__PURE__ */ icon(SentIcon, "SendIcon")
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
No painted background patch needs to match the field's surroundings. */
|
|
10
10
|
.passui-field-outline {
|
|
11
11
|
position: absolute;
|
|
12
|
-
inset: -
|
|
12
|
+
inset: calc(var(--text-footnote) / -2) 0 0;
|
|
13
13
|
min-width: 0;
|
|
14
14
|
margin: 0;
|
|
15
15
|
padding: 0 0.5rem;
|
|
@@ -23,6 +23,8 @@
|
|
|
23
23
|
overflow: hidden;
|
|
24
24
|
padding: 0;
|
|
25
25
|
font-size: var(--text-footnote);
|
|
26
|
+
line-height: 1;
|
|
27
|
+
height: 1em;
|
|
26
28
|
white-space: nowrap;
|
|
27
29
|
visibility: hidden;
|
|
28
30
|
transition: max-width 320ms ease, padding 320ms ease;
|
|
@@ -38,6 +40,7 @@
|
|
|
38
40
|
white-space: nowrap;
|
|
39
41
|
color: var(--color-label-secondary);
|
|
40
42
|
font-size: var(--text-body);
|
|
43
|
+
line-height: 1;
|
|
41
44
|
transform: translateY(-50%);
|
|
42
45
|
transform-origin: left center;
|
|
43
46
|
transition: top 320ms ease, transform 320ms ease, color 200ms ease;
|