@ai-matrx/capture 0.2.1 → 0.3.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/CHANGELOG.md +13 -0
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +49 -1
- package/dist/index.d.ts +49 -1
- package/dist/react.cjs +676 -22
- package/dist/react.cjs.map +1 -1
- package/dist/react.d.cts +224 -1
- package/dist/react.d.ts +224 -1
- package/dist/react.js +689 -25
- package/dist/react.js.map +1 -1
- package/package.json +1 -1
package/dist/react.cjs
CHANGED
|
@@ -22,11 +22,15 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
22
22
|
var react_exports = {};
|
|
23
23
|
__export(react_exports, {
|
|
24
24
|
CameraCapture: () => CameraCapture,
|
|
25
|
+
CameraCaptureV3: () => CameraCaptureV3,
|
|
25
26
|
CameraFeed: () => CameraFeed,
|
|
27
|
+
CaptureExpandingField: () => CaptureExpandingField,
|
|
26
28
|
CaptureFilmstrip: () => CaptureFilmstrip,
|
|
29
|
+
CaptureRail: () => CaptureRail,
|
|
27
30
|
CaptureSheet: () => CaptureSheet,
|
|
28
31
|
CountdownOverlay: () => CountdownOverlay,
|
|
29
32
|
GridOverlay: () => GridOverlay,
|
|
33
|
+
HoldShutter: () => HoldShutter,
|
|
30
34
|
ImageEditSheet: () => ImageEditSheet,
|
|
31
35
|
MediaViewer: () => MediaViewer,
|
|
32
36
|
ModeSelector: () => ModeSelector,
|
|
@@ -1643,15 +1647,665 @@ function CameraCapture({
|
|
|
1643
1647
|
] });
|
|
1644
1648
|
}
|
|
1645
1649
|
|
|
1646
|
-
// src/components/
|
|
1650
|
+
// src/components/CameraCaptureV3.tsx
|
|
1651
|
+
var import_react8 = require("react");
|
|
1652
|
+
var import_lucide_react5 = require("lucide-react");
|
|
1653
|
+
|
|
1654
|
+
// src/components/CaptureRail.tsx
|
|
1647
1655
|
var import_react6 = require("react");
|
|
1648
1656
|
var import_jsx_runtime12 = require("react/jsx-runtime");
|
|
1657
|
+
function CaptureRail({
|
|
1658
|
+
actions,
|
|
1659
|
+
defaultExpanded = false,
|
|
1660
|
+
className
|
|
1661
|
+
}) {
|
|
1662
|
+
const [expanded, setExpanded] = (0, import_react6.useState)(defaultExpanded);
|
|
1663
|
+
const primary = actions.filter((a) => a.primary);
|
|
1664
|
+
const extra = actions.filter((a) => !a.primary);
|
|
1665
|
+
const shown = primary.length === 0 ? actions : expanded ? actions : primary;
|
|
1666
|
+
const collapsible = primary.length > 0 && extra.length > 0;
|
|
1667
|
+
if (actions.length === 0) return null;
|
|
1668
|
+
return /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(
|
|
1669
|
+
"div",
|
|
1670
|
+
{
|
|
1671
|
+
className: cn(
|
|
1672
|
+
"pointer-events-auto flex flex-col items-center gap-1",
|
|
1673
|
+
className
|
|
1674
|
+
),
|
|
1675
|
+
children: [
|
|
1676
|
+
shown.map((action) => /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(RailButton, { action }, action.id)),
|
|
1677
|
+
collapsible ? /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|
|
1678
|
+
"button",
|
|
1679
|
+
{
|
|
1680
|
+
type: "button",
|
|
1681
|
+
onClick: () => setExpanded((open) => !open),
|
|
1682
|
+
"aria-expanded": expanded,
|
|
1683
|
+
"aria-label": expanded ? "Fewer options" : "More options",
|
|
1684
|
+
className: cn(
|
|
1685
|
+
"mt-0.5 flex h-9 w-9 touch-manipulation items-center justify-center",
|
|
1686
|
+
"rounded-full text-white/90 transition-colors hover:bg-white/10"
|
|
1687
|
+
),
|
|
1688
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|
|
1689
|
+
Chevron,
|
|
1690
|
+
{
|
|
1691
|
+
className: cn(
|
|
1692
|
+
"h-5 w-5 transition-transform duration-200",
|
|
1693
|
+
expanded && "rotate-180"
|
|
1694
|
+
)
|
|
1695
|
+
}
|
|
1696
|
+
)
|
|
1697
|
+
}
|
|
1698
|
+
) : null
|
|
1699
|
+
]
|
|
1700
|
+
}
|
|
1701
|
+
);
|
|
1702
|
+
}
|
|
1703
|
+
function RailButton({ action }) {
|
|
1704
|
+
return /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(
|
|
1705
|
+
"button",
|
|
1706
|
+
{
|
|
1707
|
+
type: "button",
|
|
1708
|
+
onClick: action.onPress,
|
|
1709
|
+
disabled: action.disabled,
|
|
1710
|
+
"aria-label": action.label,
|
|
1711
|
+
"aria-pressed": action.active ?? void 0,
|
|
1712
|
+
className: cn(
|
|
1713
|
+
"flex w-12 shrink-0 touch-manipulation flex-col items-center justify-center gap-0.5",
|
|
1714
|
+
"rounded-2xl py-1.5 transition-colors",
|
|
1715
|
+
action.active ? "text-[#FFCC00]" : "text-white",
|
|
1716
|
+
action.disabled ? "opacity-40" : "hover:bg-white/10 active:bg-white/15"
|
|
1717
|
+
),
|
|
1718
|
+
children: [
|
|
1719
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { className: "drop-shadow-[0_1px_3px_rgba(0,0,0,0.6)]", children: action.icon }),
|
|
1720
|
+
action.valueLabel ? /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { className: "text-[10px] font-semibold leading-none tabular-nums drop-shadow-[0_1px_2px_rgba(0,0,0,0.7)]", children: action.valueLabel }) : null
|
|
1721
|
+
]
|
|
1722
|
+
}
|
|
1723
|
+
);
|
|
1724
|
+
}
|
|
1725
|
+
function Chevron({ className }) {
|
|
1726
|
+
return /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|
|
1727
|
+
"svg",
|
|
1728
|
+
{
|
|
1729
|
+
viewBox: "0 0 24 24",
|
|
1730
|
+
fill: "none",
|
|
1731
|
+
stroke: "currentColor",
|
|
1732
|
+
strokeWidth: "2.5",
|
|
1733
|
+
strokeLinecap: "round",
|
|
1734
|
+
strokeLinejoin: "round",
|
|
1735
|
+
className,
|
|
1736
|
+
"aria-hidden": "true",
|
|
1737
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("path", { d: "m6 9 6 6 6-6" })
|
|
1738
|
+
}
|
|
1739
|
+
);
|
|
1740
|
+
}
|
|
1741
|
+
|
|
1742
|
+
// src/components/HoldShutter.tsx
|
|
1743
|
+
var import_react7 = require("react");
|
|
1744
|
+
var import_jsx_runtime13 = require("react/jsx-runtime");
|
|
1745
|
+
var HOLD_MS = 320;
|
|
1746
|
+
var LOCK_AFTER_MS = 1200;
|
|
1747
|
+
function HoldShutter({
|
|
1748
|
+
recording,
|
|
1749
|
+
elapsedSeconds,
|
|
1750
|
+
maxSeconds,
|
|
1751
|
+
disabled = false,
|
|
1752
|
+
onPressStart,
|
|
1753
|
+
onPhoto,
|
|
1754
|
+
onStartRecording,
|
|
1755
|
+
onStopRecording
|
|
1756
|
+
}) {
|
|
1757
|
+
const holdTimer = (0, import_react7.useRef)(null);
|
|
1758
|
+
const startedRecording = (0, import_react7.useRef)(false);
|
|
1759
|
+
const [pressed, setPressed] = (0, import_react7.useState)(false);
|
|
1760
|
+
const [locked, setLocked] = (0, import_react7.useState)(false);
|
|
1761
|
+
const clearHold = (0, import_react7.useCallback)(() => {
|
|
1762
|
+
if (holdTimer.current !== null) {
|
|
1763
|
+
clearTimeout(holdTimer.current);
|
|
1764
|
+
holdTimer.current = null;
|
|
1765
|
+
}
|
|
1766
|
+
}, []);
|
|
1767
|
+
(0, import_react7.useEffect)(() => {
|
|
1768
|
+
if (!recording) {
|
|
1769
|
+
setLocked(false);
|
|
1770
|
+
return;
|
|
1771
|
+
}
|
|
1772
|
+
if (elapsedSeconds * 1e3 >= LOCK_AFTER_MS) setLocked(true);
|
|
1773
|
+
}, [recording, elapsedSeconds]);
|
|
1774
|
+
(0, import_react7.useEffect)(() => clearHold, [clearHold]);
|
|
1775
|
+
const onPointerDown = (0, import_react7.useCallback)(
|
|
1776
|
+
(event) => {
|
|
1777
|
+
if (disabled) return;
|
|
1778
|
+
event.currentTarget.setPointerCapture?.(event.pointerId);
|
|
1779
|
+
setPressed(true);
|
|
1780
|
+
onPressStart?.();
|
|
1781
|
+
if (recording && locked) return;
|
|
1782
|
+
startedRecording.current = false;
|
|
1783
|
+
holdTimer.current = setTimeout(() => {
|
|
1784
|
+
holdTimer.current = null;
|
|
1785
|
+
startedRecording.current = true;
|
|
1786
|
+
onStartRecording();
|
|
1787
|
+
}, HOLD_MS);
|
|
1788
|
+
},
|
|
1789
|
+
[disabled, locked, onPressStart, onStartRecording, recording]
|
|
1790
|
+
);
|
|
1791
|
+
const endPress = (0, import_react7.useCallback)(() => {
|
|
1792
|
+
if (!pressed) return;
|
|
1793
|
+
setPressed(false);
|
|
1794
|
+
const wasHold = startedRecording.current;
|
|
1795
|
+
clearHold();
|
|
1796
|
+
startedRecording.current = false;
|
|
1797
|
+
if (recording && locked && !wasHold) {
|
|
1798
|
+
onStopRecording();
|
|
1799
|
+
return;
|
|
1800
|
+
}
|
|
1801
|
+
if (wasHold) {
|
|
1802
|
+
if (!locked) onStopRecording();
|
|
1803
|
+
return;
|
|
1804
|
+
}
|
|
1805
|
+
if (!recording) onPhoto();
|
|
1806
|
+
}, [clearHold, locked, onPhoto, onStopRecording, pressed, recording]);
|
|
1807
|
+
const progress = maxSeconds && maxSeconds > 0 ? Math.min(1, elapsedSeconds / maxSeconds) : 0;
|
|
1808
|
+
const R = 39;
|
|
1809
|
+
const C = 2 * Math.PI * R;
|
|
1810
|
+
return /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "relative flex h-[86px] w-[86px] shrink-0 items-center justify-center", children: [
|
|
1811
|
+
recording && maxSeconds ? /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(
|
|
1812
|
+
"svg",
|
|
1813
|
+
{
|
|
1814
|
+
className: "pointer-events-none absolute inset-0 -rotate-90",
|
|
1815
|
+
viewBox: "0 0 86 86",
|
|
1816
|
+
"aria-hidden": "true",
|
|
1817
|
+
children: [
|
|
1818
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
|
|
1819
|
+
"circle",
|
|
1820
|
+
{
|
|
1821
|
+
cx: "43",
|
|
1822
|
+
cy: "43",
|
|
1823
|
+
r: R,
|
|
1824
|
+
fill: "none",
|
|
1825
|
+
stroke: "rgba(255,255,255,0.25)",
|
|
1826
|
+
strokeWidth: "4"
|
|
1827
|
+
}
|
|
1828
|
+
),
|
|
1829
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
|
|
1830
|
+
"circle",
|
|
1831
|
+
{
|
|
1832
|
+
cx: "43",
|
|
1833
|
+
cy: "43",
|
|
1834
|
+
r: R,
|
|
1835
|
+
fill: "none",
|
|
1836
|
+
stroke: "#FF3B30",
|
|
1837
|
+
strokeWidth: "4",
|
|
1838
|
+
strokeLinecap: "round",
|
|
1839
|
+
strokeDasharray: C,
|
|
1840
|
+
strokeDashoffset: C * (1 - progress)
|
|
1841
|
+
}
|
|
1842
|
+
)
|
|
1843
|
+
]
|
|
1844
|
+
}
|
|
1845
|
+
) : null,
|
|
1846
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
|
|
1847
|
+
"button",
|
|
1848
|
+
{
|
|
1849
|
+
type: "button",
|
|
1850
|
+
disabled,
|
|
1851
|
+
onPointerDown,
|
|
1852
|
+
onPointerUp: endPress,
|
|
1853
|
+
onPointerCancel: endPress,
|
|
1854
|
+
onLostPointerCapture: endPress,
|
|
1855
|
+
onContextMenu: (e) => e.preventDefault(),
|
|
1856
|
+
"aria-label": recording ? locked ? "Stop recording" : "Recording \u2014 release to stop" : "Tap for a photo, hold to record",
|
|
1857
|
+
className: cn(
|
|
1858
|
+
"group flex h-[74px] w-[74px] shrink-0 touch-none select-none items-center justify-center",
|
|
1859
|
+
"rounded-full border-[3.5px] border-white transition-opacity",
|
|
1860
|
+
disabled && "opacity-30"
|
|
1861
|
+
),
|
|
1862
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
|
|
1863
|
+
"span",
|
|
1864
|
+
{
|
|
1865
|
+
className: cn(
|
|
1866
|
+
"block transition-all duration-200 ease-out",
|
|
1867
|
+
recording ? "h-7 w-7 rounded-[6px] bg-[#FF3B30]" : cn(
|
|
1868
|
+
"h-[62px] w-[62px] rounded-full bg-white",
|
|
1869
|
+
pressed && "scale-90"
|
|
1870
|
+
)
|
|
1871
|
+
)
|
|
1872
|
+
}
|
|
1873
|
+
)
|
|
1874
|
+
}
|
|
1875
|
+
),
|
|
1876
|
+
recording ? /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(
|
|
1877
|
+
"span",
|
|
1878
|
+
{
|
|
1879
|
+
className: cn(
|
|
1880
|
+
"pointer-events-none absolute -bottom-1 left-1/2 -translate-x-1/2 translate-y-full",
|
|
1881
|
+
"rounded-full bg-black/60 px-2 py-0.5 text-[11px] font-medium tabular-nums text-white"
|
|
1882
|
+
),
|
|
1883
|
+
children: [
|
|
1884
|
+
formatElapsed2(elapsedSeconds),
|
|
1885
|
+
locked ? " \xB7 tap to stop" : ""
|
|
1886
|
+
]
|
|
1887
|
+
}
|
|
1888
|
+
) : null
|
|
1889
|
+
] });
|
|
1890
|
+
}
|
|
1891
|
+
function formatElapsed2(totalSeconds) {
|
|
1892
|
+
const m = Math.floor(totalSeconds / 60);
|
|
1893
|
+
const s = String(Math.floor(totalSeconds % 60)).padStart(2, "0");
|
|
1894
|
+
return `${m}:${s}`;
|
|
1895
|
+
}
|
|
1896
|
+
|
|
1897
|
+
// src/components/CameraCaptureV3.tsx
|
|
1898
|
+
var import_jsx_runtime14 = require("react/jsx-runtime");
|
|
1899
|
+
var ASPECT_CYCLE2 = ["full", "4:3", "1:1", "16:9"];
|
|
1900
|
+
function CameraCaptureV3({
|
|
1901
|
+
engine,
|
|
1902
|
+
cloud,
|
|
1903
|
+
preview,
|
|
1904
|
+
media,
|
|
1905
|
+
onRecordIntent,
|
|
1906
|
+
maxRecordSeconds,
|
|
1907
|
+
onReviewOpenChange,
|
|
1908
|
+
onClose,
|
|
1909
|
+
blockedSheet,
|
|
1910
|
+
controlsHidden = false,
|
|
1911
|
+
shutterDisabled = false,
|
|
1912
|
+
slots = {}
|
|
1913
|
+
}) {
|
|
1914
|
+
const [viewerKey, setViewerKey] = (0, import_react8.useState)(null);
|
|
1915
|
+
const [editTarget, setEditTarget] = (0, import_react8.useState)(
|
|
1916
|
+
null
|
|
1917
|
+
);
|
|
1918
|
+
const [gridOn, setGridOn] = (0, import_react8.useState)(false);
|
|
1919
|
+
const [timerSetting, setTimerSetting] = (0, import_react8.useState)(0);
|
|
1920
|
+
const [aspect, setAspect] = (0, import_react8.useState)("full");
|
|
1921
|
+
const [countdown, setCountdown] = (0, import_react8.useState)(null);
|
|
1922
|
+
const [blockedDismissed, setBlockedDismissed] = (0, import_react8.useState)(false);
|
|
1923
|
+
const countdownRef = (0, import_react8.useRef)(null);
|
|
1924
|
+
const controls = useTrackControls(engine.stream);
|
|
1925
|
+
const reviewOpen = viewerKey !== null || editTarget !== null;
|
|
1926
|
+
(0, import_react8.useEffect)(() => {
|
|
1927
|
+
onReviewOpenChange?.(reviewOpen);
|
|
1928
|
+
}, [reviewOpen, onReviewOpenChange]);
|
|
1929
|
+
const clearCountdown = (0, import_react8.useCallback)(() => {
|
|
1930
|
+
if (countdownRef.current) clearInterval(countdownRef.current);
|
|
1931
|
+
countdownRef.current = null;
|
|
1932
|
+
setCountdown(null);
|
|
1933
|
+
}, []);
|
|
1934
|
+
(0, import_react8.useEffect)(() => clearCountdown, [clearCountdown]);
|
|
1935
|
+
(0, import_react8.useEffect)(() => {
|
|
1936
|
+
if (engine.recording) clearCountdown();
|
|
1937
|
+
}, [engine.recording, clearCountdown]);
|
|
1938
|
+
const onPhoto = (0, import_react8.useCallback)(() => {
|
|
1939
|
+
if (countdown !== null) {
|
|
1940
|
+
clearCountdown();
|
|
1941
|
+
return;
|
|
1942
|
+
}
|
|
1943
|
+
if (timerSetting === 0) {
|
|
1944
|
+
engine.onCapturePhoto({ aspect });
|
|
1945
|
+
return;
|
|
1946
|
+
}
|
|
1947
|
+
let remaining = timerSetting;
|
|
1948
|
+
setCountdown(remaining);
|
|
1949
|
+
countdownRef.current = setInterval(() => {
|
|
1950
|
+
remaining -= 1;
|
|
1951
|
+
if (remaining <= 0) {
|
|
1952
|
+
clearCountdown();
|
|
1953
|
+
engine.onCapturePhoto({ aspect });
|
|
1954
|
+
} else {
|
|
1955
|
+
setCountdown(remaining);
|
|
1956
|
+
}
|
|
1957
|
+
}, 1e3);
|
|
1958
|
+
}, [aspect, clearCountdown, countdown, engine, timerSetting]);
|
|
1959
|
+
const blocked = engine.blocked !== null;
|
|
1960
|
+
const coreRail = [
|
|
1961
|
+
...engine.onFlipCamera ? [
|
|
1962
|
+
{
|
|
1963
|
+
id: "flip",
|
|
1964
|
+
label: "Switch camera",
|
|
1965
|
+
icon: /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_lucide_react5.RefreshCw, { className: "h-[22px] w-[22px]" }),
|
|
1966
|
+
primary: true,
|
|
1967
|
+
onPress: engine.onFlipCamera
|
|
1968
|
+
}
|
|
1969
|
+
] : [],
|
|
1970
|
+
...controls.torchSupported ? [
|
|
1971
|
+
{
|
|
1972
|
+
id: "flash",
|
|
1973
|
+
label: "Flash",
|
|
1974
|
+
icon: controls.torchOn ? /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_lucide_react5.Zap, { className: "h-[22px] w-[22px]", fill: "currentColor" }) : /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_lucide_react5.ZapOff, { className: "h-[22px] w-[22px]" }),
|
|
1975
|
+
active: controls.torchOn,
|
|
1976
|
+
primary: true,
|
|
1977
|
+
onPress: controls.toggleTorch
|
|
1978
|
+
}
|
|
1979
|
+
] : [],
|
|
1980
|
+
{
|
|
1981
|
+
id: "timer",
|
|
1982
|
+
label: "Timer",
|
|
1983
|
+
icon: /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_lucide_react5.Timer, { className: "h-[22px] w-[22px]" }),
|
|
1984
|
+
active: timerSetting !== 0,
|
|
1985
|
+
valueLabel: timerSetting === 0 ? void 0 : `${timerSetting}s`,
|
|
1986
|
+
onPress: () => setTimerSetting((t) => t === 0 ? 3 : t === 3 ? 10 : 0)
|
|
1987
|
+
},
|
|
1988
|
+
{
|
|
1989
|
+
id: "grid",
|
|
1990
|
+
label: "Grid",
|
|
1991
|
+
icon: /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_lucide_react5.Grid3x3, { className: "h-[22px] w-[22px]" }),
|
|
1992
|
+
active: gridOn,
|
|
1993
|
+
onPress: () => setGridOn((g) => !g)
|
|
1994
|
+
},
|
|
1995
|
+
{
|
|
1996
|
+
id: "aspect",
|
|
1997
|
+
label: "Aspect",
|
|
1998
|
+
icon: /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_lucide_react5.Proportions, { className: "h-[22px] w-[22px]" }),
|
|
1999
|
+
active: aspect !== "full",
|
|
2000
|
+
valueLabel: aspect === "full" ? void 0 : aspect,
|
|
2001
|
+
onPress: () => setAspect(
|
|
2002
|
+
(a) => ASPECT_CYCLE2[(ASPECT_CYCLE2.indexOf(a) + 1) % ASPECT_CYCLE2.length] ?? "full"
|
|
2003
|
+
)
|
|
2004
|
+
},
|
|
2005
|
+
...controls.exposureSupported ? [
|
|
2006
|
+
{
|
|
2007
|
+
id: "exposure",
|
|
2008
|
+
label: "Exposure",
|
|
2009
|
+
icon: /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_lucide_react5.SunMedium, { className: "h-[22px] w-[22px]" }),
|
|
2010
|
+
active: controls.exposure !== 0,
|
|
2011
|
+
valueLabel: controls.exposure === 0 ? void 0 : `${controls.exposure > 0 ? "+" : ""}${controls.exposure}`,
|
|
2012
|
+
onPress: () => controls.setExposure(controls.exposure === 0 ? 1 : 0)
|
|
2013
|
+
}
|
|
2014
|
+
] : []
|
|
2015
|
+
];
|
|
2016
|
+
const railActions = [...coreRail, ...slots.railActions ?? []];
|
|
2017
|
+
return /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { className: "absolute inset-0 select-none overflow-hidden bg-black", children: [
|
|
2018
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)("div", { className: "absolute inset-0", children: preview }),
|
|
2019
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)(GridOverlay, { visible: gridOn && !blocked }),
|
|
2020
|
+
aspect !== "full" && !blocked && !engine.recording && /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
|
|
2021
|
+
"div",
|
|
2022
|
+
{
|
|
2023
|
+
"aria-hidden": true,
|
|
2024
|
+
className: "pointer-events-none absolute inset-0 z-10 flex items-center justify-center",
|
|
2025
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
|
|
2026
|
+
"div",
|
|
2027
|
+
{
|
|
2028
|
+
className: "shadow-[0_0_0_9999px_rgba(0,0,0,0.45)]",
|
|
2029
|
+
style: {
|
|
2030
|
+
aspectRatio: aspect === "1:1" ? "1 / 1" : aspect === "4:3" ? "3 / 4" : "9 / 16",
|
|
2031
|
+
width: aspect === "16:9" ? "100%" : void 0,
|
|
2032
|
+
height: aspect === "16:9" ? void 0 : "70%",
|
|
2033
|
+
maxWidth: "100%",
|
|
2034
|
+
maxHeight: "100%"
|
|
2035
|
+
}
|
|
2036
|
+
}
|
|
2037
|
+
)
|
|
2038
|
+
}
|
|
2039
|
+
),
|
|
2040
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)(CountdownOverlay, { seconds: countdown }),
|
|
2041
|
+
!controlsHidden && /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(
|
|
2042
|
+
"div",
|
|
2043
|
+
{
|
|
2044
|
+
className: "pointer-events-none absolute inset-x-0 top-0 z-20 px-2",
|
|
2045
|
+
style: safeTop,
|
|
2046
|
+
children: [
|
|
2047
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { className: "flex min-h-[44px] items-center gap-2 py-1.5", children: [
|
|
2048
|
+
onClose ? /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
|
|
2049
|
+
"button",
|
|
2050
|
+
{
|
|
2051
|
+
type: "button",
|
|
2052
|
+
onClick: onClose,
|
|
2053
|
+
"aria-label": "Close camera",
|
|
2054
|
+
className: "pointer-events-auto flex h-10 w-10 shrink-0 touch-manipulation items-center justify-center rounded-full text-white drop-shadow-[0_1px_3px_rgba(0,0,0,0.6)] transition-colors hover:bg-white/10",
|
|
2055
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_lucide_react5.X, { className: "h-6 w-6" })
|
|
2056
|
+
}
|
|
2057
|
+
) : /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("span", { className: "h-10 w-10 shrink-0" }),
|
|
2058
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)("div", { className: "pointer-events-auto flex min-w-0 flex-1 justify-center", children: slots.topEntry }),
|
|
2059
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)("span", { className: "h-10 w-10 shrink-0" })
|
|
2060
|
+
] }),
|
|
2061
|
+
slots.topCenter ? /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("div", { className: "pointer-events-none pb-1 text-center", children: slots.topCenter }) : null
|
|
2062
|
+
]
|
|
2063
|
+
}
|
|
2064
|
+
),
|
|
2065
|
+
slots.statusChips ? /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
|
|
2066
|
+
"div",
|
|
2067
|
+
{
|
|
2068
|
+
className: "pointer-events-none absolute inset-x-0 z-20 flex flex-col items-center gap-1.5 px-3",
|
|
2069
|
+
style: {
|
|
2070
|
+
top: `calc(env(safe-area-inset-top, 0px) + ${controlsHidden ? 12 : 64}px)`
|
|
2071
|
+
},
|
|
2072
|
+
children: slots.statusChips
|
|
2073
|
+
}
|
|
2074
|
+
) : null,
|
|
2075
|
+
!controlsHidden && !blocked && /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
|
|
2076
|
+
"div",
|
|
2077
|
+
{
|
|
2078
|
+
className: "pointer-events-none absolute right-1 z-20 flex justify-end",
|
|
2079
|
+
style: { top: `calc(env(safe-area-inset-top, 0px) + 64px)` },
|
|
2080
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(CaptureRail, { actions: railActions })
|
|
2081
|
+
}
|
|
2082
|
+
),
|
|
2083
|
+
!controlsHidden && /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { className: "absolute inset-x-0 bottom-0 z-20", style: safeBottom, children: [
|
|
2084
|
+
media && media.items.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("div", { className: "px-2 pb-1.5", children: /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
|
|
2085
|
+
CaptureFilmstrip,
|
|
2086
|
+
{
|
|
2087
|
+
items: media.items,
|
|
2088
|
+
onOpen: (item) => setViewerKey(item.key)
|
|
2089
|
+
}
|
|
2090
|
+
) }) : null,
|
|
2091
|
+
slots.aboveShutter ? /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("div", { className: "px-2 pb-1.5", children: slots.aboveShutter }) : null,
|
|
2092
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { className: "flex items-center justify-between px-3 pb-2", children: [
|
|
2093
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)("div", { className: "flex w-[86px] justify-start", children: /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
|
|
2094
|
+
"button",
|
|
2095
|
+
{
|
|
2096
|
+
type: "button",
|
|
2097
|
+
onClick: cloud.onOpenLibrary,
|
|
2098
|
+
"aria-label": "Your media \u2014 library and upload",
|
|
2099
|
+
className: "relative h-12 w-12 touch-manipulation overflow-hidden rounded-xl bg-black/40 ring-1 ring-white/30 backdrop-blur-md transition-transform active:scale-95",
|
|
2100
|
+
children: cloud.recentsThumb ?? /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("span", { className: "flex h-full w-full items-center justify-center", children: /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_lucide_react5.Images, { className: "h-5 w-5 text-white/80" }) })
|
|
2101
|
+
}
|
|
2102
|
+
) }),
|
|
2103
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
|
|
2104
|
+
HoldShutter,
|
|
2105
|
+
{
|
|
2106
|
+
recording: engine.recording,
|
|
2107
|
+
elapsedSeconds: engine.recordElapsedSeconds,
|
|
2108
|
+
...maxRecordSeconds !== void 0 ? { maxSeconds: maxRecordSeconds } : {},
|
|
2109
|
+
disabled: shutterDisabled || blocked,
|
|
2110
|
+
...onRecordIntent ? { onPressStart: onRecordIntent } : {},
|
|
2111
|
+
onPhoto,
|
|
2112
|
+
onStartRecording: engine.onStartRecording,
|
|
2113
|
+
onStopRecording: engine.onStopRecording
|
|
2114
|
+
}
|
|
2115
|
+
),
|
|
2116
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)("div", { className: "flex w-[86px] justify-end", children: slots.shutterTrailing })
|
|
2117
|
+
] }),
|
|
2118
|
+
!engine.recording && !blocked ? /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("p", { className: "pb-1.5 text-center text-[11px] text-white/60 drop-shadow-[0_1px_2px_rgba(0,0,0,0.8)]", children: "Tap for a photo \xB7 hold to record" }) : null
|
|
2119
|
+
] }),
|
|
2120
|
+
blocked && blockedSheet && !blockedDismissed && /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
|
|
2121
|
+
CaptureSheet,
|
|
2122
|
+
{
|
|
2123
|
+
open: true,
|
|
2124
|
+
onClose: () => setBlockedDismissed(true),
|
|
2125
|
+
body: blockedSheet.body,
|
|
2126
|
+
title: "Camera unavailable",
|
|
2127
|
+
actions: blockedSheet.actions
|
|
2128
|
+
}
|
|
2129
|
+
),
|
|
2130
|
+
media && viewerKey !== null && /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
|
|
2131
|
+
MediaViewer,
|
|
2132
|
+
{
|
|
2133
|
+
items: media.items,
|
|
2134
|
+
initialKey: viewerKey,
|
|
2135
|
+
keysDisabled: editTarget !== null,
|
|
2136
|
+
onClose: () => setViewerKey(null),
|
|
2137
|
+
onDelete: media.onDelete ? (item) => {
|
|
2138
|
+
media.onDelete?.(item.key);
|
|
2139
|
+
invalidateMedia(item.key);
|
|
2140
|
+
} : void 0,
|
|
2141
|
+
onEdit: media.onReplacePhoto ? (item) => {
|
|
2142
|
+
const url = getMediaUrl(item);
|
|
2143
|
+
if (url) setEditTarget({ key: item.key, url });
|
|
2144
|
+
} : void 0
|
|
2145
|
+
}
|
|
2146
|
+
),
|
|
2147
|
+
media?.onReplacePhoto && /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
|
|
2148
|
+
ImageEditSheet,
|
|
2149
|
+
{
|
|
2150
|
+
open: editTarget !== null,
|
|
2151
|
+
src: editTarget?.url ?? null,
|
|
2152
|
+
onClose: () => setEditTarget(null),
|
|
2153
|
+
onSave: (blob) => {
|
|
2154
|
+
const target = editTarget;
|
|
2155
|
+
setEditTarget(null);
|
|
2156
|
+
setViewerKey(null);
|
|
2157
|
+
if (target) {
|
|
2158
|
+
media.onReplacePhoto?.(target.key, blob);
|
|
2159
|
+
invalidateMedia(target.key);
|
|
2160
|
+
}
|
|
2161
|
+
}
|
|
2162
|
+
}
|
|
2163
|
+
),
|
|
2164
|
+
slots.overlays
|
|
2165
|
+
] });
|
|
2166
|
+
}
|
|
2167
|
+
|
|
2168
|
+
// src/components/CaptureExpandingField.tsx
|
|
2169
|
+
var import_react9 = require("react");
|
|
2170
|
+
var import_jsx_runtime15 = require("react/jsx-runtime");
|
|
2171
|
+
function CaptureExpandingField({
|
|
2172
|
+
label,
|
|
2173
|
+
placeholder,
|
|
2174
|
+
icon,
|
|
2175
|
+
onCommit,
|
|
2176
|
+
defaultExpanded = false,
|
|
2177
|
+
disabled = false,
|
|
2178
|
+
currentValue = null,
|
|
2179
|
+
className
|
|
2180
|
+
}) {
|
|
2181
|
+
const [expanded, setExpanded] = (0, import_react9.useState)(defaultExpanded);
|
|
2182
|
+
const [draft, setDraft] = (0, import_react9.useState)("");
|
|
2183
|
+
const inputRef = (0, import_react9.useRef)(null);
|
|
2184
|
+
const draftRef = (0, import_react9.useRef)(draft);
|
|
2185
|
+
draftRef.current = draft;
|
|
2186
|
+
const onCommitRef = (0, import_react9.useRef)(onCommit);
|
|
2187
|
+
onCommitRef.current = onCommit;
|
|
2188
|
+
(0, import_react9.useEffect)(() => {
|
|
2189
|
+
return () => {
|
|
2190
|
+
const trimmed = draftRef.current.trim();
|
|
2191
|
+
if (trimmed) onCommitRef.current(trimmed);
|
|
2192
|
+
};
|
|
2193
|
+
}, []);
|
|
2194
|
+
const commit = (0, import_react9.useCallback)(() => {
|
|
2195
|
+
const trimmed = draftRef.current.trim();
|
|
2196
|
+
if (trimmed) onCommitRef.current(trimmed);
|
|
2197
|
+
setDraft("");
|
|
2198
|
+
}, []);
|
|
2199
|
+
const open = (0, import_react9.useCallback)(() => {
|
|
2200
|
+
setExpanded(true);
|
|
2201
|
+
requestAnimationFrame(() => inputRef.current?.focus());
|
|
2202
|
+
}, []);
|
|
2203
|
+
const close = (0, import_react9.useCallback)(() => {
|
|
2204
|
+
commit();
|
|
2205
|
+
setExpanded(false);
|
|
2206
|
+
}, [commit]);
|
|
2207
|
+
if (!expanded) {
|
|
2208
|
+
return /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(
|
|
2209
|
+
"button",
|
|
2210
|
+
{
|
|
2211
|
+
type: "button",
|
|
2212
|
+
onClick: open,
|
|
2213
|
+
disabled,
|
|
2214
|
+
"aria-label": label,
|
|
2215
|
+
"aria-expanded": false,
|
|
2216
|
+
className: cn(
|
|
2217
|
+
"flex h-9 max-w-[62vw] items-center gap-1.5 rounded-full px-3.5",
|
|
2218
|
+
"bg-black/45 text-[13px] font-semibold text-white backdrop-blur-md",
|
|
2219
|
+
"transition-colors hover:bg-black/60 active:bg-black/70",
|
|
2220
|
+
disabled && "opacity-40",
|
|
2221
|
+
className
|
|
2222
|
+
),
|
|
2223
|
+
children: [
|
|
2224
|
+
icon ? /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { className: "shrink-0", children: icon }) : null,
|
|
2225
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { className: "truncate", children: currentValue?.trim() || label })
|
|
2226
|
+
]
|
|
2227
|
+
}
|
|
2228
|
+
);
|
|
2229
|
+
}
|
|
2230
|
+
return /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(
|
|
2231
|
+
"div",
|
|
2232
|
+
{
|
|
2233
|
+
className: cn(
|
|
2234
|
+
"flex h-9 w-[min(78vw,320px)] items-center gap-1.5 rounded-full px-3",
|
|
2235
|
+
"bg-black/60 backdrop-blur-md",
|
|
2236
|
+
className
|
|
2237
|
+
),
|
|
2238
|
+
children: [
|
|
2239
|
+
icon ? /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { className: "shrink-0 text-white/70", children: icon }) : null,
|
|
2240
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
|
|
2241
|
+
"input",
|
|
2242
|
+
{
|
|
2243
|
+
ref: inputRef,
|
|
2244
|
+
value: draft,
|
|
2245
|
+
onChange: (e) => setDraft(e.target.value),
|
|
2246
|
+
onBlur: close,
|
|
2247
|
+
onKeyDown: (e) => {
|
|
2248
|
+
if (e.key === "Enter") {
|
|
2249
|
+
commit();
|
|
2250
|
+
e.target.blur();
|
|
2251
|
+
}
|
|
2252
|
+
if (e.key === "Escape") {
|
|
2253
|
+
setDraft("");
|
|
2254
|
+
setExpanded(false);
|
|
2255
|
+
}
|
|
2256
|
+
},
|
|
2257
|
+
placeholder: placeholder ?? label,
|
|
2258
|
+
"aria-label": label,
|
|
2259
|
+
enterKeyHint: "done",
|
|
2260
|
+
autoCapitalize: "characters",
|
|
2261
|
+
autoCorrect: "off",
|
|
2262
|
+
spellCheck: false,
|
|
2263
|
+
className: cn(
|
|
2264
|
+
"min-w-0 flex-1 bg-transparent text-base text-white",
|
|
2265
|
+
"placeholder:text-white/40 focus:outline-none"
|
|
2266
|
+
)
|
|
2267
|
+
}
|
|
2268
|
+
),
|
|
2269
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
|
|
2270
|
+
"button",
|
|
2271
|
+
{
|
|
2272
|
+
type: "button",
|
|
2273
|
+
onMouseDown: (e) => e.preventDefault(),
|
|
2274
|
+
onClick: () => {
|
|
2275
|
+
setDraft("");
|
|
2276
|
+
setExpanded(false);
|
|
2277
|
+
},
|
|
2278
|
+
"aria-label": `Close ${label}`,
|
|
2279
|
+
className: "flex h-6 w-6 shrink-0 items-center justify-center rounded-full text-white/70 hover:bg-white/10 hover:text-white",
|
|
2280
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
|
|
2281
|
+
"svg",
|
|
2282
|
+
{
|
|
2283
|
+
viewBox: "0 0 24 24",
|
|
2284
|
+
fill: "none",
|
|
2285
|
+
stroke: "currentColor",
|
|
2286
|
+
strokeWidth: "2.5",
|
|
2287
|
+
strokeLinecap: "round",
|
|
2288
|
+
className: "h-3.5 w-3.5",
|
|
2289
|
+
"aria-hidden": "true",
|
|
2290
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("path", { d: "M18 6 6 18M6 6l12 12" })
|
|
2291
|
+
}
|
|
2292
|
+
)
|
|
2293
|
+
}
|
|
2294
|
+
)
|
|
2295
|
+
]
|
|
2296
|
+
}
|
|
2297
|
+
);
|
|
2298
|
+
}
|
|
2299
|
+
|
|
2300
|
+
// src/components/CameraFeed.tsx
|
|
2301
|
+
var import_react10 = require("react");
|
|
2302
|
+
var import_jsx_runtime16 = require("react/jsx-runtime");
|
|
1649
2303
|
function CameraFeed({
|
|
1650
2304
|
engine,
|
|
1651
2305
|
mirror = false
|
|
1652
2306
|
}) {
|
|
1653
2307
|
const { stream, videoRef } = engine;
|
|
1654
|
-
(0,
|
|
2308
|
+
(0, import_react10.useEffect)(() => {
|
|
1655
2309
|
const video = videoRef.current;
|
|
1656
2310
|
if (!video) return;
|
|
1657
2311
|
if (video.srcObject !== stream) video.srcObject = stream;
|
|
@@ -1659,7 +2313,7 @@ function CameraFeed({
|
|
|
1659
2313
|
video.srcObject = null;
|
|
1660
2314
|
};
|
|
1661
2315
|
}, [stream, videoRef]);
|
|
1662
|
-
return /* @__PURE__ */ (0,
|
|
2316
|
+
return /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
|
|
1663
2317
|
"video",
|
|
1664
2318
|
{
|
|
1665
2319
|
ref: videoRef,
|
|
@@ -1677,7 +2331,7 @@ function CameraFeed({
|
|
|
1677
2331
|
}
|
|
1678
2332
|
|
|
1679
2333
|
// src/engine/useDefaultEngine.ts
|
|
1680
|
-
var
|
|
2334
|
+
var import_react11 = require("react");
|
|
1681
2335
|
var RECORDING_MIME_LADDER = [
|
|
1682
2336
|
'video/mp4;codecs="avc1.42E01E,mp4a.40.2"',
|
|
1683
2337
|
"video/mp4",
|
|
@@ -1707,18 +2361,18 @@ function useDefaultCaptureEngine(options) {
|
|
|
1707
2361
|
facingMode: initialFacing = "environment",
|
|
1708
2362
|
photoQuality = 0.92
|
|
1709
2363
|
} = options;
|
|
1710
|
-
const [stream, setStream] = (0,
|
|
1711
|
-
const [blocked, setBlocked] = (0,
|
|
1712
|
-
const [facing, setFacing] = (0,
|
|
1713
|
-
const [multipleCameras, setMultipleCameras] = (0,
|
|
1714
|
-
const [recording, setRecording] = (0,
|
|
1715
|
-
const [recordElapsedSeconds, setRecordElapsedSeconds] = (0,
|
|
1716
|
-
const videoRef = (0,
|
|
1717
|
-
const streamRef = (0,
|
|
1718
|
-
const recorderRef = (0,
|
|
1719
|
-
const callbacksRef = (0,
|
|
2364
|
+
const [stream, setStream] = (0, import_react11.useState)(null);
|
|
2365
|
+
const [blocked, setBlocked] = (0, import_react11.useState)(null);
|
|
2366
|
+
const [facing, setFacing] = (0, import_react11.useState)(initialFacing);
|
|
2367
|
+
const [multipleCameras, setMultipleCameras] = (0, import_react11.useState)(false);
|
|
2368
|
+
const [recording, setRecording] = (0, import_react11.useState)(false);
|
|
2369
|
+
const [recordElapsedSeconds, setRecordElapsedSeconds] = (0, import_react11.useState)(0);
|
|
2370
|
+
const videoRef = (0, import_react11.useRef)(null);
|
|
2371
|
+
const streamRef = (0, import_react11.useRef)(null);
|
|
2372
|
+
const recorderRef = (0, import_react11.useRef)(null);
|
|
2373
|
+
const callbacksRef = (0, import_react11.useRef)({ onPhoto, onVideo, onFiles });
|
|
1720
2374
|
callbacksRef.current = { onPhoto, onVideo, onFiles };
|
|
1721
|
-
(0,
|
|
2375
|
+
(0, import_react11.useEffect)(() => {
|
|
1722
2376
|
let cancelled = false;
|
|
1723
2377
|
let acquired = null;
|
|
1724
2378
|
if (typeof navigator === "undefined" || !navigator.mediaDevices) {
|
|
@@ -1761,7 +2415,7 @@ function useDefaultCaptureEngine(options) {
|
|
|
1761
2415
|
setStream(null);
|
|
1762
2416
|
};
|
|
1763
2417
|
}, [facing]);
|
|
1764
|
-
(0,
|
|
2418
|
+
(0, import_react11.useEffect)(() => {
|
|
1765
2419
|
return () => {
|
|
1766
2420
|
const r = recorderRef.current;
|
|
1767
2421
|
if (r) {
|
|
@@ -1771,7 +2425,7 @@ function useDefaultCaptureEngine(options) {
|
|
|
1771
2425
|
}
|
|
1772
2426
|
};
|
|
1773
2427
|
}, []);
|
|
1774
|
-
const onCapturePhoto = (0,
|
|
2428
|
+
const onCapturePhoto = (0, import_react11.useCallback)(
|
|
1775
2429
|
(opts) => {
|
|
1776
2430
|
const video = videoRef.current;
|
|
1777
2431
|
if (!video || video.videoWidth === 0) return;
|
|
@@ -1811,7 +2465,7 @@ function useDefaultCaptureEngine(options) {
|
|
|
1811
2465
|
},
|
|
1812
2466
|
[photoQuality]
|
|
1813
2467
|
);
|
|
1814
|
-
const onStartRecording = (0,
|
|
2468
|
+
const onStartRecording = (0, import_react11.useCallback)(() => {
|
|
1815
2469
|
const base = streamRef.current;
|
|
1816
2470
|
if (!base || recorderRef.current) return;
|
|
1817
2471
|
void (async () => {
|
|
@@ -1878,11 +2532,11 @@ function useDefaultCaptureEngine(options) {
|
|
|
1878
2532
|
setRecording(true);
|
|
1879
2533
|
})();
|
|
1880
2534
|
}, [withAudio]);
|
|
1881
|
-
const onStopRecording = (0,
|
|
2535
|
+
const onStopRecording = (0, import_react11.useCallback)(() => {
|
|
1882
2536
|
const r = recorderRef.current;
|
|
1883
2537
|
if (r && r.recorder.state !== "inactive") r.recorder.stop();
|
|
1884
2538
|
}, []);
|
|
1885
|
-
const onUpload = (0,
|
|
2539
|
+
const onUpload = (0, import_react11.useCallback)(() => {
|
|
1886
2540
|
const input = document.createElement("input");
|
|
1887
2541
|
input.type = "file";
|
|
1888
2542
|
input.accept = "image/*,video/*";
|
|
@@ -1893,10 +2547,10 @@ function useDefaultCaptureEngine(options) {
|
|
|
1893
2547
|
};
|
|
1894
2548
|
input.click();
|
|
1895
2549
|
}, []);
|
|
1896
|
-
const onFlipCamera = (0,
|
|
2550
|
+
const onFlipCamera = (0, import_react11.useCallback)(() => {
|
|
1897
2551
|
setFacing((f) => f === "environment" ? "user" : "environment");
|
|
1898
2552
|
}, []);
|
|
1899
|
-
return (0,
|
|
2553
|
+
return (0, import_react11.useMemo)(
|
|
1900
2554
|
() => ({
|
|
1901
2555
|
stream,
|
|
1902
2556
|
videoRef,
|