@passui/react 0.1.45 → 0.1.47

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (141) hide show
  1. package/README.md +57 -46
  2. package/dist/types/src/components/accordion/accordion.d.ts +1 -1
  3. package/dist/types/src/components/breadcrumb/breadcrumb.d.ts +1 -1
  4. package/dist/types/src/components/inline-disclosure/inline-disclosure.d.ts +1 -1
  5. package/dist/types/src/components/popover/anchored-surface.d.ts +5 -1
  6. package/dist/types/src/components/popover/index.d.ts +41 -0
  7. package/dist/types/src/components/popover/popover-content.d.ts +38 -0
  8. package/dist/types/src/components/popover/popover-root.d.ts +22 -0
  9. package/dist/types/src/components/popover/popover-trigger.d.ts +23 -0
  10. package/dist/types/src/components/stepper/rolling-digit.d.ts +1 -1
  11. package/dist/types/src/components/table/table.d.ts +1 -1
  12. package/dist/types/src/components/view-controller/view-controller.d.ts +2 -2
  13. package/dist/types/src/index.d.ts +1 -1
  14. package/dist/types/src/machines/popover.machine.d.ts +30 -0
  15. package/package.json +307 -307
  16. package/src/appearance/index.ts +2 -2
  17. package/src/appearance/platform.tsx +76 -60
  18. package/src/appearance/theme.tsx +409 -377
  19. package/src/components/accordion/accordion.tsx +58 -49
  20. package/src/components/ambient/ambient.tsx +25 -25
  21. package/src/components/ambient/index.ts +1 -1
  22. package/src/components/aspect-ratio/aspect-ratio.tsx +21 -16
  23. package/src/components/breadcrumb/breadcrumb.tsx +63 -57
  24. package/src/components/button/button-styles.ts +39 -32
  25. package/src/components/button/button.tsx +91 -84
  26. package/src/components/button/icon-button.tsx +27 -25
  27. package/src/components/button/pending-spinner.tsx +8 -8
  28. package/src/components/button/use-pending-indicator.ts +11 -11
  29. package/src/components/chip/chip.tsx +35 -30
  30. package/src/components/code-block/code-block.tsx +40 -39
  31. package/src/components/combo-box/combo-box.tsx +5 -5
  32. package/src/components/command/command.tsx +124 -94
  33. package/src/components/compact-date-picker/calendar-month.ts +75 -53
  34. package/src/components/compact-date-picker/compact-date-picker.tsx +308 -289
  35. package/src/components/compact-time-picker/compact-time-picker.tsx +288 -281
  36. package/src/components/compact-time-picker/time-value.ts +32 -29
  37. package/src/components/content-unavailable-view/content-unavailable-view.tsx +64 -48
  38. package/src/components/content-view/content-view.tsx +168 -159
  39. package/src/components/content-view/index.ts +1 -1
  40. package/src/components/context-menu/conceal-menu-source.ts +25 -25
  41. package/src/components/context-menu/context-menu-host.tsx +439 -402
  42. package/src/components/context-menu/context-menu-store.ts +125 -123
  43. package/src/components/context-menu/menu-navigation.ts +25 -18
  44. package/src/components/context-menu/menu-position.ts +33 -29
  45. package/src/components/context-menu/menu-reveal.ts +32 -32
  46. package/src/components/context-menu/use-context-menu.ts +63 -56
  47. package/src/components/conversation/conversation.tsx +265 -263
  48. package/src/components/conversation/index.ts +1 -1
  49. package/src/components/date-picker/date-picker.tsx +95 -94
  50. package/src/components/date-picker/date-value.ts +20 -10
  51. package/src/components/dialog/dialog-host.tsx +105 -103
  52. package/src/components/dialog/dialog-store.ts +37 -36
  53. package/src/components/dialog/dialog.tsx +192 -179
  54. package/src/components/dialog/index.ts +1 -1
  55. package/src/components/disclosure-group/disclosure-group.tsx +93 -86
  56. package/src/components/divider/divider.tsx +24 -22
  57. package/src/components/inline-disclosure/inline-disclosure.tsx +40 -36
  58. package/src/components/keyboard-shortcut/keyboard-shortcut.tsx +23 -19
  59. package/src/components/labeled-content/labeled-content.tsx +68 -68
  60. package/src/components/locale-switcher/index.ts +1 -1
  61. package/src/components/locale-switcher/locale-switcher.tsx +278 -251
  62. package/src/components/menu/menu.tsx +75 -58
  63. package/src/components/morph/index.ts +2 -2
  64. package/src/components/morph/morph.tsx +227 -201
  65. package/src/components/morph/use-morph-disclosure.ts +19 -19
  66. package/src/components/one-time-code/one-time-code.tsx +216 -200
  67. package/src/components/picker/picker-trigger.ts +16 -13
  68. package/src/components/picker/picker.tsx +371 -345
  69. package/src/components/popover/anchored-surface.tsx +253 -229
  70. package/src/components/popover/index.ts +50 -0
  71. package/src/components/popover/popover-content.tsx +374 -0
  72. package/src/components/popover/popover-root.tsx +97 -0
  73. package/src/components/popover/popover-trigger.tsx +71 -0
  74. package/src/components/profile-image/profile-image.tsx +80 -64
  75. package/src/components/progress-view/progress-view.tsx +61 -59
  76. package/src/components/progress-view/use-liquid-progress.ts +38 -38
  77. package/src/components/radio-group/radio-group.tsx +71 -68
  78. package/src/components/search-field/expanding-search-field.tsx +191 -177
  79. package/src/components/search-field/search-field.tsx +59 -50
  80. package/src/components/search-list/search-list.tsx +246 -236
  81. package/src/components/section/section.tsx +58 -58
  82. package/src/components/secure-field/secure-field.tsx +3 -3
  83. package/src/components/segmented-control/segmented-control.tsx +136 -136
  84. package/src/components/sheet/modal-environment.ts +71 -64
  85. package/src/components/sheet/sheet-portal.tsx +58 -53
  86. package/src/components/sheet/sheet.tsx +146 -141
  87. package/src/components/sheet/use-sheet-focus.ts +97 -82
  88. package/src/components/sidebar/sidebar.tsx +78 -78
  89. package/src/components/skeleton/skeleton.tsx +30 -21
  90. package/src/components/slider/slider.tsx +113 -104
  91. package/src/components/slosh-slider/liquid-step.ts +32 -31
  92. package/src/components/slosh-slider/slosh-slider.tsx +265 -228
  93. package/src/components/stat-tile/index.ts +1 -1
  94. package/src/components/stat-tile/stat-tile.tsx +79 -68
  95. package/src/components/status-indicator/status-indicator.tsx +40 -37
  96. package/src/components/stepper/rolling-digit.tsx +82 -68
  97. package/src/components/stepper/stepper.tsx +122 -113
  98. package/src/components/swatch-picker/swatch-picker.tsx +120 -120
  99. package/src/components/tab-bar/tab-bar.tsx +149 -148
  100. package/src/components/tab-view/tab-view.tsx +140 -137
  101. package/src/components/table/table.tsx +117 -98
  102. package/src/components/text-editor/text-editor.tsx +34 -29
  103. package/src/components/text-field/text-field.tsx +182 -180
  104. package/src/components/toast/toast-store.ts +127 -115
  105. package/src/components/toast/toaster.tsx +361 -347
  106. package/src/components/toggle/toggle.tsx +297 -282
  107. package/src/components/tooltip/tooltip-host.tsx +157 -150
  108. package/src/components/view-controller/index.ts +1 -1
  109. package/src/components/view-controller/view-controller.tsx +64 -53
  110. package/src/components/wake-slider/wake-slider.tsx +220 -205
  111. package/src/hooks/scroll/minimize-decision.ts +11 -7
  112. package/src/hooks/use-anchored-disclosure.ts +19 -19
  113. package/src/hooks/use-anchored-placement.ts +29 -25
  114. package/src/hooks/use-dismiss.ts +33 -29
  115. package/src/hooks/use-floating-dismiss.ts +24 -22
  116. package/src/hooks/use-media-query.ts +67 -60
  117. package/src/hooks/use-minimize-on-scroll.ts +69 -60
  118. package/src/hooks/use-visual-viewport.ts +63 -63
  119. package/src/hooks/viewport/types.ts +16 -16
  120. package/src/hooks/viewport/viewport-metrics.ts +16 -10
  121. package/src/icons/icons.tsx +440 -328
  122. package/src/index.ts +91 -91
  123. package/src/lib/anchored-placement.ts +70 -65
  124. package/src/lib/class-names.ts +14 -13
  125. package/src/lib/clipboard.ts +8 -7
  126. package/src/lib/date.ts +61 -60
  127. package/src/lib/floating-layers.ts +39 -24
  128. package/src/lib/haptics.ts +10 -10
  129. package/src/lib/language.ts +9 -9
  130. package/src/lib/range-value.ts +27 -21
  131. package/src/lib/screen-edges.ts +33 -30
  132. package/src/lib/shapes.ts +38 -34
  133. package/src/machines/popover.machine.ts +51 -0
  134. package/src/motion/transitions.ts +46 -43
  135. package/src/styles/code-block.css +69 -43
  136. package/src/styles/motion-controls.css +393 -191
  137. package/src/tokens.ts +1 -1
  138. package/dist/types/src/components/popover/popover-fit.d.ts +0 -21
  139. package/dist/types/src/components/popover/popover.d.ts +0 -21
  140. package/src/components/popover/popover-fit.ts +0 -69
  141. package/src/components/popover/popover.tsx +0 -334
