@boyernick/standard-ui-react 0.4.2-canary.69 → 0.4.2-canary.70
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/package.json +1 -1
- package/src/modal.tsx +10 -46
package/package.json
CHANGED
package/src/modal.tsx
CHANGED
|
@@ -36,8 +36,6 @@ import {
|
|
|
36
36
|
IconArrowDownSmall,
|
|
37
37
|
IconChevronRightSmall,
|
|
38
38
|
IconCrossSmall,
|
|
39
|
-
IconZoomIn,
|
|
40
|
-
IconZoomOut,
|
|
41
39
|
} from "./icons"
|
|
42
40
|
import { cn } from "./lib/cn"
|
|
43
41
|
import { focusRing, focusRingBorder } from "./lib/focus"
|
|
@@ -89,10 +87,7 @@ export type ModalContentProps = Omit<
|
|
|
89
87
|
downloadName?: string
|
|
90
88
|
imgProps?: Omit<ImgHTMLAttributes<HTMLImageElement>, "src" | "alt">
|
|
91
89
|
children?: ReactNode
|
|
92
|
-
/**
|
|
93
|
-
* Magnification when the image is clicked or the zoom control pressed.
|
|
94
|
-
* `false` turns zoom off. Default 2.
|
|
95
|
-
*/
|
|
90
|
+
/** Magnification when the image is clicked. `false` turns zoom off. Default 2. */
|
|
96
91
|
zoom?: number | false
|
|
97
92
|
}
|
|
98
93
|
|
|
@@ -234,7 +229,10 @@ const ModalImage = ({
|
|
|
234
229
|
? "motion-safe:[transition:opacity_var(--duration-lg)_linear,scale_var(--duration-md)_var(--ease-move),translate_var(--duration-md)_var(--ease-move)] motion-safe:data-[panning]:[transition-property:opacity,scale]"
|
|
235
230
|
: "transition-opacity duration-[var(--duration-lg)] ease-linear motion-reduce:transition-none",
|
|
236
231
|
!loaded && "opacity-0",
|
|
237
|
-
|
|
232
|
+
// Sized by the image itself: width and height attributes with
|
|
233
|
+
// separate max caps made a box of another shape, which object-contain
|
|
234
|
+
// letterboxed, leaving the rounded corners on empty space.
|
|
235
|
+
"h-auto w-auto rounded-lg object-contain shadow-lg select-none",
|
|
238
236
|
// Scaled from the top-left, so the pan lands the image exactly where
|
|
239
237
|
// it is measured.
|
|
240
238
|
zoom && "origin-top-left",
|
|
@@ -325,34 +323,6 @@ const ModalDismiss = () => (
|
|
|
325
323
|
</ModalControlTooltip>
|
|
326
324
|
)
|
|
327
325
|
|
|
328
|
-
const ModalZoom = ({
|
|
329
|
-
zoomed,
|
|
330
|
-
onToggle,
|
|
331
|
-
}: {
|
|
332
|
-
zoomed: boolean
|
|
333
|
-
onToggle: () => void
|
|
334
|
-
}) => (
|
|
335
|
-
<ModalControlTooltip label={zoomed ? "Zoom out" : "Zoom in"}>
|
|
336
|
-
<GlassButton
|
|
337
|
-
type="button"
|
|
338
|
-
config={mediaGlass}
|
|
339
|
-
size="md"
|
|
340
|
-
iconOnly
|
|
341
|
-
rounded
|
|
342
|
-
aria-label={zoomed ? "Zoom out" : "Zoom in"}
|
|
343
|
-
aria-pressed={zoomed}
|
|
344
|
-
onClick={onToggle}
|
|
345
|
-
className={cn(
|
|
346
|
-
modalControlClassName,
|
|
347
|
-
// Beside Download: 16px inset, a 36px control and an 8px gap.
|
|
348
|
-
"absolute top-4 left-15 z-20",
|
|
349
|
-
)}
|
|
350
|
-
>
|
|
351
|
-
{zoomed ? <IconZoomOut aria-hidden /> : <IconZoomIn aria-hidden />}
|
|
352
|
-
</GlassButton>
|
|
353
|
-
</ModalControlTooltip>
|
|
354
|
-
)
|
|
355
|
-
|
|
356
326
|
const ModalCaption = ({ children, hidden }: { children: ReactNode; hidden?: boolean }) => (
|
|
357
327
|
<p
|
|
358
328
|
className={cn(
|
|
@@ -367,8 +337,8 @@ const ModalCaption = ({ children, hidden }: { children: ReactNode; hidden?: bool
|
|
|
367
337
|
)
|
|
368
338
|
|
|
369
339
|
/**
|
|
370
|
-
* Zoom for one image:
|
|
371
|
-
* mouse or pen pans by moving; a finger drags
|
|
340
|
+
* Zoom for one image: a click magnifies at the point, then the image pans
|
|
341
|
+
* under the pointer. A mouse or pen pans by moving; a finger drags.
|
|
372
342
|
*/
|
|
373
343
|
function useImageZoom(scale: number | false) {
|
|
374
344
|
const [zoomed, setZoomed] = useState(false)
|
|
@@ -378,22 +348,17 @@ function useImageZoom(scale: number | false) {
|
|
|
378
348
|
const aim = useRef({ x: 0, y: 0 })
|
|
379
349
|
|
|
380
350
|
const toggle = useCallback(
|
|
381
|
-
(x
|
|
351
|
+
(x: number, y: number) => {
|
|
382
352
|
const image = imageRef.current
|
|
383
353
|
const frame = frameRef.current
|
|
384
354
|
if (!scale || !image || !frame) return
|
|
385
|
-
const bounds = frame.getBoundingClientRect()
|
|
386
355
|
// The zoom itself eases, towards the point.
|
|
387
356
|
delete image.dataset.panning
|
|
388
357
|
if (zoomed) {
|
|
389
358
|
image.style.translate = "0px 0px"
|
|
390
359
|
} else {
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
x: x ?? bounds.left + bounds.width / 2,
|
|
394
|
-
y: y ?? bounds.top + bounds.height / 2,
|
|
395
|
-
}
|
|
396
|
-
panZoomedImage(image, bounds, aim.current.x, aim.current.y, scale)
|
|
360
|
+
aim.current = { x, y }
|
|
361
|
+
panZoomedImage(image, frame.getBoundingClientRect(), x, y, scale)
|
|
397
362
|
}
|
|
398
363
|
setZoomed(!zoomed)
|
|
399
364
|
},
|
|
@@ -507,7 +472,6 @@ export const ModalContent = ({
|
|
|
507
472
|
src={downloadSrc ?? src}
|
|
508
473
|
name={downloadName}
|
|
509
474
|
/>
|
|
510
|
-
{zoom ? <ModalZoom zoomed={zoomed} onToggle={() => toggle()} /> : null}
|
|
511
475
|
</GlassRoot>
|
|
512
476
|
</TooltipProvider>
|
|
513
477
|
</DialogPopup>
|