@orz/ui-content 0.0.0-stage → 0.0.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/LICENSE +29 -0
- package/README.md +410 -2
- package/dist/attachment/card-content.d.ts +26 -0
- package/dist/attachment/card-content.d.ts.map +1 -0
- package/dist/attachment/card-content.js +49 -0
- package/dist/attachment/card-content.js.map +1 -0
- package/dist/attachment/deleted.d.ts +9 -0
- package/dist/attachment/deleted.d.ts.map +1 -0
- package/dist/attachment/deleted.js +11 -0
- package/dist/attachment/deleted.js.map +1 -0
- package/dist/attachment/document-card.d.ts +32 -0
- package/dist/attachment/document-card.d.ts.map +1 -0
- package/dist/attachment/document-card.js +38 -0
- package/dist/attachment/document-card.js.map +1 -0
- package/dist/attachment/icon.d.ts +13 -0
- package/dist/attachment/icon.d.ts.map +1 -0
- package/dist/attachment/icon.js +34 -0
- package/dist/attachment/icon.js.map +1 -0
- package/dist/attachment/image-canvas.d.ts +25 -0
- package/dist/attachment/image-canvas.d.ts.map +1 -0
- package/dist/attachment/image-canvas.js +301 -0
- package/dist/attachment/image-canvas.js.map +1 -0
- package/dist/attachment/image-look.d.ts +18 -0
- package/dist/attachment/image-look.d.ts.map +1 -0
- package/dist/attachment/image-look.js +86 -0
- package/dist/attachment/image-look.js.map +1 -0
- package/dist/attachment/image-zoom.d.ts +67 -0
- package/dist/attachment/image-zoom.d.ts.map +1 -0
- package/dist/attachment/image-zoom.js +108 -0
- package/dist/attachment/image-zoom.js.map +1 -0
- package/dist/attachment/index.d.ts +12 -0
- package/dist/attachment/index.d.ts.map +1 -0
- package/dist/attachment/index.js +12 -0
- package/dist/attachment/index.js.map +1 -0
- package/dist/attachment/link.d.ts +18 -0
- package/dist/attachment/link.d.ts.map +1 -0
- package/dist/attachment/link.js +30 -0
- package/dist/attachment/link.js.map +1 -0
- package/dist/attachment/list.d.ts +26 -0
- package/dist/attachment/list.d.ts.map +1 -0
- package/dist/attachment/list.js +53 -0
- package/dist/attachment/list.js.map +1 -0
- package/dist/attachment/media-content.d.ts +21 -0
- package/dist/attachment/media-content.d.ts.map +1 -0
- package/dist/attachment/media-content.js +133 -0
- package/dist/attachment/media-content.js.map +1 -0
- package/dist/attachment/media-player.d.ts +23 -0
- package/dist/attachment/media-player.d.ts.map +1 -0
- package/dist/attachment/media-player.js +137 -0
- package/dist/attachment/media-player.js.map +1 -0
- package/dist/attachment/use-media.d.ts +27 -0
- package/dist/attachment/use-media.d.ts.map +1 -0
- package/dist/attachment/use-media.js +133 -0
- package/dist/attachment/use-media.js.map +1 -0
- package/dist/attachment/viewer.d.ts +85 -0
- package/dist/attachment/viewer.d.ts.map +1 -0
- package/dist/attachment/viewer.js +245 -0
- package/dist/attachment/viewer.js.map +1 -0
- package/dist/file-kind.d.ts +61 -0
- package/dist/file-kind.d.ts.map +1 -0
- package/dist/file-kind.js +166 -0
- package/dist/file-kind.js.map +1 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +5 -0
- package/dist/index.js.map +1 -0
- package/dist/registry.d.ts +44 -0
- package/dist/registry.d.ts.map +1 -0
- package/dist/registry.js +109 -0
- package/dist/registry.js.map +1 -0
- package/dist/source-text.d.ts +29 -0
- package/dist/source-text.d.ts.map +1 -0
- package/dist/source-text.js +101 -0
- package/dist/source-text.js.map +1 -0
- package/dist/title-bar.d.ts +23 -0
- package/dist/title-bar.d.ts.map +1 -0
- package/dist/title-bar.js +24 -0
- package/dist/title-bar.js.map +1 -0
- package/dist/types.d.ts +48 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/package.json +55 -3
- package/styles.css +4 -0
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { MediaControls } from "@orz/ui/components/media-controls";
|
|
3
|
+
import { cn } from "@orz/ui/lib/utils";
|
|
4
|
+
import { Play } from "lucide-react";
|
|
5
|
+
import { useCallback, useEffect, useRef, useState, } from "react";
|
|
6
|
+
import { useMedia } from "./use-media.js";
|
|
7
|
+
/** A video under the shared control bar, with picture-in-picture and fullscreen where the browser offers them. */
|
|
8
|
+
export function VideoPlayer(props) {
|
|
9
|
+
// A different file starts over: no position, no error, to carry.
|
|
10
|
+
return _jsx(MediaFrame, { kind: "video", ...props }, props.src);
|
|
11
|
+
}
|
|
12
|
+
/** An audio file as a header over the shared control bar; the element itself is not drawn. */
|
|
13
|
+
export function AudioPlayer(props) {
|
|
14
|
+
return _jsx(MediaFrame, { kind: "audio", ...props }, props.src);
|
|
15
|
+
}
|
|
16
|
+
const SEEK_STEP = 5;
|
|
17
|
+
/** Keys a focused control already acts on, which the frame leaves to it. */
|
|
18
|
+
const SLIDER_KEYS = new Set([
|
|
19
|
+
"ArrowLeft",
|
|
20
|
+
"ArrowRight",
|
|
21
|
+
"ArrowUp",
|
|
22
|
+
"ArrowDown",
|
|
23
|
+
"Home",
|
|
24
|
+
"End",
|
|
25
|
+
"PageUp",
|
|
26
|
+
"PageDown",
|
|
27
|
+
]);
|
|
28
|
+
const BUTTON_KEYS = new Set([" ", "Enter"]);
|
|
29
|
+
function ownsKey(target, key) {
|
|
30
|
+
if (!(target instanceof Element))
|
|
31
|
+
return false;
|
|
32
|
+
if (target.closest("input, textarea, [role=combobox], [role=listbox], [role=option]") !== null) {
|
|
33
|
+
return true;
|
|
34
|
+
}
|
|
35
|
+
if (target.closest("[role=slider]") !== null)
|
|
36
|
+
return SLIDER_KEYS.has(key);
|
|
37
|
+
if (target.closest("button") !== null)
|
|
38
|
+
return BUTTON_KEYS.has(key);
|
|
39
|
+
return false;
|
|
40
|
+
}
|
|
41
|
+
const UNPLAYABLE = "This browser can't play this file.";
|
|
42
|
+
function MediaFrame({ kind, src, title, header, autoPlay = false, loop = false, speed = 1, onError, className, }) {
|
|
43
|
+
const frameRef = useRef(null);
|
|
44
|
+
const [element, setElement] = useState(null);
|
|
45
|
+
const [media, actions] = useMedia(element);
|
|
46
|
+
const [fullscreen, setFullscreen] = useState(false);
|
|
47
|
+
// Read after mount, so a server render and the first client render agree.
|
|
48
|
+
const [fullscreenEnabled, setFullscreenEnabled] = useState(false);
|
|
49
|
+
const [pipEnabled, setPipEnabled] = useState(false);
|
|
50
|
+
const video = kind === "video";
|
|
51
|
+
useEffect(() => {
|
|
52
|
+
if (element === null)
|
|
53
|
+
return;
|
|
54
|
+
// A load resets playbackRate to the default, so both are set.
|
|
55
|
+
element.defaultPlaybackRate = speed;
|
|
56
|
+
element.playbackRate = speed;
|
|
57
|
+
}, [element, speed]);
|
|
58
|
+
const onErrorRef = useRef(onError);
|
|
59
|
+
onErrorRef.current = onError;
|
|
60
|
+
useEffect(() => {
|
|
61
|
+
if (media.failed)
|
|
62
|
+
onErrorRef.current?.(media.error);
|
|
63
|
+
}, [media.failed, media.error]);
|
|
64
|
+
useEffect(() => {
|
|
65
|
+
if (!video)
|
|
66
|
+
return;
|
|
67
|
+
setFullscreenEnabled(document.fullscreenEnabled === true);
|
|
68
|
+
setPipEnabled(document.pictureInPictureEnabled === true);
|
|
69
|
+
const onChange = () => setFullscreen(document.fullscreenElement !== null &&
|
|
70
|
+
document.fullscreenElement === frameRef.current);
|
|
71
|
+
document.addEventListener("fullscreenchange", onChange);
|
|
72
|
+
return () => document.removeEventListener("fullscreenchange", onChange);
|
|
73
|
+
}, [video]);
|
|
74
|
+
const toggleFullscreen = useCallback(() => {
|
|
75
|
+
const frame = frameRef.current;
|
|
76
|
+
if (frame === null || !document.fullscreenEnabled)
|
|
77
|
+
return;
|
|
78
|
+
// Refused when the call lacks a user gesture, say; the frame just stays as
|
|
79
|
+
// it is.
|
|
80
|
+
const ignore = () => { };
|
|
81
|
+
if (document.fullscreenElement === frame) {
|
|
82
|
+
document.exitFullscreen().catch(ignore);
|
|
83
|
+
}
|
|
84
|
+
else {
|
|
85
|
+
frame.requestFullscreen().catch(ignore);
|
|
86
|
+
}
|
|
87
|
+
}, []);
|
|
88
|
+
const known = Number.isFinite(media.duration);
|
|
89
|
+
const seekBy = (delta) => {
|
|
90
|
+
const to = Math.max(0, media.time + delta);
|
|
91
|
+
actions.seek(known ? Math.min(to, media.duration) : to);
|
|
92
|
+
};
|
|
93
|
+
const onKeyDown = (event) => {
|
|
94
|
+
if (event.altKey || event.metaKey || event.ctrlKey)
|
|
95
|
+
return;
|
|
96
|
+
if (event.defaultPrevented || ownsKey(event.target, event.key))
|
|
97
|
+
return;
|
|
98
|
+
const key = event.key;
|
|
99
|
+
if (key === " " || key === "k")
|
|
100
|
+
actions.toggle();
|
|
101
|
+
else if (key === "ArrowLeft")
|
|
102
|
+
seekBy(-SEEK_STEP);
|
|
103
|
+
else if (key === "ArrowRight")
|
|
104
|
+
seekBy(SEEK_STEP);
|
|
105
|
+
else if (/^[0-9]$/.test(key) && known) {
|
|
106
|
+
actions.seek((Number(key) / 10) * media.duration);
|
|
107
|
+
}
|
|
108
|
+
else if (key === "m")
|
|
109
|
+
actions.mute();
|
|
110
|
+
else if (key === "f" && video && fullscreenEnabled)
|
|
111
|
+
toggleFullscreen();
|
|
112
|
+
else
|
|
113
|
+
return;
|
|
114
|
+
event.preventDefault();
|
|
115
|
+
};
|
|
116
|
+
if (media.failed && onError !== undefined)
|
|
117
|
+
return null;
|
|
118
|
+
const unplayable = (_jsx("p", { "data-slot": "media-error", className: "px-3 py-4 text-center text-muted-foreground text-sm", children: UNPLAYABLE }));
|
|
119
|
+
const controls = (_jsx(MediaControls, { playing: media.playing, time: media.time, duration: media.duration, speed: media.speed, buffered: media.buffered, disabled: element === null || media.failed, portal: fullscreen ? frameRef.current : undefined, onToggle: actions.toggle, onSeek: actions.seek, onSpeed: actions.setSpeed, volume: {
|
|
120
|
+
level: media.level,
|
|
121
|
+
muted: media.muted,
|
|
122
|
+
onLevel: actions.setLevel,
|
|
123
|
+
onMute: actions.mute,
|
|
124
|
+
}, fullscreen: video && fullscreenEnabled
|
|
125
|
+
? { active: fullscreen, onToggle: toggleFullscreen }
|
|
126
|
+
: undefined, pictureInPicture: video && pipEnabled
|
|
127
|
+
? { active: media.pip, onToggle: actions.togglePip }
|
|
128
|
+
: undefined, className: cn(!video && "border-t-0") }));
|
|
129
|
+
return (_jsxs("div", { ref: frameRef, "data-slot": video ? "video-player" : "audio-player", title: title, className: cn("overflow-hidden rounded-lg border [&:fullscreen]:rounded-none [&:fullscreen]:border-0", video ? "bg-black" : "bg-card", fullscreen && "flex flex-col", className), onKeyDown: onKeyDown, children: [header, video ? (_jsx("section", { "data-slot": "media-screen",
|
|
130
|
+
// biome-ignore lint/a11y/noNoninteractiveTabindex: the picture is where the keyboard shortcuts start, as a native video's is
|
|
131
|
+
tabIndex: 0, "aria-label": title, className: cn("relative outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-inset", fullscreen && "min-h-0 flex-1"), children: media.failed ? (unplayable) : (_jsxs(_Fragment, { children: [_jsx("video", { ref: setElement, src: src,
|
|
132
|
+
// A page of embeds must not download every file.
|
|
133
|
+
preload: "metadata", playsInline: true, autoPlay: autoPlay, loop: loop, className: cn("block w-full object-contain", fullscreen && "h-full"), onClick: actions.toggle }), !media.started && element !== null && (_jsx("button", { type: "button", "aria-label": "Play video",
|
|
134
|
+
// The bar's play button is the keyboard's way in.
|
|
135
|
+
tabIndex: -1, className: "absolute inset-0 grid cursor-pointer place-items-center bg-black/40 outline-none", onClick: actions.toggle, children: _jsx("span", { className: "grid size-14 place-items-center rounded-full bg-white/85 text-black shadow-md", children: _jsx(Play, { className: "size-6 translate-x-0.5 fill-current" }) }) }))] })) })) : (_jsx("audio", { ref: setElement, src: src, preload: "metadata", autoPlay: autoPlay, loop: loop, "aria-label": title, className: "hidden" })), !video && media.failed ? unplayable : controls] }));
|
|
136
|
+
}
|
|
137
|
+
//# sourceMappingURL=media-player.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"media-player.js","sourceRoot":"","sources":["../../src/attachment/media-player.tsx"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
export type MediaState = {
|
|
2
|
+
playing: boolean;
|
|
3
|
+
/** Played, or seeked, at least once: the poster overlay is gone. */
|
|
4
|
+
started: boolean;
|
|
5
|
+
time: number;
|
|
6
|
+
/** Seconds; NaN before the metadata, Infinity for a stream or an unfinished recording. */
|
|
7
|
+
duration: number;
|
|
8
|
+
buffered: [start: number, end: number][];
|
|
9
|
+
level: number;
|
|
10
|
+
muted: boolean;
|
|
11
|
+
speed: number;
|
|
12
|
+
pip: boolean;
|
|
13
|
+
/** The element failed to load or decode its source. */
|
|
14
|
+
failed: boolean;
|
|
15
|
+
error: MediaError | null;
|
|
16
|
+
};
|
|
17
|
+
export type MediaActions = {
|
|
18
|
+
toggle(): void;
|
|
19
|
+
seek(time: number): void;
|
|
20
|
+
setLevel(level: number): void;
|
|
21
|
+
mute(): void;
|
|
22
|
+
setSpeed(speed: number): void;
|
|
23
|
+
togglePip(): void;
|
|
24
|
+
};
|
|
25
|
+
/** The control bar's values, read from a media element's events, and the actions on it. */
|
|
26
|
+
export declare function useMedia(element: HTMLMediaElement | null): [MediaState, MediaActions];
|
|
27
|
+
//# sourceMappingURL=use-media.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"use-media.d.ts","sourceRoot":"","sources":["../../src/attachment/use-media.ts"],"names":[],"mappings":"AAEA,MAAM,MAAM,UAAU,GAAG;IACvB,OAAO,EAAE,OAAO,CAAC;IACjB,oEAAoE;IACpE,OAAO,EAAE,OAAO,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,0FAA0F;IAC1F,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,CAAC,EAAE,CAAC;IACzC,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,OAAO,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,GAAG,EAAE,OAAO,CAAC;IACb,uDAAuD;IACvD,MAAM,EAAE,OAAO,CAAC;IAChB,KAAK,EAAE,UAAU,GAAG,IAAI,CAAC;CAC1B,CAAC;AAEF,MAAM,MAAM,YAAY,GAAG;IACzB,MAAM,IAAI,IAAI,CAAC;IACf,IAAI,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,IAAI,IAAI,IAAI,CAAC;IACb,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,SAAS,IAAI,IAAI,CAAC;CACnB,CAAC;AA2CF,2FAA2F;AAC3F,wBAAgB,QAAQ,CACtB,OAAO,EAAE,gBAAgB,GAAG,IAAI,GAC/B,CAAC,UAAU,EAAE,YAAY,CAAC,CA6F5B"}
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
import { useCallback, useEffect, useMemo, useState } from "react";
|
|
2
|
+
const INITIAL = {
|
|
3
|
+
playing: false,
|
|
4
|
+
started: false,
|
|
5
|
+
time: 0,
|
|
6
|
+
duration: Number.NaN,
|
|
7
|
+
buffered: [],
|
|
8
|
+
level: 1,
|
|
9
|
+
muted: false,
|
|
10
|
+
speed: 1,
|
|
11
|
+
pip: false,
|
|
12
|
+
failed: false,
|
|
13
|
+
error: null,
|
|
14
|
+
};
|
|
15
|
+
const EVENTS = [
|
|
16
|
+
"play",
|
|
17
|
+
"pause",
|
|
18
|
+
"ended",
|
|
19
|
+
"timeupdate",
|
|
20
|
+
"seeked",
|
|
21
|
+
"loadedmetadata",
|
|
22
|
+
"durationchange",
|
|
23
|
+
"progress",
|
|
24
|
+
"volumechange",
|
|
25
|
+
"ratechange",
|
|
26
|
+
"enterpictureinpicture",
|
|
27
|
+
"leavepictureinpicture",
|
|
28
|
+
];
|
|
29
|
+
/** A refused play() or picture-in-picture request (autoplay policy, an aborted load) changes nothing. */
|
|
30
|
+
const ignore = () => { };
|
|
31
|
+
function rangesOf(ranges) {
|
|
32
|
+
const pairs = [];
|
|
33
|
+
if (ranges === undefined)
|
|
34
|
+
return pairs;
|
|
35
|
+
for (let i = 0; i < ranges.length; i++) {
|
|
36
|
+
pairs.push([ranges.start(i), ranges.end(i)]);
|
|
37
|
+
}
|
|
38
|
+
return pairs;
|
|
39
|
+
}
|
|
40
|
+
/** The control bar's values, read from a media element's events, and the actions on it. */
|
|
41
|
+
export function useMedia(element) {
|
|
42
|
+
const [state, setState] = useState(INITIAL);
|
|
43
|
+
const read = useCallback((media) => {
|
|
44
|
+
setState((previous) => ({
|
|
45
|
+
playing: !media.paused,
|
|
46
|
+
started: previous.started || !media.paused,
|
|
47
|
+
time: media.currentTime,
|
|
48
|
+
duration: media.duration,
|
|
49
|
+
buffered: rangesOf(media.buffered),
|
|
50
|
+
level: media.volume,
|
|
51
|
+
muted: media.muted,
|
|
52
|
+
speed: media.playbackRate,
|
|
53
|
+
pip: typeof document !== "undefined" &&
|
|
54
|
+
document.pictureInPictureElement === media,
|
|
55
|
+
failed: previous.failed,
|
|
56
|
+
error: previous.error,
|
|
57
|
+
}));
|
|
58
|
+
}, []);
|
|
59
|
+
useEffect(() => {
|
|
60
|
+
if (element === null)
|
|
61
|
+
return;
|
|
62
|
+
const onEvent = () => read(element);
|
|
63
|
+
const onError = () => setState((previous) => ({
|
|
64
|
+
...previous,
|
|
65
|
+
playing: false,
|
|
66
|
+
failed: true,
|
|
67
|
+
error: element.error,
|
|
68
|
+
}));
|
|
69
|
+
read(element);
|
|
70
|
+
for (const name of EVENTS)
|
|
71
|
+
element.addEventListener(name, onEvent);
|
|
72
|
+
element.addEventListener("error", onError);
|
|
73
|
+
return () => {
|
|
74
|
+
for (const name of EVENTS)
|
|
75
|
+
element.removeEventListener(name, onEvent);
|
|
76
|
+
element.removeEventListener("error", onError);
|
|
77
|
+
};
|
|
78
|
+
}, [element, read]);
|
|
79
|
+
useEffect(() => {
|
|
80
|
+
if (element === null || !state.playing)
|
|
81
|
+
return;
|
|
82
|
+
// The cast bar's cadence; timeupdate alone comes about every 250 ms.
|
|
83
|
+
const interval = setInterval(() => setState((previous) => ({ ...previous, time: element.currentTime })), 100);
|
|
84
|
+
return () => clearInterval(interval);
|
|
85
|
+
}, [element, state.playing]);
|
|
86
|
+
const actions = useMemo(() => ({
|
|
87
|
+
toggle() {
|
|
88
|
+
if (element === null)
|
|
89
|
+
return;
|
|
90
|
+
if (element.paused) {
|
|
91
|
+
// Not every implementation returns the promise.
|
|
92
|
+
element.play()?.catch(ignore);
|
|
93
|
+
}
|
|
94
|
+
else {
|
|
95
|
+
element.pause();
|
|
96
|
+
}
|
|
97
|
+
},
|
|
98
|
+
seek(time) {
|
|
99
|
+
if (element === null)
|
|
100
|
+
return;
|
|
101
|
+
element.currentTime = time;
|
|
102
|
+
setState((previous) => ({ ...previous, time, started: true }));
|
|
103
|
+
},
|
|
104
|
+
setLevel(level) {
|
|
105
|
+
if (element === null)
|
|
106
|
+
return;
|
|
107
|
+
element.volume = level;
|
|
108
|
+
element.muted = false;
|
|
109
|
+
},
|
|
110
|
+
mute() {
|
|
111
|
+
if (element === null)
|
|
112
|
+
return;
|
|
113
|
+
element.muted = !element.muted;
|
|
114
|
+
},
|
|
115
|
+
setSpeed(speed) {
|
|
116
|
+
if (element === null)
|
|
117
|
+
return;
|
|
118
|
+
element.playbackRate = speed;
|
|
119
|
+
},
|
|
120
|
+
togglePip() {
|
|
121
|
+
if (!(element instanceof HTMLVideoElement))
|
|
122
|
+
return;
|
|
123
|
+
if (document.pictureInPictureElement === element) {
|
|
124
|
+
document.exitPictureInPicture().catch(ignore);
|
|
125
|
+
}
|
|
126
|
+
else {
|
|
127
|
+
element.requestPictureInPicture().catch(ignore);
|
|
128
|
+
}
|
|
129
|
+
},
|
|
130
|
+
}), [element]);
|
|
131
|
+
return [state, actions];
|
|
132
|
+
}
|
|
133
|
+
//# sourceMappingURL=use-media.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"use-media.js","sourceRoot":"","sources":["../../src/attachment/use-media.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import { type ReactNode } from "react";
|
|
2
|
+
import type { ContentSource } from "../types.ts";
|
|
3
|
+
import { type ImageLook } from "./image-look.ts";
|
|
4
|
+
export type FileSource = Extract<ContentSource, {
|
|
5
|
+
kind: "file";
|
|
6
|
+
}>;
|
|
7
|
+
/** What the viewer is showing: a set of files and a position in it. */
|
|
8
|
+
export type AttachmentViewerState = {
|
|
9
|
+
items: FileSource[];
|
|
10
|
+
index: number;
|
|
11
|
+
};
|
|
12
|
+
export type AttachmentViewerControls = {
|
|
13
|
+
/** Opens the viewer on `items[index]`, paging through `items`. */
|
|
14
|
+
open(items: FileSource[], index: number): void;
|
|
15
|
+
/** Opens the viewer on one file, paging through the set `group` gives it. */
|
|
16
|
+
show(file: FileSource): void;
|
|
17
|
+
};
|
|
18
|
+
type ViewerImage = {
|
|
19
|
+
/** Whether the dialog fills the window. */
|
|
20
|
+
maximized: boolean;
|
|
21
|
+
look: ImageLook;
|
|
22
|
+
setLook(look: ImageLook): void;
|
|
23
|
+
/** The last image's canvas height, so the next one tweens from it. */
|
|
24
|
+
lastHeight: {
|
|
25
|
+
current: number | null;
|
|
26
|
+
};
|
|
27
|
+
/** The height the canvas keeps while the pointer is on the title-bar controls. */
|
|
28
|
+
held: number | null;
|
|
29
|
+
};
|
|
30
|
+
/** What the image renderer needs from the viewer around it; null outside one. */
|
|
31
|
+
export declare function useViewerImage(): ViewerImage | null;
|
|
32
|
+
type ImageLookProps = {
|
|
33
|
+
/** The image background and scaling, controlled. Default: held in memory by the viewer. */
|
|
34
|
+
imageLook?: ImageLook;
|
|
35
|
+
/** Called when the reader picks another background or scaling. */
|
|
36
|
+
onImageLookChange?(look: ImageLook): void;
|
|
37
|
+
};
|
|
38
|
+
export type AttachmentViewerProviderProps = {
|
|
39
|
+
/** Where a browser tab shows this file; undefined when it would only download. */
|
|
40
|
+
viewHref?: (file: FileSource) => string | undefined;
|
|
41
|
+
/** The set paging covers when a single file is opened; null pages nothing. */
|
|
42
|
+
group?: (file: FileSource) => AttachmentViewerState | null;
|
|
43
|
+
/**
|
|
44
|
+
* Text files above this wait for "Preview anyway" and then draw plain. Default 1 MiB. A text
|
|
45
|
+
* file of unknown size stays a link until its size is known.
|
|
46
|
+
*/
|
|
47
|
+
textPreviewMaxBytes?: number;
|
|
48
|
+
/** Text files above this never preview; the viewer says so. Default 10 MiB. */
|
|
49
|
+
textPreviewHardMaxBytes?: number;
|
|
50
|
+
children?: ReactNode;
|
|
51
|
+
} & ImageLookProps;
|
|
52
|
+
/**
|
|
53
|
+
* Owns one viewer dialog for everything below it: link chips, inline images,
|
|
54
|
+
* list rows and document cards all open this one rather than mounting a
|
|
55
|
+
* dialog each. A nested provider shadows the outer one.
|
|
56
|
+
*/
|
|
57
|
+
export declare function AttachmentViewerProvider({ viewHref, group, textPreviewMaxBytes, textPreviewHardMaxBytes, imageLook, onImageLookChange, children, }: AttachmentViewerProviderProps): import("react").JSX.Element;
|
|
58
|
+
/** The nearest provider's controls, or null outside one. */
|
|
59
|
+
export declare function useAttachmentViewer(): AttachmentViewerControls | null;
|
|
60
|
+
/** Where an anchor to this file points: the provider's `viewHref`, else the file's `url`. */
|
|
61
|
+
export declare function useViewHref(file: FileSource): string;
|
|
62
|
+
/**
|
|
63
|
+
* Whether the viewer has something to draw for this file, which is what
|
|
64
|
+
* decides if a plain click on it is hijacked into the viewer. Text needs a
|
|
65
|
+
* known size — a file whose size the app does not know yet stays a link
|
|
66
|
+
* until it does; a size past the limits still opens the viewer, which says
|
|
67
|
+
* why it shows nothing. HTML has no size cap: the browser streams it into
|
|
68
|
+
* the iframe instead of this tab highlighting it.
|
|
69
|
+
*/
|
|
70
|
+
export declare function useCanPreview(file: FileSource): boolean;
|
|
71
|
+
export type AttachmentViewerProps = {
|
|
72
|
+
/** null, or an index outside `items`: closed. */
|
|
73
|
+
state: AttachmentViewerState | null;
|
|
74
|
+
onNavigate(index: number): void;
|
|
75
|
+
onClose(): void;
|
|
76
|
+
} & ImageLookProps;
|
|
77
|
+
/**
|
|
78
|
+
* The viewer dialog, controlled: one file at a time drawn by the registry in
|
|
79
|
+
* "viewer" placement, or a download pane when nothing can draw it. A set
|
|
80
|
+
* pages with ‹ › / arrow keys, and the controls live in the title bar, never
|
|
81
|
+
* floated over the content.
|
|
82
|
+
*/
|
|
83
|
+
export declare function AttachmentViewer({ state, onNavigate, onClose, imageLook, onImageLookChange, }: AttachmentViewerProps): import("react").JSX.Element;
|
|
84
|
+
export {};
|
|
85
|
+
//# sourceMappingURL=viewer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"viewer.d.ts","sourceRoot":"","sources":["../../src/attachment/viewer.tsx"],"names":[],"mappings":"AAiBA,OAAO,EAGL,KAAK,SAAS,EAOf,MAAM,OAAO,CAAC;AAYf,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AACjD,OAAO,EAAsB,KAAK,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAErE,MAAM,MAAM,UAAU,GAAG,OAAO,CAAC,aAAa,EAAE;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC,CAAC;AAOlE,uEAAuE;AACvE,MAAM,MAAM,qBAAqB,GAAG;IAAE,KAAK,EAAE,UAAU,EAAE,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC;AAE3E,MAAM,MAAM,wBAAwB,GAAG;IACrC,kEAAkE;IAClE,IAAI,CAAC,KAAK,EAAE,UAAU,EAAE,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IAC/C,6EAA6E;IAC7E,IAAI,CAAC,IAAI,EAAE,UAAU,GAAG,IAAI,CAAC;CAC9B,CAAC;AAUF,KAAK,WAAW,GAAG;IACjB,2CAA2C;IAC3C,SAAS,EAAE,OAAO,CAAC;IACnB,IAAI,EAAE,SAAS,CAAC;IAChB,OAAO,CAAC,IAAI,EAAE,SAAS,GAAG,IAAI,CAAC;IAC/B,sEAAsE;IACtE,UAAU,EAAE;QAAE,OAAO,EAAE,MAAM,GAAG,IAAI,CAAA;KAAE,CAAC;IACvC,kFAAkF;IAClF,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;CACrB,CAAC;AAIF,iFAAiF;AACjF,wBAAgB,cAAc,IAAI,WAAW,GAAG,IAAI,CAEnD;AAED,KAAK,cAAc,GAAG;IACpB,2FAA2F;IAC3F,SAAS,CAAC,EAAE,SAAS,CAAC;IACtB,kEAAkE;IAClE,iBAAiB,CAAC,CAAC,IAAI,EAAE,SAAS,GAAG,IAAI,CAAC;CAC3C,CAAC;AAEF,MAAM,MAAM,6BAA6B,GAAG;IAC1C,kFAAkF;IAClF,QAAQ,CAAC,EAAE,CAAC,IAAI,EAAE,UAAU,KAAK,MAAM,GAAG,SAAS,CAAC;IACpD,8EAA8E;IAC9E,KAAK,CAAC,EAAE,CAAC,IAAI,EAAE,UAAU,KAAK,qBAAqB,GAAG,IAAI,CAAC;IAC3D;;;OAGG;IACH,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,+EAA+E;IAC/E,uBAAuB,CAAC,EAAE,MAAM,CAAC;IACjC,QAAQ,CAAC,EAAE,SAAS,CAAC;CACtB,GAAG,cAAc,CAAC;AAEnB;;;;GAIG;AACH,wBAAgB,wBAAwB,CAAC,EACvC,QAAQ,EACR,KAAK,EACL,mBAA4C,EAC5C,uBAAqD,EACrD,SAAS,EACT,iBAAiB,EACjB,QAAQ,GACT,EAAE,6BAA6B,+BAyC/B;AAED,4DAA4D;AAC5D,wBAAgB,mBAAmB,IAAI,wBAAwB,GAAG,IAAI,CAErE;AAED,6FAA6F;AAC7F,wBAAgB,WAAW,CAAC,IAAI,EAAE,UAAU,GAAG,MAAM,CAGpD;AAED;;;;;;;GAOG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,UAAU,GAAG,OAAO,CAKvD;AAoKD,MAAM,MAAM,qBAAqB,GAAG;IAClC,iDAAiD;IACjD,KAAK,EAAE,qBAAqB,GAAG,IAAI,CAAC;IACpC,UAAU,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IAChC,OAAO,IAAI,IAAI,CAAC;CACjB,GAAG,cAAc,CAAC;AAEnB;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAAC,EAC/B,KAAK,EACL,UAAU,EACV,OAAO,EACP,SAAS,EACT,iBAAiB,GAClB,EAAE,qBAAqB,+BA4LvB"}
|