@protobase/ui 0.62.4 → 0.62.5

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.
@@ -1 +1 @@
1
- {"version":3,"mappings":"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","names":["__iconData","MicOff","createLucideIcon","Mic","MonitorUp","MonitorX","PhoneOff","Phone","VideoOff","Video","WifiOff","dayBefore","day","sameChatDay","viewerZone","dayIn","a","zone","b","chatDayLabel","time","today","now","text","formatWeekdayDate","ChatDivider","shown","label","line","cn","tone","import_jsx_runtime","RecordLink","rest","display","useOptionalListDisplay","around","useLayoutRecord","name","resource","AppLink","row","recordKey","signedInUserOf","state","useSignedInUser","useOptionalAuth","useMemo","keepPlaying","track","play","element","error","TrackVideo","ref","useCallback","TrackAudio","toggle","on","CallCheck","camera","cameraOn","Avatar","initialsOf","hueOf","member","notices","notice","Button","microphoneOn","microphone","onMicrophone","cameraAvailable","onCamera","onJoin","RouteLink","cancel","said","CallMessage","reason","onJoinAgain","gridColumns","width","count","callLayout","sharers","people","connectionQuality","roundTripMs","lostRatio","cannotConnect","since","activeSpeaker","loudest","level","levels","threshold","received","tracks","source","callPeople","members","self","shared","nameOf","speaker","own","theirs","screen","screenAudio","link","connections","connection","seen","CallControls","onShare","sharing","leave","buttonClass","CallTile","person","className","useWidth","setWidth","useState","observer","entry","stripMax","Grid","columns","Share","more","narrow","sharer","Tiles","layout","CallStage","messages","message","Spinner","controls","audio","key","readEveryMs","holdMs","levelOf","analyser","samples","sum","sample","useActiveSpeaker","setSpeaker","ids","import_react","context","analysers","last","timer","blockedNames","missingNames","one","media","kind","openDevices","stream","video","connectionsEveryMs","stop","useCallSession","phase","setPhase","devices","setDevices","setMicrophoneOn","setCameraOn","setTracks","setMembers","setConnections","setScreen","refusedSending","setRefusedSending","call","useRef","gone","opening","cancelled","opened","join","__vitePreload","joined","joinCall","made","sending","PublishRefused","url","toggleMicrophone","next","toggleCamera","stopSharing","toggleScreen","canShare","deviceNotices","CallView","session","auth","user","voices","useRecordCallAddress","useAppAddress","joining","address","target","to","open","href","RecordCall","useRecordCalls","client","useClient","queryClient","useQueryClient","keys","query","useQuery","queryKey","channel","offCalls","callsChannelEvent","offStatus","status","CallMark","isPending","ongoing","_Fragment","box","carouselSlides","images","image","shownImage","Carousel","slides","carousel","useCarousel","CarouselTrack","FileImage","fit","CarouselControls","Choices","options","option","value","onChange","usePickedLabels","sorted","keepPreviousData","fetchLabels","view","RecordPicker","useAdminMeta","resources","props","views","known","setKnown","fetched","labelOf","remember","current","RelationPicker","chosen","Token"],"ignoreList":[0,1,2,3,4,5,6,7,8],"sources":["../../../../../node_modules/.bun/lucide-react@1.52.0+0ac650c021fb1b59/node_modules/lucide-react/dist/esm/icons/mic-off.mjs","../../../../../node_modules/.bun/lucide-react@1.52.0+0ac650c021fb1b59/node_modules/lucide-react/dist/esm/icons/mic.mjs","../../../../../node_modules/.bun/lucide-react@1.52.0+0ac650c021fb1b59/node_modules/lucide-react/dist/esm/icons/monitor-up.mjs","../../../../../node_modules/.bun/lucide-react@1.52.0+0ac650c021fb1b59/node_modules/lucide-react/dist/esm/icons/monitor-x.mjs","../../../../../node_modules/.bun/lucide-react@1.52.0+0ac650c021fb1b59/node_modules/lucide-react/dist/esm/icons/phone-off.mjs","../../../../../node_modules/.bun/lucide-react@1.52.0+0ac650c021fb1b59/node_modules/lucide-react/dist/esm/icons/phone.mjs","../../../../../node_modules/.bun/lucide-react@1.52.0+0ac650c021fb1b59/node_modules/lucide-react/dist/esm/icons/video-off.mjs","../../../../../node_modules/.bun/lucide-react@1.52.0+0ac650c021fb1b59/node_modules/lucide-react/dist/esm/icons/video.mjs","../../../../../node_modules/.bun/lucide-react@1.52.0+0ac650c021fb1b59/node_modules/lucide-react/dist/esm/icons/wifi-off.mjs","../../../src/chat/chat-day.ts","../../../src/chat/chat-divider.tsx","../../../src/app/displays/record-link.tsx","../../../src/auth/use-signed-in-user.ts","../../../src/calls/track-media.tsx","../../../src/calls/call-check.tsx","../../../src/calls/call-message.tsx","../../../src/calls/call-layout.ts","../../../src/calls/call-people.ts","../../../src/calls/call-controls.tsx","../../../src/calls/call-tile.tsx","../../../src/calls/use-width.ts","../../../src/calls/call-stage.tsx","../../../src/calls/use-audio-levels.ts","../../../src/calls/devices.ts","../../../src/calls/use-call-session.ts","../../../src/calls/call-view.tsx","../../../src/calls/use-record-call-address.ts","../../../src/calls/record-call.tsx","../../../src/calls/use-record-calls.ts","../../../src/calls/call-mark.tsx","../../../src/carousel/carousel-images.ts","../../../src/carousel/carousel.tsx","../../../src/primitives/choices.tsx","../../../src/app/use-picked-labels.ts","../../../src/app/record-picker.tsx"],"sourcesContent":["/**\n * @license lucide-react v1.52.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.mjs';\n\nconst __iconData = {\n name: \"mic-off\",\n size: 24,\n node: [\n [\"path\", { d: \"M12 19v3\", key: \"npa21l\" }],\n [\"path\", { d: \"M15 9.34V5a3 3 0 0 0-5.68-1.33\", key: \"1gzdoj\" }],\n [\"path\", { d: \"M16.95 16.95A7 7 0 0 1 5 12v-2\", key: \"cqa7eg\" }],\n [\"path\", { d: \"M18.89 13.23A7 7 0 0 0 19 12v-2\", key: \"16hl24\" }],\n [\"path\", { d: \"m2 2 20 20\", key: \"1ooewy\" }],\n [\"path\", { d: \"M9 9v3a3 3 0 0 0 5.12 2.12\", key: \"r2i35w\" }]\n ]\n};\n__iconData.node;\nconst MicOff = createLucideIcon(__iconData);\n\nexport { __iconData, MicOff as default };\n//# sourceMappingURL=mic-off.mjs.map\n","/**\n * @license lucide-react v1.52.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.mjs';\n\nconst __iconData = {\n name: \"mic\",\n size: 24,\n node: [\n [\"path\", { d: \"M12 19v3\", key: \"npa21l\" }],\n [\"path\", { d: \"M19 10v2a7 7 0 0 1-14 0v-2\", key: \"1vc78b\" }],\n [\"rect\", { x: \"9\", y: \"2\", width: \"6\", height: \"13\", rx: \"3\", key: \"s6n7sd\" }]\n ]\n};\n__iconData.node;\nconst Mic = createLucideIcon(__iconData);\n\nexport { __iconData, Mic as default };\n//# sourceMappingURL=mic.mjs.map\n","/**\n * @license lucide-react v1.52.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.mjs';\n\nconst __iconData = {\n name: \"monitor-up\",\n size: 24,\n node: [\n [\"path\", { d: \"m9 10 3-3 3 3\", key: \"11gsxs\" }],\n [\"path\", { d: \"M12 13V7\", key: \"h0r20n\" }],\n [\"rect\", { width: \"20\", height: \"14\", x: \"2\", y: \"3\", rx: \"2\", key: \"48i651\" }],\n [\"path\", { d: \"M12 17v4\", key: \"1riwvh\" }],\n [\"path\", { d: \"M8 21h8\", key: \"1ev6f3\" }]\n ]\n};\n__iconData.node;\nconst MonitorUp = createLucideIcon(__iconData);\n\nexport { __iconData, MonitorUp as default };\n//# sourceMappingURL=monitor-up.mjs.map\n","/**\n * @license lucide-react v1.52.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.mjs';\n\nconst __iconData = {\n name: \"monitor-x\",\n size: 24,\n node: [\n [\"path\", { d: \"m14.5 12.5-5-5\", key: \"1jahn5\" }],\n [\"path\", { d: \"m9.5 12.5 5-5\", key: \"1k2t7b\" }],\n [\"rect\", { width: \"20\", height: \"14\", x: \"2\", y: \"3\", rx: \"2\", key: \"48i651\" }],\n [\"path\", { d: \"M12 17v4\", key: \"1riwvh\" }],\n [\"path\", { d: \"M8 21h8\", key: \"1ev6f3\" }]\n ]\n};\n__iconData.node;\nconst MonitorX = createLucideIcon(__iconData);\n\nexport { __iconData, MonitorX as default };\n//# sourceMappingURL=monitor-x.mjs.map\n","/**\n * @license lucide-react v1.52.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.mjs';\n\nconst __iconData = {\n name: \"phone-off\",\n size: 24,\n node: [\n [\n \"path\",\n {\n d: \"M10.1 13.9a14 14 0 0 0 3.732 2.668 1 1 0 0 0 1.213-.303l.355-.465A2 2 0 0 1 17 15h3a2 2 0 0 1 2 2v3a2 2 0 0 1-2 2 18 18 0 0 1-12.728-5.272\",\n key: \"1wngk7\"\n }\n ],\n [\"path\", { d: \"M22 2 2 22\", key: \"y4kqgn\" }],\n [\n \"path\",\n {\n d: \"M4.76 13.582A18 18 0 0 1 2 4a2 2 0 0 1 2-2h3a2 2 0 0 1 2 2v3a2 2 0 0 1-.8 1.6l-.468.351a1 1 0 0 0-.292 1.233 14 14 0 0 0 .244.473\",\n key: \"10hv5p\"\n }\n ]\n ]\n};\n__iconData.node;\nconst PhoneOff = createLucideIcon(__iconData);\n\nexport { __iconData, PhoneOff as default };\n//# sourceMappingURL=phone-off.mjs.map\n","/**\n * @license lucide-react v1.52.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.mjs';\n\nconst __iconData = {\n name: \"phone\",\n size: 24,\n node: [\n [\n \"path\",\n {\n d: \"M13.832 16.568a1 1 0 0 0 1.213-.303l.355-.465A2 2 0 0 1 17 15h3a2 2 0 0 1 2 2v3a2 2 0 0 1-2 2A18 18 0 0 1 2 4a2 2 0 0 1 2-2h3a2 2 0 0 1 2 2v3a2 2 0 0 1-.8 1.6l-.468.351a1 1 0 0 0-.292 1.233 14 14 0 0 0 6.392 6.384\",\n key: \"9njp5v\"\n }\n ]\n ]\n};\n__iconData.node;\nconst Phone = createLucideIcon(__iconData);\n\nexport { __iconData, Phone as default };\n//# sourceMappingURL=phone.mjs.map\n","/**\n * @license lucide-react v1.52.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.mjs';\n\nconst __iconData = {\n name: \"video-off\",\n size: 24,\n node: [\n [\n \"path\",\n { d: \"M10.66 6H14a2 2 0 0 1 2 2v2.5l5.248-3.062A.5.5 0 0 1 22 7.87v8.196\", key: \"w8jjjt\" }\n ],\n [\"path\", { d: \"M16 16a2 2 0 0 1-2 2H4a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h2\", key: \"1xawa7\" }],\n [\"path\", { d: \"m2 2 20 20\", key: \"1ooewy\" }]\n ]\n};\n__iconData.node;\nconst VideoOff = createLucideIcon(__iconData);\n\nexport { __iconData, VideoOff as default };\n//# sourceMappingURL=video-off.mjs.map\n","/**\n * @license lucide-react v1.52.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.mjs';\n\nconst __iconData = {\n name: \"video\",\n size: 24,\n node: [\n [\n \"path\",\n {\n d: \"m16 13 5.223 3.482a.5.5 0 0 0 .777-.416V7.87a.5.5 0 0 0-.752-.432L16 10.5\",\n key: \"ftymec\"\n }\n ],\n [\"rect\", { x: \"2\", y: \"6\", width: \"14\", height: \"12\", rx: \"2\", key: \"158x01\" }]\n ]\n};\n__iconData.node;\nconst Video = createLucideIcon(__iconData);\n\nexport { __iconData, Video as default };\n//# sourceMappingURL=video.mjs.map\n","/**\n * @license lucide-react v1.52.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.mjs';\n\nconst __iconData = {\n name: \"wifi-off\",\n size: 24,\n node: [\n [\"path\", { d: \"M12 20h.01\", key: \"zekei9\" }],\n [\"path\", { d: \"M8.5 16.429a5 5 0 0 1 7 0\", key: \"1bycff\" }],\n [\"path\", { d: \"M5 12.859a10 10 0 0 1 5.17-2.69\", key: \"1dl1wf\" }],\n [\"path\", { d: \"M19 12.859a10 10 0 0 0-2.007-1.523\", key: \"4k23kn\" }],\n [\"path\", { d: \"M2 8.82a15 15 0 0 1 4.177-2.643\", key: \"1grhjp\" }],\n [\"path\", { d: \"M22 8.82a15 15 0 0 0-11.288-3.764\", key: \"z3jwby\" }],\n [\"path\", { d: \"m2 2 20 20\", key: \"1ooewy\" }]\n ]\n};\n__iconData.node;\nconst WifiOff = createLucideIcon(__iconData);\n\nexport { __iconData, WifiOff as default };\n//# sourceMappingURL=wifi-off.mjs.map\n","import { formatWeekdayDate } from '../format/date'\nimport { dayIn, viewerZone } from '../format/zone'\nimport { text } from './messages'\n\nconst dayBefore = (day: string) => new Date(Date.parse(`${day}T00:00:00Z`) - 86_400_000).toISOString().slice(0, 10)\n\n/** Whether two ISO timestamps fall on the same day in `zone`, the viewer's unless given: a day divider goes between two messages that do not. */\nexport const sameChatDay = (a: string, b: string, zone = viewerZone()) => dayIn(Date.parse(a), zone) === dayIn(Date.parse(b), zone)\n\n/** The label of the divider above a day's first message, sent at `time`: \"Today\", \"Yesterday\" or \"Mon, 26 Oct 2026\", as the viewer's calendar in `zone` has it. */\nexport const chatDayLabel = (time: string, now = Date.now(), zone = viewerZone()) => {\n const day = dayIn(Date.parse(time), zone)\n const today = dayIn(now, zone)\n if (day === today) return text('today')\n if (day === dayBefore(today)) return text('yesterday')\n return formatWeekdayDate(Date.parse(`${day}T00:00:00Z`))\n}\n","import { cn } from '../lib/cn'\nimport { text } from './messages'\n\nexport type ChatDividerProps =\n /** A muted line between the messages of two days, labelled with the later one, such as by `chatDayLabel`. */\n | { tone?: 'day'; label: string }\n /** A line above the first message the reader has not seen, \"New messages\" unless labelled otherwise. */\n | { tone: 'new'; label?: string }\n\n/**\n * A line across a chat with a label in its middle, between the messages of two days or above the new ones. Marked\n * `data-chat-divider`, so a thread keeps the reader's place on the message below it, not on the divider.\n */\nexport const ChatDivider = ({ tone = 'day', label }: ChatDividerProps) => {\n const shown = label ?? text('newMessages')\n const line = cn('h-px flex-1', tone === 'new' ? 'bg-danger' : 'bg-border')\n return (\n <div role=\"separator\" aria-label={shown} data-tone={tone} data-chat-divider=\"\" className=\"flex items-center gap-3 text-xs font-medium\">\n <span className={line} />\n <span className={tone === 'new' ? 'text-danger' : 'text-muted-foreground'}>{shown}</span>\n <span className={line} />\n </div>\n )\n}\n","import type { AnchorHTMLAttributes } from 'react'\nimport type { KeyValue } from '@protobase/schema'\nimport { useLayoutRecord } from '../pages/record-scope'\nimport { AppLink } from '../use-app-address'\nimport { useOptionalListDisplay } from './display-context'\nimport type { ListDisplayRow } from './list-displays'\n\ntype Target = { row: ListDisplayRow; resource?: never; recordKey?: never } | { row?: never; resource?: string; recordKey: KeyValue | readonly KeyValue[] }\n\n/**\n * A link to a record's page, through the app's addresses: a list display's `row`, or a `recordKey` of `resource`. The\n * resource defaults to the list display's or the record's around it, so a custom component never writes a path.\n */\nexport const RecordLink = ({ row, resource, recordKey, ...rest }: AnchorHTMLAttributes<HTMLAnchorElement> & Target) => {\n const display = useOptionalListDisplay()\n const around = useLayoutRecord()\n const name = resource ?? display?.resource ?? around?.model.name\n if (name === undefined) throw new Error('RecordLink needs a resource outside a list display or a record')\n return <AppLink to={{ kind: 'record', resource: name, key: row ? row.key : recordKey }} {...rest} />\n}\n","import { useMemo } from 'react'\nimport { useOptionalAuth, type AuthState } from './auth-provider'\n\n/** Who is signed in: their user id, the id `.author()` stores and mentions hold, and their name. */\nexport type SignedInUser = { id: string; name?: string }\n\n/** The signed-in person of an auth state; none while it loads, for a visitor, and before the sign-in finished. */\nexport const signedInUserOf = (state: AuthState | undefined): SignedInUser | undefined => {\n if (state?.kind !== 'signed-in') return\n const { id, name } = state.user\n return { id, ...(name && { name }) }\n}\n\n/**\n * The signed-in person, from the session the app already holds, such as for a filter on their own user id;\n * `undefined` while the session loads, for a visitor and when nobody is signed in.\n */\nexport const useSignedInUser = (): SignedInUser | undefined => {\n const state = useOptionalAuth()?.state\n return useMemo(() => signedInUserOf(state), [state])\n}\n","import { useCallback, type VideoHTMLAttributes } from 'react'\n\n// Plays the element again whenever it pauses while its track is live: a media element the page takes out and puts\n// back, as React does when it moves a tile, is paused by the browser, and nothing else would play it again. A play the\n// browser cut short, or does not allow yet, is left to the next pause.\nconst keepPlaying = (element: HTMLMediaElement, track: MediaStreamTrack) => {\n element.srcObject = new MediaStream([track])\n const play = () => {\n if (track.readyState !== 'live') return\n element.play().catch((error: unknown) => {\n if (error instanceof DOMException && (error.name === 'AbortError' || error.name === 'NotAllowedError')) return\n throw error\n })\n }\n element.addEventListener('pause', play)\n return () => element.removeEventListener('pause', play)\n}\n\n/** A video element showing the track, muted, inline, playing as soon as it can and for as long as the track is live. */\nexport const TrackVideo = ({ track, ...rest }: { track: MediaStreamTrack } & VideoHTMLAttributes<HTMLVideoElement>) => {\n const ref = useCallback((element: HTMLVideoElement | null) => (element ? keepPlaying(element, track) : undefined), [track])\n return <video ref={ref} autoPlay playsInline muted {...rest} />\n}\n\n/** Plays the track's sound, unseen, for as long as the track is live. */\nexport const TrackAudio = ({ track }: { track: MediaStreamTrack }) => {\n const ref = useCallback((element: HTMLAudioElement | null) => (element ? keepPlaying(element, track) : undefined), [track])\n return <audio ref={ref} autoPlay />\n}\n","import { Mic, MicOff, Video, VideoOff } from 'lucide-react'\nimport { hueOf, initialsOf } from '../auth/user-to-shell'\nimport { cn } from '../lib/cn'\nimport { Avatar } from '../primitives/avatar'\nimport { Button } from '../primitives/button'\nimport { RouteLink, type RouteTarget } from '../primitives/route-link'\nimport { text } from './messages'\nimport { TrackVideo } from './track-media'\n\nexport type CallCheckProps = {\n name: string\n member: string\n /** The member's camera as it will be sent, to see before joining. */\n camera?: MediaStreamTrack\n microphoneOn: boolean\n cameraOn: boolean\n /** Whether the browser has a microphone and a camera it may use. */\n microphone: boolean\n cameraAvailable: boolean\n notices: string[]\n onMicrophone: () => void\n onCamera: () => void\n onJoin: () => void\n /** Where the member goes without joining. */\n cancel: RouteTarget\n}\n\nconst toggle = (on: boolean) => cn('size-10 rounded-full', !on && 'bg-danger-soft text-danger-text')\n\n/**\n * The check of the microphone and camera before joining: the member's own camera as the others will see it, or their\n * initials, microphone and camera on and off, plain messages for a blocked or missing device, and Join.\n */\nexport const CallCheck = ({ name, member, camera, microphoneOn, cameraOn, microphone, cameraAvailable, notices, onMicrophone, onCamera, onJoin, cancel }: CallCheckProps) => (\n <section aria-label={text('preview')} className=\"flex size-full min-h-0 flex-col items-center justify-center gap-3 bg-background p-4\">\n <figure className=\"relative flex aspect-video w-full max-w-md items-center justify-center overflow-hidden rounded-lg bg-neutral-900\">\n {camera && cameraOn ? <TrackVideo track={camera} aria-label={text('preview')} className=\"size-full -scale-x-100 object-cover\" /> : <Avatar initials={initialsOf(name)} hue={hueOf(member)} size=\"md\" className=\"size-16 text-xl ring-0\" />}\n </figure>\n {notices.length > 0 && (\n <div role=\"status\" className=\"flex w-full max-w-md flex-col gap-1\">\n {notices.map((notice) => (\n <p key={notice} className=\"rounded-md bg-warning-soft px-3 py-1.5 text-xs text-foreground\">\n {notice}\n </p>\n ))}\n </div>\n )}\n <div className=\"flex items-center gap-2\">\n <Button size=\"icon\" aria-label={text('microphone')} aria-pressed={microphoneOn} disabled={!microphone} className={toggle(microphoneOn)} onClick={onMicrophone}>\n {microphoneOn ? <Mic className=\"size-4\" /> : <MicOff className=\"size-4\" />}\n </Button>\n <Button size=\"icon\" aria-label={text('camera')} aria-pressed={cameraOn} disabled={!cameraAvailable} className={toggle(cameraOn)} onClick={onCamera}>\n {cameraOn ? <Video className=\"size-4\" /> : <VideoOff className=\"size-4\" />}\n </Button>\n <Button variant=\"primary\" className=\"h-10 rounded-full px-5\" onClick={onJoin}>\n {text('joinCall')}\n </Button>\n <RouteLink to={cancel} className=\"px-2 text-sm text-muted-foreground hover:text-foreground\">\n {text('leave')}\n </RouteLink>\n </div>\n </section>\n)\n","import type { CallLeftReason } from '@protobase/client/calls'\nimport { Button } from '../primitives/button'\nimport { text } from './messages'\n\nconst said: Record<Exclude<CallLeftReason, 'rejoin'>, Parameters<typeof text>[0]> = { ended: 'ended', removed: 'removed', full: 'full', refused: 'refused', unavailable: 'unavailable' }\n\n/** Why the member is not in the call, in plain words, and, unless they were removed, a way to join again. */\nexport const CallMessage = ({ reason, onJoinAgain }: { reason: CallLeftReason; onJoinAgain?: () => void }) => (\n <section role=\"status\" className=\"flex size-full min-h-0 flex-col items-center justify-center gap-3 bg-background p-4 text-center\">\n <p className=\"text-sm text-foreground\">{text(reason === 'rejoin' ? 'ended' : said[reason])}</p>\n {onJoinAgain && reason !== 'removed' && reason !== 'refused' && <Button onClick={onJoinAgain}>{text('callAgain')}</Button>}\n </section>\n)\n","/**\n * How a call's tiles are laid out: `alone` while the member is the only one in it, `grid` for everyone at the same\n * size, `share` with a screen share large and the people in a strip beside or under it.\n */\nexport type CallLayout = { kind: 'alone' } | { kind: 'grid'; columns: number } | { kind: 'share'; sharer: string }\n\n/** Below this width the view is a phone's: one column of two people, then two columns, and the strip goes under a share. */\nexport const narrowWidth = 640\n\n/** The columns a grid of `count` tiles takes in a view `width` pixels wide: as square as fits, fewer on a phone. */\nexport const gridColumns = (count: number, width: number) => {\n if (width < narrowWidth) return count <= 2 ? 1 : 2\n return Math.min(4, Math.ceil(Math.sqrt(count)))\n}\n\n/** The layout for these people, the member included, and the member sharing their screen, the first of them if several do. */\nexport const callLayout = ({ people, sharers, width }: { people: number; sharers: readonly string[]; width: number }): CallLayout => {\n if (sharers[0] !== undefined) return { kind: 'share', sharer: sharers[0] }\n if (people <= 1) return { kind: 'alone' }\n return { kind: 'grid', columns: gridColumns(people, width) }\n}\n\n/** How a connection fares, as its tile shows it: poor past a round trip of 400 ms or a loss of 5% of the media. */\nexport const connectionQuality = ({ roundTripMs, lostRatio }: { roundTripMs?: number; lostRatio?: number }) => ((roundTripMs ?? 0) > 400 || (lostRatio ?? 0) > 0.05 ? 'poor' : 'good')\n\n/** How long a connection may stay unconnected before its tile says the browser cannot connect to that person. */\nexport const connectGiveUpMs = 15_000\n\n/** Whether the browser cannot connect to someone: their connection failed, or is not up `connectGiveUpMs` after they came. */\nexport const cannotConnect = (state: RTCPeerConnectionState | undefined, since: number, now: number) => state === 'failed' || (state !== 'connected' && now - since >= connectGiveUpMs)\n\n/** The loudest of these levels, from 0 to 1, when one is loud enough to be someone speaking. */\nexport const activeSpeaker = (levels: ReadonlyMap<string, number>, threshold = 0.05) => {\n let loudest: [string, number] | undefined\n for (const [member, level] of levels) if (level >= threshold && (!loudest || level > loudest[1])) loudest = [member, level]\n return loudest?.[0]\n}\n","import type { CallConnection, CallRosterMember, CallTrack } from '@protobase/client/calls'\nimport { cannotConnect, connectionQuality } from './call-layout'\nimport type { CallPerson } from './call-person'\n\n/** What the member sends themselves: their own tracks, and which of them are on. */\nexport type OwnMedia = { microphone?: MediaStreamTrack; camera?: MediaStreamTrack; screen?: MediaStreamTrack; microphoneOn: boolean; cameraOn: boolean }\n\nexport type PeopleInput = {\n members: readonly CallRosterMember[]\n self: string\n tracks: readonly CallTrack[]\n own: OwnMedia\n nameOf: (member: string) => string\n speaker?: string\n connections: readonly CallConnection[]\n /** When this browser first knew of each member, by member: how long their connection has had to come up. */\n seen: ReadonlyMap<string, number>\n now: number\n}\n\nconst received = (tracks: readonly CallTrack[], source: CallTrack['source']) => tracks.find((track) => track.source === source && track.track)\n\n/** Everyone in the call as the view draws them, in the order they came, the member among them as `self`. */\nexport const callPeople = ({ members, self, tracks, own, nameOf, speaker, connections, seen, now }: PeopleInput): CallPerson[] => {\n const roster = members.some((member) => member.member === self) ? members : [{ member: self, joined_at: '' }, ...members]\n return roster.map(({ member }): CallPerson => {\n const shared = { member, name: nameOf(member), ...(speaker === member && { speaking: true }) }\n if (member === self) {\n return { ...shared, self: true, ...(own.camera && { camera: own.camera }), ...(own.microphone && { microphone: own.microphone }), ...(own.screen && { screen: own.screen }), microphoneOff: !own.microphone || !own.microphoneOn, cameraOff: !own.camera || !own.cameraOn }\n }\n const theirs = tracks.filter((track) => track.member === member)\n const [camera, microphone, screen, screenAudio] = (['camera', 'microphone', 'screen', 'screen-audio'] as const).map((source) => received(theirs, source))\n const link = connections.find((connection) => connection.member === member)\n const connection = cannotConnect(link?.state, seen.get(member) ?? now, now) ? 'failed' : link?.state === 'connected' ? connectionQuality(link) : undefined\n return {\n ...shared,\n ...(camera && { camera: camera.track! }),\n ...(microphone && { microphone: microphone.track! }),\n ...(screen && { screen: screen.track! }),\n ...(screenAudio && { screenAudio: screenAudio.track! }),\n microphoneOff: !microphone || microphone.muted,\n cameraOff: !camera || camera.muted,\n ...(connection && { connection }),\n }\n })\n}\n","import { Mic, MicOff, MonitorUp, MonitorX, PhoneOff, Video, VideoOff } from 'lucide-react'\nimport { buttonClass, Button } from '../primitives/button'\nimport { RouteLink, type RouteTarget } from '../primitives/route-link'\nimport { cn } from '../lib/cn'\nimport { text } from './messages'\n\nexport type CallControlsProps = {\n microphoneOn: boolean\n cameraOn: boolean\n /** Whether the member shares their screen; no share button where the browser cannot share one, as on a phone. */\n sharing?: boolean\n onMicrophone: () => void\n onCamera: () => void\n onShare?: () => void\n /** Where Leave goes, such as the record's page without its call: leaving the page leaves the call. */\n leave: RouteTarget\n}\n\nconst toggle = (on: boolean) => cn('size-10 rounded-full', !on && 'bg-danger-soft text-danger-text')\n\n/** The member's controls: microphone, camera and screen share on and off, and Leave, a link out of the call. */\nexport const CallControls = ({ microphoneOn, cameraOn, sharing, onMicrophone, onCamera, onShare, leave }: CallControlsProps) => (\n <div role=\"toolbar\" aria-label={text('joinCall')} className=\"flex shrink-0 items-center justify-center gap-2 py-2\">\n <Button size=\"icon\" aria-label={text('microphone')} aria-pressed={microphoneOn} title={text('microphone')} className={toggle(microphoneOn)} onClick={onMicrophone}>\n {microphoneOn ? <Mic className=\"size-4\" /> : <MicOff className=\"size-4\" />}\n </Button>\n <Button size=\"icon\" aria-label={text('camera')} aria-pressed={cameraOn} title={text('camera')} className={toggle(cameraOn)} onClick={onCamera}>\n {cameraOn ? <Video className=\"size-4\" /> : <VideoOff className=\"size-4\" />}\n </Button>\n {onShare && (\n <Button size=\"icon\" aria-label={sharing ? text('stopSharing') : text('shareScreen')} aria-pressed={Boolean(sharing)} title={sharing ? text('stopSharing') : text('shareScreen')} className=\"size-10 rounded-full\" onClick={onShare}>\n {sharing ? <MonitorX className=\"size-4\" /> : <MonitorUp className=\"size-4\" />}\n </Button>\n )}\n <RouteLink to={leave} className={cn(buttonClass({ variant: 'danger' }), 'h-10 rounded-full px-4')}>\n <PhoneOff className=\"size-4\" />\n {text('leave')}\n </RouteLink>\n </div>\n)\n","import { MicOff, WifiOff } from 'lucide-react'\nimport { hueOf, initialsOf } from '../auth/user-to-shell'\nimport { cn } from '../lib/cn'\nimport { Avatar } from '../primitives/avatar'\nimport type { CallPerson } from './call-person'\nimport { text } from './messages'\nimport { TrackVideo } from './track-media'\n\n/**\n * One person in a call: their camera, or their initials while it sends nothing; their name, a mark while their\n * microphone is off or their connection is poor, a ring while they speak, and a plain message when the member's\n * browser cannot connect to them. `screen` draws their screen share instead, whole.\n */\nexport const CallTile = ({ person, screen = false, className }: { person: CallPerson; screen?: boolean; className?: string }) => {\n const track = screen ? person.screen : person.cameraOff ? undefined : person.camera\n const label = screen ? (person.self ? text('youAreSharing') : text('sharing', person.name)) : person.self ? `${person.name} (${text('you')})` : person.name\n return (\n <figure\n data-member={person.member}\n data-speaking={person.speaking ? 'true' : undefined}\n aria-label={label}\n className={cn('relative flex min-h-0 min-w-0 items-center justify-center overflow-hidden rounded-lg bg-neutral-900 ring-offset-2 ring-offset-background', person.speaking && !screen && 'ring-2 ring-success', className)}\n >\n {track ? (\n <TrackVideo track={track} className={cn('size-full', screen ? 'object-contain' : 'object-cover', person.self && !screen && '-scale-x-100')} />\n ) : (\n <Avatar initials={initialsOf(person.name)} hue={hueOf(person.member)} size=\"md\" className=\"size-16 text-xl ring-0\" />\n )}\n {person.connection === 'failed' && !person.self && (\n <p role=\"status\" className=\"absolute inset-x-1 top-1 truncate rounded bg-black/70 px-2 py-1 text-center text-xs text-white\">\n {text('cannotConnect', person.name)}\n </p>\n )}\n <figcaption className=\"absolute bottom-1.5 left-1.5 flex max-w-[calc(100%-0.75rem)] items-center gap-1 rounded bg-black/60 px-1.5 py-0.5 text-xs text-white\">\n {!screen && person.microphoneOff && <MicOff role=\"img\" aria-label={text('muted')} className=\"size-3 shrink-0\" />}\n {!screen && person.connection === 'poor' && <WifiOff role=\"img\" aria-label={text('poorConnection')} className=\"size-3 shrink-0 text-warning\" />}\n <span className=\"truncate\">{label}</span>\n </figcaption>\n </figure>\n )\n}\n","import { useCallback, useState } from 'react'\n\n/** The width of the element the returned ref is put on, followed as it changes; 0 until it is drawn. */\nexport const useWidth = <T extends HTMLElement>() => {\n const [width, setWidth] = useState(0)\n const ref = useCallback((element: T | null) => {\n if (!element) return\n setWidth(element.clientWidth)\n const observer = new ResizeObserver(([entry]) => setWidth(entry!.contentRect.width))\n observer.observe(element)\n return () => observer.disconnect()\n }, [])\n return { ref, width }\n}\n","import { Spinner } from '../primitives/spinner'\nimport { cn } from '../lib/cn'\nimport { CallControls, type CallControlsProps } from './call-controls'\nimport { callLayout, type CallLayout } from './call-layout'\nimport type { CallPerson } from './call-person'\nimport { CallTile } from './call-tile'\nimport { text } from './messages'\nimport { TrackAudio } from './track-media'\nimport { useWidth } from './use-width'\n\nexport type CallStageProps = {\n /** Everyone in the call, the member too, in the order they came. */\n people: CallPerson[]\n /** `resuming` while the link to the server is restored; media keeps flowing meanwhile. */\n state: 'joining' | 'joined' | 'resuming'\n /** Plain messages for the member, such as a blocked camera. */\n notices?: string[]\n controls: CallControlsProps\n className?: string\n}\n\n// The most people the strip beside a screen share shows; the rest are a count.\nconst stripMax = 4\n\nconst Grid = ({ people, columns }: { people: CallPerson[]; columns: number }) => (\n <div className=\"grid size-full min-h-0 gap-2\" style={{ gridTemplateColumns: `repeat(${columns}, minmax(0, 1fr))`, gridTemplateRows: `repeat(${Math.ceil(people.length / columns)}, minmax(0, 1fr))` }}>\n {people.map((person) => (\n <CallTile key={person.member} person={person} />\n ))}\n </div>\n)\n\nconst Share = ({ people, sharer, narrow }: { people: CallPerson[]; sharer: CallPerson; narrow: boolean }) => {\n const shown = people.slice(0, stripMax)\n const more = people.length - shown.length\n return (\n <div className={cn('flex size-full min-h-0 gap-2', narrow ? 'flex-col' : 'flex-row')}>\n <CallTile person={sharer} screen className=\"min-h-0 flex-1\" />\n <div className={cn('flex shrink-0 gap-2', narrow ? 'h-20 flex-row' : 'w-40 flex-col')}>\n {shown.map((person) => (\n <CallTile key={person.member} person={person} className={narrow ? 'aspect-video h-full' : 'aspect-video w-full'} />\n ))}\n {more > 0 && <p className=\"flex items-center justify-center rounded-lg bg-muted px-2 text-xs text-muted-foreground\">+{more}</p>}\n </div>\n </div>\n )\n}\n\nconst Tiles = ({ layout, people, narrow }: { layout: CallLayout; people: CallPerson[]; narrow: boolean }) => {\n if (layout.kind === 'share') return <Share people={people} sharer={people.find((person) => person.member === layout.sharer)!} narrow={narrow} />\n if (layout.kind === 'grid') return <Grid people={people} columns={layout.columns} />\n return (\n <div className=\"relative size-full min-h-0\">\n <CallTile person={people[0]!} className=\"size-full\" />\n <p className=\"absolute inset-x-0 top-3 text-center text-sm text-white drop-shadow\">{text('alone')}</p>\n </div>\n )\n}\n\n/**\n * A call as the member sees it, filling its parent: everyone at the same size, with the one speaking ringed; a screen\n * share large with the people beside it, or under it on a phone; the member alone; then the controls. The others'\n * sound plays unseen.\n */\nexport const CallStage = ({ people, state, notices = [], controls, className }: CallStageProps) => {\n const { ref, width } = useWidth<HTMLDivElement>()\n const narrow = width > 0 && width < 640\n const layout = callLayout({ people: people.length, sharers: people.filter((person) => person.screen).map((person) => person.member), width })\n const messages = [...(state === 'resuming' ? [text('reconnecting')] : []), ...notices]\n return (\n <section ref={ref} aria-label={text('joinCall')} data-layout={layout.kind} className={cn('flex size-full min-h-0 flex-col gap-2 bg-background p-2', className)}>\n {messages.length > 0 && (\n <div role=\"status\" className=\"flex shrink-0 flex-col gap-1\">\n {messages.map((message) => (\n <p key={message} className=\"flex items-center gap-2 rounded-md bg-warning-soft px-3 py-1.5 text-xs text-foreground\">\n {message === text('reconnecting') && <Spinner className=\"size-3\" />}\n {message}\n </p>\n ))}\n </div>\n )}\n <div className=\"min-h-0 flex-1\">\n {state === 'joining' ? (\n <p role=\"status\" className=\"flex size-full items-center justify-center gap-2 text-muted-foreground\">\n <Spinner className=\"size-4\" />\n {text('connecting')}\n </p>\n ) : (\n <Tiles layout={layout} people={people} narrow={narrow} />\n )}\n </div>\n <CallControls {...controls} />\n {people\n .filter((person) => !person.self)\n .flatMap((person) => [['microphone', person.microphone] as const, ['screen-audio', person.screenAudio] as const].map(([source, track]) => track && { key: `${person.member} ${source}`, track }))\n .filter((audio) => audio !== undefined)\n .map(({ key, track }) => (\n <TrackAudio key={key} track={track} />\n ))}\n </section>\n )\n}\n","import { useEffect, useState } from 'react'\nimport { activeSpeaker } from './call-layout'\n\n// How often the levels are read, and how long the last speaker keeps the ring after they stop, so it does not flicker.\nconst readEveryMs = 200\nconst holdMs = 1000\n\n// A level from 0 to 1: the root mean square of the samples.\nconst levelOf = (analyser: AnalyserNode, samples: Float32Array<ArrayBuffer>) => {\n analyser.getFloatTimeDomainData(samples)\n let sum = 0\n for (const sample of samples) sum += sample * sample\n return Math.min(1, Math.sqrt(sum / samples.length) * 4)\n}\n\n/** Who of these members is speaking, by the sound of their microphone tracks, read in the browser through Web Audio. */\nexport const useActiveSpeaker = (tracks: ReadonlyMap<string, MediaStreamTrack>) => {\n const [speaker, setSpeaker] = useState<string>()\n const ids = [...tracks].map(([member, track]) => `${member}:${track.id}`).join(',')\n useEffect(() => {\n if (tracks.size === 0 || typeof AudioContext === 'undefined') return\n const context = new AudioContext()\n const analysers = new Map(\n [...tracks].map(([member, track]) => {\n const analyser = context.createAnalyser()\n analyser.fftSize = 512\n context.createMediaStreamSource(new MediaStream([track])).connect(analyser)\n return [member, analyser] as const\n }),\n )\n const samples = new Float32Array(512)\n let last: { member: string; at: number } | undefined\n const timer = setInterval(() => {\n const loudest = activeSpeaker(new Map([...analysers].map(([member, analyser]) => [member, levelOf(analyser, samples)])))\n if (loudest) last = { member: loudest, at: Date.now() }\n setSpeaker(last && Date.now() - last.at < holdMs ? last.member : undefined)\n }, readEveryMs)\n return () => {\n clearInterval(timer)\n void context.close()\n }\n // Keyed by the tracks' ids, which `tracks` changes with, so a new map of the same tracks reads on.\n }, [ids])\n return speaker\n}\n","/** The member's microphone and camera as the browser gives them, and why one is missing: blocked, or none found. */\nexport type Devices = { microphone?: MediaStreamTrack; camera?: MediaStreamTrack; blocked: { microphone: boolean; camera: boolean }; none: boolean }\n\n// What `getUserMedia` rejects with for a device the person or the browser keeps from the page, or that is not there.\nconst blockedNames = new Set(['NotAllowedError', 'SecurityError'])\nconst missingNames = new Set(['NotFoundError', 'NotReadableError', 'OverconstrainedError'])\n\ntype Kind = 'audio' | 'video'\n\n// One kind of device: its track, or whether it is blocked or missing.\nconst one = async (media: MediaDevices, kind: Kind): Promise<{ track?: MediaStreamTrack; blocked: boolean }> => {\n try {\n const stream = await media.getUserMedia({ [kind]: true })\n return { track: stream.getTracks()[0]!, blocked: false }\n } catch (error) {\n if (!(error instanceof DOMException)) throw error\n if (blockedNames.has(error.name)) return { blocked: true }\n if (missingNames.has(error.name)) return { blocked: false }\n throw error\n }\n}\n\n/**\n * Asks for the microphone and the camera at once, so the browser asks the person once; when that is refused, each on\n * its own, to tell which one is blocked or missing.\n */\nexport const openDevices = async (media: MediaDevices = navigator.mediaDevices): Promise<Devices> => {\n try {\n const stream = await media.getUserMedia({ audio: true, video: true })\n return { microphone: stream.getAudioTracks()[0], camera: stream.getVideoTracks()[0], blocked: { microphone: false, camera: false }, none: false }\n } catch (error) {\n if (!(error instanceof DOMException) || !(blockedNames.has(error.name) || missingNames.has(error.name))) throw error\n }\n const [audio, video] = [await one(media, 'audio'), await one(media, 'video')]\n return {\n ...(audio.track && { microphone: audio.track }),\n ...(video.track && { camera: video.track }),\n blocked: { microphone: audio.blocked, camera: video.blocked },\n none: !audio.track && !video.track && !audio.blocked && !video.blocked,\n }\n}\n","import { useCallback, useEffect, useRef, useState } from 'react'\nimport type { Call, CallConnection, CallLeftReason, CallRosterMember, CallTrack } from '@protobase/client/calls'\nimport { openDevices, type Devices } from './devices'\n\n/** Where the member stands: checking their devices, joining, in the call (`resuming` while its link is restored), or out of it. */\nexport type CallPhase = { kind: 'check' } | { kind: 'joining' } | { kind: 'in'; resuming: boolean } | { kind: 'left'; reason: CallLeftReason }\n\n// How often the connections' state and quality are read while in the call.\nconst connectionsEveryMs = 2000\n\nconst stop = (tracks: readonly (MediaStreamTrack | undefined)[]) => {\n for (const track of tracks) track?.stop()\n}\n\n/**\n * The member's session in the call the app's function at `url` admits them to: their devices from the start, for the\n * check before joining; then the call, which `join` joins after the click, with what they send and receive, and who\n * is in it. Leaving the page leaves the call and stops the devices.\n */\nexport const useCallSession = (url: string) => {\n const [phase, setPhase] = useState<CallPhase>({ kind: 'check' })\n const [devices, setDevices] = useState<Devices>()\n const [microphoneOn, setMicrophoneOn] = useState(true)\n const [cameraOn, setCameraOn] = useState(true)\n const [tracks, setTracks] = useState<CallTrack[]>([])\n const [members, setMembers] = useState<CallRosterMember[]>([])\n const [connections, setConnections] = useState<CallConnection[]>([])\n const [screen, setScreen] = useState<{ video: MediaStreamTrack; audio?: MediaStreamTrack }>()\n const [refusedSending, setRefusedSending] = useState(false)\n const call = useRef<Call | undefined>(undefined)\n const gone = useRef(false)\n const own = useRef<(MediaStreamTrack | undefined)[]>([])\n const seen = useRef(new Map<string, number>())\n\n // The devices as they open: a join clicked before they did waits for them.\n const opening = useRef<Promise<Devices | undefined>>(Promise.resolve(undefined))\n\n useEffect(() => {\n let cancelled = false\n gone.current = false\n opening.current = openDevices().then((opened) => {\n if (cancelled) {\n stop([opened.microphone, opened.camera])\n return\n }\n own.current.push(opened.microphone, opened.camera)\n setDevices(opened)\n return opened\n })\n return () => {\n cancelled = true\n gone.current = true\n call.current?.leave()\n call.current = undefined\n stop(own.current)\n own.current = []\n }\n }, [])\n\n useEffect(() => {\n for (const { member } of members) if (!seen.current.has(member)) seen.current.set(member, Date.now())\n }, [members])\n\n useEffect(() => {\n if (phase.kind !== 'in') return\n const timer = setInterval(() => void call.current?.connections().then(setConnections), connectionsEveryMs)\n return () => clearInterval(timer)\n }, [phase.kind])\n\n const join = useCallback(async () => {\n setPhase({ kind: 'joining' })\n const { joinCall, PublishRefused } = await import('@protobase/client/calls')\n const joined = await joinCall({\n url,\n onTracks: setTracks,\n onMembers: setMembers,\n onState: (state) => {\n if (state.state === 'joined' || state.state === 'resuming') setPhase({ kind: 'in', resuming: state.state === 'resuming' })\n if (state.state === 'left') setPhase({ kind: 'left', reason: state.reason })\n },\n }).then(\n (made) => made,\n // A join that failed is left, and `onState` said why.\n () => undefined,\n )\n if (!joined) return\n if (gone.current) return joined.leave()\n call.current = joined\n const opened = await opening.current\n const sending = { ...(opened?.microphone && { microphone: opened.microphone }), ...(opened?.camera && { camera: opened.camera }) }\n await joined.publish(sending).then(\n () => {\n if (sending.microphone) joined.mute('microphone', !microphoneOn)\n if (sending.camera) joined.mute('camera', !cameraOn)\n },\n (error: unknown) => {\n if (!(error instanceof PublishRefused)) throw error\n setRefusedSending(true)\n },\n )\n }, [url, microphoneOn, cameraOn])\n\n const toggleMicrophone = useCallback(() => {\n const next = !microphoneOn\n setMicrophoneOn(next)\n if (devices?.microphone) devices.microphone.enabled = next\n call.current?.mute('microphone', !next)\n }, [microphoneOn, devices])\n\n const toggleCamera = useCallback(() => {\n const next = !cameraOn\n setCameraOn(next)\n if (devices?.camera) devices.camera.enabled = next\n call.current?.mute('camera', !next)\n }, [cameraOn, devices])\n\n const stopSharing = useCallback(async (shared: { video: MediaStreamTrack; audio?: MediaStreamTrack }) => {\n setScreen(undefined)\n stop([shared.video, shared.audio])\n await call.current?.unpublish('screen')\n if (shared.audio) await call.current?.unpublish('screen-audio')\n }, [])\n\n const toggleScreen = useCallback(async () => {\n if (screen) return stopSharing(screen)\n let display: MediaStream\n try {\n display = await navigator.mediaDevices.getDisplayMedia({ video: true, audio: true })\n } catch (error) {\n // The person closed the browser's picker without sharing.\n if (error instanceof DOMException && error.name === 'NotAllowedError') return\n throw error\n }\n const shared = { video: display.getVideoTracks()[0]!, ...(display.getAudioTracks()[0] && { audio: display.getAudioTracks()[0] }) }\n own.current.push(shared.video, shared.audio)\n shared.video.addEventListener('ended', () => void stopSharing(shared))\n await call.current?.publish({ screen: shared.video, ...(shared.audio && { 'screen-audio': shared.audio }) })\n setScreen(shared)\n }, [screen, stopSharing])\n\n const canShare = typeof navigator !== 'undefined' && typeof navigator.mediaDevices?.getDisplayMedia === 'function'\n\n return {\n phase,\n devices,\n microphoneOn,\n cameraOn,\n tracks,\n members,\n connections,\n screen,\n refusedSending,\n seen: seen.current,\n self: call.current?.participant,\n join,\n toggleMicrophone,\n toggleCamera,\n ...(canShare && { toggleScreen }),\n }\n}\n","import { useState } from 'react'\nimport { useOptionalAuth } from '../auth/auth-provider'\nimport type { RouteTarget } from '../primitives/route-link'\nimport { CallCheck } from './call-check'\nimport { CallMessage } from './call-message'\nimport { callPeople } from './call-people'\nimport { CallStage } from './call-stage'\nimport { text } from './messages'\nimport { useActiveSpeaker } from './use-audio-levels'\nimport { useCallSession } from './use-call-session'\n\nexport type CallViewProps = {\n /** The socket of the app's function that admits the member, as `joinCall` takes it, such as `/api/functions/call?conversation=7`. */\n url: string\n /** Where Leave goes; leaving the page leaves the call. */\n leave: RouteTarget\n /** A member's name, by the member the app's function admits them as, such as a user id; the member itself by default. */\n nameOf?: (member: string) => string\n className?: string\n}\n\nconst deviceNotices = (devices: ReturnType<typeof useCallSession>['devices'], refusedSending: boolean) => [\n ...(devices?.blocked.microphone ? [text('noMicrophone')] : []),\n ...(devices?.blocked.camera ? [text('noCamera')] : []),\n ...(devices?.none ? [text('noDevices')] : []),\n ...(refusedSending ? [text('refused')] : []),\n]\n\n/**\n * A call, ready-made, that fills its parent, such as a column beside a conversation's messages: a check of the\n * microphone and camera first, then, after Join, everyone in the call with the one speaking ringed, a screen share\n * large, microphone, camera, screen share and Leave, the quality of each connection, Reconnecting while the link is\n * restored, and plain words for a full call, a blocked device or someone the browser cannot connect to. Made for small\n * peer-to-peer calls, at a desktop's width or a phone's.\n */\nexport const CallView = ({ url, leave, nameOf = (member) => member, className }: CallViewProps) => {\n const session = useCallSession(url)\n const auth = useOptionalAuth()\n const user = auth?.state.kind === 'signed-in' ? auth.state.user : undefined\n const self = session.self ?? user?.id ?? ''\n const [now] = useState(() => Date.now())\n const { devices, phase } = session\n const own = { ...(devices?.microphone && { microphone: devices.microphone }), ...(devices?.camera && { camera: devices.camera }), ...(session.screen && { screen: session.screen.video }), microphoneOn: session.microphoneOn, cameraOn: session.cameraOn }\n const voices = new Map([...(devices?.microphone && session.microphoneOn ? [[self, devices.microphone] as const] : []), ...session.tracks.filter((track) => track.source === 'microphone' && track.track && !track.muted).map((track) => [track.member, track.track!] as const)])\n const speaker = useActiveSpeaker(phase.kind === 'in' ? voices : new Map())\n const notices = deviceNotices(devices, session.refusedSending)\n\n if (phase.kind === 'left') return <CallMessage reason={phase.reason} onJoinAgain={() => void session.join()} />\n if (phase.kind === 'check') {\n return (\n <CallCheck\n name={user?.name ?? text('you')}\n member={self}\n {...(devices?.camera && { camera: devices.camera })}\n microphoneOn={session.microphoneOn}\n cameraOn={session.cameraOn}\n microphone={Boolean(devices?.microphone)}\n cameraAvailable={Boolean(devices?.camera)}\n notices={notices}\n onMicrophone={session.toggleMicrophone}\n onCamera={session.toggleCamera}\n onJoin={() => void session.join()}\n cancel={leave}\n />\n )\n }\n const people = callPeople({ members: session.members, self, tracks: session.tracks, own, nameOf, ...(speaker && { speaker }), connections: session.connections, seen: session.seen, now: Math.max(now, Date.now()) })\n return (\n <CallStage\n {...(className && { className })}\n people={people}\n state={phase.kind === 'joining' ? 'joining' : phase.resuming ? 'resuming' : 'joined'}\n notices={notices}\n controls={{\n microphoneOn: session.microphoneOn && Boolean(devices?.microphone),\n cameraOn: session.cameraOn && Boolean(devices?.camera),\n sharing: Boolean(session.screen),\n onMicrophone: session.toggleMicrophone,\n onCamera: session.toggleCamera,\n ...(session.toggleScreen && { onShare: () => void session.toggleScreen!() }),\n leave,\n }}\n />\n )\n}\n","import { useAppAddress } from '../app/use-app-address'\n\n/**\n * A record's call as the app's address holds it: whether the page joins it (`call=join`), the link that joins it, as a\n * ring's Accept and a call mark's Join open it, and the link back to the record without the call, as Leave opens it.\n */\nexport const useRecordCallAddress = (resource: string, recordKey: string) => {\n const { address, href, open } = useAppAddress()\n const joining = address?.kind === 'record' && address.resource === resource && address.key === recordKey && address.call === 'join'\n const target = (to: string) => ({ href: to, onFollow: () => open(to) })\n return { joining, join: target(href({ kind: 'record', resource, key: recordKey, call: 'join' })), leave: target(href({ kind: 'record', resource, key: recordKey })) }\n}\n","import { CallView, type CallViewProps } from './call-view'\nimport { useRecordCallAddress } from './use-record-call-address'\n\nexport type RecordCallProps = Omit<CallViewProps, 'leave'> & { resource: string; recordKey: string }\n\n/**\n * The record's call view while the app's address joins it (`call=join`, as Accept and Join open it), and nothing\n * otherwise: put it beside the record's own content, such as on a full-area record page. Leave goes back to the record.\n */\nexport const RecordCall = ({ resource, recordKey, ...rest }: RecordCallProps) => {\n const { joining, leave } = useRecordCallAddress(resource, recordKey)\n if (!joining) return null\n return <CallView key={`${resource}/${recordKey}`} leave={leave} {...rest} />\n}\n","import { useQuery, useQueryClient } from '@tanstack/react-query'\nimport { useEffect } from 'react'\nimport type { RecordCall } from '@protobase/client'\nimport { callsChannelEvent } from '@protobase/schema/internal'\nimport { useClient } from '../data/api-provider'\nimport { keys } from '../data/query-keys'\n\n/**\n * A record's latest calls, the one going on first, kept current over the record's channel, on the one socket the page\n * shares for every channel it holds: the server sends the calls there whenever they change, so following a record's\n * calls opens no connection of its own on a page that holds a channel already. Read again whenever the channel joins,\n * as after a lost connection.\n */\nexport const useRecordCalls = (resource: string, recordKey: string) => {\n const client = useClient()\n const queryClient = useQueryClient()\n const key = keys.recordCalls(resource, recordKey)\n const query = useQuery({ queryKey: key, queryFn: () => client.calls(resource, recordKey) })\n\n useEffect(() => {\n const queryKey = keys.recordCalls(resource, recordKey)\n const channel = client.channel(resource, recordKey)\n // Only the server's own message: anyone on the channel can broadcast under the same event.\n const offCalls = channel.on(callsChannelEvent, (message) => message.server && queryClient.setQueryData<RecordCall[]>(queryKey, (message.payload as { items: RecordCall[] }).items))\n const offStatus = channel.onStatus((status) => status.state === 'joined' && void queryClient.invalidateQueries({ queryKey }))\n return () => {\n offCalls()\n offStatus()\n channel.leave()\n }\n }, [client, queryClient, resource, recordKey])\n\n return { ...query, ongoing: query.data?.find((call) => call.ended_at === null) }\n}\n","import { Phone } from 'lucide-react'\nimport { cn } from '../lib/cn'\nimport { buttonClass } from '../primitives/button'\nimport { RouteLink } from '../primitives/route-link'\nimport { text } from './messages'\nimport { useRecordCalls } from './use-record-calls'\nimport { useRecordCallAddress } from './use-record-call-address'\n\nexport type CallMarkProps = { resource: string; recordKey: string; className?: string }\n\n/**\n * A record's call, for the app to place where it wants, such as a conversation's header: Start call while there is\n * none, and \"Call in progress · 3 · Join\" while one goes on, live. Start call and Join are links to the record's page\n * that joins its call (`call=join`); on that page itself, Join is left out.\n */\nexport const CallMark = ({ resource, recordKey, className }: CallMarkProps) => {\n const { ongoing, isPending } = useRecordCalls(resource, recordKey)\n const { joining, join } = useRecordCallAddress(resource, recordKey)\n if (isPending) return null\n if (!ongoing) {\n if (joining) return null\n return (\n <RouteLink to={join} className={cn(buttonClass({ size: 'sm' }), className)}>\n <Phone className=\"size-3.5\" />\n {text('startCall')}\n </RouteLink>\n )\n }\n const count = ongoing.members.length\n return (\n <span role=\"status\" className={cn('inline-flex items-center gap-1.5 rounded-md bg-success-soft px-2 py-0.5 text-body text-foreground', className)}>\n <Phone className=\"size-3.5 text-success\" />\n {text('inProgress')}\n <span aria-hidden>·</span>\n <span aria-label={text('people', count)}>{count}</span>\n {!joining && (\n <>\n <span aria-hidden>·</span>\n <RouteLink to={join} className={buttonClass({ variant: 'primary', size: 'sm' })}>\n {text('join')}\n </RouteLink>\n </>\n )}\n </span>\n )\n}\n","import type { StoredFile } from '@protobase/client'\nimport { shownImage } from '../live/file-values'\n\n/** An image a carousel shows: a link with what it shows, or a file field's value, as records carry it. */\nexport type CarouselImage = { src: string; alt: string } | (StoredFile & { alt?: string })\n\n// A frame up to about half a page wide: of a file's variants, the smallest that covers it is drawn, the file itself when none does\nconst box = { width: 640, height: 480 }\n\n/** What each slide draws, in order: a file that is missing or is no raster image is left out. */\nexport const carouselSlides = (images: readonly CarouselImage[]) =>\n images.flatMap((image) => {\n if ('src' in image) return [{ image: { url: image.src }, alt: image.alt }]\n const shown = shownImage(image, box)\n return shown ? [{ image: shown, alt: image.alt ?? '' }] : []\n })\n","import { cn } from '../lib/cn'\nimport { FileImage } from '../live/file-image'\nimport { CarouselControls } from './carousel-controls'\nimport { carouselSlides, type CarouselImage } from './carousel-images'\nimport { CarouselTrack } from './carousel-track'\nimport { useCarousel } from './use-carousel'\n\nexport type CarouselProps = {\n /** The images in order: links with what each shows, or file field values. */\n images: readonly CarouselImage[]\n /** What the images are, read out with the carousel. */\n label?: string\n /** `cover` fills the frame and crops what overflows it, the default; `contain` shows each image whole. */\n fit?: 'cover' | 'contain'\n /** Whether a swipe steps through the images; off, it scrolls what the carousel sits in, such as a row that scrolls sideways. */\n swipe?: boolean\n /** The frame's classes, such as its aspect ratio, border and rounding. */\n className?: string\n}\n\n/**\n * Images side by side in a frame that snaps image by image, swiped on a touch screen or moved by arrows on hover, with\n * dots marking the one in view; the record cards' photos step the same way. A single image shows without arrows or dots.\n */\nexport const Carousel = ({ images, label, fit = 'cover', swipe = true, className }: CarouselProps) => {\n const slides = carouselSlides(images)\n const carousel = useCarousel(slides.length)\n return (\n <div role=\"group\" aria-roledescription=\"carousel\" aria-label={label} className={cn('group/carousel relative overflow-hidden', className)}>\n <CarouselTrack\n data-carousel-track\n carousel={carousel}\n swipe={swipe}\n slides={slides.map(({ image, alt }) => (\n <FileImage image={image} alt={alt} loading=\"lazy\" className={cn('size-full', fit === 'cover' ? 'object-cover' : 'object-contain')} />\n ))}\n />\n <CarouselControls carousel={carousel} count={slides.length} swipe={swipe} reveal=\"group-hover/carousel:opacity-100\" className=\"inset-0\" />\n </div>\n )\n}\n","import type { ReactNode } from 'react'\nimport { cn } from '../lib/cn'\n\nexport type ChoiceOption<T extends string> = { value: T; label: string; description?: ReactNode; disabled?: boolean }\n\n/**\n * `name` groups the radio buttons, so that the arrow keys move between them; `label` names the group for screen\n * readers. A disabled option shows and cannot be chosen.\n */\nexport type ChoicesProps<T extends string> = { name: string; label?: string; options: Array<ChoiceOption<T>>; value: T | undefined; onChange: (value: T) => void }\n\n/** One of a few options, each a card of its own row with a line that says what it means; the chosen one is outlined. */\nexport const Choices = <T extends string>({ name, label, options, value, onChange }: ChoicesProps<T>) => (\n <div role=\"radiogroup\" aria-label={label} className=\"flex flex-col gap-2\">\n {options.map((option) => (\n <label\n key={option.value}\n className={cn(\n 'block rounded-lg border p-3 transition-colors has-[:focus-visible]:outline-2 has-[:focus-visible]:outline-offset-2 has-[:focus-visible]:outline-primary',\n option.disabled ? 'cursor-default bg-background opacity-60' : option.value === value ? 'cursor-pointer border-primary bg-primary-soft' : 'cursor-pointer bg-background hover:bg-surface',\n )}\n >\n <input type=\"radio\" name={name} value={option.value} checked={option.value === value} disabled={option.disabled} onChange={() => onChange(option.value)} className=\"sr-only\" />\n <span className={cn('block font-medium', option.value === value && 'text-primary-text')}>{option.label}</span>\n {option.description && <span className=\"mt-0.5 block text-xs leading-snug text-muted-foreground\">{option.description}</span>}\n </label>\n ))}\n </div>\n)\n","import { keepPreviousData, useQuery, useQueryClient } from '@tanstack/react-query'\nimport type { ResourceModel, ViewModel } from '@protobase/schema'\nimport { useClient } from '../data/api-provider'\nimport { keys } from '../data/query-keys'\nimport { fetchLabels, type Labels } from '../live/relation-labels'\n\n/** The names of the chosen records, fetched in one list call; the previous names stay while the next ones load. */\nexport const usePickedLabels = (target: ResourceModel, view: ViewModel | undefined, ids: string[]): Labels => {\n const client = useClient()\n const queryClient = useQueryClient()\n const sorted = [...new Set(ids)].sort()\n const labels = useQuery({\n queryKey: keys.pickedLabels(target.name, sorted.join(',')),\n enabled: sorted.length > 0,\n placeholderData: keepPreviousData,\n queryFn: () => fetchLabels(queryClient, client, target, sorted, view),\n })\n return labels.data ?? new Map()\n}\n","import { useState } from 'react'\nimport { Token } from '../primitives/token'\nimport { useAdminMeta } from './meta-gate'\nimport { RelationPicker } from './relation-picker'\nimport { usePickedLabels } from './use-picked-labels'\n\ntype One = {\n multiple?: false\n /** The chosen record's key, as text; `undefined` for none. */\n value: string | undefined\n onChange: (key: string) => void\n}\n\ntype Several = {\n multiple: true\n /** The chosen records' keys, as text. */\n value: string[]\n onChange: (keys: string[]) => void\n}\n\nexport type RecordPickerProps = (One | Several) & {\n /** The name of the resource whose records it picks. */\n resource: string\n invalid?: boolean\n}\n\n/**\n * Picks records of a resource of the app with the create form's relation picker: type to narrow them by their search\n * fields or title, scroll for more, choose with the mouse or the keyboard. With `multiple`, each choice is added as a\n * token that can be taken off again, and choosing a chosen record takes it off.\n */\nexport const RecordPicker = (props: RecordPickerProps) => {\n const { resources, views } = useAdminMeta()\n const target = resources[props.resource]\n if (!target) throw new Error(`RecordPicker: the app has no resource named \"${props.resource}\"`)\n if (target.primaryKey.length !== 1) throw new Error(`RecordPicker: \"${props.resource}\" has a composite key, which a picker cannot name`)\n const view = views[props.resource]\n const keys = props.multiple ? props.value : props.value === undefined ? [] : [props.value]\n // The names of records chosen here, so a choice shows its name before the names are fetched.\n const [known, setKnown] = useState<Record<string, string>>({})\n const fetched = usePickedLabels(target, view, keys)\n const labelOf = (key: string) => known[key] ?? fetched.get(key) ?? key\n const remember = (key: string, label: string) => setKnown((current) => ({ ...current, [key]: label }))\n\n if (!props.multiple) {\n const { value, onChange } = props\n return (\n <RelationPicker\n target={target}\n view={view}\n value={value ?? ''}\n label={value === undefined ? undefined : labelOf(value)}\n invalid={props.invalid}\n onChange={(key, label) => {\n remember(key, label)\n onChange(key)\n }}\n />\n )\n }\n\n const { value, onChange } = props\n return (\n <div className=\"flex flex-col gap-2\">\n <RelationPicker\n target={target}\n view={view}\n value=\"\"\n chosen={value}\n several\n invalid={props.invalid}\n onChange={(key, label) => {\n remember(key, label)\n onChange(value.includes(key) ? value.filter((chosen) => chosen !== key) : [...value, key])\n }}\n />\n {value.length > 0 && (\n <div className=\"flex flex-wrap gap-1\">\n {value.map((key) => (\n <Token key={key} label={labelOf(key)} onRemove={() => onChange(value.filter((chosen) => chosen !== key))} />\n ))}\n </div>\n )}\n </div>\n )\n}\n"],"file":"shared-protobase-ui-CX80Ectk.js","debugId":"97f3411c-b648-4ca9-acbb-6be69060b6df"}
1
+ {"version":3,"mappings":"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","names":["__iconData","MicOff","createLucideIcon","Mic","MonitorUp","MonitorX","PhoneOff","Phone","VideoOff","Video","WifiOff","dayBefore","day","sameChatDay","viewerZone","dayIn","a","zone","b","chatDayLabel","time","today","now","text","formatWeekdayDate","ChatDivider","shown","label","line","cn","tone","import_jsx_runtime","RecordLink","rest","display","useOptionalListDisplay","around","useLayoutRecord","name","resource","AppLink","row","recordKey","signedInUserOf","state","useSignedInUser","useOptionalAuth","useMemo","keepPlaying","track","play","element","error","TrackVideo","ref","useCallback","TrackAudio","toggle","on","CallCheck","camera","cameraOn","Avatar","initialsOf","hueOf","member","notices","notice","Button","microphoneOn","microphone","onMicrophone","cameraAvailable","onCamera","onJoin","RouteLink","cancel","said","CallMessage","reason","onJoinAgain","gridColumns","width","count","callLayout","sharers","people","connectionQuality","roundTripMs","lostRatio","cannotConnect","since","activeSpeaker","loudest","level","levels","threshold","received","tracks","source","callPeople","members","self","shared","nameOf","speaker","own","theirs","screen","screenAudio","link","connections","connection","seen","CallControls","onShare","sharing","leave","buttonClass","CallTile","person","className","useWidth","setWidth","useState","observer","entry","stripMax","Grid","columns","Share","more","narrow","sharer","Tiles","layout","CallStage","messages","message","Spinner","controls","audio","key","readEveryMs","holdMs","levelOf","analyser","samples","sum","sample","useActiveSpeaker","setSpeaker","ids","import_react","context","analysers","last","timer","blockedNames","missingNames","one","media","kind","openDevices","stream","video","connectionsEveryMs","stop","useCallSession","phase","setPhase","devices","setDevices","setMicrophoneOn","setCameraOn","setTracks","setMembers","setConnections","setScreen","refusedSending","setRefusedSending","call","useRef","gone","opening","cancelled","opened","join","__vitePreload","joined","joinCall","made","sending","PublishRefused","url","toggleMicrophone","next","toggleCamera","stopSharing","toggleScreen","canShare","deviceNotices","CallView","session","auth","user","voices","useRecordCallAddress","useAppAddress","joining","address","target","to","open","href","RecordCall","useRecordCalls","client","useClient","queryClient","useQueryClient","keys","query","useQuery","queryKey","channel","offCalls","callsChannelEvent","offStatus","status","CallMark","isPending","ongoing","_Fragment","box","carouselSlides","images","image","shownImage","Carousel","slides","carousel","useCarousel","CarouselTrack","FileImage","fit","CarouselControls","Choices","options","option","value","onChange","usePickedLabels","sorted","keepPreviousData","fetchLabels","view","RecordPicker","useAdminMeta","resources","props","views","known","setKnown","fetched","labelOf","remember","current","RelationPicker","chosen","Token"],"ignoreList":[0,1,2,3,4,5,6,7,8],"sources":["../../../../../node_modules/.bun/lucide-react@1.52.0+0ac650c021fb1b59/node_modules/lucide-react/dist/esm/icons/mic-off.mjs","../../../../../node_modules/.bun/lucide-react@1.52.0+0ac650c021fb1b59/node_modules/lucide-react/dist/esm/icons/mic.mjs","../../../../../node_modules/.bun/lucide-react@1.52.0+0ac650c021fb1b59/node_modules/lucide-react/dist/esm/icons/monitor-up.mjs","../../../../../node_modules/.bun/lucide-react@1.52.0+0ac650c021fb1b59/node_modules/lucide-react/dist/esm/icons/monitor-x.mjs","../../../../../node_modules/.bun/lucide-react@1.52.0+0ac650c021fb1b59/node_modules/lucide-react/dist/esm/icons/phone-off.mjs","../../../../../node_modules/.bun/lucide-react@1.52.0+0ac650c021fb1b59/node_modules/lucide-react/dist/esm/icons/phone.mjs","../../../../../node_modules/.bun/lucide-react@1.52.0+0ac650c021fb1b59/node_modules/lucide-react/dist/esm/icons/video-off.mjs","../../../../../node_modules/.bun/lucide-react@1.52.0+0ac650c021fb1b59/node_modules/lucide-react/dist/esm/icons/video.mjs","../../../../../node_modules/.bun/lucide-react@1.52.0+0ac650c021fb1b59/node_modules/lucide-react/dist/esm/icons/wifi-off.mjs","../../../src/chat/chat-day.ts","../../../src/chat/chat-divider.tsx","../../../src/app/displays/record-link.tsx","../../../src/auth/use-signed-in-user.ts","../../../src/calls/track-media.tsx","../../../src/calls/call-check.tsx","../../../src/calls/call-message.tsx","../../../src/calls/call-layout.ts","../../../src/calls/call-people.ts","../../../src/calls/call-controls.tsx","../../../src/calls/call-tile.tsx","../../../src/calls/use-width.ts","../../../src/calls/call-stage.tsx","../../../src/calls/use-audio-levels.ts","../../../src/calls/devices.ts","../../../src/calls/use-call-session.ts","../../../src/calls/call-view.tsx","../../../src/calls/use-record-call-address.ts","../../../src/calls/record-call.tsx","../../../src/calls/use-record-calls.ts","../../../src/calls/call-mark.tsx","../../../src/carousel/carousel-images.ts","../../../src/carousel/carousel.tsx","../../../src/primitives/choices.tsx","../../../src/app/use-picked-labels.ts","../../../src/app/record-picker.tsx"],"sourcesContent":["/**\n * @license lucide-react v1.52.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.mjs';\n\nconst __iconData = {\n name: \"mic-off\",\n size: 24,\n node: [\n [\"path\", { d: \"M12 19v3\", key: \"npa21l\" }],\n [\"path\", { d: \"M15 9.34V5a3 3 0 0 0-5.68-1.33\", key: \"1gzdoj\" }],\n [\"path\", { d: \"M16.95 16.95A7 7 0 0 1 5 12v-2\", key: \"cqa7eg\" }],\n [\"path\", { d: \"M18.89 13.23A7 7 0 0 0 19 12v-2\", key: \"16hl24\" }],\n [\"path\", { d: \"m2 2 20 20\", key: \"1ooewy\" }],\n [\"path\", { d: \"M9 9v3a3 3 0 0 0 5.12 2.12\", key: \"r2i35w\" }]\n ]\n};\n__iconData.node;\nconst MicOff = createLucideIcon(__iconData);\n\nexport { __iconData, MicOff as default };\n//# sourceMappingURL=mic-off.mjs.map\n","/**\n * @license lucide-react v1.52.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.mjs';\n\nconst __iconData = {\n name: \"mic\",\n size: 24,\n node: [\n [\"path\", { d: \"M12 19v3\", key: \"npa21l\" }],\n [\"path\", { d: \"M19 10v2a7 7 0 0 1-14 0v-2\", key: \"1vc78b\" }],\n [\"rect\", { x: \"9\", y: \"2\", width: \"6\", height: \"13\", rx: \"3\", key: \"s6n7sd\" }]\n ]\n};\n__iconData.node;\nconst Mic = createLucideIcon(__iconData);\n\nexport { __iconData, Mic as default };\n//# sourceMappingURL=mic.mjs.map\n","/**\n * @license lucide-react v1.52.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.mjs';\n\nconst __iconData = {\n name: \"monitor-up\",\n size: 24,\n node: [\n [\"path\", { d: \"m9 10 3-3 3 3\", key: \"11gsxs\" }],\n [\"path\", { d: \"M12 13V7\", key: \"h0r20n\" }],\n [\"rect\", { width: \"20\", height: \"14\", x: \"2\", y: \"3\", rx: \"2\", key: \"48i651\" }],\n [\"path\", { d: \"M12 17v4\", key: \"1riwvh\" }],\n [\"path\", { d: \"M8 21h8\", key: \"1ev6f3\" }]\n ]\n};\n__iconData.node;\nconst MonitorUp = createLucideIcon(__iconData);\n\nexport { __iconData, MonitorUp as default };\n//# sourceMappingURL=monitor-up.mjs.map\n","/**\n * @license lucide-react v1.52.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.mjs';\n\nconst __iconData = {\n name: \"monitor-x\",\n size: 24,\n node: [\n [\"path\", { d: \"m14.5 12.5-5-5\", key: \"1jahn5\" }],\n [\"path\", { d: \"m9.5 12.5 5-5\", key: \"1k2t7b\" }],\n [\"rect\", { width: \"20\", height: \"14\", x: \"2\", y: \"3\", rx: \"2\", key: \"48i651\" }],\n [\"path\", { d: \"M12 17v4\", key: \"1riwvh\" }],\n [\"path\", { d: \"M8 21h8\", key: \"1ev6f3\" }]\n ]\n};\n__iconData.node;\nconst MonitorX = createLucideIcon(__iconData);\n\nexport { __iconData, MonitorX as default };\n//# sourceMappingURL=monitor-x.mjs.map\n","/**\n * @license lucide-react v1.52.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.mjs';\n\nconst __iconData = {\n name: \"phone-off\",\n size: 24,\n node: [\n [\n \"path\",\n {\n d: \"M10.1 13.9a14 14 0 0 0 3.732 2.668 1 1 0 0 0 1.213-.303l.355-.465A2 2 0 0 1 17 15h3a2 2 0 0 1 2 2v3a2 2 0 0 1-2 2 18 18 0 0 1-12.728-5.272\",\n key: \"1wngk7\"\n }\n ],\n [\"path\", { d: \"M22 2 2 22\", key: \"y4kqgn\" }],\n [\n \"path\",\n {\n d: \"M4.76 13.582A18 18 0 0 1 2 4a2 2 0 0 1 2-2h3a2 2 0 0 1 2 2v3a2 2 0 0 1-.8 1.6l-.468.351a1 1 0 0 0-.292 1.233 14 14 0 0 0 .244.473\",\n key: \"10hv5p\"\n }\n ]\n ]\n};\n__iconData.node;\nconst PhoneOff = createLucideIcon(__iconData);\n\nexport { __iconData, PhoneOff as default };\n//# sourceMappingURL=phone-off.mjs.map\n","/**\n * @license lucide-react v1.52.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.mjs';\n\nconst __iconData = {\n name: \"phone\",\n size: 24,\n node: [\n [\n \"path\",\n {\n d: \"M13.832 16.568a1 1 0 0 0 1.213-.303l.355-.465A2 2 0 0 1 17 15h3a2 2 0 0 1 2 2v3a2 2 0 0 1-2 2A18 18 0 0 1 2 4a2 2 0 0 1 2-2h3a2 2 0 0 1 2 2v3a2 2 0 0 1-.8 1.6l-.468.351a1 1 0 0 0-.292 1.233 14 14 0 0 0 6.392 6.384\",\n key: \"9njp5v\"\n }\n ]\n ]\n};\n__iconData.node;\nconst Phone = createLucideIcon(__iconData);\n\nexport { __iconData, Phone as default };\n//# sourceMappingURL=phone.mjs.map\n","/**\n * @license lucide-react v1.52.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.mjs';\n\nconst __iconData = {\n name: \"video-off\",\n size: 24,\n node: [\n [\n \"path\",\n { d: \"M10.66 6H14a2 2 0 0 1 2 2v2.5l5.248-3.062A.5.5 0 0 1 22 7.87v8.196\", key: \"w8jjjt\" }\n ],\n [\"path\", { d: \"M16 16a2 2 0 0 1-2 2H4a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h2\", key: \"1xawa7\" }],\n [\"path\", { d: \"m2 2 20 20\", key: \"1ooewy\" }]\n ]\n};\n__iconData.node;\nconst VideoOff = createLucideIcon(__iconData);\n\nexport { __iconData, VideoOff as default };\n//# sourceMappingURL=video-off.mjs.map\n","/**\n * @license lucide-react v1.52.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.mjs';\n\nconst __iconData = {\n name: \"video\",\n size: 24,\n node: [\n [\n \"path\",\n {\n d: \"m16 13 5.223 3.482a.5.5 0 0 0 .777-.416V7.87a.5.5 0 0 0-.752-.432L16 10.5\",\n key: \"ftymec\"\n }\n ],\n [\"rect\", { x: \"2\", y: \"6\", width: \"14\", height: \"12\", rx: \"2\", key: \"158x01\" }]\n ]\n};\n__iconData.node;\nconst Video = createLucideIcon(__iconData);\n\nexport { __iconData, Video as default };\n//# sourceMappingURL=video.mjs.map\n","/**\n * @license lucide-react v1.52.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.mjs';\n\nconst __iconData = {\n name: \"wifi-off\",\n size: 24,\n node: [\n [\"path\", { d: \"M12 20h.01\", key: \"zekei9\" }],\n [\"path\", { d: \"M8.5 16.429a5 5 0 0 1 7 0\", key: \"1bycff\" }],\n [\"path\", { d: \"M5 12.859a10 10 0 0 1 5.17-2.69\", key: \"1dl1wf\" }],\n [\"path\", { d: \"M19 12.859a10 10 0 0 0-2.007-1.523\", key: \"4k23kn\" }],\n [\"path\", { d: \"M2 8.82a15 15 0 0 1 4.177-2.643\", key: \"1grhjp\" }],\n [\"path\", { d: \"M22 8.82a15 15 0 0 0-11.288-3.764\", key: \"z3jwby\" }],\n [\"path\", { d: \"m2 2 20 20\", key: \"1ooewy\" }]\n ]\n};\n__iconData.node;\nconst WifiOff = createLucideIcon(__iconData);\n\nexport { __iconData, WifiOff as default };\n//# sourceMappingURL=wifi-off.mjs.map\n","import { formatWeekdayDate } from '../format/date'\nimport { dayIn, viewerZone } from '../format/zone'\nimport { text } from './messages'\n\nconst dayBefore = (day: string) => new Date(Date.parse(`${day}T00:00:00Z`) - 86_400_000).toISOString().slice(0, 10)\n\n/** Whether two ISO timestamps fall on the same day in `zone`, the viewer's unless given: a day divider goes between two messages that do not. */\nexport const sameChatDay = (a: string, b: string, zone = viewerZone()) => dayIn(Date.parse(a), zone) === dayIn(Date.parse(b), zone)\n\n/** The label of the divider above a day's first message, sent at `time`: \"Today\", \"Yesterday\" or \"Mon, 26 Oct 2026\", as the viewer's calendar in `zone` has it. */\nexport const chatDayLabel = (time: string, now = Date.now(), zone = viewerZone()) => {\n const day = dayIn(Date.parse(time), zone)\n const today = dayIn(now, zone)\n if (day === today) return text('today')\n if (day === dayBefore(today)) return text('yesterday')\n return formatWeekdayDate(Date.parse(`${day}T00:00:00Z`))\n}\n","import { cn } from '../lib/cn'\nimport { text } from './messages'\n\nexport type ChatDividerProps =\n /** A muted line between the messages of two days, labelled with the later one, such as by `chatDayLabel`. */\n | { tone?: 'day'; label: string }\n /** A line above the first message the reader has not seen, \"New messages\" unless labelled otherwise. */\n | { tone: 'new'; label?: string }\n\n/**\n * A line across a chat with a label in its middle, between the messages of two days or above the new ones. Marked\n * `data-chat-divider`, so a thread keeps the reader's place on the message below it, not on the divider.\n */\nexport const ChatDivider = ({ tone = 'day', label }: ChatDividerProps) => {\n const shown = label ?? text('newMessages')\n const line = cn('h-px flex-1', tone === 'new' ? 'bg-danger' : 'bg-border')\n return (\n <div role=\"separator\" aria-label={shown} data-tone={tone} data-chat-divider=\"\" className=\"flex items-center gap-3 text-xs font-medium\">\n <span className={line} />\n <span className={tone === 'new' ? 'text-danger' : 'text-muted-foreground'}>{shown}</span>\n <span className={line} />\n </div>\n )\n}\n","import type { AnchorHTMLAttributes } from 'react'\nimport type { KeyValue } from '@protobase/schema'\nimport { useLayoutRecord } from '../pages/record-scope'\nimport { AppLink } from '../use-app-address'\nimport { useOptionalListDisplay } from './display-context'\nimport type { ListDisplayRow } from './list-displays'\n\ntype Target = { row: ListDisplayRow; resource?: never; recordKey?: never } | { row?: never; resource?: string; recordKey: KeyValue | readonly KeyValue[] }\n\n/**\n * A link to a record's page, through the app's addresses: a list display's `row`, or a `recordKey` of `resource`. The\n * resource defaults to the list display's or the record's around it, so a custom component never writes a path.\n */\nexport const RecordLink = ({ row, resource, recordKey, ...rest }: AnchorHTMLAttributes<HTMLAnchorElement> & Target) => {\n const display = useOptionalListDisplay()\n const around = useLayoutRecord()\n const name = resource ?? display?.resource ?? around?.model.name\n if (name === undefined) throw new Error('RecordLink needs a resource outside a list display or a record')\n return <AppLink to={{ kind: 'record', resource: name, key: row ? row.key : recordKey }} {...rest} />\n}\n","import { useMemo } from 'react'\nimport { useOptionalAuth, type AuthState } from './auth-provider'\n\n/** Who is signed in: their user id, the id `.author()` stores and mentions hold, and their name. */\nexport type SignedInUser = { id: string; name?: string }\n\n/** The signed-in person of an auth state; none while it loads, for a visitor, and before the sign-in finished. */\nexport const signedInUserOf = (state: AuthState | undefined): SignedInUser | undefined => {\n if (state?.kind !== 'signed-in') return\n const { id, name } = state.user\n return { id, ...(name && { name }) }\n}\n\n/**\n * The signed-in person, from the session the app already holds, such as for a filter on their own user id;\n * `undefined` while the session loads, for a visitor and when nobody is signed in.\n */\nexport const useSignedInUser = (): SignedInUser | undefined => {\n const state = useOptionalAuth()?.state\n return useMemo(() => signedInUserOf(state), [state])\n}\n","import { useCallback, type VideoHTMLAttributes } from 'react'\n\n// Plays the element again whenever it pauses while its track is live: a media element the page takes out and puts\n// back, as React does when it moves a tile, is paused by the browser, and nothing else would play it again. A play the\n// browser cut short, or does not allow yet, is left to the next pause.\nconst keepPlaying = (element: HTMLMediaElement, track: MediaStreamTrack) => {\n element.srcObject = new MediaStream([track])\n const play = () => {\n if (track.readyState !== 'live') return\n element.play().catch((error: unknown) => {\n if (error instanceof DOMException && (error.name === 'AbortError' || error.name === 'NotAllowedError')) return\n throw error\n })\n }\n element.addEventListener('pause', play)\n return () => element.removeEventListener('pause', play)\n}\n\n/** A video element showing the track, muted, inline, playing as soon as it can and for as long as the track is live. */\nexport const TrackVideo = ({ track, ...rest }: { track: MediaStreamTrack } & VideoHTMLAttributes<HTMLVideoElement>) => {\n const ref = useCallback((element: HTMLVideoElement | null) => (element ? keepPlaying(element, track) : undefined), [track])\n return <video ref={ref} autoPlay playsInline muted {...rest} />\n}\n\n/** Plays the track's sound, unseen, for as long as the track is live. */\nexport const TrackAudio = ({ track }: { track: MediaStreamTrack }) => {\n const ref = useCallback((element: HTMLAudioElement | null) => (element ? keepPlaying(element, track) : undefined), [track])\n return <audio ref={ref} autoPlay />\n}\n","import { Mic, MicOff, Video, VideoOff } from 'lucide-react'\nimport { hueOf, initialsOf } from '../auth/user-to-shell'\nimport { cn } from '../lib/cn'\nimport { Avatar } from '../primitives/avatar'\nimport { Button } from '../primitives/button'\nimport { RouteLink, type RouteTarget } from '../primitives/route-link'\nimport { text } from './messages'\nimport { TrackVideo } from './track-media'\n\nexport type CallCheckProps = {\n name: string\n member: string\n /** The member's camera as it will be sent, to see before joining. */\n camera?: MediaStreamTrack\n microphoneOn: boolean\n cameraOn: boolean\n /** Whether the browser has a microphone and a camera it may use. */\n microphone: boolean\n cameraAvailable: boolean\n notices: string[]\n onMicrophone: () => void\n onCamera: () => void\n onJoin: () => void\n /** Where the member goes without joining. */\n cancel: RouteTarget\n}\n\nconst toggle = (on: boolean) => cn('size-10 rounded-full', !on && 'bg-danger-soft text-danger-text')\n\n/**\n * The check of the microphone and camera before joining: the member's own camera as the others will see it, or their\n * initials, microphone and camera on and off, plain messages for a blocked or missing device, and Join.\n */\nexport const CallCheck = ({ name, member, camera, microphoneOn, cameraOn, microphone, cameraAvailable, notices, onMicrophone, onCamera, onJoin, cancel }: CallCheckProps) => (\n <section aria-label={text('preview')} className=\"flex size-full min-h-0 flex-col items-center justify-center gap-3 bg-background p-4\">\n <figure className=\"relative flex aspect-video w-full max-w-md items-center justify-center overflow-hidden rounded-lg bg-neutral-900\">\n {camera && cameraOn ? <TrackVideo track={camera} aria-label={text('preview')} className=\"size-full -scale-x-100 object-cover\" /> : <Avatar initials={initialsOf(name)} hue={hueOf(member)} size=\"md\" className=\"size-16 text-xl ring-0\" />}\n </figure>\n {notices.length > 0 && (\n <div role=\"status\" className=\"flex w-full max-w-md flex-col gap-1\">\n {notices.map((notice) => (\n <p key={notice} className=\"rounded-md bg-warning-soft px-3 py-1.5 text-xs text-foreground\">\n {notice}\n </p>\n ))}\n </div>\n )}\n <div className=\"flex items-center gap-2\">\n <Button size=\"icon\" aria-label={text('microphone')} aria-pressed={microphoneOn} disabled={!microphone} className={toggle(microphoneOn)} onClick={onMicrophone}>\n {microphoneOn ? <Mic className=\"size-4\" /> : <MicOff className=\"size-4\" />}\n </Button>\n <Button size=\"icon\" aria-label={text('camera')} aria-pressed={cameraOn} disabled={!cameraAvailable} className={toggle(cameraOn)} onClick={onCamera}>\n {cameraOn ? <Video className=\"size-4\" /> : <VideoOff className=\"size-4\" />}\n </Button>\n <Button variant=\"primary\" className=\"h-10 rounded-full px-5\" onClick={onJoin}>\n {text('joinCall')}\n </Button>\n <RouteLink to={cancel} className=\"px-2 text-sm text-muted-foreground hover:text-foreground\">\n {text('leave')}\n </RouteLink>\n </div>\n </section>\n)\n","import type { CallLeftReason } from '@protobase/client/calls'\nimport { Button } from '../primitives/button'\nimport { text } from './messages'\n\nconst said: Record<Exclude<CallLeftReason, 'rejoin'>, Parameters<typeof text>[0]> = { ended: 'ended', removed: 'removed', full: 'full', refused: 'refused', unavailable: 'unavailable' }\n\n/** Why the member is not in the call, in plain words, and, unless they were removed, a way to join again. */\nexport const CallMessage = ({ reason, onJoinAgain }: { reason: CallLeftReason; onJoinAgain?: () => void }) => (\n <section role=\"status\" className=\"flex size-full min-h-0 flex-col items-center justify-center gap-3 bg-background p-4 text-center\">\n <p className=\"text-sm text-foreground\">{text(reason === 'rejoin' ? 'ended' : said[reason])}</p>\n {onJoinAgain && reason !== 'removed' && reason !== 'refused' && <Button onClick={onJoinAgain}>{text('callAgain')}</Button>}\n </section>\n)\n","/**\n * How a call's tiles are laid out: `alone` while the member is the only one in it, `grid` for everyone at the same\n * size, `share` with a screen share large and the people in a strip beside or under it.\n */\nexport type CallLayout = { kind: 'alone' } | { kind: 'grid'; columns: number } | { kind: 'share'; sharer: string }\n\n/** Below this width the view is a phone's: one column of two people, then two columns, and the strip goes under a share. */\nexport const narrowWidth = 640\n\n/** The columns a grid of `count` tiles takes in a view `width` pixels wide: as square as fits, fewer on a phone. */\nexport const gridColumns = (count: number, width: number) => {\n if (width < narrowWidth) return count <= 2 ? 1 : 2\n return Math.min(4, Math.ceil(Math.sqrt(count)))\n}\n\n/** The layout for these people, the member included, and the member sharing their screen, the first of them if several do. */\nexport const callLayout = ({ people, sharers, width }: { people: number; sharers: readonly string[]; width: number }): CallLayout => {\n if (sharers[0] !== undefined) return { kind: 'share', sharer: sharers[0] }\n if (people <= 1) return { kind: 'alone' }\n return { kind: 'grid', columns: gridColumns(people, width) }\n}\n\n/** How a connection fares, as its tile shows it: poor past a round trip of 400 ms or a loss of 5% of the media. */\nexport const connectionQuality = ({ roundTripMs, lostRatio }: { roundTripMs?: number; lostRatio?: number }) => ((roundTripMs ?? 0) > 400 || (lostRatio ?? 0) > 0.05 ? 'poor' : 'good')\n\n/** How long a connection may stay unconnected before its tile says the browser cannot connect to that person. */\nexport const connectGiveUpMs = 15_000\n\n/** Whether the browser cannot connect to someone: their connection failed, or is not up `connectGiveUpMs` after they came. */\nexport const cannotConnect = (state: RTCPeerConnectionState | undefined, since: number, now: number) => state === 'failed' || (state !== 'connected' && now - since >= connectGiveUpMs)\n\n/** The loudest of these levels, from 0 to 1, when one is loud enough to be someone speaking. */\nexport const activeSpeaker = (levels: ReadonlyMap<string, number>, threshold = 0.05) => {\n let loudest: [string, number] | undefined\n for (const [member, level] of levels) if (level >= threshold && (!loudest || level > loudest[1])) loudest = [member, level]\n return loudest?.[0]\n}\n","import type { CallConnection, CallRosterMember, CallTrack } from '@protobase/client/calls'\nimport { cannotConnect, connectionQuality } from './call-layout'\nimport type { CallPerson } from './call-person'\n\n/** What the member sends themselves: their own tracks, and which of them are on. */\nexport type OwnMedia = { microphone?: MediaStreamTrack; camera?: MediaStreamTrack; screen?: MediaStreamTrack; microphoneOn: boolean; cameraOn: boolean }\n\nexport type PeopleInput = {\n members: readonly CallRosterMember[]\n self: string\n tracks: readonly CallTrack[]\n own: OwnMedia\n nameOf: (member: string) => string\n speaker?: string\n connections: readonly CallConnection[]\n /** When this browser first knew of each member, by member: how long their connection has had to come up. */\n seen: ReadonlyMap<string, number>\n now: number\n}\n\nconst received = (tracks: readonly CallTrack[], source: CallTrack['source']) => tracks.find((track) => track.source === source && track.track)\n\n/** Everyone in the call as the view draws them, in the order they came, the member among them as `self`. */\nexport const callPeople = ({ members, self, tracks, own, nameOf, speaker, connections, seen, now }: PeopleInput): CallPerson[] => {\n const roster = members.some((member) => member.member === self) ? members : [{ member: self, joined_at: '' }, ...members]\n return roster.map(({ member }): CallPerson => {\n const shared = { member, name: nameOf(member), ...(speaker === member && { speaking: true }) }\n if (member === self) {\n return { ...shared, self: true, ...(own.camera && { camera: own.camera }), ...(own.microphone && { microphone: own.microphone }), ...(own.screen && { screen: own.screen }), microphoneOff: !own.microphone || !own.microphoneOn, cameraOff: !own.camera || !own.cameraOn }\n }\n const theirs = tracks.filter((track) => track.member === member)\n const [camera, microphone, screen, screenAudio] = (['camera', 'microphone', 'screen', 'screen-audio'] as const).map((source) => received(theirs, source))\n const link = connections.find((connection) => connection.member === member)\n const connection = cannotConnect(link?.state, seen.get(member) ?? now, now) ? 'failed' : link?.state === 'connected' ? connectionQuality(link) : undefined\n return {\n ...shared,\n ...(camera && { camera: camera.track! }),\n ...(microphone && { microphone: microphone.track! }),\n ...(screen && { screen: screen.track! }),\n ...(screenAudio && { screenAudio: screenAudio.track! }),\n microphoneOff: !microphone || microphone.muted,\n cameraOff: !camera || camera.muted,\n ...(connection && { connection }),\n }\n })\n}\n","import { Mic, MicOff, MonitorUp, MonitorX, PhoneOff, Video, VideoOff } from 'lucide-react'\nimport { buttonClass, Button } from '../primitives/button'\nimport { RouteLink, type RouteTarget } from '../primitives/route-link'\nimport { cn } from '../lib/cn'\nimport { text } from './messages'\n\nexport type CallControlsProps = {\n microphoneOn: boolean\n cameraOn: boolean\n /** Whether the member shares their screen; no share button where the browser cannot share one, as on a phone. */\n sharing?: boolean\n onMicrophone: () => void\n onCamera: () => void\n onShare?: () => void\n /** Where Leave goes, such as the record's page without its call: leaving the page leaves the call. */\n leave: RouteTarget\n}\n\nconst toggle = (on: boolean) => cn('size-10 rounded-full', !on && 'bg-danger-soft text-danger-text')\n\n/** The member's controls: microphone, camera and screen share on and off, and Leave, a link out of the call. */\nexport const CallControls = ({ microphoneOn, cameraOn, sharing, onMicrophone, onCamera, onShare, leave }: CallControlsProps) => (\n <div role=\"toolbar\" aria-label={text('joinCall')} className=\"flex shrink-0 items-center justify-center gap-2 py-2\">\n <Button size=\"icon\" aria-label={text('microphone')} aria-pressed={microphoneOn} title={text('microphone')} className={toggle(microphoneOn)} onClick={onMicrophone}>\n {microphoneOn ? <Mic className=\"size-4\" /> : <MicOff className=\"size-4\" />}\n </Button>\n <Button size=\"icon\" aria-label={text('camera')} aria-pressed={cameraOn} title={text('camera')} className={toggle(cameraOn)} onClick={onCamera}>\n {cameraOn ? <Video className=\"size-4\" /> : <VideoOff className=\"size-4\" />}\n </Button>\n {onShare && (\n <Button size=\"icon\" aria-label={sharing ? text('stopSharing') : text('shareScreen')} aria-pressed={Boolean(sharing)} title={sharing ? text('stopSharing') : text('shareScreen')} className=\"size-10 rounded-full\" onClick={onShare}>\n {sharing ? <MonitorX className=\"size-4\" /> : <MonitorUp className=\"size-4\" />}\n </Button>\n )}\n <RouteLink to={leave} className={cn(buttonClass({ variant: 'danger' }), 'h-10 rounded-full px-4')}>\n <PhoneOff className=\"size-4\" />\n {text('leave')}\n </RouteLink>\n </div>\n)\n","import { MicOff, WifiOff } from 'lucide-react'\nimport { hueOf, initialsOf } from '../auth/user-to-shell'\nimport { cn } from '../lib/cn'\nimport { Avatar } from '../primitives/avatar'\nimport type { CallPerson } from './call-person'\nimport { text } from './messages'\nimport { TrackVideo } from './track-media'\n\n/**\n * One person in a call: their camera, or their initials while it sends nothing; their name, a mark while their\n * microphone is off or their connection is poor, a ring while they speak, and a plain message when the member's\n * browser cannot connect to them. `screen` draws their screen share instead, whole.\n */\nexport const CallTile = ({ person, screen = false, className }: { person: CallPerson; screen?: boolean; className?: string }) => {\n const track = screen ? person.screen : person.cameraOff ? undefined : person.camera\n const label = screen ? (person.self ? text('youAreSharing') : text('sharing', person.name)) : person.self ? `${person.name} (${text('you')})` : person.name\n return (\n <figure\n data-member={person.member}\n data-speaking={person.speaking ? 'true' : undefined}\n aria-label={label}\n className={cn('relative flex min-h-0 min-w-0 items-center justify-center overflow-hidden rounded-lg bg-neutral-900 ring-offset-2 ring-offset-background', person.speaking && !screen && 'ring-2 ring-success', className)}\n >\n {track ? (\n <TrackVideo track={track} className={cn('size-full', screen ? 'object-contain' : 'object-cover', person.self && !screen && '-scale-x-100')} />\n ) : (\n <Avatar initials={initialsOf(person.name)} hue={hueOf(person.member)} size=\"md\" className=\"size-16 text-xl ring-0\" />\n )}\n {person.connection === 'failed' && !person.self && (\n <p role=\"status\" className=\"absolute inset-x-1 top-1 truncate rounded bg-black/70 px-2 py-1 text-center text-xs text-white\">\n {text('cannotConnect', person.name)}\n </p>\n )}\n <figcaption className=\"absolute bottom-1.5 left-1.5 flex max-w-[calc(100%-0.75rem)] items-center gap-1 rounded bg-black/60 px-1.5 py-0.5 text-xs text-white\">\n {!screen && person.microphoneOff && <MicOff role=\"img\" aria-label={text('muted')} className=\"size-3 shrink-0\" />}\n {!screen && person.connection === 'poor' && <WifiOff role=\"img\" aria-label={text('poorConnection')} className=\"size-3 shrink-0 text-warning\" />}\n <span className=\"truncate\">{label}</span>\n </figcaption>\n </figure>\n )\n}\n","import { useCallback, useState } from 'react'\n\n/** The width of the element the returned ref is put on, followed as it changes; 0 until it is drawn. */\nexport const useWidth = <T extends HTMLElement>() => {\n const [width, setWidth] = useState(0)\n const ref = useCallback((element: T | null) => {\n if (!element) return\n setWidth(element.clientWidth)\n const observer = new ResizeObserver(([entry]) => setWidth(entry!.contentRect.width))\n observer.observe(element)\n return () => observer.disconnect()\n }, [])\n return { ref, width }\n}\n","import { Spinner } from '../primitives/spinner'\nimport { cn } from '../lib/cn'\nimport { CallControls, type CallControlsProps } from './call-controls'\nimport { callLayout, type CallLayout } from './call-layout'\nimport type { CallPerson } from './call-person'\nimport { CallTile } from './call-tile'\nimport { text } from './messages'\nimport { TrackAudio } from './track-media'\nimport { useWidth } from './use-width'\n\nexport type CallStageProps = {\n /** Everyone in the call, the member too, in the order they came. */\n people: CallPerson[]\n /** `resuming` while the link to the server is restored; media keeps flowing meanwhile. */\n state: 'joining' | 'joined' | 'resuming'\n /** Plain messages for the member, such as a blocked camera. */\n notices?: string[]\n controls: CallControlsProps\n className?: string\n}\n\n// The most people the strip beside a screen share shows; the rest are a count.\nconst stripMax = 4\n\nconst Grid = ({ people, columns }: { people: CallPerson[]; columns: number }) => (\n <div className=\"grid size-full min-h-0 gap-2\" style={{ gridTemplateColumns: `repeat(${columns}, minmax(0, 1fr))`, gridTemplateRows: `repeat(${Math.ceil(people.length / columns)}, minmax(0, 1fr))` }}>\n {people.map((person) => (\n <CallTile key={person.member} person={person} />\n ))}\n </div>\n)\n\nconst Share = ({ people, sharer, narrow }: { people: CallPerson[]; sharer: CallPerson; narrow: boolean }) => {\n const shown = people.slice(0, stripMax)\n const more = people.length - shown.length\n return (\n <div className={cn('flex size-full min-h-0 gap-2', narrow ? 'flex-col' : 'flex-row')}>\n <CallTile person={sharer} screen className=\"min-h-0 flex-1\" />\n <div className={cn('flex shrink-0 gap-2', narrow ? 'h-20 flex-row' : 'w-40 flex-col')}>\n {shown.map((person) => (\n <CallTile key={person.member} person={person} className={narrow ? 'aspect-video h-full' : 'aspect-video w-full'} />\n ))}\n {more > 0 && <p className=\"flex items-center justify-center rounded-lg bg-muted px-2 text-xs text-muted-foreground\">+{more}</p>}\n </div>\n </div>\n )\n}\n\nconst Tiles = ({ layout, people, narrow }: { layout: CallLayout; people: CallPerson[]; narrow: boolean }) => {\n if (layout.kind === 'share') return <Share people={people} sharer={people.find((person) => person.member === layout.sharer)!} narrow={narrow} />\n if (layout.kind === 'grid') return <Grid people={people} columns={layout.columns} />\n return (\n <div className=\"relative size-full min-h-0\">\n <CallTile person={people[0]!} className=\"size-full\" />\n <p className=\"absolute inset-x-0 top-3 text-center text-sm text-white drop-shadow\">{text('alone')}</p>\n </div>\n )\n}\n\n/**\n * A call as the member sees it, filling its parent: everyone at the same size, with the one speaking ringed; a screen\n * share large with the people beside it, or under it on a phone; the member alone; then the controls. The others'\n * sound plays unseen.\n */\nexport const CallStage = ({ people, state, notices = [], controls, className }: CallStageProps) => {\n const { ref, width } = useWidth<HTMLDivElement>()\n const narrow = width > 0 && width < 640\n const layout = callLayout({ people: people.length, sharers: people.filter((person) => person.screen).map((person) => person.member), width })\n const messages = [...(state === 'resuming' ? [text('reconnecting')] : []), ...notices]\n return (\n <section ref={ref} aria-label={text('joinCall')} data-layout={layout.kind} className={cn('flex size-full min-h-0 flex-col gap-2 bg-background p-2', className)}>\n {messages.length > 0 && (\n <div role=\"status\" className=\"flex shrink-0 flex-col gap-1\">\n {messages.map((message) => (\n <p key={message} className=\"flex items-center gap-2 rounded-md bg-warning-soft px-3 py-1.5 text-xs text-foreground\">\n {message === text('reconnecting') && <Spinner className=\"size-3\" />}\n {message}\n </p>\n ))}\n </div>\n )}\n <div className=\"min-h-0 flex-1\">\n {state === 'joining' ? (\n <p role=\"status\" className=\"flex size-full items-center justify-center gap-2 text-muted-foreground\">\n <Spinner className=\"size-4\" />\n {text('connecting')}\n </p>\n ) : (\n <Tiles layout={layout} people={people} narrow={narrow} />\n )}\n </div>\n <CallControls {...controls} />\n {people\n .filter((person) => !person.self)\n .flatMap((person) => [['microphone', person.microphone] as const, ['screen-audio', person.screenAudio] as const].map(([source, track]) => track && { key: `${person.member} ${source}`, track }))\n .filter((audio) => audio !== undefined)\n .map(({ key, track }) => (\n <TrackAudio key={key} track={track} />\n ))}\n </section>\n )\n}\n","import { useEffect, useState } from 'react'\nimport { activeSpeaker } from './call-layout'\n\n// How often the levels are read, and how long the last speaker keeps the ring after they stop, so it does not flicker.\nconst readEveryMs = 200\nconst holdMs = 1000\n\n// A level from 0 to 1: the root mean square of the samples.\nconst levelOf = (analyser: AnalyserNode, samples: Float32Array<ArrayBuffer>) => {\n analyser.getFloatTimeDomainData(samples)\n let sum = 0\n for (const sample of samples) sum += sample * sample\n return Math.min(1, Math.sqrt(sum / samples.length) * 4)\n}\n\n/** Who of these members is speaking, by the sound of their microphone tracks, read in the browser through Web Audio. */\nexport const useActiveSpeaker = (tracks: ReadonlyMap<string, MediaStreamTrack>) => {\n const [speaker, setSpeaker] = useState<string>()\n const ids = [...tracks].map(([member, track]) => `${member}:${track.id}`).join(',')\n useEffect(() => {\n if (tracks.size === 0 || typeof AudioContext === 'undefined') return\n const context = new AudioContext()\n const analysers = new Map(\n [...tracks].map(([member, track]) => {\n const analyser = context.createAnalyser()\n analyser.fftSize = 512\n context.createMediaStreamSource(new MediaStream([track])).connect(analyser)\n return [member, analyser] as const\n }),\n )\n const samples = new Float32Array(512)\n let last: { member: string; at: number } | undefined\n const timer = setInterval(() => {\n const loudest = activeSpeaker(new Map([...analysers].map(([member, analyser]) => [member, levelOf(analyser, samples)])))\n if (loudest) last = { member: loudest, at: Date.now() }\n setSpeaker(last && Date.now() - last.at < holdMs ? last.member : undefined)\n }, readEveryMs)\n return () => {\n clearInterval(timer)\n void context.close()\n }\n // Keyed by the tracks' ids, which `tracks` changes with, so a new map of the same tracks reads on.\n }, [ids])\n return speaker\n}\n","/** The member's microphone and camera as the browser gives them, and why one is missing: blocked, or none found. */\nexport type Devices = { microphone?: MediaStreamTrack; camera?: MediaStreamTrack; blocked: { microphone: boolean; camera: boolean }; none: boolean }\n\n// What `getUserMedia` rejects with for a device the person or the browser keeps from the page, or that is not there.\nconst blockedNames = new Set(['NotAllowedError', 'SecurityError'])\nconst missingNames = new Set(['NotFoundError', 'NotReadableError', 'OverconstrainedError'])\n\ntype Kind = 'audio' | 'video'\n\n// One kind of device: its track, or whether it is blocked or missing.\nconst one = async (media: MediaDevices, kind: Kind): Promise<{ track?: MediaStreamTrack; blocked: boolean }> => {\n try {\n const stream = await media.getUserMedia({ [kind]: true })\n return { track: stream.getTracks()[0]!, blocked: false }\n } catch (error) {\n if (!(error instanceof DOMException)) throw error\n if (blockedNames.has(error.name)) return { blocked: true }\n if (missingNames.has(error.name)) return { blocked: false }\n throw error\n }\n}\n\n/**\n * Asks for the microphone and the camera at once, so the browser asks the person once; when that is refused, each on\n * its own, to tell which one is blocked or missing.\n */\nexport const openDevices = async (media: MediaDevices = navigator.mediaDevices): Promise<Devices> => {\n try {\n const stream = await media.getUserMedia({ audio: true, video: true })\n return { microphone: stream.getAudioTracks()[0], camera: stream.getVideoTracks()[0], blocked: { microphone: false, camera: false }, none: false }\n } catch (error) {\n if (!(error instanceof DOMException) || !(blockedNames.has(error.name) || missingNames.has(error.name))) throw error\n }\n const [audio, video] = [await one(media, 'audio'), await one(media, 'video')]\n return {\n ...(audio.track && { microphone: audio.track }),\n ...(video.track && { camera: video.track }),\n blocked: { microphone: audio.blocked, camera: video.blocked },\n none: !audio.track && !video.track && !audio.blocked && !video.blocked,\n }\n}\n","import { useCallback, useEffect, useRef, useState } from 'react'\nimport type { Call, CallConnection, CallLeftReason, CallRosterMember, CallTrack } from '@protobase/client/calls'\nimport { openDevices, type Devices } from './devices'\n\n/** Where the member stands: checking their devices, joining, in the call (`resuming` while its link is restored), or out of it. */\nexport type CallPhase = { kind: 'check' } | { kind: 'joining' } | { kind: 'in'; resuming: boolean } | { kind: 'left'; reason: CallLeftReason }\n\n// How often the connections' state and quality are read while in the call.\nconst connectionsEveryMs = 2000\n\nconst stop = (tracks: readonly (MediaStreamTrack | undefined)[]) => {\n for (const track of tracks) track?.stop()\n}\n\n/**\n * The member's session in the call the app's function at `url` admits them to: their devices from the start, for the\n * check before joining; then the call, which `join` joins after the click, with what they send and receive, and who\n * is in it. Leaving the page leaves the call and stops the devices.\n */\nexport const useCallSession = (url: string) => {\n const [phase, setPhase] = useState<CallPhase>({ kind: 'check' })\n const [devices, setDevices] = useState<Devices>()\n const [microphoneOn, setMicrophoneOn] = useState(true)\n const [cameraOn, setCameraOn] = useState(true)\n const [tracks, setTracks] = useState<CallTrack[]>([])\n const [members, setMembers] = useState<CallRosterMember[]>([])\n const [connections, setConnections] = useState<CallConnection[]>([])\n const [screen, setScreen] = useState<{ video: MediaStreamTrack; audio?: MediaStreamTrack }>()\n const [refusedSending, setRefusedSending] = useState(false)\n const call = useRef<Call | undefined>(undefined)\n const gone = useRef(false)\n const own = useRef<(MediaStreamTrack | undefined)[]>([])\n const seen = useRef(new Map<string, number>())\n\n // The devices as they open: a join clicked before they did waits for them.\n const opening = useRef<Promise<Devices | undefined>>(Promise.resolve(undefined))\n\n useEffect(() => {\n let cancelled = false\n gone.current = false\n opening.current = openDevices().then((opened) => {\n if (cancelled) {\n stop([opened.microphone, opened.camera])\n return\n }\n own.current.push(opened.microphone, opened.camera)\n setDevices(opened)\n return opened\n })\n return () => {\n cancelled = true\n gone.current = true\n call.current?.leave()\n call.current = undefined\n stop(own.current)\n own.current = []\n }\n }, [])\n\n useEffect(() => {\n for (const { member } of members) if (!seen.current.has(member)) seen.current.set(member, Date.now())\n }, [members])\n\n useEffect(() => {\n if (phase.kind !== 'in') return\n const timer = setInterval(() => void call.current?.connections().then(setConnections), connectionsEveryMs)\n return () => clearInterval(timer)\n }, [phase.kind])\n\n const join = useCallback(async () => {\n setPhase({ kind: 'joining' })\n const { joinCall, PublishRefused } = await import('@protobase/client/calls')\n const joined = await joinCall({\n url,\n onTracks: setTracks,\n onMembers: setMembers,\n onState: (state) => {\n if (state.state === 'joined' || state.state === 'resuming') setPhase({ kind: 'in', resuming: state.state === 'resuming' })\n if (state.state === 'left') setPhase({ kind: 'left', reason: state.reason })\n },\n }).then(\n (made) => made,\n // A join that failed is left, and `onState` said why.\n () => undefined,\n )\n if (!joined) return\n if (gone.current) return joined.leave()\n call.current = joined\n const opened = await opening.current\n const sending = { ...(opened?.microphone && { microphone: opened.microphone }), ...(opened?.camera && { camera: opened.camera }) }\n await joined.publish(sending).then(\n () => {\n if (sending.microphone) joined.mute('microphone', !microphoneOn)\n if (sending.camera) joined.mute('camera', !cameraOn)\n },\n (error: unknown) => {\n if (!(error instanceof PublishRefused)) throw error\n setRefusedSending(true)\n },\n )\n }, [url, microphoneOn, cameraOn])\n\n const toggleMicrophone = useCallback(() => {\n const next = !microphoneOn\n setMicrophoneOn(next)\n if (devices?.microphone) devices.microphone.enabled = next\n call.current?.mute('microphone', !next)\n }, [microphoneOn, devices])\n\n const toggleCamera = useCallback(() => {\n const next = !cameraOn\n setCameraOn(next)\n if (devices?.camera) devices.camera.enabled = next\n call.current?.mute('camera', !next)\n }, [cameraOn, devices])\n\n const stopSharing = useCallback(async (shared: { video: MediaStreamTrack; audio?: MediaStreamTrack }) => {\n setScreen(undefined)\n stop([shared.video, shared.audio])\n await call.current?.unpublish('screen')\n if (shared.audio) await call.current?.unpublish('screen-audio')\n }, [])\n\n const toggleScreen = useCallback(async () => {\n if (screen) return stopSharing(screen)\n let display: MediaStream\n try {\n display = await navigator.mediaDevices.getDisplayMedia({ video: true, audio: true })\n } catch (error) {\n // The person closed the browser's picker without sharing.\n if (error instanceof DOMException && error.name === 'NotAllowedError') return\n throw error\n }\n const shared = { video: display.getVideoTracks()[0]!, ...(display.getAudioTracks()[0] && { audio: display.getAudioTracks()[0] }) }\n own.current.push(shared.video, shared.audio)\n shared.video.addEventListener('ended', () => void stopSharing(shared))\n await call.current?.publish({ screen: shared.video, ...(shared.audio && { 'screen-audio': shared.audio }) })\n setScreen(shared)\n }, [screen, stopSharing])\n\n const canShare = typeof navigator !== 'undefined' && typeof navigator.mediaDevices?.getDisplayMedia === 'function'\n\n return {\n phase,\n devices,\n microphoneOn,\n cameraOn,\n tracks,\n members,\n connections,\n screen,\n refusedSending,\n seen: seen.current,\n self: call.current?.participant,\n join,\n toggleMicrophone,\n toggleCamera,\n ...(canShare && { toggleScreen }),\n }\n}\n","import { useState } from 'react'\nimport { useOptionalAuth } from '../auth/auth-provider'\nimport type { RouteTarget } from '../primitives/route-link'\nimport { CallCheck } from './call-check'\nimport { CallMessage } from './call-message'\nimport { callPeople } from './call-people'\nimport { CallStage } from './call-stage'\nimport { text } from './messages'\nimport { useActiveSpeaker } from './use-audio-levels'\nimport { useCallSession } from './use-call-session'\n\nexport type CallViewProps = {\n /** The socket of the app's function that admits the member, as `joinCall` takes it, such as `/api/functions/call?conversation=7`. */\n url: string\n /** Where Leave goes; leaving the page leaves the call. */\n leave: RouteTarget\n /** A member's name, by the member the app's function admits them as, such as a user id; the member itself by default. */\n nameOf?: (member: string) => string\n className?: string\n}\n\nconst deviceNotices = (devices: ReturnType<typeof useCallSession>['devices'], refusedSending: boolean) => [\n ...(devices?.blocked.microphone ? [text('noMicrophone')] : []),\n ...(devices?.blocked.camera ? [text('noCamera')] : []),\n ...(devices?.none ? [text('noDevices')] : []),\n ...(refusedSending ? [text('refused')] : []),\n]\n\n/**\n * A call, ready-made, that fills its parent, such as a column beside a conversation's messages: a check of the\n * microphone and camera first, then, after Join, everyone in the call with the one speaking ringed, a screen share\n * large, microphone, camera, screen share and Leave, the quality of each connection, Reconnecting while the link is\n * restored, and plain words for a full call, a blocked device or someone the browser cannot connect to. Made for small\n * peer-to-peer calls, at a desktop's width or a phone's.\n */\nexport const CallView = ({ url, leave, nameOf = (member) => member, className }: CallViewProps) => {\n const session = useCallSession(url)\n const auth = useOptionalAuth()\n const user = auth?.state.kind === 'signed-in' ? auth.state.user : undefined\n const self = session.self ?? user?.id ?? ''\n const [now] = useState(() => Date.now())\n const { devices, phase } = session\n const own = { ...(devices?.microphone && { microphone: devices.microphone }), ...(devices?.camera && { camera: devices.camera }), ...(session.screen && { screen: session.screen.video }), microphoneOn: session.microphoneOn, cameraOn: session.cameraOn }\n const voices = new Map([...(devices?.microphone && session.microphoneOn ? [[self, devices.microphone] as const] : []), ...session.tracks.filter((track) => track.source === 'microphone' && track.track && !track.muted).map((track) => [track.member, track.track!] as const)])\n const speaker = useActiveSpeaker(phase.kind === 'in' ? voices : new Map())\n const notices = deviceNotices(devices, session.refusedSending)\n\n if (phase.kind === 'left') return <CallMessage reason={phase.reason} onJoinAgain={() => void session.join()} />\n if (phase.kind === 'check') {\n return (\n <CallCheck\n name={user?.name ?? text('you')}\n member={self}\n {...(devices?.camera && { camera: devices.camera })}\n microphoneOn={session.microphoneOn}\n cameraOn={session.cameraOn}\n microphone={Boolean(devices?.microphone)}\n cameraAvailable={Boolean(devices?.camera)}\n notices={notices}\n onMicrophone={session.toggleMicrophone}\n onCamera={session.toggleCamera}\n onJoin={() => void session.join()}\n cancel={leave}\n />\n )\n }\n const people = callPeople({ members: session.members, self, tracks: session.tracks, own, nameOf, ...(speaker && { speaker }), connections: session.connections, seen: session.seen, now: Math.max(now, Date.now()) })\n return (\n <CallStage\n {...(className && { className })}\n people={people}\n state={phase.kind === 'joining' ? 'joining' : phase.resuming ? 'resuming' : 'joined'}\n notices={notices}\n controls={{\n microphoneOn: session.microphoneOn && Boolean(devices?.microphone),\n cameraOn: session.cameraOn && Boolean(devices?.camera),\n sharing: Boolean(session.screen),\n onMicrophone: session.toggleMicrophone,\n onCamera: session.toggleCamera,\n ...(session.toggleScreen && { onShare: () => void session.toggleScreen!() }),\n leave,\n }}\n />\n )\n}\n","import { useAppAddress } from '../app/use-app-address'\n\n/**\n * A record's call as the app's address holds it: whether the page joins it (`call=join`), the link that joins it, as a\n * ring's Accept and a call mark's Join open it, and the link back to the record without the call, as Leave opens it.\n */\nexport const useRecordCallAddress = (resource: string, recordKey: string) => {\n const { address, href, open } = useAppAddress()\n const joining = address?.kind === 'record' && address.resource === resource && address.key === recordKey && address.call === 'join'\n const target = (to: string) => ({ href: to, onFollow: () => open(to) })\n return { joining, join: target(href({ kind: 'record', resource, key: recordKey, call: 'join' })), leave: target(href({ kind: 'record', resource, key: recordKey })) }\n}\n","import { CallView, type CallViewProps } from './call-view'\nimport { useRecordCallAddress } from './use-record-call-address'\n\nexport type RecordCallProps = Omit<CallViewProps, 'leave'> & { resource: string; recordKey: string }\n\n/**\n * The record's call view while the app's address joins it (`call=join`, as Accept and Join open it), and nothing\n * otherwise: put it beside the record's own content, such as on a full-area record page. Leave goes back to the record.\n */\nexport const RecordCall = ({ resource, recordKey, ...rest }: RecordCallProps) => {\n const { joining, leave } = useRecordCallAddress(resource, recordKey)\n if (!joining) return null\n return <CallView key={`${resource}/${recordKey}`} leave={leave} {...rest} />\n}\n","import { useQuery, useQueryClient } from '@tanstack/react-query'\nimport { useEffect } from 'react'\nimport type { RecordCall } from '@protobase/client'\nimport { callsChannelEvent } from '@protobase/schema/internal'\nimport { useClient } from '../data/api-provider'\nimport { keys } from '../data/query-keys'\n\n/**\n * A record's latest calls, the one going on first, kept current over the record's channel, on the one socket the page\n * shares for every channel it holds: the server sends the calls there whenever they change, so following a record's\n * calls opens no connection of its own on a page that holds a channel already. Read again whenever the channel joins,\n * as after a lost connection.\n */\nexport const useRecordCalls = (resource: string, recordKey: string) => {\n const client = useClient()\n const queryClient = useQueryClient()\n const key = keys.recordCalls(resource, recordKey)\n const query = useQuery({ queryKey: key, queryFn: () => client.calls(resource, recordKey) })\n\n useEffect(() => {\n const queryKey = keys.recordCalls(resource, recordKey)\n const channel = client.channel(resource, recordKey)\n // Only the server's own message: anyone on the channel can broadcast under the same event.\n const offCalls = channel.on(callsChannelEvent, (message) => message.server && queryClient.setQueryData<RecordCall[]>(queryKey, (message.payload as { items: RecordCall[] }).items))\n const offStatus = channel.onStatus((status) => status.state === 'joined' && void queryClient.invalidateQueries({ queryKey }))\n return () => {\n offCalls()\n offStatus()\n channel.leave()\n }\n }, [client, queryClient, resource, recordKey])\n\n return { ...query, ongoing: query.data?.find((call) => call.ended_at === null) }\n}\n","import { Phone } from 'lucide-react'\nimport { cn } from '../lib/cn'\nimport { buttonClass } from '../primitives/button'\nimport { RouteLink } from '../primitives/route-link'\nimport { text } from './messages'\nimport { useRecordCalls } from './use-record-calls'\nimport { useRecordCallAddress } from './use-record-call-address'\n\nexport type CallMarkProps = { resource: string; recordKey: string; className?: string }\n\n/**\n * A record's call, for the app to place where it wants, such as a conversation's header: Start call while there is\n * none, and \"Call in progress · 3 · Join\" while one goes on, live. Start call and Join are links to the record's page\n * that joins its call (`call=join`); on that page itself, Join is left out.\n */\nexport const CallMark = ({ resource, recordKey, className }: CallMarkProps) => {\n const { ongoing, isPending } = useRecordCalls(resource, recordKey)\n const { joining, join } = useRecordCallAddress(resource, recordKey)\n if (isPending) return null\n if (!ongoing) {\n if (joining) return null\n return (\n <RouteLink to={join} className={cn(buttonClass({ size: 'sm' }), className)}>\n <Phone className=\"size-3.5\" />\n {text('startCall')}\n </RouteLink>\n )\n }\n const count = ongoing.members.length\n return (\n <span role=\"status\" className={cn('inline-flex items-center gap-1.5 rounded-md bg-success-soft px-2 py-0.5 text-body text-foreground', className)}>\n <Phone className=\"size-3.5 text-success\" />\n {text('inProgress')}\n <span aria-hidden>·</span>\n <span aria-label={text('people', count)}>{count}</span>\n {!joining && (\n <>\n <span aria-hidden>·</span>\n <RouteLink to={join} className={buttonClass({ variant: 'primary', size: 'sm' })}>\n {text('join')}\n </RouteLink>\n </>\n )}\n </span>\n )\n}\n","import type { StoredFile } from '@protobase/client'\nimport { shownImage } from '../live/file-values'\n\n/** An image a carousel shows: a link with what it shows, or a file field's value, as records carry it. */\nexport type CarouselImage = { src: string; alt: string } | (StoredFile & { alt?: string })\n\n// A frame up to about half a page wide: of a file's variants, the smallest that covers it is drawn, the file itself when none does\nconst box = { width: 640, height: 480 }\n\n/** What each slide draws, in order: a file that is missing or is no raster image is left out. */\nexport const carouselSlides = (images: readonly CarouselImage[]) =>\n images.flatMap((image) => {\n if ('src' in image) return [{ image: { url: image.src }, alt: image.alt }]\n const shown = shownImage(image, box)\n return shown ? [{ image: shown, alt: image.alt ?? '' }] : []\n })\n","import { cn } from '../lib/cn'\nimport { FileImage } from '../live/file-image'\nimport { CarouselControls } from './carousel-controls'\nimport { carouselSlides, type CarouselImage } from './carousel-images'\nimport { CarouselTrack } from './carousel-track'\nimport { useCarousel } from './use-carousel'\n\nexport type CarouselProps = {\n /** The images in order: links with what each shows, or file field values. */\n images: readonly CarouselImage[]\n /** What the images are, read out with the carousel. */\n label?: string\n /** `cover` fills the frame and crops what overflows it, the default; `contain` shows each image whole. */\n fit?: 'cover' | 'contain'\n /** Whether a swipe steps through the images; off, it scrolls what the carousel sits in, such as a row that scrolls sideways. */\n swipe?: boolean\n /** The frame's classes, such as its aspect ratio, border and rounding. */\n className?: string\n}\n\n/**\n * Images side by side in a frame that snaps image by image, swiped on a touch screen or moved by arrows on hover, with\n * dots marking the one in view; the record cards' photos step the same way. A single image shows without arrows or dots.\n */\nexport const Carousel = ({ images, label, fit = 'cover', swipe = true, className }: CarouselProps) => {\n const slides = carouselSlides(images)\n const carousel = useCarousel(slides.length)\n return (\n <div role=\"group\" aria-roledescription=\"carousel\" aria-label={label} className={cn('group/carousel relative overflow-hidden', className)}>\n <CarouselTrack\n data-carousel-track\n carousel={carousel}\n swipe={swipe}\n slides={slides.map(({ image, alt }) => (\n <FileImage image={image} alt={alt} loading=\"lazy\" className={cn('size-full', fit === 'cover' ? 'object-cover' : 'object-contain')} />\n ))}\n />\n <CarouselControls carousel={carousel} count={slides.length} swipe={swipe} reveal=\"group-hover/carousel:opacity-100\" className=\"inset-0\" />\n </div>\n )\n}\n","import type { ReactNode } from 'react'\nimport { cn } from '../lib/cn'\n\nexport type ChoiceOption<T extends string> = { value: T; label: string; description?: ReactNode; disabled?: boolean }\n\n/**\n * `name` groups the radio buttons, so that the arrow keys move between them; `label` names the group for screen\n * readers. A disabled option shows and cannot be chosen.\n */\nexport type ChoicesProps<T extends string> = { name: string; label?: string; options: Array<ChoiceOption<T>>; value: T | undefined; onChange: (value: T) => void }\n\n/** One of a few options, each a card of its own row with a line that says what it means; the chosen one is outlined. */\nexport const Choices = <T extends string>({ name, label, options, value, onChange }: ChoicesProps<T>) => (\n <div role=\"radiogroup\" aria-label={label} className=\"flex flex-col gap-2\">\n {options.map((option) => (\n <label\n key={option.value}\n className={cn(\n 'block rounded-lg border p-3 transition-colors has-[:focus-visible]:outline-2 has-[:focus-visible]:outline-offset-2 has-[:focus-visible]:outline-primary',\n option.disabled ? 'cursor-default bg-background opacity-60' : option.value === value ? 'cursor-pointer border-primary bg-primary-soft' : 'cursor-pointer bg-background hover:bg-surface',\n )}\n >\n <input type=\"radio\" name={name} value={option.value} checked={option.value === value} disabled={option.disabled} onChange={() => onChange(option.value)} className=\"sr-only\" />\n <span className={cn('block font-medium', option.value === value && 'text-primary-text')}>{option.label}</span>\n {option.description && <span className=\"mt-0.5 block text-xs leading-snug text-muted-foreground\">{option.description}</span>}\n </label>\n ))}\n </div>\n)\n","import { keepPreviousData, useQuery, useQueryClient } from '@tanstack/react-query'\nimport type { ResourceModel, ViewModel } from '@protobase/schema'\nimport { useClient } from '../data/api-provider'\nimport { keys } from '../data/query-keys'\nimport { fetchLabels, type Labels } from '../live/relation-labels'\n\n/** The names of the chosen records, fetched in one list call; the previous names stay while the next ones load. */\nexport const usePickedLabels = (target: ResourceModel, view: ViewModel | undefined, ids: string[]): Labels => {\n const client = useClient()\n const queryClient = useQueryClient()\n const sorted = [...new Set(ids)].sort()\n const labels = useQuery({\n queryKey: keys.pickedLabels(target.name, sorted.join(',')),\n enabled: sorted.length > 0,\n placeholderData: keepPreviousData,\n queryFn: () => fetchLabels(queryClient, client, target, sorted, view),\n })\n return labels.data ?? new Map()\n}\n","import { useState } from 'react'\nimport { Token } from '../primitives/token'\nimport { useAdminMeta } from './meta-gate'\nimport { RelationPicker } from './relation-picker'\nimport { usePickedLabels } from './use-picked-labels'\n\ntype One = {\n multiple?: false\n /** The chosen record's key, as text; `undefined` for none. */\n value: string | undefined\n onChange: (key: string) => void\n}\n\ntype Several = {\n multiple: true\n /** The chosen records' keys, as text. */\n value: string[]\n onChange: (keys: string[]) => void\n}\n\nexport type RecordPickerProps = (One | Several) & {\n /** The name of the resource whose records it picks. */\n resource: string\n invalid?: boolean\n}\n\n/**\n * Picks records of a resource of the app with the create form's relation picker: type to narrow them by their search\n * fields or title, scroll for more, choose with the mouse or the keyboard. With `multiple`, each choice is added as a\n * token that can be taken off again, and choosing a chosen record takes it off.\n */\nexport const RecordPicker = (props: RecordPickerProps) => {\n const { resources, views } = useAdminMeta()\n const target = resources[props.resource]\n if (!target) throw new Error(`RecordPicker: the app has no resource named \"${props.resource}\"`)\n if (target.primaryKey.length !== 1) throw new Error(`RecordPicker: \"${props.resource}\" has a composite key, which a picker cannot name`)\n const view = views[props.resource]\n const keys = props.multiple ? props.value : props.value === undefined ? [] : [props.value]\n // The names of records chosen here, so a choice shows its name before the names are fetched.\n const [known, setKnown] = useState<Record<string, string>>({})\n const fetched = usePickedLabels(target, view, keys)\n const labelOf = (key: string) => known[key] ?? fetched.get(key) ?? key\n const remember = (key: string, label: string) => setKnown((current) => ({ ...current, [key]: label }))\n\n if (!props.multiple) {\n const { value, onChange } = props\n return (\n <RelationPicker\n target={target}\n view={view}\n value={value ?? ''}\n label={value === undefined ? undefined : labelOf(value)}\n invalid={props.invalid}\n onChange={(key, label) => {\n remember(key, label)\n onChange(key)\n }}\n />\n )\n }\n\n const { value, onChange } = props\n return (\n <div className=\"flex flex-col gap-2\">\n <RelationPicker\n target={target}\n view={view}\n value=\"\"\n chosen={value}\n several\n invalid={props.invalid}\n onChange={(key, label) => {\n remember(key, label)\n onChange(value.includes(key) ? value.filter((chosen) => chosen !== key) : [...value, key])\n }}\n />\n {value.length > 0 && (\n <div className=\"flex flex-wrap gap-1\">\n {value.map((key) => (\n <Token key={key} label={labelOf(key)} onRemove={() => onChange(value.filter((chosen) => chosen !== key))} />\n ))}\n </div>\n )}\n </div>\n )\n}\n"],"file":"shared-protobase-ui-COFhNI_R.js","debugId":"8e161348-fd17-482b-87bd-bec9fb3428cf"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@protobase/ui",
3
- "version": "0.62.4",
3
+ "version": "0.62.5",
4
4
  "description": "The Protobase admin app and the React hooks and components for custom UI.",
5
5
  "license": "Apache-2.0",
6
6
  "repository": {
@@ -39,9 +39,9 @@
39
39
  "dependencies": {
40
40
  "@dnd-kit/core": "^6.3.1",
41
41
  "@dnd-kit/sortable": "^10.0.0",
42
- "@protobase/client": "0.62.4",
43
- "@protobase/layout": "0.62.4",
44
- "@protobase/schema": "0.62.4",
42
+ "@protobase/client": "0.62.5",
43
+ "@protobase/layout": "0.62.5",
44
+ "@protobase/schema": "0.62.5",
45
45
  "@sentry/browser": "^11.7.0",
46
46
  "@tanstack/react-query": "^5.104.1",
47
47
  "@tanstack/react-table": "^9.2.6",