@@ -1,69 +0,0 @@
1
- import { type PlacementFrame, placeInViewport } from "../../lib/anchored-placement"
2
-
3
- interface PanelRect {
4
- left: number
5
- top: number
6
- width: number
7
- height: number
8
- }
9
-
10
- interface AnchorRect {
11
- top: number
12
- bottom: number
13
- }
14
-
15
- export interface PopoverFit {
16
- shiftX: number
17
- shiftY: number
18
- maxWidth: number
19
- maxHeight?: number
20
- above: boolean
21
- }
22
-
23
- /** Keep an absolutely positioned popover visible without scaling its contents. */
24
- export function fitPopover(
25
- panel: PanelRect,
26
- anchor: AnchorRect | undefined,
27
- frame: Pick<PlacementFrame, "viewport" | "edges">,
28
- gap = 6,
29
- origin: "top-left" | "top-right" = "top-left"
30
- ): PopoverFit {
31
- const { viewport, edges } = frame
32
- const topEdge = edges.top
33
- const bottomEdge = viewport.height - edges.bottom
34
- const availableHeight = Math.max(0, bottomEdge - topEdge)
35
- const placement = placeInViewport(
36
- {
37
- ...frame,
38
- anchor: {
39
- left: panel.left,
40
- top: anchor?.top ?? panel.top,
41
- bottom: anchor?.bottom ?? panel.top,
42
- },
43
- },
44
- panel.width,
45
- panel.height,
46
- gap
47
- )
48
-
49
- const above = Boolean(anchor && panel.top + panel.height > bottomEdge && placement.above)
50
- const aboveHeight = anchor ? Math.max(0, anchor.top - topEdge - gap) : 0
51
- const visibleHeight = above
52
- ? Math.min(panel.height, aboveHeight)
53
- : Math.min(panel.height, availableHeight)
54
- const desiredTop = above
55
- ? (anchor?.top ?? panel.top) - gap - visibleHeight
56
- : Math.max(topEdge, Math.min(panel.top, bottomEdge - visibleHeight))
57
- const heightRoom = above ? aboveHeight : Math.max(0, bottomEdge - desiredTop)
58
-
59
- return {
60
- shiftX:
61
- placement.left -
62
- panel.left -
63
- (origin === "top-right" ? panel.width - placement.width : 0),
64
- shiftY: desiredTop - panel.top,
65
- maxWidth: Math.max(0, viewport.width - edges.left - edges.right),
66
- maxHeight: panel.height > heightRoom ? heightRoom : undefined,
67
- above,
68
- }
69
- }
@@ -1,334 +0,0 @@
1
- import {
2
- AnimatePresence,
3
- type HTMLMotionProps,
4
- motion,
5
- useIsPresent,
6
- useReducedMotion,
7
- } from "motion/react"
8
- import { type ReactNode, type RefObject, useLayoutEffect, useRef, useState } from "react"
9
- import { concealMenuSource } from "../context-menu/conceal-menu-source"
10
- import { menuSurfaceExit, menuSurfaceReveal } from "../context-menu/menu-reveal"
11
- import { cn } from "../../lib/class-names"
12
- import { screenEdges } from "../../lib/screen-edges"
13
- import {
14
- contentCrossfade,
15
- floatingPanelMotion,
16
- fluidCollapse,
17
- fluidOvershoot,
18
- spring,
19
- } from "../../motion/transitions"
20
- import { fitPopover, type PopoverFit } from "./popover-fit"
21
-
22
- export type PopoverOrigin = "top-left" | "top-right"
23
- export type PopoverSize = "sm" | "md"
24
-
25
- const surfaceRadius: Record<PopoverSize, string> = {
26
- sm: "rounded-3xl",
27
- md: "rounded-5xl",
28
- }
29
-
30
- export interface PopoverProps extends Omit<HTMLMotionProps<"div">, "children"> {
31
- open: boolean
32
- children?: ReactNode
33
- /** Which corner the popover grows from. */
34
- origin?: PopoverOrigin
35
- /** Trigger whose shape the popover uses during its opening and closing motion. */
36
- anchorRef?: RefObject<HTMLElement | null>
37
- /** Surface corner radius. @default "md" */
38
- size?: PopoverSize
39
- }
40
-
41
- /**
42
- * A glass surface that springs open from its anchor. Position it with
43
- * `className` (it is absolutely positioned within a relative parent); it
44
- * flips above its relative parent when the bottom edge is short, and
45
- * stays inside the visible viewport as it resizes or scrolls.
46
- */
47
- export function Popover({ open, ...props }: PopoverProps) {
48
- return <AnimatePresence>{open && <OpenPopover {...props} />}</AnimatePresence>
49
- }
50
-
51
- function OpenPopover({
52
- origin = "top-left",
53
- anchorRef,
54
- size = "md",
55
- className,
56
- style,
57
- children,
58
- ...props
59
- }: Omit<PopoverProps, "open">) {
60
- const ref = useRef<HTMLDivElement>(null)
61
- const reducedMotion = useReducedMotion()
62
- const present = useIsPresent()
63
- const [settled, setSettled] = useState(false)
64
- const [material, setMaterial] = useState({ width: 0, height: 0, radius: 0 })
65
- const [fit, setFit] = useState<PopoverFit>({
66
- shiftX: 0,
67
- shiftY: 0,
68
- maxWidth: 0,
69
- above: false,
70
- })
71
- const [reveal, setReveal] = useState<ReturnType<typeof menuSurfaceReveal> | null>(null)
72
- const popoverMotion = floatingPanelMotion(fit.above ? "above" : "below")
73
-
74
- // For anchored popovers, the surface morphs from the trigger via
75
- // menuSurfaceReveal. For non-anchored popovers, we use scale + the
76
- // fluid overshoot spring so the panel grows from the origin corner
77
- // with a physical bounce — Apple's matched-geometry feel.
78
-
79
- useLayoutEffect(() => {
80
- const refit = () => {
81
- const element = ref.current
82
- if (!element) return
83
- // Measure the authored position without the opening animation or
84
- // our viewport correction. This prevents cumulative drift.
85
- const transform = element.style.transform
86
- const translate = element.style.translate
87
- const maxHeight = element.style.maxHeight
88
- const maxWidth = element.style.maxWidth
89
- element.style.transform = "none"
90
- element.style.translate = "none"
91
- element.style.maxHeight = "none"
92
- element.style.maxWidth = "none"
93
- const rect = element.getBoundingClientRect()
94
- const neededHeight = Math.max(rect.height, element.scrollHeight)
95
- const radius = Number.parseFloat(getComputedStyle(element).borderTopLeftRadius) || 0
96
- setMaterial((current) =>
97
- current.width === rect.width &&
98
- current.height === neededHeight &&
99
- current.radius === radius
100
- ? current
101
- : { width: rect.width, height: neededHeight, radius }
102
- )
103
- element.style.transform = transform
104
- element.style.translate = translate
105
- element.style.maxHeight = maxHeight
106
- element.style.maxWidth = maxWidth
107
-
108
- const visualViewport = window.visualViewport
109
- const offsetLeft = visualViewport?.offsetLeft ?? 0
110
- const offsetTop = visualViewport?.offsetTop ?? 0
111
- const edges = screenEdges()
112
- const offsetParent = element.offsetParent
113
- const anchor =
114
- offsetParent instanceof HTMLElement && offsetParent !== document.body
115
- ? offsetParent.getBoundingClientRect()
116
- : undefined
117
- const trigger = anchorRef?.current?.getBoundingClientRect()
118
- const target = {
119
- left: trigger
120
- ? origin === "top-right"
121
- ? trigger.right - rect.width
122
- : trigger.left
123
- : rect.left,
124
- top: trigger?.top ?? rect.top,
125
- width: rect.width,
126
- height: neededHeight,
127
- }
128
- const next = fitPopover(
129
- target,
130
- trigger ?? anchor,
131
- {
132
- viewport: {
133
- width: offsetLeft + (visualViewport?.width ?? window.innerWidth),
134
- height: offsetTop + (visualViewport?.height ?? window.innerHeight),
135
- },
136
- edges: {
137
- ...edges,
138
- left: offsetLeft + edges.left,
139
- top: offsetTop + edges.top,
140
- },
141
- },
142
- trigger ? -trigger.height : 6,
143
- origin
144
- )
145
- next.shiftX += target.left - rect.left
146
- next.shiftY += target.top - rect.top
147
- setFit((current) => {
148
- if (
149
- current.shiftX === next.shiftX &&
150
- current.shiftY === next.shiftY &&
151
- current.maxWidth === next.maxWidth &&
152
- current.maxHeight === next.maxHeight &&
153
- current.above === next.above
154
- )
155
- return current
156
- return next
157
- })
158
- }
159
- refit()
160
- let frame = 0
161
- const scheduleRefit = () => {
162
- cancelAnimationFrame(frame)
163
- frame = requestAnimationFrame(refit)
164
- }
165
- const observer = new ResizeObserver(scheduleRefit)
166
- if (ref.current) observer.observe(ref.current)
167
- const viewport = window.visualViewport
168
- viewport?.addEventListener("resize", scheduleRefit)
169
- viewport?.addEventListener("scroll", scheduleRefit)
170
- window.addEventListener("resize", scheduleRefit)
171
- window.addEventListener("scroll", scheduleRefit, true)
172
- return () => {
173
- observer.disconnect()
174
- cancelAnimationFrame(frame)
175
- viewport?.removeEventListener("resize", scheduleRefit)
176
- viewport?.removeEventListener("scroll", scheduleRefit)
177
- window.removeEventListener("resize", scheduleRefit)
178
- window.removeEventListener("scroll", scheduleRefit, true)
179
- }
180
- }, [origin, anchorRef])
181
-
182
- useLayoutEffect(() => {
183
- const source = anchorRef?.current
184
- const panel = ref.current
185
- if (!source || !panel) return
186
- const sourceRect = source.getBoundingClientRect()
187
- const panelRect = panel.getBoundingClientRect()
188
- setReveal(
189
- menuSurfaceReveal(
190
- {
191
- left: sourceRect.left,
192
- top: sourceRect.top,
193
- width: sourceRect.width,
194
- height: sourceRect.height,
195
- },
196
- {
197
- left: panelRect.left,
198
- top: panelRect.top,
199
- width: fit.maxWidth || panelRect.width,
200
- height: fit.maxHeight
201
- ? Math.min(fit.maxHeight, panelRect.height)
202
- : panelRect.height,
203
- }
204
- )
205
- )
206
- }, [anchorRef, fit])
207
-
208
- useLayoutEffect(() => {
209
- const source = anchorRef?.current
210
- if (!source || !present) return
211
- const restoreSource = concealMenuSource(source, false)
212
- return () => {
213
- restoreSource()
214
- }
215
- }, [anchorRef, present])
216
-
217
- return (
218
- <motion.div
219
- ref={ref}
220
- {...(!anchorRef && popoverMotion)}
221
- initial={
222
- anchorRef
223
- ? { "--popover-content-opacity": reducedMotion ? 1 : 0 }
224
- : reducedMotion
225
- ? { opacity: 0 }
226
- : popoverMotion.initial
227
- }
228
- animate={
229
- anchorRef
230
- ? { "--popover-content-opacity": 1 }
231
- : reducedMotion
232
- ? { opacity: 1 }
233
- : popoverMotion.animate
234
- }
235
- exit={
236
- anchorRef
237
- ? {
238
- "--popover-content-opacity": 0,
239
- transition: { duration: reducedMotion ? 0 : 0.06 },
240
- }
241
- : reducedMotion
242
- ? { opacity: 0 }
243
- : popoverMotion.exit
244
- }
245
- transition={
246
- anchorRef
247
- ? reducedMotion
248
- ? { duration: 0 }
249
- : { duration: 0.16, delay: 0.06 }
250
- : reducedMotion
251
- ? { duration: 0 }
252
- : popoverMotion.transition
253
- }
254
- style={{
255
- transformOrigin:
256
- origin === "top-left"
257
- ? `0% ${fit.above ? "100%" : "0%"}`
258
- : `100% ${fit.above ? "100%" : "0%"}`,
259
- translate: `${fit.shiftX}px ${fit.shiftY}px`,
260
- maxWidth: fit.maxWidth || undefined,
261
- maxHeight: fit.maxHeight,
262
- overflowY:
263
- fit.maxHeight !== undefined && (!anchorRef || (present && settled))
264
- ? "auto"
265
- : undefined,
266
- ...style,
267
- }}
268
- className={cn(
269
- anchorRef
270
- ? "isolate [&>:not([data-popover-surface])]:opacity-[var(--popover-content-opacity)]"
271
- : "glass-menu",
272
- "absolute z-40 outline-none",
273
- surfaceRadius[size],
274
- className
275
- )}
276
- {...props}
277
- >
278
- {anchorRef && (
279
- <motion.div
280
- key={reveal ? "surface" : "measure"}
281
- aria-hidden="true"
282
- data-popover-surface=""
283
- onAnimationComplete={() => {
284
- if (reveal) setSettled(true)
285
- }}
286
- className={cn(
287
- "glass-menu pointer-events-none absolute top-0 left-0 -z-10",
288
- surfaceRadius[size]
289
- )}
290
- style={{ width: "100%", height: "100%" }}
291
- initial={reducedMotion || !reveal ? { opacity: 0 } : reveal}
292
- animate={
293
- reveal
294
- ? {
295
- x: 0,
296
- y: 0,
297
- width: material.width,
298
- height: fit.maxHeight
299
- ? Math.min(material.height, fit.maxHeight)
300
- : material.height,
301
- opacity: 1,
302
- borderRadius: material.radius,
303
- }
304
- : undefined
305
- }
306
- exit={
307
- reducedMotion || !reveal
308
- ? { opacity: 0 }
309
- : { ...menuSurfaceExit(reveal), transition: fluidCollapse }
310
- }
311
- transition={
312
- reducedMotion
313
- ? { duration: 0 }
314
- : { ...fluidOvershoot, opacity: { duration: 0.16 } }
315
- }
316
- />
317
- )}
318
- <motion.div
319
- initial={reducedMotion ? false : anchorRef ? { opacity: 0 } : undefined}
320
- animate={reducedMotion ? undefined : anchorRef ? { opacity: 1 } : undefined}
321
- exit={
322
- reducedMotion
323
- ? undefined
324
- : anchorRef
325
- ? { opacity: 0, transition: { duration: 0.12 } }
326
- : undefined
327
- }
328
- transition={reducedMotion ? { duration: 0 } : { duration: 0.16, delay: 0.06 }}
329
- >
330
- {children}
331
- </motion.div>
332
- </motion.div>
333
- )
334
- }