@passui/react 0.1.39 → 0.1.41
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/code-block/code-block.d.ts +5 -2
- package/dist/types/src/components/content-view/content-view.d.ts +5 -2
- package/dist/types/src/components/context-menu/context-menu-store.d.ts +7 -2
- package/dist/types/src/components/conversation/conversation.d.ts +7 -2
- package/dist/types/src/components/one-time-code/one-time-code.d.ts +4 -1
- package/dist/types/src/components/popover/popover.d.ts +3 -0
- package/dist/types/src/components/search-list/search-list.d.ts +4 -1
- package/dist/types/src/components/sidebar/sidebar.d.ts +8 -3
- package/dist/types/src/components/slosh-slider/slosh-slider.d.ts +4 -1
- package/dist/types/src/components/toast/toast-store.d.ts +5 -0
- package/dist/types/src/components/tooltip/tooltip-host.d.ts +1 -0
- package/package.json +1 -1
- package/src/components/code-block/code-block.tsx +7 -1
- package/src/components/content-view/content-view.tsx +60 -8
- package/src/components/context-menu/context-menu-host.tsx +44 -15
- package/src/components/context-menu/context-menu-store.ts +10 -1
- package/src/components/conversation/conversation.tsx +93 -19
- package/src/components/one-time-code/one-time-code.tsx +22 -2
- package/src/components/popover/popover.tsx +15 -2
- package/src/components/search-list/search-list.tsx +27 -9
- package/src/components/sidebar/sidebar.tsx +38 -11
- package/src/components/slosh-slider/slosh-slider.tsx +6 -0
- package/src/components/toast/toast-store.ts +7 -0
- package/src/components/toast/toaster.tsx +56 -23
- package/src/components/tooltip/tooltip-host.tsx +14 -1
- package/src/styles/code-block.css +12 -0
- package/src/styles/motion-controls.css +8 -0
|
@@ -7,12 +7,39 @@ import {
|
|
|
7
7
|
getToasts,
|
|
8
8
|
subscribeToasts,
|
|
9
9
|
type Toast,
|
|
10
|
+
type ToastSize,
|
|
10
11
|
type ToastTone,
|
|
11
12
|
toast as toastApi,
|
|
12
13
|
toastLimits,
|
|
13
14
|
} from "./toast-store"
|
|
14
15
|
|
|
15
|
-
const PILL = 40
|
|
16
|
+
const PILL: Record<ToastSize, number> = { sm: 32, md: 40, lg: 48 }
|
|
17
|
+
|
|
18
|
+
const contentClasses: Record<ToastSize, string> = {
|
|
19
|
+
sm: "absolute top-0 left-0 flex w-max max-w-[min(420px,calc(100vw-24px))] items-start gap-2 py-2 pr-3 pl-2 text-on-inverse",
|
|
20
|
+
md: "absolute top-0 left-0 flex w-max max-w-[min(420px,calc(100vw-24px))] items-start gap-2.5 py-[10px] pr-4 pl-[10px] text-on-inverse",
|
|
21
|
+
lg: "absolute top-0 left-0 flex w-max max-w-[min(420px,calc(100vw-24px))] items-start gap-3 py-3 pr-5 pl-3 text-on-inverse",
|
|
22
|
+
}
|
|
23
|
+
const titleClasses: Record<ToastSize, string> = {
|
|
24
|
+
sm: "text-footnote leading-4 font-semibold",
|
|
25
|
+
md: "text-subheadline leading-5 font-semibold",
|
|
26
|
+
lg: "text-body leading-6 font-semibold",
|
|
27
|
+
}
|
|
28
|
+
const descriptionClasses: Record<ToastSize, string> = {
|
|
29
|
+
sm: "text-caption2 leading-snug text-on-inverse/70",
|
|
30
|
+
md: "text-footnote leading-snug text-on-inverse/70",
|
|
31
|
+
lg: "text-subheadline leading-snug text-on-inverse/70",
|
|
32
|
+
}
|
|
33
|
+
const actionClasses: Record<ToastSize, string> = {
|
|
34
|
+
sm: "ml-1 shrink-0 self-center rounded-full bg-on-inverse/12 px-2.5 py-0.5 text-caption2 font-semibold text-on-inverse transition-colors hover:bg-on-inverse/20",
|
|
35
|
+
md: "ml-1 shrink-0 self-center rounded-full bg-on-inverse/12 px-3 py-1 text-footnote font-semibold text-on-inverse transition-colors hover:bg-on-inverse/20",
|
|
36
|
+
lg: "ml-1 shrink-0 self-center rounded-full bg-on-inverse/12 px-3.5 py-1.5 text-subheadline font-semibold text-on-inverse transition-colors hover:bg-on-inverse/20",
|
|
37
|
+
}
|
|
38
|
+
const toneIconClasses: Record<ToastSize, string> = {
|
|
39
|
+
sm: "flex size-4 shrink-0 items-center justify-center rounded-full",
|
|
40
|
+
md: "flex size-5 shrink-0 items-center justify-center rounded-full",
|
|
41
|
+
lg: "flex size-6 shrink-0 items-center justify-center rounded-full",
|
|
42
|
+
}
|
|
16
43
|
const EMPTY: Toast[] = []
|
|
17
44
|
/** A little loose, so the body overshoots and settles like a drop of honey. */
|
|
18
45
|
const BODY_SPRING = {
|
|
@@ -110,10 +137,11 @@ function ToastItem({
|
|
|
110
137
|
filterId: string
|
|
111
138
|
reducedMotion: boolean
|
|
112
139
|
}) {
|
|
140
|
+
const pill = PILL[toast.size]
|
|
113
141
|
const content = useRef<HTMLDivElement>(null)
|
|
114
142
|
const [size, setSize] = useState({
|
|
115
|
-
width:
|
|
116
|
-
height:
|
|
143
|
+
width: pill,
|
|
144
|
+
height: pill,
|
|
117
145
|
})
|
|
118
146
|
const [open, setOpen] = useState(false)
|
|
119
147
|
|
|
@@ -143,8 +171,8 @@ function ToastItem({
|
|
|
143
171
|
return () => clearTimeout(timer)
|
|
144
172
|
}, [toast.id, toast.duration, paused])
|
|
145
173
|
|
|
146
|
-
const width = open ? size.width :
|
|
147
|
-
const height = open ? size.height :
|
|
174
|
+
const width = open ? size.width : pill
|
|
175
|
+
const height = open ? size.height : pill
|
|
148
176
|
// Older toasts tuck in behind the newest, and fan out on hover.
|
|
149
177
|
const stacked = !expanded && index > 0
|
|
150
178
|
|
|
@@ -156,7 +184,7 @@ function ToastItem({
|
|
|
156
184
|
initial={reducedMotion ? false : { opacity: 0, y: -24, scale: 0.6 }}
|
|
157
185
|
animate={{
|
|
158
186
|
opacity: stacked ? 1 - index * 0.25 : 1,
|
|
159
|
-
y: stacked ? index * 9 : index * (
|
|
187
|
+
y: stacked ? index * 9 : index * (pill + 14) + index * 6,
|
|
160
188
|
scale: stacked ? 1 - index * 0.05 : 1,
|
|
161
189
|
}}
|
|
162
190
|
exit={
|
|
@@ -180,7 +208,7 @@ function ToastItem({
|
|
|
180
208
|
<motion.div
|
|
181
209
|
role="status"
|
|
182
210
|
className="pointer-events-auto relative"
|
|
183
|
-
initial={{ width:
|
|
211
|
+
initial={{ width: pill, height: pill }}
|
|
184
212
|
animate={{ width, height }}
|
|
185
213
|
transition={reducedMotion ? { duration: 0 } : BODY_SPRING}
|
|
186
214
|
>
|
|
@@ -194,21 +222,21 @@ function ToastItem({
|
|
|
194
222
|
>
|
|
195
223
|
<motion.span
|
|
196
224
|
className="absolute top-3 left-3 rounded-full bg-inverse shadow-xl"
|
|
197
|
-
style={{ width:
|
|
225
|
+
style={{ width: pill, height: pill }}
|
|
198
226
|
animate={{ scale: open ? 1 : 1.06 }}
|
|
199
227
|
transition={reducedMotion ? { duration: 0 } : spring.bouncy}
|
|
200
228
|
/>
|
|
201
229
|
<motion.span
|
|
202
230
|
className="absolute top-3 left-3 bg-inverse"
|
|
203
231
|
initial={{
|
|
204
|
-
width:
|
|
205
|
-
height:
|
|
206
|
-
borderRadius:
|
|
232
|
+
width: pill,
|
|
233
|
+
height: pill,
|
|
234
|
+
borderRadius: pill / 2,
|
|
207
235
|
}}
|
|
208
236
|
animate={{
|
|
209
237
|
width,
|
|
210
238
|
height,
|
|
211
|
-
borderRadius: Math.min(
|
|
239
|
+
borderRadius: Math.min(pill / 2, height / 2, 22),
|
|
212
240
|
}}
|
|
213
241
|
transition={reducedMotion ? { duration: 0 } : BODY_SPRING}
|
|
214
242
|
/>
|
|
@@ -217,8 +245,8 @@ function ToastItem({
|
|
|
217
245
|
{/* Content, crisp above the shapes. */}
|
|
218
246
|
<motion.div
|
|
219
247
|
ref={content}
|
|
220
|
-
className=
|
|
221
|
-
style={{ minHeight:
|
|
248
|
+
className={contentClasses[toast.size]}
|
|
249
|
+
style={{ minHeight: pill }}
|
|
222
250
|
animate={{ opacity: open ? 1 : 0 }}
|
|
223
251
|
transition={
|
|
224
252
|
reducedMotion
|
|
@@ -229,12 +257,12 @@ function ToastItem({
|
|
|
229
257
|
}
|
|
230
258
|
}
|
|
231
259
|
>
|
|
232
|
-
<ToneIcon tone={toast.tone} reducedMotion={reducedMotion} />
|
|
260
|
+
<ToneIcon tone={toast.tone} size={toast.size} reducedMotion={reducedMotion} />
|
|
233
261
|
<div className="flex min-w-0 flex-col py-px">
|
|
234
262
|
<AnimatePresence mode="popLayout" initial={false}>
|
|
235
263
|
<motion.span
|
|
236
264
|
key={toast.title}
|
|
237
|
-
className=
|
|
265
|
+
className={titleClasses[toast.size]}
|
|
238
266
|
initial={
|
|
239
267
|
reducedMotion
|
|
240
268
|
? false
|
|
@@ -264,7 +292,7 @@ function ToastItem({
|
|
|
264
292
|
</motion.span>
|
|
265
293
|
</AnimatePresence>
|
|
266
294
|
{toast.description && (
|
|
267
|
-
<span className=
|
|
295
|
+
<span className={descriptionClasses[toast.size]}>
|
|
268
296
|
{toast.description}
|
|
269
297
|
</span>
|
|
270
298
|
)}
|
|
@@ -276,7 +304,7 @@ function ToastItem({
|
|
|
276
304
|
toast.action?.onClick()
|
|
277
305
|
toastApi.dismiss(toast.id)
|
|
278
306
|
}}
|
|
279
|
-
className=
|
|
307
|
+
className={actionClasses[toast.size]}
|
|
280
308
|
>
|
|
281
309
|
{toast.action.label}
|
|
282
310
|
</button>
|
|
@@ -294,15 +322,20 @@ const toneColors: Record<ToastTone, string> = {
|
|
|
294
322
|
loading: "bg-on-inverse/15 text-on-inverse",
|
|
295
323
|
}
|
|
296
324
|
|
|
297
|
-
function ToneIcon({
|
|
325
|
+
function ToneIcon({
|
|
326
|
+
tone,
|
|
327
|
+
size,
|
|
328
|
+
reducedMotion,
|
|
329
|
+
}: {
|
|
330
|
+
tone: ToastTone
|
|
331
|
+
size: ToastSize
|
|
332
|
+
reducedMotion: boolean
|
|
333
|
+
}) {
|
|
298
334
|
return (
|
|
299
335
|
<AnimatePresence mode="popLayout" initial={false}>
|
|
300
336
|
<motion.span
|
|
301
337
|
key={tone}
|
|
302
|
-
className={cn(
|
|
303
|
-
"flex size-5 shrink-0 items-center justify-center rounded-full",
|
|
304
|
-
toneColors[tone]
|
|
305
|
-
)}
|
|
338
|
+
className={cn(toneIconClasses[size], toneColors[tone])}
|
|
306
339
|
initial={
|
|
307
340
|
reducedMotion
|
|
308
341
|
? false
|
|
@@ -1,6 +1,15 @@
|
|
|
1
1
|
import { AnimatePresence, motion, useReducedMotion } from "motion/react"
|
|
2
2
|
import { spring } from "../../motion/transitions"
|
|
3
3
|
import { useEffect, useId, useState } from "react"
|
|
4
|
+
import { cn } from "../../lib/class-names"
|
|
5
|
+
|
|
6
|
+
export type TooltipSize = "sm" | "md" | "lg"
|
|
7
|
+
|
|
8
|
+
const tooltipClasses: Record<TooltipSize, string> = {
|
|
9
|
+
sm: "pointer-events-none fixed z-[80] max-w-[200px] rounded-md bg-inverse px-2 py-1 text-center text-caption2 leading-tight font-medium text-on-inverse shadow-lg",
|
|
10
|
+
md: "pointer-events-none fixed z-[80] max-w-[240px] rounded-md bg-inverse px-2.5 py-1.5 text-center text-caption leading-tight font-medium text-on-inverse shadow-lg",
|
|
11
|
+
lg: "pointer-events-none fixed z-[80] max-w-[280px] rounded-md bg-inverse px-3 py-2 text-center text-footnote leading-tight font-medium text-on-inverse shadow-lg",
|
|
12
|
+
}
|
|
4
13
|
|
|
5
14
|
interface Tip {
|
|
6
15
|
text: string
|
|
@@ -8,6 +17,7 @@ interface Tip {
|
|
|
8
17
|
y: number
|
|
9
18
|
/** Shown above the element when there's no room below. */
|
|
10
19
|
above: boolean
|
|
20
|
+
size: TooltipSize
|
|
11
21
|
}
|
|
12
22
|
|
|
13
23
|
const DELAY = 450
|
|
@@ -45,11 +55,14 @@ export function TooltipHost() {
|
|
|
45
55
|
if (!text) return
|
|
46
56
|
const rect = element.getBoundingClientRect()
|
|
47
57
|
const above = rect.bottom + 40 > window.innerHeight
|
|
58
|
+
const sizeAttr = element.getAttribute("data-tooltip-size")
|
|
59
|
+
const size: TooltipSize = sizeAttr === "sm" || sizeAttr === "lg" ? sizeAttr : "md"
|
|
48
60
|
setTip({
|
|
49
61
|
text,
|
|
50
62
|
x: rect.left + rect.width / 2,
|
|
51
63
|
y: above ? rect.top - MARGIN : rect.bottom + MARGIN,
|
|
52
64
|
above,
|
|
65
|
+
size,
|
|
53
66
|
})
|
|
54
67
|
lastShown = Date.now()
|
|
55
68
|
}
|
|
@@ -121,7 +134,7 @@ export function TooltipHost() {
|
|
|
121
134
|
id={tooltipId}
|
|
122
135
|
key={tip.text + tip.x}
|
|
123
136
|
role="tooltip"
|
|
124
|
-
className=
|
|
137
|
+
className={cn(tooltipClasses[tip.size])}
|
|
125
138
|
style={{
|
|
126
139
|
left: Math.min(Math.max(tip.x, 128), window.innerWidth - 128),
|
|
127
140
|
top: tip.y,
|
|
@@ -24,6 +24,18 @@
|
|
|
24
24
|
user-select: none;
|
|
25
25
|
}
|
|
26
26
|
.passui-code-block:not([data-line-numbers]) pre { padding-inline-start: 1rem; }
|
|
27
|
+
.passui-code-block[data-size="sm"] pre {
|
|
28
|
+
padding-block: 0.75rem;
|
|
29
|
+
font-size: var(--text-caption);
|
|
30
|
+
line-height: 1.6;
|
|
31
|
+
}
|
|
32
|
+
.passui-code-block[data-size="sm"][data-line-numbers] .line::before { width: 2.5rem; margin-inline-end: 1rem; }
|
|
33
|
+
.passui-code-block[data-size="lg"] pre {
|
|
34
|
+
padding-block: 1.25rem;
|
|
35
|
+
font-size: var(--text-subheadline);
|
|
36
|
+
line-height: 1.8;
|
|
37
|
+
}
|
|
38
|
+
.passui-code-block[data-size="lg"][data-line-numbers] .line::before { width: 3.5rem; margin-inline-end: 1.5rem; }
|
|
27
39
|
.passui-code-block .shiki, .passui-code-block .shiki span { color: var(--shiki-light); background: transparent !important; }
|
|
28
40
|
@media (prefers-color-scheme: dark) {
|
|
29
41
|
.passui-code-block .shiki, .passui-code-block .shiki span { color: var(--shiki-dark); }
|
|
@@ -80,6 +80,10 @@
|
|
|
80
80
|
.passui-one-time-code:is([data-status="verifying"], [data-status="success"]) .passui-otp-capsule { opacity: 1; transform: translateX(-50%) scaleX(1); }
|
|
81
81
|
.passui-one-time-code:is([data-status="verifying"], [data-status="success"]) .passui-otp-digits { opacity: 0; }
|
|
82
82
|
.passui-otp-check { position: absolute; left: 50%; top: 50%; transform: translate(-50%, -50%); color: var(--color-on-accent); opacity: 0; pointer-events: none; }
|
|
83
|
+
.passui-one-time-code[data-size="sm"] .passui-otp-row { height: 2.5rem; }
|
|
84
|
+
.passui-one-time-code[data-size="sm"] .passui-otp-digit { font-size: var(--text-title); }
|
|
85
|
+
.passui-one-time-code[data-size="lg"] .passui-otp-row { height: 3.5rem; }
|
|
86
|
+
.passui-one-time-code[data-size="lg"] .passui-otp-digit { font-size: var(--text-title2); }
|
|
83
87
|
.passui-one-time-code[data-status="success"] .passui-otp-check { opacity: 1; transition: opacity 160ms 240ms; }
|
|
84
88
|
/* A wrong code shivers, then drains right to left. Selecting the single
|
|
85
89
|
input afterward lets the next keystroke replace it without a trap. */
|
|
@@ -129,6 +133,10 @@
|
|
|
129
133
|
calc(100% - var(--slosh-lean, 0px)) 100%, 0 100%);
|
|
130
134
|
}
|
|
131
135
|
.passui-slosh-track:dir(rtl) .passui-slosh-fill { transform: scaleX(-1); }
|
|
136
|
+
.passui-slosh-slider[data-size="sm"] .passui-slosh-track { height: 2rem; }
|
|
137
|
+
.passui-slosh-slider[data-size="sm"] .passui-slosh-knob { top: 4px; bottom: 4px; }
|
|
138
|
+
.passui-slosh-slider[data-size="lg"] .passui-slosh-track { height: 3rem; }
|
|
139
|
+
.passui-slosh-slider[data-size="lg"] .passui-slosh-knob { top: 8px; bottom: 8px; width: 4px; margin-inline-start: -2px; }
|
|
132
140
|
.passui-slosh-knob {
|
|
133
141
|
position: absolute;
|
|
134
142
|
top: 6px;
|