@unityevolv/ofiskit-ui-map 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (103) hide show
  1. package/LICENSE +661 -0
  2. package/README.md +34 -0
  3. package/dist/Announcer.d.ts +21 -0
  4. package/dist/Announcer.d.ts.map +1 -0
  5. package/dist/Announcer.js +32 -0
  6. package/dist/Announcer.js.map +1 -0
  7. package/dist/CallAudio.d.ts +32 -0
  8. package/dist/CallAudio.d.ts.map +1 -0
  9. package/dist/CallAudio.js +72 -0
  10. package/dist/CallAudio.js.map +1 -0
  11. package/dist/CallControls.d.ts +60 -0
  12. package/dist/CallControls.d.ts.map +1 -0
  13. package/dist/CallControls.js +62 -0
  14. package/dist/CallControls.js.map +1 -0
  15. package/dist/CallTiles.d.ts +48 -0
  16. package/dist/CallTiles.d.ts.map +1 -0
  17. package/dist/CallTiles.js +134 -0
  18. package/dist/CallTiles.js.map +1 -0
  19. package/dist/DevicePanel.d.ts +32 -0
  20. package/dist/DevicePanel.d.ts.map +1 -0
  21. package/dist/DevicePanel.js +133 -0
  22. package/dist/DevicePanel.js.map +1 -0
  23. package/dist/Knocks.d.ts +46 -0
  24. package/dist/Knocks.d.ts.map +1 -0
  25. package/dist/Knocks.js +46 -0
  26. package/dist/Knocks.js.map +1 -0
  27. package/dist/OfficeMap.d.ts +69 -0
  28. package/dist/OfficeMap.d.ts.map +1 -0
  29. package/dist/OfficeMap.js +222 -0
  30. package/dist/OfficeMap.js.map +1 -0
  31. package/dist/Overflow.d.ts +41 -0
  32. package/dist/Overflow.d.ts.map +1 -0
  33. package/dist/Overflow.js +82 -0
  34. package/dist/Overflow.js.map +1 -0
  35. package/dist/PersonAvatar.d.ts +32 -0
  36. package/dist/PersonAvatar.d.ts.map +1 -0
  37. package/dist/PersonAvatar.js +80 -0
  38. package/dist/PersonAvatar.js.map +1 -0
  39. package/dist/Reactions.d.ts +47 -0
  40. package/dist/Reactions.d.ts.map +1 -0
  41. package/dist/Reactions.js +61 -0
  42. package/dist/Reactions.js.map +1 -0
  43. package/dist/RoomBar.d.ts +43 -0
  44. package/dist/RoomBar.d.ts.map +1 -0
  45. package/dist/RoomBar.js +120 -0
  46. package/dist/RoomBar.js.map +1 -0
  47. package/dist/Share.d.ts +74 -0
  48. package/dist/Share.d.ts.map +1 -0
  49. package/dist/Share.js +115 -0
  50. package/dist/Share.js.map +1 -0
  51. package/dist/StatusControl.d.ts +25 -0
  52. package/dist/StatusControl.d.ts.map +1 -0
  53. package/dist/StatusControl.js +77 -0
  54. package/dist/StatusControl.js.map +1 -0
  55. package/dist/controls.d.ts +32 -0
  56. package/dist/controls.d.ts.map +1 -0
  57. package/dist/controls.js +24 -0
  58. package/dist/controls.js.map +1 -0
  59. package/dist/hooks.d.ts +60 -0
  60. package/dist/hooks.d.ts.map +1 -0
  61. package/dist/hooks.js +182 -0
  62. package/dist/hooks.js.map +1 -0
  63. package/dist/index.d.ts +45 -0
  64. package/dist/index.d.ts.map +1 -0
  65. package/dist/index.js +45 -0
  66. package/dist/index.js.map +1 -0
  67. package/dist/layout.d.ts +65 -0
  68. package/dist/layout.d.ts.map +1 -0
  69. package/dist/layout.js +93 -0
  70. package/dist/layout.js.map +1 -0
  71. package/dist/placement.d.ts +70 -0
  72. package/dist/placement.d.ts.map +1 -0
  73. package/dist/placement.js +83 -0
  74. package/dist/placement.js.map +1 -0
  75. package/dist/sounds.d.ts +30 -0
  76. package/dist/sounds.d.ts.map +1 -0
  77. package/dist/sounds.js +125 -0
  78. package/dist/sounds.js.map +1 -0
  79. package/dist/status.d.ts +47 -0
  80. package/dist/status.d.ts.map +1 -0
  81. package/dist/status.js +65 -0
  82. package/dist/status.js.map +1 -0
  83. package/dist/theme.d.ts +27 -0
  84. package/dist/theme.d.ts.map +1 -0
  85. package/dist/theme.js +57 -0
  86. package/dist/theme.js.map +1 -0
  87. package/dist/tileLayout.d.ts +27 -0
  88. package/dist/tileLayout.d.ts.map +1 -0
  89. package/dist/tileLayout.js +41 -0
  90. package/dist/tileLayout.js.map +1 -0
  91. package/dist/useCall.d.ts +107 -0
  92. package/dist/useCall.d.ts.map +1 -0
  93. package/dist/useCall.js +238 -0
  94. package/dist/useCall.js.map +1 -0
  95. package/dist/useShare.d.ts +54 -0
  96. package/dist/useShare.d.ts.map +1 -0
  97. package/dist/useShare.js +114 -0
  98. package/dist/useShare.js.map +1 -0
  99. package/dist/useSounds.d.ts +31 -0
  100. package/dist/useSounds.d.ts.map +1 -0
  101. package/dist/useSounds.js +56 -0
  102. package/dist/useSounds.js.map +1 -0
  103. package/package.json +25 -0
@@ -0,0 +1,82 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { Popover } from '@unityevolv/unitykit';
3
+ import { PersonAvatar } from './PersonAvatar.js';
4
+ /**
5
+ * The people a room has no cell for.
6
+ *
7
+ * User areas are display slots, not seats, so a room can hold more people than it
8
+ * has cells — and when it does, the last cell counts the rest. The counter is drawn
9
+ * **as an avatar** rather than as a badge: it takes a person's place in the room,
10
+ * it sits in a person's cell, and the thing it stands for is people. A small pill
11
+ * in a row of faces reads as a notification rather than as four more colleagues.
12
+ *
13
+ * Opening it shows those people the same way the room shows everybody else: as
14
+ * avatars, with their status and whatever they are doing in the call, three
15
+ * across and three down, scrolling for the rest. A list of names would be the one
16
+ * place in the office where people stopped looking like people.
17
+ */
18
+ /** Three across and three down, then it scrolls. */
19
+ export const OVERFLOW_COLUMNS = 3;
20
+ export const OVERFLOW_ROWS = 3;
21
+ /** Each avatar in the grid, in pixels. Fixed, because the room's cells can be tiny. */
22
+ const CELL = 60;
23
+ /**
24
+ * One row: the face, the name under it, and room above it for a raised hand, which
25
+ * sits outside the circle on purpose and would otherwise be clipped by the row
26
+ * above.
27
+ */
28
+ const ROW = 72;
29
+ const GAP = 4;
30
+ /**
31
+ * How tall the list may be.
32
+ *
33
+ * Three rows, and the rest scroll: a room of forty people is a panel of nine faces
34
+ * and a scrollbar, not a panel taller than the map. Fewer when the screen has less
35
+ * room than that on either side of the counter — Radix measures what is available,
36
+ * and a short phone may have less than three rows' worth above or below. The
37
+ * subtraction is the panel's own padding.
38
+ */
39
+ export const OVERFLOW_MAX_HEIGHT = `min(${OVERFLOW_ROWS * ROW + (OVERFLOW_ROWS - 1) * GAP}px, calc(var(--radix-popover-content-available-height, 100vh) - 3.5rem))`;
40
+ /**
41
+ * Give the popover's dialog the list's name.
42
+ *
43
+ * The kit's Popover renders Radix's content as `role="dialog"` and has no prop to
44
+ * name it, so without this every screen reader announces an unnamed dialog before
45
+ * it reaches the list. Set from inside, once the list is mounted, because the
46
+ * dialog is the list's own ancestor and nothing outside the popover can reach it.
47
+ * Worth moving into the kit, where every popover would get it.
48
+ */
49
+ const nameTheDialog = (name) => (node) => {
50
+ node?.closest('[role="dialog"]')?.setAttribute('aria-label', name);
51
+ };
52
+ export function OverflowAvatar({ roomName, tokens, size, reducedMotion = false, reactions, }) {
53
+ const count = tokens.length;
54
+ // The same proportions as a person's avatar, so the counter lines up with the
55
+ // row it is in rather than looking like something laid on top of it.
56
+ const face = Math.round(size * 0.62);
57
+ const label = `+${count}`;
58
+ return (_jsx(Popover, { width: "auto", trigger: _jsxs("button", { type: "button", "aria-label": `${count} more in ${roomName}. Activate to see them.`, "data-testid": "overflow-avatar", className: "flex cursor-pointer select-none flex-col items-center gap-1 rounded-lg focus-visible:outline-2 focus-visible:outline-primary", style: { width: size }, children: [_jsx("span", { "aria-hidden": "true", className: "grid place-items-center rounded-full bg-neutral font-semibold text-neutral-content ring-1 ring-base-300",
59
+ // Three characters from +10 upwards, so the digits shrink rather than
60
+ // spill out of the circle.
61
+ style: {
62
+ width: face,
63
+ height: face,
64
+ fontSize: Math.max(10, face * (label.length > 2 ? 0.32 : 0.38)),
65
+ }, children: label }), _jsx("span", { "aria-hidden": "true", className: "max-w-full truncate rounded bg-base-100/85 px-1 text-center leading-tight text-base-content backdrop-blur-[2px]", style: { fontSize: Math.max(9, size * 0.17) }, children: "more" })] }), children: _jsx("ul", { "aria-label": `${count} more in ${roomName}`, "data-testid": "overflow-grid",
66
+ /*
67
+ Focusable, so the keyboard can scroll it.
68
+
69
+ Nothing inside is focusable — an avatar here is a picture of a person, not
70
+ a control — so without this the people after the ninth could be seen with
71
+ a mouse wheel and reached by nobody else. Being the first thing that takes
72
+ focus also means the popover opens onto a named list rather than onto its
73
+ own frame.
74
+ */
75
+ tabIndex: 0, ref: nameTheDialog(`${count} more in ${roomName}`), className: "grid overflow-y-auto overscroll-contain rounded focus-visible:outline-2 focus-visible:outline-primary", style: {
76
+ gridTemplateColumns: `repeat(${OVERFLOW_COLUMNS}, ${CELL}px)`,
77
+ gridAutoRows: `${ROW}px`,
78
+ gap: GAP,
79
+ maxHeight: OVERFLOW_MAX_HEIGHT,
80
+ }, children: tokens.map((token) => (_jsx("li", { className: "flex justify-center pt-2.5", children: _jsx(PersonAvatar, { person: token.person, size: CELL, ...(token.deviceId ? { deviceId: token.deviceId } : {}), linked: token.linked, reducedMotion: reducedMotion, reactions: reactions?.get(token.person.userId) ?? [] }) }, token.key))) }) }));
81
+ }
82
+ //# sourceMappingURL=Overflow.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Overflow.js","sourceRoot":"","sources":["../src/Overflow.tsx"],"names":[],"mappings":"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"}
@@ -0,0 +1,32 @@
1
+ import type { PublicPresence } from '@unityevolv/ofiskit-realtime-client';
2
+ import type { LiveReaction } from './useCall.js';
3
+ /**
4
+ * One person, standing in a room.
5
+ *
6
+ * Drawn as a kit surface rather than straight onto the background image: the
7
+ * image is whatever an author generated, and nothing legible can be guaranteed on
8
+ * top of it. Everything here has its own background and its own contrast in both
9
+ * themes.
10
+ */
11
+ export interface PersonAvatarProps {
12
+ person: PublicPresence;
13
+ /** The avatar cell's width in pixels, from the template's avatar size. */
14
+ size: number;
15
+ /**
16
+ * Which of this person's devices this avatar is for.
17
+ *
18
+ * Somebody here on two devices is drawn twice, one avatar per device, because
19
+ * each is a real screen with its own camera and microphone. Both are the same
20
+ * person, and the pair says so.
21
+ */
22
+ deviceId?: string;
23
+ /** Linked to another avatar for the same person, so the pair reads as one. */
24
+ linked?: boolean;
25
+ /** Drops the pulse on the speaking ring. The ring itself stays. */
26
+ reducedMotion?: boolean;
27
+ /** What is in the air over this person right now. From `useReactions`. */
28
+ reactions?: readonly LiveReaction[];
29
+ onClick?(): void;
30
+ }
31
+ export declare function PersonAvatar({ person, size, deviceId, linked, reducedMotion, reactions, onClick, }: PersonAvatarProps): import("react").JSX.Element;
32
+ //# sourceMappingURL=PersonAvatar.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"PersonAvatar.d.ts","sourceRoot":"","sources":["../src/PersonAvatar.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,qCAAqC,CAAA;AAKzE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,cAAc,CAAA;AAEhD;;;;;;;GAOG;AAEH,MAAM,WAAW,iBAAiB;IAChC,MAAM,EAAE,cAAc,CAAA;IACtB,0EAA0E;IAC1E,IAAI,EAAE,MAAM,CAAA;IACZ;;;;;;OAMG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,8EAA8E;IAC9E,MAAM,CAAC,EAAE,OAAO,CAAA;IAChB,mEAAmE;IACnE,aAAa,CAAC,EAAE,OAAO,CAAA;IACvB,0EAA0E;IAC1E,SAAS,CAAC,EAAE,SAAS,YAAY,EAAE,CAAA;IACnC,OAAO,CAAC,IAAI,IAAI,CAAA;CACjB;AAmCD,wBAAgB,YAAY,CAAC,EAC3B,MAAM,EACN,IAAI,EACJ,QAAQ,EACR,MAAc,EACd,aAAqB,EACrB,SAAS,EACT,OAAO,GACR,EAAE,iBAAiB,+BAoMnB"}
@@ -0,0 +1,80 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { Icon, Tooltip } from '@unityevolv/unitykit';
3
+ import { handRaised, isMuted, isPhoneOnly, isSharing, isSpeaking } from '@unityevolv/ofiskit-realtime-client';
4
+ import { ReactionFloat } from './Reactions.js';
5
+ import { StatusDot, describeStatus } from './status.js';
6
+ /**
7
+ * A phone, drawn here rather than imported.
8
+ *
9
+ * The kit's icon set has no phone in it, and `ofiskit/no-lucide-direct` exists to
10
+ * stop anybody reaching around the kit for one — an icon from outside is a
11
+ * different weight from every other icon in the product. Drawn inline instead, in
12
+ * `currentColor`, which is the same thing `status.tsx` does for the status shapes
13
+ * and for the same reason. It is decoration: the avatar's label already says "on a
14
+ * phone".
15
+ */
16
+ function PhoneGlyph({ size }) {
17
+ return (_jsxs("svg", { viewBox: "0 0 12 12", width: size, height: size, "aria-hidden": "true", focusable: "false", children: [_jsx("rect", { x: "3.25", y: "1", width: "5.5", height: "10", rx: "1.25", fill: "none", stroke: "currentColor", strokeWidth: "1.25" }), _jsx("rect", { x: "5", y: "9", width: "2", height: "0.9", rx: "0.45", fill: "currentColor" })] }));
18
+ }
19
+ function initials(name) {
20
+ const parts = name.trim().split(/\s+/).slice(0, 2);
21
+ return parts.map((part) => part[0]?.toUpperCase() ?? '').join('') || '?';
22
+ }
23
+ export function PersonAvatar({ person, size, deviceId, linked = false, reducedMotion = false, reactions, onClick, }) {
24
+ const device = deviceId ? person.devices.find((one) => one.deviceId === deviceId) : undefined;
25
+ const reconnecting = person.status === 'reconnecting';
26
+ /*
27
+ * What the call looks like from the map.
28
+ *
29
+ * Per device where this avatar *is* a device, and across the person otherwise —
30
+ * somebody drawn once while in the call from a laptop and a phone is speaking if
31
+ * either of them is, and muted only if both are.
32
+ */
33
+ const speaking = device ? device.inCall && device.speaking : isSpeaking(person);
34
+ const microphoneOff = device ? device.inCall && device.muted : isMuted(person);
35
+ const sharing = device ? device.sharing : isSharing(person);
36
+ const hand = device ? device.inCall && device.handRaisedAt !== null : handRaised(person);
37
+ const face = Math.round(size * 0.62);
38
+ const description = describeStatus(person.status, person.custom);
39
+ /**
40
+ * One label carrying everything the picture says.
41
+ *
42
+ * Drawing is not telling: a badge in the corner of an avatar is invisible to a
43
+ * screen reader unless it is in here, and status is the whole reason somebody
44
+ * decides whether to walk into a room.
45
+ */
46
+ const label = [
47
+ person.displayName,
48
+ description,
49
+ linked ? `also here on another device${device ? ` (this one is ${device.kind})` : ''}` : '',
50
+ isPhoneOnly(person) ? 'on a phone' : '',
51
+ // Every badge drawn in a corner of this avatar, said. A ring on a picture is
52
+ // invisible to a screen reader, and "who is talking" is most of what somebody
53
+ // wants from a room they cannot see.
54
+ hand ? 'hand raised' : '',
55
+ sharing ? 'sharing their screen' : '',
56
+ microphoneOff ? 'microphone off' : '',
57
+ speaking ? 'speaking' : '',
58
+ ]
59
+ .filter(Boolean)
60
+ .join(', ');
61
+ const body = (_jsxs("span", { className: "flex select-none flex-col items-center gap-1", style: { width: size }, "data-testid": "person-avatar", children: [_jsxs("span", { className: "relative inline-flex", style: { width: face, height: face }, children: [_jsx(ReactionFloat, { reactions: reactions ?? [], size: Math.max(16, Math.round(face * 0.5)) }), linked && (_jsx("span", { "aria-hidden": "true", className: "absolute -inset-1 rounded-full ring-2 ring-primary/50" })), speaking && (_jsx("span", { "aria-hidden": "true", className: [
62
+ 'absolute -inset-1 rounded-full ring-2 ring-primary',
63
+ reducedMotion ? '' : 'animate-pulse',
64
+ ].join(' ') })), person.photoUrl ? (_jsx("img", { src: person.photoUrl, alt: "", className: [
65
+ 'rounded-full bg-base-200 object-cover ring-1 ring-base-300',
66
+ reconnecting ? 'opacity-50' : '',
67
+ ].join(' '), style: { width: face, height: face } })) : (_jsx("span", { "aria-hidden": "true", className: [
68
+ 'grid place-items-center rounded-full bg-base-300 font-semibold text-base-content ring-1 ring-base-300',
69
+ reconnecting ? 'opacity-50' : '',
70
+ ].join(' '), style: { width: face, height: face, fontSize: Math.max(10, face * 0.38) }, children: initials(person.displayName) })), hand && (_jsx("span", { "aria-hidden": "true", className: "absolute -top-2.5 left-1/2 -translate-x-1/2 rounded-full bg-base-100 px-0.5 leading-none text-primary", children: _jsx(Icon, { name: "raise-hand", size: "xs" }) })), sharing && (_jsx("span", { "aria-hidden": "true", className: "absolute -right-1 -top-1 rounded-full bg-base-100 p-0.5 leading-none text-primary", children: _jsx(Icon, { name: "share", size: "xs" }) })), microphoneOff && (_jsx("span", { "aria-hidden": "true", className: "absolute -left-1 -top-1 rounded-full bg-base-100 p-0.5 leading-none text-base-content/70", children: _jsx(Icon, { name: "mic-off", size: "xs" }) })), _jsx("span", { className: "absolute -bottom-0.5 -right-0.5 rounded-full bg-base-100 p-px leading-none", children: _jsx(StatusDot, { status: person.status, size: Math.max(9, face * 0.3), labelled: false }) }), isPhoneOnly(person) && (_jsx("span", { className: "absolute -bottom-1 -left-1 rounded-full bg-base-100 p-0.5 leading-none text-base-content/70", children: _jsx(PhoneGlyph, { size: Math.max(8, face * 0.26) }) }))] }), _jsx("span", { className: [
71
+ 'max-w-full truncate rounded px-1 text-center leading-tight',
72
+ 'bg-base-100/85 text-base-content backdrop-blur-[2px]',
73
+ linked ? 'ring-1 ring-primary/60' : '',
74
+ ].join(' '), style: { fontSize: Math.max(9, size * 0.17) }, children: person.displayName })] }));
75
+ const content = onClick ? (_jsx("button", { type: "button", onClick: onClick, className: "cursor-pointer", "aria-label": label, children: body })) : (_jsx("span", { role: "img", "aria-label": label, children: body }));
76
+ // The custom status is shown on hover on the web, so the map is not covered in
77
+ // text while still carrying it for anybody who wants it.
78
+ return person.custom?.text ? _jsx(Tooltip, { content: description, children: content }) : content;
79
+ }
80
+ //# sourceMappingURL=PersonAvatar.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"PersonAvatar.js","sourceRoot":"","sources":["../src/PersonAvatar.tsx"],"names":[],"mappings":"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"}
@@ -0,0 +1,47 @@
1
+ import type { Reaction } from '@unityevolv/ofiskit-realtime-client';
2
+ import type { LiveReaction } from './useCall.js';
3
+ /**
4
+ * Reacting without interrupting, and seeing that somebody did.
5
+ *
6
+ * Two pieces that belong together: the picker somebody sends from, and the float
7
+ * that appears over whoever sent it. Both are here so the set of reactions is read
8
+ * from one place and drawn the same way over a tile and over an avatar.
9
+ *
10
+ * **Nothing is stored.** A reaction floats for a few seconds and then it has
11
+ * stopped existing — not archived, not in the office state, not on the server.
12
+ * Somebody who was not looking missed it, which is what happens with a nod.
13
+ */
14
+ export interface ReactionFloatProps {
15
+ /** What is in the air over this person right now. Empty draws nothing at all. */
16
+ reactions: readonly LiveReaction[];
17
+ /** Roughly how big to draw them, in pixels. A tile wants more than an avatar. */
18
+ size?: number;
19
+ }
20
+ /**
21
+ * The reactions in the air over one person.
22
+ *
23
+ * Absolutely positioned and `pointer-events-none`, so it can never take a click
24
+ * meant for the tile or the avatar underneath it — a reaction that swallows the
25
+ * mute button is worse than no reaction.
26
+ *
27
+ * Announced politely rather than drawn only. It is deliberately **not** assertive:
28
+ * applause must not interrupt a screen reader mid-sentence, which is the whole
29
+ * point of reacting this way rather than saying something.
30
+ */
31
+ export declare function ReactionFloat({ reactions, size }: ReactionFloatProps): import("react").JSX.Element | null;
32
+ export interface ReactionPickerProps {
33
+ onReact(reaction: Reaction): void;
34
+ disabled?: boolean;
35
+ }
36
+ /**
37
+ * The six, in a row.
38
+ *
39
+ * A row rather than a menu behind a menu: this is pressed in the middle of
40
+ * somebody else's sentence, and anything that takes two decisions will not be
41
+ * used. Every one is a real button with a real name, because an emoji on its own
42
+ * is not a label — "thumbs up" is.
43
+ */
44
+ export declare function ReactionPicker({ onReact, disabled }: ReactionPickerProps): import("react").JSX.Element;
45
+ /** The words a live region says when somebody reacts. Used by the host's announcer. */
46
+ export declare function describeReaction(displayName: string, reaction: string): string;
47
+ //# sourceMappingURL=Reactions.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Reactions.d.ts","sourceRoot":"","sources":["../src/Reactions.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,qCAAqC,CAAA;AAInE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,cAAc,CAAA;AAEhD;;;;;;;;;;GAUG;AAEH,MAAM,WAAW,kBAAkB;IACjC,iFAAiF;IACjF,SAAS,EAAE,SAAS,YAAY,EAAE,CAAA;IAClC,iFAAiF;IACjF,IAAI,CAAC,EAAE,MAAM,CAAA;CACd;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,aAAa,CAAC,EAAE,SAAS,EAAE,IAAS,EAAE,EAAE,kBAAkB,sCA4BzE;AAED,MAAM,WAAW,mBAAmB;IAClC,OAAO,CAAC,QAAQ,EAAE,QAAQ,GAAG,IAAI,CAAA;IACjC,QAAQ,CAAC,EAAE,OAAO,CAAA;CACnB;AAED;;;;;;;GAOG;AACH,wBAAgB,cAAc,CAAC,EAAE,OAAO,EAAE,QAAgB,EAAE,EAAE,mBAAmB,+BA0BhF;AAmBD,uFAAuF;AACvF,wBAAgB,gBAAgB,CAAC,WAAW,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,CAG9E"}
@@ -0,0 +1,61 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { REACTIONS } from '@unityevolv/ofiskit-realtime-client';
3
+ import { useReducedMotion } from './hooks.js';
4
+ /**
5
+ * The reactions in the air over one person.
6
+ *
7
+ * Absolutely positioned and `pointer-events-none`, so it can never take a click
8
+ * meant for the tile or the avatar underneath it — a reaction that swallows the
9
+ * mute button is worse than no reaction.
10
+ *
11
+ * Announced politely rather than drawn only. It is deliberately **not** assertive:
12
+ * applause must not interrupt a screen reader mid-sentence, which is the whole
13
+ * point of reacting this way rather than saying something.
14
+ */
15
+ export function ReactionFloat({ reactions, size = 22 }) {
16
+ const reducedMotion = useReducedMotion();
17
+ if (reactions.length === 0)
18
+ return null;
19
+ return (_jsx("span", { className: "pointer-events-none absolute inset-x-0 bottom-1/3 z-20 flex items-end justify-center gap-0.5", "data-testid": "reaction-float", children: reactions.map((one) => (_jsx("span", {
20
+ // A bob rather than a static badge, because a reaction that appears with
21
+ // no movement reads as a badge somebody earned rather than as a thing
22
+ // that just happened. Still, and still visible, under reduced motion.
23
+ className: ['leading-none drop-shadow', reducedMotion ? '' : 'animate-bounce'].join(' '), style: { fontSize: size }, children: _jsx("span", { "aria-hidden": "true", children: one.reaction }) }, one.id))) }));
24
+ }
25
+ /**
26
+ * The six, in a row.
27
+ *
28
+ * A row rather than a menu behind a menu: this is pressed in the middle of
29
+ * somebody else's sentence, and anything that takes two decisions will not be
30
+ * used. Every one is a real button with a real name, because an emoji on its own
31
+ * is not a label — "thumbs up" is.
32
+ */
33
+ export function ReactionPicker({ onReact, disabled = false }) {
34
+ return (_jsx("div", { role: "group", "aria-label": "React", "data-testid": "reaction-picker", className: "flex items-center gap-0.5", children: REACTIONS.map((reaction) => (_jsx("button", { type: "button", disabled: disabled, onClick: () => onReact(reaction), "aria-label": `React with ${NAMES[reaction]}`, className: [
35
+ 'inline-flex h-8 w-8 items-center justify-center rounded-lg text-lg leading-none',
36
+ 'focus-visible:outline-2 focus-visible:outline-offset-1 focus-visible:outline-primary',
37
+ disabled ? 'cursor-not-allowed opacity-40' : 'hover:bg-base-200',
38
+ ].join(' '), children: _jsx("span", { "aria-hidden": "true", children: reaction }) }, reaction))) }));
39
+ }
40
+ /**
41
+ * What each one is called.
42
+ *
43
+ * Here rather than in the protocol, because a name is for a person to read and the
44
+ * protocol carries what both sides must agree on. The keys are exhaustive against
45
+ * the set, so adding a reaction without naming it is a compile error rather than a
46
+ * button announced as "react with".
47
+ */
48
+ const NAMES = {
49
+ '👍': 'thumbs up',
50
+ '👏': 'applause',
51
+ '🎉': 'celebration',
52
+ '😂': 'laughing',
53
+ '❤️': 'love',
54
+ '😮': 'surprise',
55
+ };
56
+ /** The words a live region says when somebody reacts. Used by the host's announcer. */
57
+ export function describeReaction(displayName, reaction) {
58
+ const name = NAMES[reaction];
59
+ return name ? `${displayName} reacted: ${name}.` : `${displayName} reacted.`;
60
+ }
61
+ //# sourceMappingURL=Reactions.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Reactions.js","sourceRoot":"","sources":["../src/Reactions.tsx"],"names":[],"mappings":";AACA,OAAO,EAAE,SAAS,EAAE,MAAM,qCAAqC,CAAA;AAE/D,OAAO,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAA;AAsB7C;;;;;;;;;;GAUG;AACH,MAAM,UAAU,aAAa,CAAC,EAAE,SAAS,EAAE,IAAI,GAAG,EAAE,EAAsB;IACxE,MAAM,aAAa,GAAG,gBAAgB,EAAE,CAAA;IACxC,IAAI,SAAS,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,IAAI,CAAA;IAEvC,OAAO,CACL,eACE,SAAS,EAAC,8FAA8F,iBAC5F,gBAAgB,YAE3B,SAAS,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,CACtB;YAEE,yEAAyE;YACzE,sEAAsE;YACtE,sEAAsE;YACtE,SAAS,EAAE,CAAC,0BAA0B,EAAE,aAAa,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,gBAAgB,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,EACxF,KAAK,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,YAOzB,8BAAkB,MAAM,YAAE,GAAG,CAAC,QAAQ,GAAQ,IAZzC,GAAG,CAAC,EAAE,CAaN,CACR,CAAC,GACG,CACR,CAAA;AACH,CAAC;AAOD;;;;;;;GAOG;AACH,MAAM,UAAU,cAAc,CAAC,EAAE,OAAO,EAAE,QAAQ,GAAG,KAAK,EAAuB;IAC/E,OAAO,CACL,cACE,IAAI,EAAC,OAAO,gBACD,OAAO,iBACN,iBAAiB,EAC7B,SAAS,EAAC,2BAA2B,YAEpC,SAAS,CAAC,GAAG,CAAC,CAAC,QAAQ,EAAE,EAAE,CAAC,CAC3B,iBAEE,IAAI,EAAC,QAAQ,EACb,QAAQ,EAAE,QAAQ,EAClB,OAAO,EAAE,GAAG,EAAE,CAAC,OAAO,CAAC,QAAQ,CAAC,gBACpB,cAAc,KAAK,CAAC,QAAQ,CAAC,EAAE,EAC3C,SAAS,EAAE;gBACT,iFAAiF;gBACjF,sFAAsF;gBACtF,QAAQ,CAAC,CAAC,CAAC,+BAA+B,CAAC,CAAC,CAAC,mBAAmB;aACjE,CAAC,IAAI,CAAC,GAAG,CAAC,YAEX,8BAAkB,MAAM,YAAE,QAAQ,GAAQ,IAXrC,QAAQ,CAYN,CACV,CAAC,GACE,CACP,CAAA;AACH,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,KAAK,GAA6B;IACtC,IAAI,EAAE,WAAW;IACjB,IAAI,EAAE,UAAU;IAChB,IAAI,EAAE,aAAa;IACnB,IAAI,EAAE,UAAU;IAChB,IAAI,EAAE,MAAM;IACZ,IAAI,EAAE,UAAU;CACjB,CAAA;AAED,uFAAuF;AACvF,MAAM,UAAU,gBAAgB,CAAC,WAAmB,EAAE,QAAgB;IACpE,MAAM,IAAI,GAAG,KAAK,CAAC,QAAoB,CAAC,CAAA;IACxC,OAAO,IAAI,CAAC,CAAC,CAAC,GAAG,WAAW,aAAa,IAAI,GAAG,CAAC,CAAC,CAAC,GAAG,WAAW,WAAW,CAAA;AAC9E,CAAC"}
@@ -0,0 +1,43 @@
1
+ import type { RoomCall } from '@unityevolv/ofiskit-realtime-client';
2
+ import type { Room } from '@unityevolv/ofiskit-template';
3
+ /**
4
+ * The bar on a room: its name, what is happening in it, and what you can do.
5
+ *
6
+ * Two rows. The action row carries the name, the occupancy, the lock state and
7
+ * the controls. The message row underneath explains why a control is disabled,
8
+ * and is collapsed entirely when there is nothing to say, so an ordinary open room
9
+ * does not carry a blank line.
10
+ *
11
+ * Controls that cannot be used are **disabled and visible, never hidden**. A
12
+ * person needs to know that joining is a thing that exists and why they cannot do
13
+ * it right now; a control that vanishes teaches them nothing. The server refuses
14
+ * the same action independently, so the disabled state is a convenience and never
15
+ * the control.
16
+ */
17
+ export interface RoomBarProps {
18
+ room: Room;
19
+ occupancy: number;
20
+ /** Null when the office does not cap rooms, which the free office never does. */
21
+ capacity: number | null;
22
+ locked: boolean;
23
+ inside: boolean;
24
+ /**
25
+ * The call happening in this room, if there is one.
26
+ *
27
+ * Null in reception and the break room always, because neither hosts a call —
28
+ * and null in an ordinary room where nobody has started one yet. A room with a
29
+ * call in it is the single most useful thing on this bar: it is the difference
30
+ * between walking in on a conversation and joining one.
31
+ */
32
+ call?: RoomCall | null;
33
+ /** The identity adapter's answer, when the host has one. Never invented here. */
34
+ forbiddenReason?: string | null;
35
+ /** How wide the room is on screen, which decides how much the bar can show. */
36
+ width: number;
37
+ onJoin(): void;
38
+ onKnock(): void;
39
+ onLock(): void;
40
+ onUnlock(): void;
41
+ }
42
+ export declare function RoomBar(props: RoomBarProps): import("react").JSX.Element;
43
+ //# sourceMappingURL=RoomBar.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"RoomBar.d.ts","sourceRoot":"","sources":["../src/RoomBar.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,qCAAqC,CAAA;AACnE,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,8BAA8B,CAAA;AAGxD;;;;;;;;;;;;;GAaG;AAEH,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,IAAI,CAAA;IACV,SAAS,EAAE,MAAM,CAAA;IACjB,iFAAiF;IACjF,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAA;IACvB,MAAM,EAAE,OAAO,CAAA;IACf,MAAM,EAAE,OAAO,CAAA;IACf;;;;;;;OAOG;IACH,IAAI,CAAC,EAAE,QAAQ,GAAG,IAAI,CAAA;IACtB,iFAAiF;IACjF,eAAe,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IAC/B,+EAA+E;IAC/E,KAAK,EAAE,MAAM,CAAA;IACb,MAAM,IAAI,IAAI,CAAA;IACd,OAAO,IAAI,IAAI,CAAA;IACf,MAAM,IAAI,IAAI,CAAA;IACd,QAAQ,IAAI,IAAI,CAAA;CACjB;AAsCD,wBAAgB,OAAO,CAAC,KAAK,EAAE,YAAY,+BA8N1C"}
@@ -0,0 +1,120 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { Button, Icon } from '@unityevolv/unitykit';
3
+ import { hostsCalls } from '@unityevolv/ofiskit-template';
4
+ /** Below this, the bar shows icons only and the name is truncated. */
5
+ const COMPACT_BELOW = 190;
6
+ /**
7
+ * Below this there is room for the name and the action and nothing else.
8
+ *
9
+ * A room this narrow is a room on a phone's map, where a bar is about 65 to 90
10
+ * pixels wide. The name at its two-character minimum, the gaps and a worded Join
11
+ * come to about 62, so a call badge beside them — even as a bare icon — would push
12
+ * Join off the bar's clipped edge.
13
+ */
14
+ const TINY_BELOW = 110;
15
+ export function RoomBar(props) {
16
+ const { room, occupancy, capacity, locked, inside, forbiddenReason, width } = props;
17
+ const compact = width < COMPACT_BELOW;
18
+ const tiny = width < TINY_BELOW;
19
+ const full = capacity !== null && occupancy >= capacity;
20
+ const lockable = hostsCalls(room.type);
21
+ /*
22
+ * The call, and whether there is a seat left in it.
23
+ *
24
+ * Two different fullnesses live on this bar and they are not the same thing: the
25
+ * room can have space for ten more people while the call in it has none, because
26
+ * the cap on the call is the provider's and the cap on the room is the office's.
27
+ * Saying "full" without saying which would send somebody away from a room they
28
+ * could have walked into.
29
+ */
30
+ const call = hostsCalls(room.type) ? (props.call ?? null) : null;
31
+ const callFull = call !== null && call.participants.length >= call.limit;
32
+ const actions = [];
33
+ if (!inside) {
34
+ if (locked) {
35
+ actions.push({
36
+ key: 'knock',
37
+ label: 'Knock',
38
+ onClick: props.onKnock,
39
+ disabled: Boolean(forbiddenReason),
40
+ ...(forbiddenReason ? { reason: forbiddenReason } : {}),
41
+ variant: 'secondary',
42
+ });
43
+ }
44
+ else {
45
+ // The adapter's reason wins over the room being full: "you are a guest" is
46
+ // more useful than "it is full", because one of them will still be true in
47
+ // ten minutes.
48
+ const reason = forbiddenReason ?? (full ? `${room.name} is full.` : undefined);
49
+ actions.push({
50
+ key: 'join',
51
+ label: 'Join',
52
+ onClick: props.onJoin,
53
+ disabled: Boolean(reason),
54
+ ...(reason ? { reason } : {}),
55
+ variant: 'primary',
56
+ });
57
+ }
58
+ }
59
+ else if (lockable) {
60
+ actions.push(locked
61
+ ? {
62
+ key: 'unlock',
63
+ label: 'Unlock',
64
+ icon: 'unlock',
65
+ onClick: props.onUnlock,
66
+ disabled: false,
67
+ variant: 'secondary',
68
+ }
69
+ : {
70
+ key: 'lock',
71
+ label: 'Lock',
72
+ icon: 'lock',
73
+ onClick: props.onLock,
74
+ disabled: false,
75
+ variant: 'secondary',
76
+ });
77
+ }
78
+ // One message at a time. Two stacked reasons is a paragraph on a room bar, and
79
+ // the first one is the one stopping you. A full call comes second, because it
80
+ // stops you doing less: you can still go in and listen.
81
+ const message = actions.find((action) => action.disabled)?.reason ??
82
+ (callFull ? `The call in ${room.name} is full. You can still go in.` : null);
83
+ const typeIcon = room.type === 'reception' ? 'reception' : room.type === 'break' ? 'break-room' : 'office';
84
+ return (_jsxs("div", {
85
+ // Translucent enough for the room's picture to show through, which is what
86
+ // ties the bar to the room it sits on. The blur is what keeps it readable over
87
+ // any picture: the surface still carries the contrast, never the image.
88
+ className: "pointer-events-auto flex w-full flex-col overflow-hidden rounded-md bg-base-100/50 text-base-content shadow backdrop-blur-sm", "data-testid": `room-bar-${room.id}`, children: [_jsxs("div", { className: "flex min-w-0 items-center gap-1.5 px-1.5 py-1", children: [_jsx("span", { className: ['shrink-0 text-base-content/70', compact ? 'hidden' : ''].join(' '), children: _jsx(Icon, { name: typeIcon, size: "xs", title: room.type === 'break'
89
+ ? 'Break room — where you go when you are stepping away'
90
+ : room.type === 'reception'
91
+ ? 'Reception — where you arrive'
92
+ : undefined }) }), _jsx("span", { className: ['flex-1 truncate text-xs font-medium', tiny ? 'min-w-0' : 'min-w-[2ch]'].join(' '), title: room.name, children: room.name }), call && !tiny && (_jsxs("span", { role: "img", "aria-label": `Call with ${call.participants.length} ${call.participants.length === 1 ? 'person' : 'people'}${callFull ? ', full' : ''}`, "data-testid": `room-call-${room.id}`, className: [
93
+ 'inline-flex shrink-0 items-center gap-0.5 rounded px-1 py-px text-[10px] font-medium tabular-nums',
94
+ callFull ? 'bg-base-200 text-base-content/70' : 'bg-primary/15 text-primary',
95
+ ].join(' '), children: [_jsx(Icon, { name: "mic", size: "xs" }), !compact && (_jsxs("span", { "aria-hidden": "true", children: [call.participants.length, "/", call.limit] }))] })), locked && !compact && (_jsx("span", { className: "shrink-0 text-base-content/70", children: _jsx(Icon, { name: "lock", size: "xs", title: `${room.name} is locked` }) })), !compact && (_jsx("span", { className: "shrink-0 text-[10px] tabular-nums text-base-content/60", children: capacity === null ? occupancy : `${occupancy}/${capacity}` })), actions.map((action) => {
96
+ const shared = {
97
+ size: 'xs',
98
+ variant: action.variant,
99
+ // Tighter on a narrow bar, where a worded button has nothing to shrink
100
+ // to: the utility beats the kit's own padding, which lives in the
101
+ // component layer below it.
102
+ className: compact && !action.icon ? 'shrink-0 px-1' : 'shrink-0',
103
+ onClick: action.onClick,
104
+ disabled: action.disabled,
105
+ ...(action.disabled && action.reason ? { 'aria-describedby': `${room.id}-why` } : {}),
106
+ };
107
+ /*
108
+ Lock and Unlock are a padlock at every width, with the word as their
109
+ accessible name. Join and Knock are words at every width, with less
110
+ padding around them on a narrow bar. What gives way instead is
111
+ everything else: the head count, the room-type icon and the lock icon on
112
+ a narrow bar, the call badge's count and then the badge itself on the
113
+ tiniest — and the name truncates to its first letters, or on the very
114
+ tiniest to nothing, because the room's action is never the thing that
115
+ goes.
116
+ */
117
+ return action.icon ? (_jsx(Button, { ...shared, icon: action.icon, "aria-label": action.label }, action.key)) : (_jsx(Button, { ...shared, children: action.label }, action.key));
118
+ })] }), message && (_jsx("p", { id: `${room.id}-why`, className: "border-t border-base-300 bg-base-200/70 px-1.5 py-0.5 text-[10px] leading-snug text-base-content/75", children: message }))] }));
119
+ }
120
+ //# sourceMappingURL=RoomBar.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"RoomBar.js","sourceRoot":"","sources":["../src/RoomBar.tsx"],"names":[],"mappings":"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"}
@@ -0,0 +1,74 @@
1
+ import type { ScreenSource } from '@unityevolv/ofiskit-realtime-client';
2
+ /**
3
+ * Showing a screen to the people in the call.
4
+ *
5
+ * Four pieces, separate because they appear in different places: the share itself
6
+ * fills the call view, the indicator follows the sharer everywhere including back
7
+ * onto the map, and the two questions are asked once and then gone.
8
+ *
9
+ * Provider-independent, like the tiles: a share here is a stream and a name, and
10
+ * nothing in this file knows whether a mesh or somebody's SFU delivered it.
11
+ */
12
+ export interface ShareStageProps {
13
+ /** Whose screen it is. Used in the caption and in the accessible name. */
14
+ sharerName: string;
15
+ /** True when it is your own screen, which is drawn completely differently. */
16
+ mine: boolean;
17
+ /** The share, once it arrives. Absent is a loading state and not an error. */
18
+ stream?: MediaStream | null;
19
+ /** The chosen speaker, so a shared tab's sound goes where the voices go. */
20
+ speakerDeviceId?: string;
21
+ /** Offered only on your own share, and never more than one click away. */
22
+ onStop?(): void;
23
+ }
24
+ export declare function ShareStage({ sharerName, mine, stream, speakerDeviceId, onStop }: ShareStageProps): import("react").JSX.Element;
25
+ /**
26
+ * The sharer's own reminder that they are still sharing.
27
+ *
28
+ * Persistent, not dismissible, and present in every view including the map, because
29
+ * forgetting to stop is the commonest failure in any call product and the
30
+ * consequence of it is somebody's inbox on a projector. The stop control is here as
31
+ * well as in the bar so that it is one click from wherever the person has wandered.
32
+ */
33
+ export declare function SharingBanner({ onStop }: {
34
+ onStop(): void;
35
+ }): import("react").JSX.Element;
36
+ /**
37
+ * Taking over somebody else's share.
38
+ *
39
+ * Asked rather than refused, because the person who wants to show something next is
40
+ * usually right that they do — and asked rather than done quietly, because a share
41
+ * that disappears mid-sentence looks like a crash to whoever was presenting.
42
+ */
43
+ export declare function TakeOverDialog({ sharerName, onConfirm, onCancel, }: {
44
+ sharerName: string;
45
+ onConfirm(): void;
46
+ onCancel(): void;
47
+ }): import("react").JSX.Element;
48
+ export interface ScreenSourcePickerProps {
49
+ /** The host's list, exactly as it gave it. Filtered here, not by the caller. */
50
+ sources: readonly ScreenSource[];
51
+ onPick(sourceId: string): void;
52
+ onCancel(): void;
53
+ }
54
+ /**
55
+ * The picker for a platform whose browser has none.
56
+ *
57
+ * On the web this never appears: `getDisplayMedia` opens the browser's own picker,
58
+ * which people already know and which is the only one that can offer a single tab.
59
+ * A desktop app has no such dialog — the platform hands over a list of screens and
60
+ * windows and expects the app to draw it — so this is that list.
61
+ *
62
+ * Our own window is never in it. Sharing the app that is doing the sharing produces
63
+ * an infinite mirror, and it is dropped by `usableSources` rather than here, so the
64
+ * rule belongs to the list rather than to this one drawing of it.
65
+ */
66
+ export declare function ScreenSourcePicker({ sources, onPick, onCancel }: ScreenSourcePickerProps): import("react").JSX.Element;
67
+ /**
68
+ * What a live region says about a share.
69
+ *
70
+ * Politely, and named. A share is a change to what is on everybody's screen, and
71
+ * somebody who cannot see it change is precisely the person who needs telling.
72
+ */
73
+ export declare function describeShare(sharerName: string, sharing: boolean): string;
74
+ //# sourceMappingURL=Share.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Share.d.ts","sourceRoot":"","sources":["../src/Share.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,qCAAqC,CAAA;AAIvE;;;;;;;;;GASG;AAEH,MAAM,WAAW,eAAe;IAC9B,0EAA0E;IAC1E,UAAU,EAAE,MAAM,CAAA;IAClB,8EAA8E;IAC9E,IAAI,EAAE,OAAO,CAAA;IACb,8EAA8E;IAC9E,MAAM,CAAC,EAAE,WAAW,GAAG,IAAI,CAAA;IAC3B,4EAA4E;IAC5E,eAAe,CAAC,EAAE,MAAM,CAAA;IACxB,0EAA0E;IAC1E,MAAM,CAAC,IAAI,IAAI,CAAA;CAChB;AAED,wBAAgB,UAAU,CAAC,EAAE,UAAU,EAAE,IAAI,EAAE,MAAM,EAAE,eAAe,EAAE,MAAM,EAAE,EAAE,eAAe,+BA2FhG;AAED;;;;;;;GAOG;AACH,wBAAgB,aAAa,CAAC,EAAE,MAAM,EAAE,EAAE;IAAE,MAAM,IAAI,IAAI,CAAA;CAAE,+BAoB3D;AAED;;;;;;GAMG;AACH,wBAAgB,cAAc,CAAC,EAC7B,UAAU,EACV,SAAS,EACT,QAAQ,GACT,EAAE;IACD,UAAU,EAAE,MAAM,CAAA;IAClB,SAAS,IAAI,IAAI,CAAA;IACjB,QAAQ,IAAI,IAAI,CAAA;CACjB,+BA2BA;AAED,MAAM,WAAW,uBAAuB;IACtC,gFAAgF;IAChF,OAAO,EAAE,SAAS,YAAY,EAAE,CAAA;IAChC,MAAM,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAA;IAC9B,QAAQ,IAAI,IAAI,CAAA;CACjB;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,kBAAkB,CAAC,EAAE,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,EAAE,uBAAuB,+BA0DxF;AAED;;;;;GAKG;AACH,wBAAgB,aAAa,CAAC,UAAU,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,GAAG,MAAM,CAI1E"}