From 2cdec071cccbf4d47a4e15a633e096a519acdff5 Mon Sep 17 00:00:00 2001 From: Greg Holmes Date: Wed, 19 Jun 2024 12:23:04 +0100 Subject: [PATCH 01/19] Introduced vite-react-avatar-stack --- .../.codesandbox/Dockerfile | 1 + examples/vite-react-avatar-stack/.env.example | 2 + examples/vite-react-avatar-stack/.gitignore | 26 + examples/vite-react-avatar-stack/README.md | 39 + examples/vite-react-avatar-stack/favicon.ico | Bin 0 -> 3262 bytes .../images/avatar-stack.png | Bin 0 -> 29528 bytes examples/vite-react-avatar-stack/index.html | 24 + examples/vite-react-avatar-stack/package.json | 29 + examples/vite-react-avatar-stack/src/App.tsx | 16 + .../src/components/AvatarStack.module.css | 9 + .../src/components/AvatarStack.tsx | 51 + .../src/components/Avatars.module.css | 187 ++++ .../src/components/Avatars.tsx | 217 ++++ examples/vite-react-avatar-stack/src/env.d.ts | 5 + .../src/hooks/useClickOutsideList.ts | 34 + .../vite-react-avatar-stack/src/index.tsx | 25 + .../src/styles/global.css | 234 ++++ .../src/utils/helpers.ts | 45 + .../tailwind.config.js | 132 +++ .../vite-react-avatar-stack/tsconfig.json | 26 + .../tsconfig.node.json | 8 + .../vite-react-avatar-stack/vite.config.ts | 7 + examples/vite-react-avatar-stack/yarn.lock | 996 ++++++++++++++++++ src/main.tsx | 4 + src/routes/Home.tsx | 6 + src/routes/JavascriptTemplate.tsx | 28 + src/routes/VanillaAvatarStack.tsx | 11 + src/routes/ViteReactAvatarStack.tsx | 28 + 28 files changed, 2190 insertions(+) create mode 100644 examples/vite-react-avatar-stack/.codesandbox/Dockerfile create mode 100644 examples/vite-react-avatar-stack/.env.example create mode 100644 examples/vite-react-avatar-stack/.gitignore create mode 100644 examples/vite-react-avatar-stack/README.md create mode 100644 examples/vite-react-avatar-stack/favicon.ico create mode 100644 examples/vite-react-avatar-stack/images/avatar-stack.png create mode 100644 examples/vite-react-avatar-stack/index.html create mode 100644 examples/vite-react-avatar-stack/package.json create mode 100644 examples/vite-react-avatar-stack/src/App.tsx create mode 100644 examples/vite-react-avatar-stack/src/components/AvatarStack.module.css create mode 100644 examples/vite-react-avatar-stack/src/components/AvatarStack.tsx create mode 100644 examples/vite-react-avatar-stack/src/components/Avatars.module.css create mode 100644 examples/vite-react-avatar-stack/src/components/Avatars.tsx create mode 100644 examples/vite-react-avatar-stack/src/env.d.ts create mode 100644 examples/vite-react-avatar-stack/src/hooks/useClickOutsideList.ts create mode 100644 examples/vite-react-avatar-stack/src/index.tsx create mode 100644 examples/vite-react-avatar-stack/src/styles/global.css create mode 100644 examples/vite-react-avatar-stack/src/utils/helpers.ts create mode 100644 examples/vite-react-avatar-stack/tailwind.config.js create mode 100644 examples/vite-react-avatar-stack/tsconfig.json create mode 100644 examples/vite-react-avatar-stack/tsconfig.node.json create mode 100644 examples/vite-react-avatar-stack/vite.config.ts create mode 100644 examples/vite-react-avatar-stack/yarn.lock create mode 100644 src/routes/JavascriptTemplate.tsx create mode 100644 src/routes/VanillaAvatarStack.tsx create mode 100644 src/routes/ViteReactAvatarStack.tsx diff --git a/examples/vite-react-avatar-stack/.codesandbox/Dockerfile b/examples/vite-react-avatar-stack/.codesandbox/Dockerfile new file mode 100644 index 0000000..3739923 --- /dev/null +++ b/examples/vite-react-avatar-stack/.codesandbox/Dockerfile @@ -0,0 +1 @@ +FROM node:18-bullseye \ No newline at end of file diff --git a/examples/vite-react-avatar-stack/.env.example b/examples/vite-react-avatar-stack/.env.example new file mode 100644 index 0000000..dbcc501 --- /dev/null +++ b/examples/vite-react-avatar-stack/.env.example @@ -0,0 +1,2 @@ +# Use your own API KEY from Ably here: +VITE_ABLY_KEY= diff --git a/examples/vite-react-avatar-stack/.gitignore b/examples/vite-react-avatar-stack/.gitignore new file mode 100644 index 0000000..26a3ac4 --- /dev/null +++ b/examples/vite-react-avatar-stack/.gitignore @@ -0,0 +1,26 @@ +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +pnpm-debug.log* +lerna-debug.log* + +.env + +node_modules +dist +dist-ssr +*.local + +# Editor directories and files +.vscode/* +!.vscode/extensions.json +.idea +.DS_Store +*.suo +*.ntvs* +*.njsproj +*.sln +*.sw? diff --git a/examples/vite-react-avatar-stack/README.md b/examples/vite-react-avatar-stack/README.md new file mode 100644 index 0000000..76a4c5a --- /dev/null +++ b/examples/vite-react-avatar-stack/README.md @@ -0,0 +1,39 @@ +## Overview + +![Avatar stack Start screen](./images/avatar-stack.png) + +This folder contains the code for the Avatar stack - a demo of how you can leverage [Ably Spaces](https://github.com/ably/spaces) to show a list of currently online users. + +Try out the [live demo](https://examples.ably.dev/avatar-stack) of the Avatar stack. + +## Running locally + +- Fork or clone the [example](https://github.com/ably-labs/realtime-examples/examples/vite-react-avatar-stack). +- Sign up for an account on [Ably](https://ably.com/sign-up?utm_source=ably-labs&utm_medium=github&utm_campaign=avatar-stack) and get an API KEY. +- Rename `.env.example` to `.env` and fill in your API KEY in the `VITE_ABLY_KEY` environment variable. +- Run `yarn` to install dependencies. +- Run `yarn dev` and go to http://localhost:5173 + +## Runtime Requirements + +- [Node.js](https://nodejs.org/en/) +- Ably API Key +- [Yarn](https://yarnpkg.com/) + +## Resources + +- Learn more about how to build your own [Avatar stack](https://ably.com/examples/avatar-stack?utm_source=ably-labs&utm_medium=github&utm_campaign=avatar-stack). +- To see what else is possible with Ably check out our other [realtime examples](https://ably.com/examples?utm_source=ably-labs&utm_medium=github&utm_campaign=avatar-stack). + +## Support, feedback and troubleshooting + +- [Create a GitHub Issue](https://github.com/ably-labs/realtime-examples/issues) +- [Ably Spaces On GitHub](https://github.com/ably/spaces) +- [Join our Discord server](https://discord.gg/q89gDHZcBK) +- [Follow us on Twitter](https://twitter.com/ablyrealtime) +- [Use our SDKs](https://github.com/ably/) +- [Visit our website](https://ably.com?utm_source=ably-labs&utm_medium=github&utm_campaign=avatar-stack) + +--- + +[![Ably logo](https://static.ably.dev/badge-black.svg?serverless-websockets-quest)](https://ably.com?utm_source=ably-labs&utm_medium=github&utm_campaign=avatar-stack) diff --git a/examples/vite-react-avatar-stack/favicon.ico b/examples/vite-react-avatar-stack/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..483a4b24839316fea296e21ba293daf7476412d1 GIT binary patch literal 3262 zcmeH{*-{fh6o!W+lgvJonL)uV5e34&3b>BDqJrSlcmisd zr#liz#(O;8vIrGD`#wpw~;FN;5L#iB%5dCQ$Vza@D74i1S{~D;Vt}hOG>7K^Cf+Y zbOZ4#MC(7zC)^`*MaaP|1z&_W2X_WmqkC7fEuOT=n@Havd5w4-)#r$wbth}zq6PTG zDzZ=V0$c@mr(jRO96hy*hNN3aH<7$Syn*Bu;+Ke@qxuxlV?+-nP96uX2$mImNyy$j z+<7=ta3|qRz;5*Ll_AvJCci-S*$MaqME4QgkrLiA!bNezCz-P6#S@?K2^9@EW3X?Y z62o0X6i@g%Vnr6sPn7IT$l*OX#E?zG6I5g|M3LQDc(ZV+d0fRPoSO)4bn{svAz2wx zCHxU0YNjoB75TPwh*(YK%4#`BVrO8_A*#b6d{ksxBXCD@;N(Xyl_4Y(s|=Az-F~X~ z#1L(@CeOm25)`o#Be1TksOR&AMskLbhTKJP8_sGwGrWc1*pL~pL)>Xt^RjByMYE9W zs9claWS=KeRtIZhh_}>94(T>!Ps5pnHQAXLz9wHqQkFiJx(qE6{PyFy;fxgT!u zGLGl(Drn8aC=bEB0CO-uEw_-zL!4HZu>pHb9PUjshhdU@QOKnQ4CP@Q3yJ9dkOt#D4w#953v{vO0b&j zqTou2{*eBw(s&GIbuq#K4e?N5I2f=oVEqMYK5>YiL%>%;rscw|Ihqe4j|__+C|pNj%wd(t?|Q3^Tpx*r-SC_ x{k`Vb%3kYzSZnQMwWDk&Lw1y**4o9Mj3#h!sK=KtfQ-WfJ(_z!>qAZ@;5!R|Ate9+ literal 0 HcmV?d00001 diff --git a/examples/vite-react-avatar-stack/images/avatar-stack.png b/examples/vite-react-avatar-stack/images/avatar-stack.png new file mode 100644 index 0000000000000000000000000000000000000000..59e203833dad0ef3c089f7e20274ce9bd2b788cc GIT binary patch literal 29528 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 KOOKqr{yzW{ffpqJ literal 0 HcmV?d00001 diff --git a/examples/vite-react-avatar-stack/index.html b/examples/vite-react-avatar-stack/index.html new file mode 100644 index 0000000..55a9f12 --- /dev/null +++ b/examples/vite-react-avatar-stack/index.html @@ -0,0 +1,24 @@ + + + + + + + + + + + Ably Realtime Examples - Avatar stack + + + +
+ + + diff --git a/examples/vite-react-avatar-stack/package.json b/examples/vite-react-avatar-stack/package.json new file mode 100644 index 0000000..3c81c26 --- /dev/null +++ b/examples/vite-react-avatar-stack/package.json @@ -0,0 +1,29 @@ +{ + "name": "@ably-labs/vite-react-avatar-stack", + "license": "Apache-2.0", + "version": "1.0.0", + "private": true, + "scripts": { + "dev": "vite", + "build": "tsc && vite build", + "preview": "vite preview", + "format": "prettier --write ." + }, + "dependencies": { + "@ably/spaces": "0.2.0", + "ably": "1.2.45", + "classnames": "^2.3.2", + "dayjs": "^1.11.4", + "nanoid": "^5.0.1", + "random-words": "^2.0.0", + "react": "^18.2.0", + "react-dom": "^18.2.0" + }, + "devDependencies": { + "@types/react": "^18.2.0", + "@types/react-dom": "^18.2.0", + "@vitejs/plugin-react": "^4.1.0", + "typescript": "5.2.2", + "vite": "^4.4.9" + } +} diff --git a/examples/vite-react-avatar-stack/src/App.tsx b/examples/vite-react-avatar-stack/src/App.tsx new file mode 100644 index 0000000..808d4e4 --- /dev/null +++ b/examples/vite-react-avatar-stack/src/App.tsx @@ -0,0 +1,16 @@ +import Spaces from "@ably/spaces"; +import { SpaceProvider, SpacesProvider } from "@ably/spaces/react"; +import AvatarStack from "./components/AvatarStack"; +import { getSpaceNameFromUrl } from "./utils/helpers"; + +const spaceName = getSpaceNameFromUrl(); + +const App = ({ spaces }: { spaces: Spaces }) => ( + + + + + +); + +export default App; diff --git a/examples/vite-react-avatar-stack/src/components/AvatarStack.module.css b/examples/vite-react-avatar-stack/src/components/AvatarStack.module.css new file mode 100644 index 0000000..33dbfa7 --- /dev/null +++ b/examples/vite-react-avatar-stack/src/components/AvatarStack.module.css @@ -0,0 +1,9 @@ +.container { + width: 100%; + display: flex; + justify-content: center; + align-items: center; + position: relative; + background-color: #f4f8fb; + height: 100vh; + } diff --git a/examples/vite-react-avatar-stack/src/components/AvatarStack.tsx b/examples/vite-react-avatar-stack/src/components/AvatarStack.tsx new file mode 100644 index 0000000..076443c --- /dev/null +++ b/examples/vite-react-avatar-stack/src/components/AvatarStack.tsx @@ -0,0 +1,51 @@ +import { useMemo, useEffect } from "react"; +import { type SpaceMember } from "@ably/spaces"; +import { useSpace, useMembers } from "@ably/spaces/react"; + +import Avatars from "./Avatars"; +import styles from "./AvatarStack.module.css"; + +const colors = [ + "#9951F5", + "#7A1BF2", + "#5F0BC9", +]; + +export const mockNames = [ + "Anum Reeve", + "Tiernan Stubbs", + "Hakim Hernandez", +]; + +type Member = Omit & { + profileData: { memberColor: string; name: string }; +}; + +const AvatarStack = () => { + const name = useMemo(() => { + return mockNames[Math.floor(Math.random() * mockNames.length)]; + }, []); + const memberColor = useMemo(() => { + return colors[Math.floor(Math.random() * colors.length)]; + }, []); + + /** 💡 Get a handle on a space instance 💡 */ + const { space } = useSpace(); + + /** 💡 Enter the space as soon as it's available 💡 */ + useEffect(() => { + space?.enter({ name, memberColor }); + }, [space]); + + /** 💡 Get everybody except the local member in the space and the local member 💡 */ + const { others, self } = useMembers(); + + return ( +
+ {/** 💡 Stack of first 5 user avatars including yourself.💡 */} + +
+ ); +}; + +export default AvatarStack; diff --git a/examples/vite-react-avatar-stack/src/components/Avatars.module.css b/examples/vite-react-avatar-stack/src/components/Avatars.module.css new file mode 100644 index 0000000..3176879 --- /dev/null +++ b/examples/vite-react-avatar-stack/src/components/Avatars.module.css @@ -0,0 +1,187 @@ +/** AVATARS **/ + +.container { + position: relative; + display: flex; +} + +.avatarContainer { + position: absolute; + right: 0; + display: flex; + flex-direction: column; + align-items: center; +} + +.avatar { + background-color: rgb(234 88 12); + height: 3rem; + width: 3rem; + border-radius: 9999px; + display: flex; + align-items: center; + justify-content: center; + position: relative; + border: 2px solid #e2e7ef; +} + +.name { + font-size: 0.75rem; + line-height: 1rem; + color: rgb(255 255 255); +} + +.statusIndicator, +.statusIndicatorOnline { + width: 10px; + height: 10px; + border-radius: 9999px; + border: 1.5px solid #e2e7ef; + position: absolute; + bottom: 0.3rem; + left: -0.2rem; + transform: translateY(50%) translateX(50%); +} + +.popup { + position: absolute; + top: 4rem; + padding: 1rem; + background-color: #000; + border-radius: 8px; + color: #fff; + min-width: 240px; +} + +.nameOthers { + z-index: 20; + font-size: 0.75rem; +} + +.statusIndicatorOnline { + background-color: #10b981; +} + +.textWhite { + color: #fff; +} + +.inactiveColor { + color: rgb(156 163 175); +} + +.inactiveBackground { + background-color: rgb(156 163 175); +} + +/** END AVATARS **/ + +/** SURPLUS **/ + +.surplusContainer { + right: 0; + display: flex; + flex-direction: column; + align-items: center; + position: absolute; +} + +.badge { + display: flex; + justify-content: center; + align-items: center; + position: absolute; + right: 0; + color: #fff; + font-size: 0.875rem; + background-color: #718096; + border: 2px solid #cbd5e0; + height: 3rem; + width: 3rem; + border-radius: 9999px; + margin-bottom: 0.5rem; + user-select: none; +} + +.list { + max-height: 70px; + overflow-y: auto; + padding: 0.5rem; + position: relative; + top: 3.5rem; + left: 1.5rem; + min-width: 280px; + max-height: 250px; + left: 6rem; + background-color: #39414e; + border-radius: 8px; + color: #fff; +} + +.user { + padding: 0.5rem; +} + +.user:hover { + background-color: #4a5568; + border-radius: 8px; +} + +@media screen and (min-width: 768px) { + .user { + padding: 0.75rem; + } +} + +/** END SURPLUS **/ + +/** USER INFO **/ + +.userInfoContainer { + height: 2rem; + width: 2rem; + border-radius: 9999px; + display: flex; + flex-shrink: 0; + align-items: center; + justify-content: center; + position: relative; + border: 2px solid #cbd5e0; +} + +.statusIndicator { + width: 10px; + height: 10px; + border-radius: 9999px; +} + +.wrapper { + display: flex; + justify-content: flex-start; + align-items: center; +} + +.userList { + padding-left: 0.75rem; + width: 100%; +} + +.name { + display: block; + font-weight: 600; + font-size: 0.875rem; + margin: 0 0 2px 0; +} + +.statusIndicatorText { + font-weight: 500; + font-size: 0.75rem; + margin: 0 0 0 0.3rem; + color: #89929f; +} + +.smallText { + font-size: 0.75rem; +} + +/** END USER INFO **/ diff --git a/examples/vite-react-avatar-stack/src/components/Avatars.tsx b/examples/vite-react-avatar-stack/src/components/Avatars.tsx new file mode 100644 index 0000000..e344585 --- /dev/null +++ b/examples/vite-react-avatar-stack/src/components/Avatars.tsx @@ -0,0 +1,217 @@ +import { useState } from "react"; +import classNames from "classnames"; +import { FunctionComponent } from "react"; +import dayjs from "dayjs"; +import relativeTime from "dayjs/plugin/relativeTime"; +import useClickOutsideList from "../hooks/useClickOutsideList"; + +import { + MAX_USERS_BEFORE_LIST, + calculateRightOffset, + calculateTotalWidth, +} from "../utils/helpers"; + +import type { Member } from "../utils/helpers"; + +import styles from "./Avatars.module.css"; + +dayjs.extend(relativeTime); + +const OtherAvatars = ({ + users, + usersCount, +}: { + users: Member[]; + usersCount: number; +}) => { + const [hoveredClientId, setHoveredClientId] = useState(null); + + return ( + <> + {users.map((user, index) => { + const rightOffset = calculateRightOffset({ usersCount, index }); + const userInitials = user.profileData.name + .split(" ") + .map((word: string) => word.charAt(0)) + .join(""); + + const initialsCSS = classNames( + { + [styles.textWhite]: user.isConnected, + [styles.inactiveColor]: !user.isConnected, + }, + styles.nameOthers, + ); + + const statusIndicatorCSS = classNames( + { + [styles.statusIndicatorOnline]: user.isConnected, + [styles.inactiveBackground]: !user.isConnected, + }, + styles.statusIndicator, + ); + + return ( +
+
setHoveredClientId(user.clientId)} + onMouseLeave={() => setHoveredClientId(null)} + id="avatar" + > +

{userInitials}

+
+
+ + {hoveredClientId === user.clientId ? ( +
+ +
+ ) : null} +
+ ); + })} + + ); +}; + +const UserInfo: FunctionComponent<{ user: Member; isSelf?: boolean }> = ({ + user, + isSelf, +}) => { + const initials = user.profileData.name + .split(" ") + .map((word: string) => word.charAt(0)) + .join(""); + + const statusIndicatorText = user.isConnected + ? "Online" + : "Last seen " + dayjs().to(user.lastEvent.timestamp); + + const name = isSelf + ? `${user.profileData.name} (You)` + : user.profileData.name; + + return ( +
+
+

+ {initials} +

+
+ + {/* 💡 Display the name of the user from the `profileData` object 💡 */} +
+

{name}

+
+
+

{statusIndicatorText}

+
+
+
+ ); +}; + +const Surplus: FunctionComponent<{ otherUsers: Member[] }> = ({ + otherUsers, +}) => { + const [showList, setShowList] = useState(false); + const { listRef, plusButtonRef } = useClickOutsideList(() => + setShowList(false), + ); + + return otherUsers.length > MAX_USERS_BEFORE_LIST ? ( +
+
{ + setShowList(!showList); + }} + > + +{otherUsers.slice(MAX_USERS_BEFORE_LIST).length} +
+ + {showList ? ( +
+ {otherUsers.slice(MAX_USERS_BEFORE_LIST).map((user) => ( +
+ +
+ ))} +
+ ) : null} +
+ ) : null; +}; + +const Avatars = ({ + otherUsers, + self, +}: { + otherUsers: Member[]; + self: Member | null; +}) => { + const [hover, setHover] = useState(false); + const totalWidth = calculateTotalWidth({ users: otherUsers }); + + return ( +
+
setHover(true)} + onMouseLeave={() => setHover(false)} + > +

You

+
+ + {hover && self ? ( +
+ +
+ ) : null} +
+ + {/** 💡 Dropdown list of surplus users 💡 */} + +
+ ); +}; + +export default Avatars; diff --git a/examples/vite-react-avatar-stack/src/env.d.ts b/examples/vite-react-avatar-stack/src/env.d.ts new file mode 100644 index 0000000..e8cfc0d --- /dev/null +++ b/examples/vite-react-avatar-stack/src/env.d.ts @@ -0,0 +1,5 @@ +/// + +interface ImportMetaEnv { + readonly VITE_ABLY_KEY: string; +} diff --git a/examples/vite-react-avatar-stack/src/hooks/useClickOutsideList.ts b/examples/vite-react-avatar-stack/src/hooks/useClickOutsideList.ts new file mode 100644 index 0000000..c30ad84 --- /dev/null +++ b/examples/vite-react-avatar-stack/src/hooks/useClickOutsideList.ts @@ -0,0 +1,34 @@ +import { useEffect, useRef } from "react"; + +const useClickOutsideList = (callback: () => void) => { + const listRef = useRef(null); + const plusButtonRef = useRef(null); + + // 💡 Handler to click outside user list + useEffect(() => { + const listener = (event: MouseEvent | TouchEvent) => { + if ( + !listRef.current || + listRef.current.contains(event.target as Node) || + !plusButtonRef.current || + plusButtonRef.current.contains(event.target as Node) + ) { + return; + } + + callback(); + }; + + document.addEventListener("mousedown", listener); + document.addEventListener("touchstart", listener); + + return () => { + document.removeEventListener("mousedown", listener); + document.removeEventListener("touchstart", listener); + }; + }, [listRef, plusButtonRef]); + + return { listRef, plusButtonRef }; +}; + +export default useClickOutsideList; diff --git a/examples/vite-react-avatar-stack/src/index.tsx b/examples/vite-react-avatar-stack/src/index.tsx new file mode 100644 index 0000000..b67c491 --- /dev/null +++ b/examples/vite-react-avatar-stack/src/index.tsx @@ -0,0 +1,25 @@ +import ReactDOM from "react-dom/client"; +import { AblyProvider } from "ably/react"; +import Spaces from "@ably/spaces"; +import { nanoid } from "nanoid"; +import { Realtime } from "ably"; + +import App from "./App"; + +import "./styles/global.css"; + +const client = new Realtime.Promise({ + clientId: nanoid(), + key: import.meta.env.VITE_ABLY_KEY, +}); + +const spaces = new Spaces(client); + +ReactDOM.createRoot(document.getElementById("root")!).render( + // Mismatch between react-router-dom and latest react + // See https://github.com/remix-run/remix/issues/7514 + // @ts-ignore + + + , +); diff --git a/examples/vite-react-avatar-stack/src/styles/global.css b/examples/vite-react-avatar-stack/src/styles/global.css new file mode 100644 index 0000000..68e0614 --- /dev/null +++ b/examples/vite-react-avatar-stack/src/styles/global.css @@ -0,0 +1,234 @@ +html { + line-height: 1.5; + -webkit-text-size-adjust: 100%; + -moz-tab-size: 4; + -o-tab-size: 4; + tab-size: 4; + font-family: Inter, ui-sans-serif, system-ui; +} + +body { + margin: 0; + line-height: inherit; +} + +hr { + height: 0; + color: inherit; + border-top-width: 1px; +} + +abbr:where([title]) { + -webkit-text-decoration: underline dotted; + text-decoration: underline dotted; +} + +h1, +h2, +h3, +h4, +h5, +h6 { + font-size: inherit; + font-weight: inherit; +} + +a { + color: inherit; + text-decoration: inherit; +} + +b, +strong { + font-weight: bolder; +} + +code, +kbd, +samp, +pre { + font-family: + ui-monospace, + SFMono-Regular, + Menlo, + Monaco, + Consolas, + Liberation Mono, + Courier New, + monospace; + font-size: 1em; +} + +small { + font-size: 80%; +} + +sub, +sup { + font-size: 75%; + line-height: 0; + position: relative; + vertical-align: baseline; +} + +sub { + bottom: -0.25em; +} + +sup { + top: -0.5em; +} + +table { + text-indent: 0; + border-color: inherit; + border-collapse: collapse; +} + +button, +input, +optgroup, +select, +textarea { + font-family: inherit; + font-size: 100%; + font-weight: inherit; + line-height: inherit; + color: inherit; + margin: 0; + padding: 0; +} + +button, +select { + text-transform: none; +} + +button, +[type="button"], +[type="reset"], +[type="submit"] { + -webkit-appearance: button; + background-color: transparent; + background-image: none; +} + +:-moz-focusring { + outline: auto; +} + +:-moz-ui-invalid { + box-shadow: none; +} + +progress { + vertical-align: baseline; +} + +::-webkit-inner-spin-button, +::-webkit-outer-spin-button { + height: auto; +} + +[type="search"] { + -webkit-appearance: textfield; + outline-offset: -2px; +} + +::-webkit-search-decoration { + -webkit-appearance: none; +} + +::-webkit-file-upload-button { + -webkit-appearance: button; + font: inherit; +} + +summary { + display: list-item; +} + +blockquote, +dl, +dd, +h1, +h2, +h3, +h4, +h5, +h6, +hr, +figure, +p, +pre { + margin: 0; +} + +fieldset { + margin: 0; + padding: 0; +} + +legend { + padding: 0; +} + +ol, +ul, +menu { + list-style: none; + margin: 0; + padding: 0; +} + +textarea { + resize: vertical; +} + +input::-moz-placeholder, +textarea::-moz-placeholder { + opacity: 1; + color: #9ca3af; +} + +input::placeholder, +textarea::placeholder { + opacity: 1; + color: #9ca3af; +} + +button, +[role="button"] { + cursor: pointer; +} + +:disabled { + cursor: default; +} + +img, +svg, +video, +canvas, +audio, +iframe, +embed, +object { + display: block; + vertical-align: middle; +} + +img, +video { + max-width: 100%; + height: auto; +} + +*, +:before, +:after { + box-sizing: border-box; + border-width: 0; + border-style: solid; + border-color: currentColor; +} diff --git a/examples/vite-react-avatar-stack/src/utils/helpers.ts b/examples/vite-react-avatar-stack/src/utils/helpers.ts new file mode 100644 index 0000000..e9b87d6 --- /dev/null +++ b/examples/vite-react-avatar-stack/src/utils/helpers.ts @@ -0,0 +1,45 @@ +import { type SpaceMember } from "@ably/spaces"; +import { generate } from "random-words"; + +export const REMOVE_USER_AFTER_MILLIS = 120_000; +export const MAX_USERS_BEFORE_LIST = 4; +export const HORIZONTAL_SPACING_OFFSET = 40; +export const OVERLAP_AMOUNT = 40; +export const AVATAR_WIDTH = 48; + +export type Member = Omit & { + profileData: { memberColor: string; name: string }; +}; + +export const getSpaceNameFromUrl = () => { + const url = new URL(window.location.href); + const spaceNameInParams = url.searchParams.get("space"); + + if (spaceNameInParams) { + return spaceNameInParams; + } else { + const generatedName = generate({ exactly: 3, join: "-" }); + url.searchParams.set("space", generatedName); + window.history.replaceState({}, "", `?${url.searchParams.toString()}`); + return generatedName; + } +}; + +export function calculateRightOffset({ + usersCount, + index = 0, +}: { + usersCount: number; + index: number; +}): number { + return usersCount > MAX_USERS_BEFORE_LIST + ? (index + 1) * HORIZONTAL_SPACING_OFFSET + : index * HORIZONTAL_SPACING_OFFSET; +} + +export function calculateTotalWidth({ users }: { users: Member[] }): number { + return ( + AVATAR_WIDTH + + OVERLAP_AMOUNT * Math.min(users.length, MAX_USERS_BEFORE_LIST + 1) + ); +} diff --git a/examples/vite-react-avatar-stack/tailwind.config.js b/examples/vite-react-avatar-stack/tailwind.config.js new file mode 100644 index 0000000..27fa99a --- /dev/null +++ b/examples/vite-react-avatar-stack/tailwind.config.js @@ -0,0 +1,132 @@ +/** @type {import('tailwindcss').Config} */ + +module.exports = { + content: ["./index.html", "./src/**/*.{js,ts,jsx,tsx}"], + + safelist: [ + "border-[#9951F5]", + "border-[#7A1BF2]", + "border-[#5F0BC9]", + "border-[#460894]", + "border-[#00E80B]", + "border-[#00C008]", + "border-[#008E06]", + "border-[#FF17D2]", + "border-[#D400AB]", + "border-[#9C007E]", + "border-[#2CC0FF]", + "border-[#00A5EC]", + "border-[#0284CD]", + "border-[#E4B200]", + "border-[#AC8600]", + "bg-[#9951F5]", + "bg-[#7A1BF2]", + "bg-[#5F0BC9]", + "bg-[#460894]", + "bg-[#00E80B]", + "bg-[#00C008]", + "bg-[#008E06]", + "bg-[#FF17D2]", + "bg-[#D400AB]", + "bg-[#9C007E]", + "bg-[#2CC0FF]", + "bg-[#00A5EC]", + "bg-[#0284CD]", + "bg-[#E4B200]", + "bg-[#AC8600]", + ], + + theme: { + colors: { + white: "#FFFFFF", + black: "#000000", + "slate-50": "#F4F8FB", + "slate-100": "#f1f5f9", + "slate-150": "#EDF1F6", + "slate-200": "#e2e8f0", + "slate-250": "#E2E7EF", + "slate-300": "#cbd5e1", + "slate-400": "#94a3b8", + "slate-500": "#64748b", + "slate-600": "#475569", + "slate-700": "#334155", + "slate-800": "#1e293b", + "slate-900": "#0f172a", + "gray-100": "#f3f4f6", + "gray-200": "#e5e7eb", + "gray-300": "#d1d5db", + "gray-325": "#ADB6C2", + "gray-350": "#C6CED9", + "gray-400": "#9ca3af", + "gray-500": "#6b7280", + "gray-600": "#4b5563", + "gray-700": "#374151", + "gray-800": "#1f2937", + "gray-900": "#111827", + "orange-100": "#FFF5F1", + "orange-200": "#FFE3D8", + "orange-300": "#FFC4AE", + "orange-400": "#FF9B79", + "orange-500": "#FF723F", + "orange-600": "#FF5416", + "orange-700": "#FE372B", + "orange-800": "#E40000", + "orange-900": "#B82202", + "orange-1000": "#751500", + "orange-1100": "#2A0B00", + "yellow-100": "#FFFBEF", + "yellow-200": "#FFF0BA", + "yellow-300": "#FFE27C", + "yellow-400": "#FFD43D", + "yellow-500": "#FFC700", + "yellow-600": "#E4B200", + "yellow-700": "#AC8600", + "yellow-800": "#654F00", + "yellow-900": "#291C01", + "green-100": "#F1FFF1", + "green-200": "#B8FFBB", + "green-300": "#80FF85", + "green-400": "#08FF13", + "green-500": "#00E80B", + "green-600": "#00C008", + "green-700": "#008E06", + "green-800": "#005303", + "green-900": "#002A02", + "blue-100": "#F1FBFF", + "blue-200": "#B8EAFF", + "blue-300": "#80D9FF", + "blue-400": "#4AD4FF", + "blue-500": "#2CC0FF", + "blue-600": "#00A5EC", + "blue-700": "#0284CD", + "blue-800": "#004B75", + "blue-900": "#001B2A", + "purple-100": "#F7F2FE", + "purple-200": "#D8BCFB", + "purple-300": "#B986F8", + "purple-400": "#9951F5", + "purple-500": "#7A1BF2", + "purple-600": "#5F0BC9", + "purple-700": "#460894", + "purple-800": "#2D055E", + "purple-900": "#130228", + "pink-100": "#FFF1FC", + "pink-200": "#FFB8F1", + "pink-300": "#FF80E6", + "pink-400": "#FF47DB", + "pink-500": "#FF17D2", + "pink-600": "#D400AB", + "pink-700": "#9C007E", + "pink-800": "#630050", + "pink-900": "#2A0022", + "red-100": "#FFF1F1", + "red-600": "#E40000", + }, + extend: { + fontFamily: { + sans: ["Inter", "ui-sans-serif", "system-ui"], + }, + }, + }, + plugins: [], +}; diff --git a/examples/vite-react-avatar-stack/tsconfig.json b/examples/vite-react-avatar-stack/tsconfig.json new file mode 100644 index 0000000..b55c9e8 --- /dev/null +++ b/examples/vite-react-avatar-stack/tsconfig.json @@ -0,0 +1,26 @@ +{ + "compilerOptions": { + "target": "ESNext", + "useDefineForClassFields": true, + "lib": ["DOM", "DOM.Iterable", "ESNext"], + "allowJs": false, + "skipLibCheck": true, + "esModuleInterop": false, + "allowSyntheticDefaultImports": true, + "strict": true, + "forceConsistentCasingInFileNames": true, + "module": "ESNext", + "moduleResolution": "Node", + "resolveJsonModule": true, + "isolatedModules": true, + "noEmit": true, + "jsx": "react-jsx" + }, + "types": ["vite/client"], + "include": ["src"], + "references": [ + { + "path": "./tsconfig.node.json" + } + ] +} diff --git a/examples/vite-react-avatar-stack/tsconfig.node.json b/examples/vite-react-avatar-stack/tsconfig.node.json new file mode 100644 index 0000000..e993792 --- /dev/null +++ b/examples/vite-react-avatar-stack/tsconfig.node.json @@ -0,0 +1,8 @@ +{ + "compilerOptions": { + "composite": true, + "module": "esnext", + "moduleResolution": "node" + }, + "include": ["vite.config.ts"] +} diff --git a/examples/vite-react-avatar-stack/vite.config.ts b/examples/vite-react-avatar-stack/vite.config.ts new file mode 100644 index 0000000..9cc50ea --- /dev/null +++ b/examples/vite-react-avatar-stack/vite.config.ts @@ -0,0 +1,7 @@ +import { defineConfig } from "vite"; +import react from "@vitejs/plugin-react"; + +// https://vitejs.dev/config/ +export default defineConfig({ + plugins: [react()], +}); diff --git a/examples/vite-react-avatar-stack/yarn.lock b/examples/vite-react-avatar-stack/yarn.lock new file mode 100644 index 0000000..54f4c81 --- /dev/null +++ b/examples/vite-react-avatar-stack/yarn.lock @@ -0,0 +1,996 @@ +# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. +# yarn lockfile v1 + + +"@ably/msgpack-js@^0.4.0": + version "0.4.0" + resolved "https://registry.yarnpkg.com/@ably/msgpack-js/-/msgpack-js-0.4.0.tgz#aaaf5d8dffacf7aa253effd8c3488aa09130e6a2" + integrity sha512-IPt/BoiQwCWubqoNik1aw/6M/DleMdrxJOUpSja6xmMRbT2p1TA8oqKWgfZabqzrq8emRNeSl/+4XABPNnW5pQ== + dependencies: + bops "^1.0.1" + +"@ably/spaces@0.2.0": + version "0.2.0" + resolved "https://registry.yarnpkg.com/@ably/spaces/-/spaces-0.2.0.tgz#ba999c634421e98fb063d443846c8c8d059a77c0" + integrity sha512-s2QE4uzWoS67Sq0z0KTTWlRtvHbCg9FyN+0K/8Agv+hvPY9Fe2r0oozae/Lj2Q2i7oEUiRvoYl37rX9Xk9x+fQ== + dependencies: + nanoid "^5.0.2" + +"@ampproject/remapping@^2.2.0": + version "2.2.1" + resolved "https://registry.yarnpkg.com/@ampproject/remapping/-/remapping-2.2.1.tgz#99e8e11851128b8702cd57c33684f1d0f260b630" + integrity sha512-lFMjJTrFL3j7L9yBxwYfCq2k6qqwHyzuUl/XBnif78PWTJYyL/dfowQHWE3sp6U6ZzqWiiIZnpTMO96zhkjwtg== + dependencies: + "@jridgewell/gen-mapping" "^0.3.0" + "@jridgewell/trace-mapping" "^0.3.9" + +"@babel/code-frame@^7.22.13": + version "7.22.13" + resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.22.13.tgz#e3c1c099402598483b7a8c46a721d1038803755e" + integrity sha512-XktuhWlJ5g+3TJXc5upd9Ks1HutSArik6jf2eAjYFyIOf4ej3RN+184cZbzDvbPnuTJIUhPKKJE3cIsYTiAT3w== + dependencies: + "@babel/highlight" "^7.22.13" + chalk "^2.4.2" + +"@babel/compat-data@^7.22.9": + version "7.22.20" + resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.22.20.tgz#8df6e96661209623f1975d66c35ffca66f3306d0" + integrity sha512-BQYjKbpXjoXwFW5jGqiizJQQT/aC7pFm9Ok1OWssonuguICi264lbgMzRp2ZMmRSlfkX6DsWDDcsrctK8Rwfiw== + +"@babel/core@^7.22.20": + version "7.23.0" + resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.23.0.tgz#f8259ae0e52a123eb40f552551e647b506a94d83" + integrity sha512-97z/ju/Jy1rZmDxybphrBuI+jtJjFVoz7Mr9yUQVVVi+DNZE333uFQeMOqcCIy1x3WYBIbWftUSLmbNXNT7qFQ== + dependencies: + "@ampproject/remapping" "^2.2.0" + "@babel/code-frame" "^7.22.13" + "@babel/generator" "^7.23.0" + "@babel/helper-compilation-targets" "^7.22.15" + "@babel/helper-module-transforms" "^7.23.0" + "@babel/helpers" "^7.23.0" + "@babel/parser" "^7.23.0" + "@babel/template" "^7.22.15" + "@babel/traverse" "^7.23.0" + "@babel/types" "^7.23.0" + convert-source-map "^2.0.0" + debug "^4.1.0" + gensync "^1.0.0-beta.2" + json5 "^2.2.3" + semver "^6.3.1" + +"@babel/generator@^7.23.0": + version "7.23.0" + resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.23.0.tgz#df5c386e2218be505b34837acbcb874d7a983420" + integrity sha512-lN85QRR+5IbYrMWM6Y4pE/noaQtg4pNiqeNGX60eqOfo6gtEj6uw/JagelB8vVztSd7R6M5n1+PQkDbHbBRU4g== + dependencies: + "@babel/types" "^7.23.0" + "@jridgewell/gen-mapping" "^0.3.2" + "@jridgewell/trace-mapping" "^0.3.17" + jsesc "^2.5.1" + +"@babel/helper-compilation-targets@^7.22.15": + version "7.22.15" + resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.22.15.tgz#0698fc44551a26cf29f18d4662d5bf545a6cfc52" + integrity sha512-y6EEzULok0Qvz8yyLkCvVX+02ic+By2UdOhylwUOvOn9dvYc9mKICJuuU1n1XBI02YWsNsnrY1kc6DVbjcXbtw== + dependencies: + "@babel/compat-data" "^7.22.9" + "@babel/helper-validator-option" "^7.22.15" + browserslist "^4.21.9" + lru-cache "^5.1.1" + semver "^6.3.1" + +"@babel/helper-environment-visitor@^7.22.20": + version "7.22.20" + resolved "https://registry.yarnpkg.com/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.20.tgz#96159db61d34a29dba454c959f5ae4a649ba9167" + integrity sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA== + +"@babel/helper-function-name@^7.23.0": + version "7.23.0" + resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.23.0.tgz#1f9a3cdbd5b2698a670c30d2735f9af95ed52759" + integrity sha512-OErEqsrxjZTJciZ4Oo+eoZqeW9UIiOcuYKRJA4ZAgV9myA+pOXhhmpfNCKjEH/auVfEYVFJ6y1Tc4r0eIApqiw== + dependencies: + "@babel/template" "^7.22.15" + "@babel/types" "^7.23.0" + +"@babel/helper-hoist-variables@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/helper-hoist-variables/-/helper-hoist-variables-7.22.5.tgz#c01a007dac05c085914e8fb652b339db50d823bb" + integrity sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw== + dependencies: + "@babel/types" "^7.22.5" + +"@babel/helper-module-imports@^7.22.15": + version "7.22.15" + resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.22.15.tgz#16146307acdc40cc00c3b2c647713076464bdbf0" + integrity sha512-0pYVBnDKZO2fnSPCrgM/6WMc7eS20Fbok+0r88fp+YtWVLZrp4CkafFGIp+W0VKw4a22sgebPT99y+FDNMdP4w== + dependencies: + "@babel/types" "^7.22.15" + +"@babel/helper-module-transforms@^7.23.0": + version "7.23.0" + resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.23.0.tgz#3ec246457f6c842c0aee62a01f60739906f7047e" + integrity sha512-WhDWw1tdrlT0gMgUJSlX0IQvoO1eN279zrAUbVB+KpV2c3Tylz8+GnKOLllCS6Z/iZQEyVYxhZVUdPTqs2YYPw== + dependencies: + "@babel/helper-environment-visitor" "^7.22.20" + "@babel/helper-module-imports" "^7.22.15" + "@babel/helper-simple-access" "^7.22.5" + "@babel/helper-split-export-declaration" "^7.22.6" + "@babel/helper-validator-identifier" "^7.22.20" + +"@babel/helper-plugin-utils@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.22.5.tgz#dd7ee3735e8a313b9f7b05a773d892e88e6d7295" + integrity sha512-uLls06UVKgFG9QD4OeFYLEGteMIAa5kpTPcFL28yuCIIzsf6ZyKZMllKVOCZFhiZ5ptnwX4mtKdWCBE/uT4amg== + +"@babel/helper-simple-access@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/helper-simple-access/-/helper-simple-access-7.22.5.tgz#4938357dc7d782b80ed6dbb03a0fba3d22b1d5de" + integrity sha512-n0H99E/K+Bika3++WNL17POvo4rKWZ7lZEp1Q+fStVbUi8nxPQEBOlTmCOxW/0JsS56SKKQ+ojAe2pHKJHN35w== + dependencies: + "@babel/types" "^7.22.5" + +"@babel/helper-split-export-declaration@^7.22.6": + version "7.22.6" + resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.22.6.tgz#322c61b7310c0997fe4c323955667f18fcefb91c" + integrity sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g== + dependencies: + "@babel/types" "^7.22.5" + +"@babel/helper-string-parser@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/helper-string-parser/-/helper-string-parser-7.22.5.tgz#533f36457a25814cf1df6488523ad547d784a99f" + integrity sha512-mM4COjgZox8U+JcXQwPijIZLElkgEpO5rsERVDJTc2qfCDfERyob6k5WegS14SX18IIjv+XD+GrqNumY5JRCDw== + +"@babel/helper-validator-identifier@^7.22.19", "@babel/helper-validator-identifier@^7.22.20": + version "7.22.20" + resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz#c4ae002c61d2879e724581d96665583dbc1dc0e0" + integrity sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A== + +"@babel/helper-validator-option@^7.22.15": + version "7.22.15" + resolved "https://registry.yarnpkg.com/@babel/helper-validator-option/-/helper-validator-option-7.22.15.tgz#694c30dfa1d09a6534cdfcafbe56789d36aba040" + integrity sha512-bMn7RmyFjY/mdECUbgn9eoSY4vqvacUnS9i9vGAGttgFWesO6B4CYWA7XlpbWgBt71iv/hfbPlynohStqnu5hA== + +"@babel/helpers@^7.23.0": + version "7.23.1" + resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.23.1.tgz#44e981e8ce2b9e99f8f0b703f3326a4636c16d15" + integrity sha512-chNpneuK18yW5Oxsr+t553UZzzAs3aZnFm4bxhebsNTeshrC95yA7l5yl7GBAG+JG1rF0F7zzD2EixK9mWSDoA== + dependencies: + "@babel/template" "^7.22.15" + "@babel/traverse" "^7.23.0" + "@babel/types" "^7.23.0" + +"@babel/highlight@^7.22.13": + version "7.22.20" + resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.22.20.tgz#4ca92b71d80554b01427815e06f2df965b9c1f54" + integrity sha512-dkdMCN3py0+ksCgYmGG8jKeGA/8Tk+gJwSYYlFGxG5lmhfKNoAy004YpLxpS1W2J8m/EK2Ew+yOs9pVRwO89mg== + dependencies: + "@babel/helper-validator-identifier" "^7.22.20" + chalk "^2.4.2" + js-tokens "^4.0.0" + +"@babel/parser@^7.1.0", "@babel/parser@^7.20.7", "@babel/parser@^7.23.0": + version "7.23.0" + resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.23.0.tgz#da950e622420bf96ca0d0f2909cdddac3acd8719" + integrity sha512-vvPKKdMemU85V9WE/l5wZEmImpCtLqbnTvqDS2U1fJ96KrxoW7KrXhNsNCblQlg8Ck4b85yxdTyelsMUgFUXiw== + +"@babel/parser@^7.22.15": + version "7.22.16" + resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.22.16.tgz#180aead7f247305cce6551bea2720934e2fa2c95" + integrity sha512-+gPfKv8UWeKKeJTUxe59+OobVcrYHETCsORl61EmSkmgymguYk/X5bp7GuUIXaFsc6y++v8ZxPsLSSuujqDphA== + +"@babel/plugin-transform-react-jsx-self@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-jsx-self/-/plugin-transform-react-jsx-self-7.22.5.tgz#ca2fdc11bc20d4d46de01137318b13d04e481d8e" + integrity sha512-nTh2ogNUtxbiSbxaT4Ds6aXnXEipHweN9YRgOX/oNXdf0cCrGn/+2LozFa3lnPV5D90MkjhgckCPBrsoSc1a7g== + dependencies: + "@babel/helper-plugin-utils" "^7.22.5" + +"@babel/plugin-transform-react-jsx-source@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-jsx-source/-/plugin-transform-react-jsx-source-7.22.5.tgz#49af1615bfdf6ed9d3e9e43e425e0b2b65d15b6c" + integrity sha512-yIiRO6yobeEIaI0RTbIr8iAK9FcBHLtZq0S89ZPjDLQXBA4xvghaKqI0etp/tF3htTM0sazJKKLz9oEiGRtu7w== + dependencies: + "@babel/helper-plugin-utils" "^7.22.5" + +"@babel/template@^7.22.15": + version "7.22.15" + resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.22.15.tgz#09576efc3830f0430f4548ef971dde1350ef2f38" + integrity sha512-QPErUVm4uyJa60rkI73qneDacvdvzxshT3kksGqlGWYdOTIUOwJ7RDUL8sGqslY1uXWSL6xMFKEXDS3ox2uF0w== + dependencies: + "@babel/code-frame" "^7.22.13" + "@babel/parser" "^7.22.15" + "@babel/types" "^7.22.15" + +"@babel/traverse@^7.23.0": + version "7.23.2" + resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.23.2.tgz#329c7a06735e144a506bdb2cad0268b7f46f4ad8" + integrity sha512-azpe59SQ48qG6nu2CzcMLbxUudtN+dOM9kDbUqGq3HXUJRlo7i8fvPoxQUzYgLZ4cMVmuZgm8vvBpNeRhd6XSw== + dependencies: + "@babel/code-frame" "^7.22.13" + "@babel/generator" "^7.23.0" + "@babel/helper-environment-visitor" "^7.22.20" + "@babel/helper-function-name" "^7.23.0" + "@babel/helper-hoist-variables" "^7.22.5" + "@babel/helper-split-export-declaration" "^7.22.6" + "@babel/parser" "^7.23.0" + "@babel/types" "^7.23.0" + debug "^4.1.0" + globals "^11.1.0" + +"@babel/types@^7.0.0", "@babel/types@^7.20.7", "@babel/types@^7.23.0": + version "7.23.0" + resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.23.0.tgz#8c1f020c9df0e737e4e247c0619f58c68458aaeb" + integrity sha512-0oIyUfKoI3mSqMvsxBdclDwxXKXAUA8v/apZbc+iSyARYou1o8ZGDxbUYyLFoW2arqS2jDGqJuZvv1d/io1axg== + dependencies: + "@babel/helper-string-parser" "^7.22.5" + "@babel/helper-validator-identifier" "^7.22.20" + to-fast-properties "^2.0.0" + +"@babel/types@^7.22.15", "@babel/types@^7.22.5": + version "7.22.19" + resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.22.19.tgz#7425343253556916e440e662bb221a93ddb75684" + integrity sha512-P7LAw/LbojPzkgp5oznjE6tQEIWbp4PkkfrZDINTro9zgBRtI324/EYsiSI7lhPbpIQ+DCeR2NNmMWANGGfZsg== + dependencies: + "@babel/helper-string-parser" "^7.22.5" + "@babel/helper-validator-identifier" "^7.22.19" + to-fast-properties "^2.0.0" + +"@esbuild/android-arm64@0.18.20": + version "0.18.20" + resolved "https://registry.yarnpkg.com/@esbuild/android-arm64/-/android-arm64-0.18.20.tgz#984b4f9c8d0377443cc2dfcef266d02244593622" + integrity sha512-Nz4rJcchGDtENV0eMKUNa6L12zz2zBDXuhj/Vjh18zGqB44Bi7MBMSXjgunJgjRhCmKOjnPuZp4Mb6OKqtMHLQ== + +"@esbuild/android-arm@0.18.20": + version "0.18.20" + resolved "https://registry.yarnpkg.com/@esbuild/android-arm/-/android-arm-0.18.20.tgz#fedb265bc3a589c84cc11f810804f234947c3682" + integrity sha512-fyi7TDI/ijKKNZTUJAQqiG5T7YjJXgnzkURqmGj13C6dCqckZBLdl4h7bkhHt/t0WP+zO9/zwroDvANaOqO5Sw== + +"@esbuild/android-x64@0.18.20": + version "0.18.20" + resolved "https://registry.yarnpkg.com/@esbuild/android-x64/-/android-x64-0.18.20.tgz#35cf419c4cfc8babe8893d296cd990e9e9f756f2" + integrity sha512-8GDdlePJA8D6zlZYJV/jnrRAi6rOiNaCC/JclcXpB+KIuvfBN4owLtgzY2bsxnx666XjJx2kDPUmnTtR8qKQUg== + +"@esbuild/darwin-arm64@0.18.20": + version "0.18.20" + resolved "https://registry.yarnpkg.com/@esbuild/darwin-arm64/-/darwin-arm64-0.18.20.tgz#08172cbeccf95fbc383399a7f39cfbddaeb0d7c1" + integrity sha512-bxRHW5kHU38zS2lPTPOyuyTm+S+eobPUnTNkdJEfAddYgEcll4xkT8DB9d2008DtTbl7uJag2HuE5NZAZgnNEA== + +"@esbuild/darwin-x64@0.18.20": + version "0.18.20" + resolved "https://registry.yarnpkg.com/@esbuild/darwin-x64/-/darwin-x64-0.18.20.tgz#d70d5790d8bf475556b67d0f8b7c5bdff053d85d" + integrity sha512-pc5gxlMDxzm513qPGbCbDukOdsGtKhfxD1zJKXjCCcU7ju50O7MeAZ8c4krSJcOIJGFR+qx21yMMVYwiQvyTyQ== + +"@esbuild/freebsd-arm64@0.18.20": + version "0.18.20" + resolved "https://registry.yarnpkg.com/@esbuild/freebsd-arm64/-/freebsd-arm64-0.18.20.tgz#98755cd12707f93f210e2494d6a4b51b96977f54" + integrity sha512-yqDQHy4QHevpMAaxhhIwYPMv1NECwOvIpGCZkECn8w2WFHXjEwrBn3CeNIYsibZ/iZEUemj++M26W3cNR5h+Tw== + +"@esbuild/freebsd-x64@0.18.20": + version "0.18.20" + resolved "https://registry.yarnpkg.com/@esbuild/freebsd-x64/-/freebsd-x64-0.18.20.tgz#c1eb2bff03915f87c29cece4c1a7fa1f423b066e" + integrity sha512-tgWRPPuQsd3RmBZwarGVHZQvtzfEBOreNuxEMKFcd5DaDn2PbBxfwLcj4+aenoh7ctXcbXmOQIn8HI6mCSw5MQ== + +"@esbuild/linux-arm64@0.18.20": + version "0.18.20" + resolved "https://registry.yarnpkg.com/@esbuild/linux-arm64/-/linux-arm64-0.18.20.tgz#bad4238bd8f4fc25b5a021280c770ab5fc3a02a0" + integrity sha512-2YbscF+UL7SQAVIpnWvYwM+3LskyDmPhe31pE7/aoTMFKKzIc9lLbyGUpmmb8a8AixOL61sQ/mFh3jEjHYFvdA== + +"@esbuild/linux-arm@0.18.20": + version "0.18.20" + resolved "https://registry.yarnpkg.com/@esbuild/linux-arm/-/linux-arm-0.18.20.tgz#3e617c61f33508a27150ee417543c8ab5acc73b0" + integrity sha512-/5bHkMWnq1EgKr1V+Ybz3s1hWXok7mDFUMQ4cG10AfW3wL02PSZi5kFpYKrptDsgb2WAJIvRcDm+qIvXf/apvg== + +"@esbuild/linux-ia32@0.18.20": + version "0.18.20" + resolved "https://registry.yarnpkg.com/@esbuild/linux-ia32/-/linux-ia32-0.18.20.tgz#699391cccba9aee6019b7f9892eb99219f1570a7" + integrity sha512-P4etWwq6IsReT0E1KHU40bOnzMHoH73aXp96Fs8TIT6z9Hu8G6+0SHSw9i2isWrD2nbx2qo5yUqACgdfVGx7TA== + +"@esbuild/linux-loong64@0.18.20": + version "0.18.20" + resolved "https://registry.yarnpkg.com/@esbuild/linux-loong64/-/linux-loong64-0.18.20.tgz#e6fccb7aac178dd2ffb9860465ac89d7f23b977d" + integrity sha512-nXW8nqBTrOpDLPgPY9uV+/1DjxoQ7DoB2N8eocyq8I9XuqJ7BiAMDMf9n1xZM9TgW0J8zrquIb/A7s3BJv7rjg== + +"@esbuild/linux-mips64el@0.18.20": + version "0.18.20" + resolved "https://registry.yarnpkg.com/@esbuild/linux-mips64el/-/linux-mips64el-0.18.20.tgz#eeff3a937de9c2310de30622a957ad1bd9183231" + integrity sha512-d5NeaXZcHp8PzYy5VnXV3VSd2D328Zb+9dEq5HE6bw6+N86JVPExrA6O68OPwobntbNJ0pzCpUFZTo3w0GyetQ== + +"@esbuild/linux-ppc64@0.18.20": + version "0.18.20" + resolved "https://registry.yarnpkg.com/@esbuild/linux-ppc64/-/linux-ppc64-0.18.20.tgz#2f7156bde20b01527993e6881435ad79ba9599fb" + integrity sha512-WHPyeScRNcmANnLQkq6AfyXRFr5D6N2sKgkFo2FqguP44Nw2eyDlbTdZwd9GYk98DZG9QItIiTlFLHJHjxP3FA== + +"@esbuild/linux-riscv64@0.18.20": + version "0.18.20" + resolved "https://registry.yarnpkg.com/@esbuild/linux-riscv64/-/linux-riscv64-0.18.20.tgz#6628389f210123d8b4743045af8caa7d4ddfc7a6" + integrity sha512-WSxo6h5ecI5XH34KC7w5veNnKkju3zBRLEQNY7mv5mtBmrP/MjNBCAlsM2u5hDBlS3NGcTQpoBvRzqBcRtpq1A== + +"@esbuild/linux-s390x@0.18.20": + version "0.18.20" + resolved "https://registry.yarnpkg.com/@esbuild/linux-s390x/-/linux-s390x-0.18.20.tgz#255e81fb289b101026131858ab99fba63dcf0071" + integrity sha512-+8231GMs3mAEth6Ja1iK0a1sQ3ohfcpzpRLH8uuc5/KVDFneH6jtAJLFGafpzpMRO6DzJ6AvXKze9LfFMrIHVQ== + +"@esbuild/linux-x64@0.18.20": + version "0.18.20" + resolved "https://registry.yarnpkg.com/@esbuild/linux-x64/-/linux-x64-0.18.20.tgz#c7690b3417af318a9b6f96df3031a8865176d338" + integrity sha512-UYqiqemphJcNsFEskc73jQ7B9jgwjWrSayxawS6UVFZGWrAAtkzjxSqnoclCXxWtfwLdzU+vTpcNYhpn43uP1w== + +"@esbuild/netbsd-x64@0.18.20": + version "0.18.20" + resolved "https://registry.yarnpkg.com/@esbuild/netbsd-x64/-/netbsd-x64-0.18.20.tgz#30e8cd8a3dded63975e2df2438ca109601ebe0d1" + integrity sha512-iO1c++VP6xUBUmltHZoMtCUdPlnPGdBom6IrO4gyKPFFVBKioIImVooR5I83nTew5UOYrk3gIJhbZh8X44y06A== + +"@esbuild/openbsd-x64@0.18.20": + version "0.18.20" + resolved "https://registry.yarnpkg.com/@esbuild/openbsd-x64/-/openbsd-x64-0.18.20.tgz#7812af31b205055874c8082ea9cf9ab0da6217ae" + integrity sha512-e5e4YSsuQfX4cxcygw/UCPIEP6wbIL+se3sxPdCiMbFLBWu0eiZOJ7WoD+ptCLrmjZBK1Wk7I6D/I3NglUGOxg== + +"@esbuild/sunos-x64@0.18.20": + version "0.18.20" + resolved "https://registry.yarnpkg.com/@esbuild/sunos-x64/-/sunos-x64-0.18.20.tgz#d5c275c3b4e73c9b0ecd38d1ca62c020f887ab9d" + integrity sha512-kDbFRFp0YpTQVVrqUd5FTYmWo45zGaXe0X8E1G/LKFC0v8x0vWrhOWSLITcCn63lmZIxfOMXtCfti/RxN/0wnQ== + +"@esbuild/win32-arm64@0.18.20": + version "0.18.20" + resolved "https://registry.yarnpkg.com/@esbuild/win32-arm64/-/win32-arm64-0.18.20.tgz#73bc7f5a9f8a77805f357fab97f290d0e4820ac9" + integrity sha512-ddYFR6ItYgoaq4v4JmQQaAI5s7npztfV4Ag6NrhiaW0RrnOXqBkgwZLofVTlq1daVTQNhtI5oieTvkRPfZrePg== + +"@esbuild/win32-ia32@0.18.20": + version "0.18.20" + resolved "https://registry.yarnpkg.com/@esbuild/win32-ia32/-/win32-ia32-0.18.20.tgz#ec93cbf0ef1085cc12e71e0d661d20569ff42102" + integrity sha512-Wv7QBi3ID/rROT08SABTS7eV4hX26sVduqDOTe1MvGMjNd3EjOz4b7zeexIR62GTIEKrfJXKL9LFxTYgkyeu7g== + +"@esbuild/win32-x64@0.18.20": + version "0.18.20" + resolved "https://registry.yarnpkg.com/@esbuild/win32-x64/-/win32-x64-0.18.20.tgz#786c5f41f043b07afb1af37683d7c33668858f6d" + integrity sha512-kTdfRcSiDfQca/y9QIkng02avJ+NCaQvrMejlsB3RRv5sE9rRoeBPISaZpKxHELzRxZyLvNts1P27W3wV+8geQ== + +"@jridgewell/gen-mapping@^0.3.0", "@jridgewell/gen-mapping@^0.3.2": + version "0.3.3" + resolved "https://registry.yarnpkg.com/@jridgewell/gen-mapping/-/gen-mapping-0.3.3.tgz#7e02e6eb5df901aaedb08514203b096614024098" + integrity sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ== + dependencies: + "@jridgewell/set-array" "^1.0.1" + "@jridgewell/sourcemap-codec" "^1.4.10" + "@jridgewell/trace-mapping" "^0.3.9" + +"@jridgewell/resolve-uri@^3.1.0": + version "3.1.1" + resolved "https://registry.yarnpkg.com/@jridgewell/resolve-uri/-/resolve-uri-3.1.1.tgz#c08679063f279615a3326583ba3a90d1d82cc721" + integrity sha512-dSYZh7HhCDtCKm4QakX0xFpsRDqjjtZf/kjI/v3T3Nwt5r8/qz/M19F9ySyOqU94SXBmeG9ttTul+YnR4LOxFA== + +"@jridgewell/set-array@^1.0.1": + version "1.1.2" + resolved "https://registry.yarnpkg.com/@jridgewell/set-array/-/set-array-1.1.2.tgz#7c6cf998d6d20b914c0a55a91ae928ff25965e72" + integrity sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw== + +"@jridgewell/sourcemap-codec@^1.4.10", "@jridgewell/sourcemap-codec@^1.4.14": + version "1.4.15" + resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz#d7c6e6755c78567a951e04ab52ef0fd26de59f32" + integrity sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg== + +"@jridgewell/trace-mapping@^0.3.17", "@jridgewell/trace-mapping@^0.3.9": + version "0.3.19" + resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.19.tgz#f8a3249862f91be48d3127c3cfe992f79b4b8811" + integrity sha512-kf37QtfW+Hwx/buWGMPcR60iF9ziHa6r/CZJIHbmcm4+0qrXiVdxegAH0F6yddEVQ7zdkjcGCgCzUu+BcbhQxw== + dependencies: + "@jridgewell/resolve-uri" "^3.1.0" + "@jridgewell/sourcemap-codec" "^1.4.14" + +"@sindresorhus/is@^4.0.0": + version "4.6.0" + resolved "https://registry.yarnpkg.com/@sindresorhus/is/-/is-4.6.0.tgz#3c7c9c46e678feefe7a2e5bb609d3dbd665ffb3f" + integrity sha512-t09vSN3MdfsyCHoFcTRCH/iUtG7OJ0CsjzB8cjAmKc/va/kIgeDI/TxsigdncE/4be734m0cvIYwNaV4i2XqAw== + +"@szmarczak/http-timer@^4.0.5": + version "4.0.6" + resolved "https://registry.yarnpkg.com/@szmarczak/http-timer/-/http-timer-4.0.6.tgz#b4a914bb62e7c272d4e5989fe4440f812ab1d807" + integrity sha512-4BAffykYOgO+5nzBWYwE3W90sBgLJoUPRWWcL8wlyiM8IB8ipJz3UMJ9KXQd1RKQXpKp8Tutn80HZtWsu2u76w== + dependencies: + defer-to-connect "^2.0.0" + +"@types/babel__core@^7.20.2": + version "7.20.2" + resolved "https://registry.yarnpkg.com/@types/babel__core/-/babel__core-7.20.2.tgz#215db4f4a35d710256579784a548907237728756" + integrity sha512-pNpr1T1xLUc2l3xJKuPtsEky3ybxN3m4fJkknfIpTCTfIZCDW57oAg+EfCgIIp2rvCe0Wn++/FfodDS4YXxBwA== + dependencies: + "@babel/parser" "^7.20.7" + "@babel/types" "^7.20.7" + "@types/babel__generator" "*" + "@types/babel__template" "*" + "@types/babel__traverse" "*" + +"@types/babel__generator@*": + version "7.6.5" + resolved "https://registry.yarnpkg.com/@types/babel__generator/-/babel__generator-7.6.5.tgz#281f4764bcbbbc51fdded0f25aa587b4ce14da95" + integrity sha512-h9yIuWbJKdOPLJTbmSpPzkF67e659PbQDba7ifWm5BJ8xTv+sDmS7rFmywkWOvXedGTivCdeGSIIX8WLcRTz8w== + dependencies: + "@babel/types" "^7.0.0" + +"@types/babel__template@*": + version "7.4.2" + resolved "https://registry.yarnpkg.com/@types/babel__template/-/babel__template-7.4.2.tgz#843e9f1f47c957553b0c374481dc4772921d6a6b" + integrity sha512-/AVzPICMhMOMYoSx9MoKpGDKdBRsIXMNByh1PXSZoa+v6ZoLa8xxtsT/uLQ/NJm0XVAWl/BvId4MlDeXJaeIZQ== + dependencies: + "@babel/parser" "^7.1.0" + "@babel/types" "^7.0.0" + +"@types/babel__traverse@*": + version "7.20.2" + resolved "https://registry.yarnpkg.com/@types/babel__traverse/-/babel__traverse-7.20.2.tgz#4ddf99d95cfdd946ff35d2b65c978d9c9bf2645d" + integrity sha512-ojlGK1Hsfce93J0+kn3H5R73elidKUaZonirN33GSmgTUMpzI/MIFfSpF3haANe3G1bEBS9/9/QEqwTzwqFsKw== + dependencies: + "@babel/types" "^7.20.7" + +"@types/cacheable-request@^6.0.1": + version "6.0.3" + resolved "https://registry.yarnpkg.com/@types/cacheable-request/-/cacheable-request-6.0.3.tgz#a430b3260466ca7b5ca5bfd735693b36e7a9d183" + integrity sha512-IQ3EbTzGxIigb1I3qPZc1rWJnH0BmSKv5QYTalEwweFvyBDLSAe24zP0le/hyi7ecGfZVlIVAg4BZqb8WBwKqw== + dependencies: + "@types/http-cache-semantics" "*" + "@types/keyv" "^3.1.4" + "@types/node" "*" + "@types/responselike" "^1.0.0" + +"@types/http-cache-semantics@*": + version "4.0.2" + resolved "https://registry.yarnpkg.com/@types/http-cache-semantics/-/http-cache-semantics-4.0.2.tgz#abe102d06ccda1efdf0ed98c10ccf7f36a785a41" + integrity sha512-FD+nQWA2zJjh4L9+pFXqWOi0Hs1ryBCfI+985NjluQ1p8EYtoLvjLOKidXBtZ4/IcxDX4o8/E8qDS3540tNliw== + +"@types/keyv@^3.1.4": + version "3.1.4" + resolved "https://registry.yarnpkg.com/@types/keyv/-/keyv-3.1.4.tgz#3ccdb1c6751b0c7e52300bcdacd5bcbf8faa75b6" + integrity sha512-BQ5aZNSCpj7D6K2ksrRCTmKRLEpnPvWDiLPfoGyhZ++8YtiK9d/3DBKPJgry359X/P1PfruyYwvnvwFjuEiEIg== + dependencies: + "@types/node" "*" + +"@types/node@*": + version "20.6.2" + resolved "https://registry.yarnpkg.com/@types/node/-/node-20.6.2.tgz#a065925409f59657022e9063275cd0b9bd7e1b12" + integrity sha512-Y+/1vGBHV/cYk6OI1Na/LHzwnlNCAfU3ZNGrc1LdRe/LAIbdDPTTv/HU3M7yXN448aTVDq3eKRm2cg7iKLb8gw== + +"@types/prop-types@*": + version "15.7.6" + resolved "https://registry.yarnpkg.com/@types/prop-types/-/prop-types-15.7.6.tgz#bbf819813d6be21011b8f5801058498bec555572" + integrity sha512-RK/kBbYOQQHLYj9Z95eh7S6t7gq4Ojt/NT8HTk8bWVhA5DaF+5SMnxHKkP4gPNN3wAZkKP+VjAf0ebtYzf+fxg== + +"@types/react-dom@^18.2.0": + version "18.2.8" + resolved "https://registry.yarnpkg.com/@types/react-dom/-/react-dom-18.2.8.tgz#338f1b0a646c9f10e0a97208c1d26b9f473dffd6" + integrity sha512-bAIvO5lN/U8sPGvs1Xm61rlRHHaq5rp5N3kp9C+NJ/Q41P8iqjkXSu0+/qu8POsjH9pNWb0OYabFez7taP7omw== + dependencies: + "@types/react" "*" + +"@types/react@*": + version "18.2.22" + resolved "https://registry.yarnpkg.com/@types/react/-/react-18.2.22.tgz#abe778a1c95a07fa70df40a52d7300a40b949ccb" + integrity sha512-60fLTOLqzarLED2O3UQImc/lsNRgG0jE/a1mPW9KjMemY0LMITWEsbS4VvZ4p6rorEHd5YKxxmMKSDK505GHpA== + dependencies: + "@types/prop-types" "*" + "@types/scheduler" "*" + csstype "^3.0.2" + +"@types/react@^18.2.0": + version "18.2.23" + resolved "https://registry.yarnpkg.com/@types/react/-/react-18.2.23.tgz#60ad6cf4895e93bed858db0e03bcc4ff97d0410e" + integrity sha512-qHLW6n1q2+7KyBEYnrZpcsAmU/iiCh9WGCKgXvMxx89+TYdJWRjZohVIo9XTcoLhfX3+/hP0Pbulu3bCZQ9PSA== + dependencies: + "@types/prop-types" "*" + "@types/scheduler" "*" + csstype "^3.0.2" + +"@types/responselike@^1.0.0": + version "1.0.0" + resolved "https://registry.yarnpkg.com/@types/responselike/-/responselike-1.0.0.tgz#251f4fe7d154d2bad125abe1b429b23afd262e29" + integrity sha512-85Y2BjiufFzaMIlvJDvTTB8Fxl2xfLo4HgmHzVBz08w4wDePCTjYw66PdrolO0kzli3yam/YCgRufyo1DdQVTA== + dependencies: + "@types/node" "*" + +"@types/scheduler@*": + version "0.16.3" + resolved "https://registry.yarnpkg.com/@types/scheduler/-/scheduler-0.16.3.tgz#cef09e3ec9af1d63d2a6cc5b383a737e24e6dcf5" + integrity sha512-5cJ8CB4yAx7BH1oMvdU0Jh9lrEXyPkar6F9G/ERswkCuvP4KQZfZkSjcMbAICCpQTN4OuZn8tz0HiKv9TGZgrQ== + +"@vitejs/plugin-react@^4.1.0": + version "4.1.0" + resolved "https://registry.yarnpkg.com/@vitejs/plugin-react/-/plugin-react-4.1.0.tgz#e4f56f46fd737c5d386bb1f1ade86ba275fe09bd" + integrity sha512-rM0SqazU9iqPUraQ2JlIvReeaxOoRj6n+PzB1C0cBzIbd8qP336nC39/R9yPi3wVcah7E7j/kdU1uCUqMEU4OQ== + dependencies: + "@babel/core" "^7.22.20" + "@babel/plugin-transform-react-jsx-self" "^7.22.5" + "@babel/plugin-transform-react-jsx-source" "^7.22.5" + "@types/babel__core" "^7.20.2" + react-refresh "^0.14.0" + +ably@1.2.45: + version "1.2.45" + resolved "https://registry.yarnpkg.com/ably/-/ably-1.2.45.tgz#9da9b3faae18614160dd7ff1e5e93de948f984bd" + integrity sha512-8Jk8XT0dSPcLcZ8zSAF+mRtwMzaQR5dWHqGdx9Y859ZLhXiqf4gQb7P+4Elqy1l1IIRoDWgyt0fkyfo7ngUdMA== + dependencies: + "@ably/msgpack-js" "^0.4.0" + got "^11.8.5" + ws "^5.1" + +ansi-styles@^3.2.1: + version "3.2.1" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d" + integrity sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA== + dependencies: + color-convert "^1.9.0" + +async-limiter@~1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/async-limiter/-/async-limiter-1.0.1.tgz#dd379e94f0db8310b08291f9d64c3209766617fd" + integrity sha512-csOlWGAcRFJaI6m+F2WKdnMKr4HhdhFVBk0H/QbJFMCr+uO2kwohwXQPxw/9OCxp05r5ghVBFSyioixx3gfkNQ== + +base64-js@1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.0.2.tgz#474211c95e6cf2a547db461e4f6778b51d08fa65" + integrity sha512-ZXBDPMt/v/8fsIqn+Z5VwrhdR6jVka0bYobHdGia0Nxi7BJ9i/Uvml3AocHIBtIIBhZjBw5MR0aR4ROs/8+SNg== + +bops@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/bops/-/bops-1.0.1.tgz#502aaf00ee119db1dbae088e3df4bea2e241dbcc" + integrity sha512-qCMBuZKP36tELrrgXpAfM+gHzqa0nLsWZ+L37ncsb8txYlnAoxOPpVp+g7fK0sGkMXfA0wl8uQkESqw3v4HNag== + dependencies: + base64-js "1.0.2" + to-utf8 "0.0.1" + +browserslist@^4.21.9: + version "4.21.10" + resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.21.10.tgz#dbbac576628c13d3b2231332cb2ec5a46e015bb0" + integrity sha512-bipEBdZfVH5/pwrvqc+Ub0kUPVfGUhlKxbvfD+z1BDnPEO/X98ruXGA1WP5ASpAFKan7Qr6j736IacbZQuAlKQ== + dependencies: + caniuse-lite "^1.0.30001517" + electron-to-chromium "^1.4.477" + node-releases "^2.0.13" + update-browserslist-db "^1.0.11" + +cacheable-lookup@^5.0.3: + version "5.0.4" + resolved "https://registry.yarnpkg.com/cacheable-lookup/-/cacheable-lookup-5.0.4.tgz#5a6b865b2c44357be3d5ebc2a467b032719a7005" + integrity sha512-2/kNscPhpcxrOigMZzbiWF7dz8ilhb/nIHU3EyZiXWXpeq/au8qJ8VhdftMkty3n7Gj6HIGalQG8oiBNB3AJgA== + +cacheable-request@^7.0.2: + version "7.0.4" + resolved "https://registry.yarnpkg.com/cacheable-request/-/cacheable-request-7.0.4.tgz#7a33ebf08613178b403635be7b899d3e69bbe817" + integrity sha512-v+p6ongsrp0yTGbJXjgxPow2+DL93DASP4kXCDKb8/bwRtt9OEF3whggkkDkGNzgcWy2XaF4a8nZglC7uElscg== + dependencies: + clone-response "^1.0.2" + get-stream "^5.1.0" + http-cache-semantics "^4.0.0" + keyv "^4.0.0" + lowercase-keys "^2.0.0" + normalize-url "^6.0.1" + responselike "^2.0.0" + +caniuse-lite@^1.0.30001517: + version "1.0.30001538" + resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001538.tgz#9dbc6b9af1ff06b5eb12350c2012b3af56744f3f" + integrity sha512-HWJnhnID+0YMtGlzcp3T9drmBJUVDchPJ08tpUGFLs9CYlwWPH2uLgpHn8fND5pCgXVtnGS3H4QR9XLMHVNkHw== + +chalk@^2.4.2: + version "2.4.2" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424" + integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ== + dependencies: + ansi-styles "^3.2.1" + escape-string-regexp "^1.0.5" + supports-color "^5.3.0" + +classnames@^2.3.2: + version "2.3.2" + resolved "https://registry.yarnpkg.com/classnames/-/classnames-2.3.2.tgz#351d813bf0137fcc6a76a16b88208d2560a0d924" + integrity sha512-CSbhY4cFEJRe6/GQzIk5qXZ4Jeg5pcsP7b5peFSDpffpe1cqjASH/n9UTjBwOp6XpMSTwQ8Za2K5V02ueA7Tmw== + +clone-response@^1.0.2: + version "1.0.3" + resolved "https://registry.yarnpkg.com/clone-response/-/clone-response-1.0.3.tgz#af2032aa47816399cf5f0a1d0db902f517abb8c3" + integrity sha512-ROoL94jJH2dUVML2Y/5PEDNaSHgeOdSDicUyS7izcF63G6sTc/FTjLub4b8Il9S8S0beOfYt0TaA5qvFK+w0wA== + dependencies: + mimic-response "^1.0.0" + +color-convert@^1.9.0: + version "1.9.3" + resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8" + integrity sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg== + dependencies: + color-name "1.1.3" + +color-name@1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25" + integrity sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw== + +convert-source-map@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-2.0.0.tgz#4b560f649fc4e918dd0ab75cf4961e8bc882d82a" + integrity sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg== + +csstype@^3.0.2: + version "3.1.2" + resolved "https://registry.yarnpkg.com/csstype/-/csstype-3.1.2.tgz#1d4bf9d572f11c14031f0436e1c10bc1f571f50b" + integrity sha512-I7K1Uu0MBPzaFKg4nI5Q7Vs2t+3gWWW648spaF+Rg7pI9ds18Ugn+lvg4SHczUdKlHI5LWBXyqfS8+DufyBsgQ== + +dayjs@^1.11.4: + version "1.11.9" + resolved "https://registry.yarnpkg.com/dayjs/-/dayjs-1.11.9.tgz#9ca491933fadd0a60a2c19f6c237c03517d71d1a" + integrity sha512-QvzAURSbQ0pKdIye2txOzNaHmxtUBXerpY0FJsFXUMKbIZeFm5ht1LS/jFsrncjnmtv8HsG0W2g6c0zUjZWmpA== + +debug@^4.1.0: + version "4.3.4" + resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.4.tgz#1319f6579357f2338d3337d2cdd4914bb5dcc865" + integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ== + dependencies: + ms "2.1.2" + +decompress-response@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/decompress-response/-/decompress-response-6.0.0.tgz#ca387612ddb7e104bd16d85aab00d5ecf09c66fc" + integrity sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ== + dependencies: + mimic-response "^3.1.0" + +defer-to-connect@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/defer-to-connect/-/defer-to-connect-2.0.1.tgz#8016bdb4143e4632b77a3449c6236277de520587" + integrity sha512-4tvttepXG1VaYGrRibk5EwJd1t4udunSOVMdLSAL6mId1ix438oPwPZMALY41FCijukO1L0twNcGsdzS7dHgDg== + +electron-to-chromium@^1.4.477: + version "1.4.523" + resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.523.tgz#f82f99243c827df05c26776d49712cb284972df6" + integrity sha512-9AreocSUWnzNtvLcbpng6N+GkXnCcBR80IQkxRC9Dfdyg4gaWNUPBujAHUpKkiUkoSoR9UlhA4zD/IgBklmhzg== + +end-of-stream@^1.1.0: + version "1.4.4" + resolved "https://registry.yarnpkg.com/end-of-stream/-/end-of-stream-1.4.4.tgz#5ae64a5f45057baf3626ec14da0ca5e4b2431eb0" + integrity sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q== + dependencies: + once "^1.4.0" + +esbuild@^0.18.10: + version "0.18.20" + resolved "https://registry.yarnpkg.com/esbuild/-/esbuild-0.18.20.tgz#4709f5a34801b43b799ab7d6d82f7284a9b7a7a6" + integrity sha512-ceqxoedUrcayh7Y7ZX6NdbbDzGROiyVBgC4PriJThBKSVPWnnFHZAkfI1lJT8QFkOwH4qOS2SJkS4wvpGl8BpA== + optionalDependencies: + "@esbuild/android-arm" "0.18.20" + "@esbuild/android-arm64" "0.18.20" + "@esbuild/android-x64" "0.18.20" + "@esbuild/darwin-arm64" "0.18.20" + "@esbuild/darwin-x64" "0.18.20" + "@esbuild/freebsd-arm64" "0.18.20" + "@esbuild/freebsd-x64" "0.18.20" + "@esbuild/linux-arm" "0.18.20" + "@esbuild/linux-arm64" "0.18.20" + "@esbuild/linux-ia32" "0.18.20" + "@esbuild/linux-loong64" "0.18.20" + "@esbuild/linux-mips64el" "0.18.20" + "@esbuild/linux-ppc64" "0.18.20" + "@esbuild/linux-riscv64" "0.18.20" + "@esbuild/linux-s390x" "0.18.20" + "@esbuild/linux-x64" "0.18.20" + "@esbuild/netbsd-x64" "0.18.20" + "@esbuild/openbsd-x64" "0.18.20" + "@esbuild/sunos-x64" "0.18.20" + "@esbuild/win32-arm64" "0.18.20" + "@esbuild/win32-ia32" "0.18.20" + "@esbuild/win32-x64" "0.18.20" + +escalade@^3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.1.1.tgz#d8cfdc7000965c5a0174b4a82eaa5c0552742e40" + integrity sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw== + +escape-string-regexp@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" + integrity sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg== + +fsevents@~2.3.2: + version "2.3.3" + resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.3.tgz#cac6407785d03675a2a5e1a5305c697b347d90d6" + integrity sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw== + +gensync@^1.0.0-beta.2: + version "1.0.0-beta.2" + resolved "https://registry.yarnpkg.com/gensync/-/gensync-1.0.0-beta.2.tgz#32a6ee76c3d7f52d46b2b1ae5d93fea8580a25e0" + integrity sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg== + +get-stream@^5.1.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-5.2.0.tgz#4966a1795ee5ace65e706c4b7beb71257d6e22d3" + integrity sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA== + dependencies: + pump "^3.0.0" + +globals@^11.1.0: + version "11.12.0" + resolved "https://registry.yarnpkg.com/globals/-/globals-11.12.0.tgz#ab8795338868a0babd8525758018c2a7eb95c42e" + integrity sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA== + +got@^11.8.5: + version "11.8.6" + resolved "https://registry.yarnpkg.com/got/-/got-11.8.6.tgz#276e827ead8772eddbcfc97170590b841823233a" + integrity sha512-6tfZ91bOr7bOXnK7PRDCGBLa1H4U080YHNaAQ2KsMGlLEzRbk44nsZF2E1IeRc3vtJHPVbKCYgdFbaGO2ljd8g== + dependencies: + "@sindresorhus/is" "^4.0.0" + "@szmarczak/http-timer" "^4.0.5" + "@types/cacheable-request" "^6.0.1" + "@types/responselike" "^1.0.0" + cacheable-lookup "^5.0.3" + cacheable-request "^7.0.2" + decompress-response "^6.0.0" + http2-wrapper "^1.0.0-beta.5.2" + lowercase-keys "^2.0.0" + p-cancelable "^2.0.0" + responselike "^2.0.0" + +has-flag@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd" + integrity sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw== + +http-cache-semantics@^4.0.0: + version "4.1.1" + resolved "https://registry.yarnpkg.com/http-cache-semantics/-/http-cache-semantics-4.1.1.tgz#abe02fcb2985460bf0323be664436ec3476a6d5a" + integrity sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ== + +http2-wrapper@^1.0.0-beta.5.2: + version "1.0.3" + resolved "https://registry.yarnpkg.com/http2-wrapper/-/http2-wrapper-1.0.3.tgz#b8f55e0c1f25d4ebd08b3b0c2c079f9590800b3d" + integrity sha512-V+23sDMr12Wnz7iTcDeJr3O6AIxlnvT/bmaAAAP/Xda35C90p9599p0F1eHR/N1KILWSoWVAiOMFjBBXaXSMxg== + dependencies: + quick-lru "^5.1.1" + resolve-alpn "^1.0.0" + +"js-tokens@^3.0.0 || ^4.0.0", js-tokens@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" + integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ== + +jsesc@^2.5.1: + version "2.5.2" + resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-2.5.2.tgz#80564d2e483dacf6e8ef209650a67df3f0c283a4" + integrity sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA== + +json-buffer@3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/json-buffer/-/json-buffer-3.0.1.tgz#9338802a30d3b6605fbe0613e094008ca8c05a13" + integrity sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ== + +json5@^2.2.3: + version "2.2.3" + resolved "https://registry.yarnpkg.com/json5/-/json5-2.2.3.tgz#78cd6f1a19bdc12b73db5ad0c61efd66c1e29283" + integrity sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg== + +keyv@^4.0.0: + version "4.5.3" + resolved "https://registry.yarnpkg.com/keyv/-/keyv-4.5.3.tgz#00873d2b046df737963157bd04f294ca818c9c25" + integrity sha512-QCiSav9WaX1PgETJ+SpNnx2PRRapJ/oRSXM4VO5OGYGSjrxbKPVFVhB3l2OCbLCk329N8qyAtsJjSjvVBWzEug== + dependencies: + json-buffer "3.0.1" + +loose-envify@^1.1.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.4.0.tgz#71ee51fa7be4caec1a63839f7e682d8132d30caf" + integrity sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q== + dependencies: + js-tokens "^3.0.0 || ^4.0.0" + +lowercase-keys@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/lowercase-keys/-/lowercase-keys-2.0.0.tgz#2603e78b7b4b0006cbca2fbcc8a3202558ac9479" + integrity sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA== + +lru-cache@^5.1.1: + version "5.1.1" + resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-5.1.1.tgz#1da27e6710271947695daf6848e847f01d84b920" + integrity sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w== + dependencies: + yallist "^3.0.2" + +mimic-response@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/mimic-response/-/mimic-response-1.0.1.tgz#4923538878eef42063cb8a3e3b0798781487ab1b" + integrity sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ== + +mimic-response@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/mimic-response/-/mimic-response-3.1.0.tgz#2d1d59af9c1b129815accc2c46a022a5ce1fa3c9" + integrity sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ== + +ms@2.1.2: + version "2.1.2" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" + integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== + +nanoid@^3.3.6: + version "3.3.6" + resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.6.tgz#443380c856d6e9f9824267d960b4236ad583ea4c" + integrity sha512-BGcqMMJuToF7i1rt+2PWSNVnWIkGCU78jBG3RxO/bZlnZPK2Cmi2QaffxGO/2RvWi9sL+FAiRiXMgsyxQ1DIDA== + +nanoid@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-5.0.1.tgz#3e95d775a8bc8a98afbf0a237e2bbc6a71b0662e" + integrity sha512-vWeVtV5Cw68aML/QaZvqN/3QQXc6fBfIieAlu05m7FZW2Dgb+3f0xc0TTxuJW+7u30t7iSDTV/j3kVI0oJqIfQ== + +nanoid@^5.0.2: + version "5.0.2" + resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-5.0.2.tgz#97588ebc70166d0feaf73ccd2799bb4ceaebf692" + integrity sha512-2ustYUX1R2rL/Br5B/FMhi8d5/QzvkJ912rBYxskcpu0myTHzSZfTr1LAS2Sm7jxRUObRrSBFoyzwAhL49aVSg== + +node-releases@^2.0.13: + version "2.0.13" + resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.13.tgz#d5ed1627c23e3461e819b02e57b75e4899b1c81d" + integrity sha512-uYr7J37ae/ORWdZeQ1xxMJe3NtdmqMC/JZK+geofDrkLUApKRHPd18/TxtBOJ4A0/+uUIliorNrfYV6s1b02eQ== + +normalize-url@^6.0.1: + version "6.1.0" + resolved "https://registry.yarnpkg.com/normalize-url/-/normalize-url-6.1.0.tgz#40d0885b535deffe3f3147bec877d05fe4c5668a" + integrity sha512-DlL+XwOy3NxAQ8xuC0okPgK46iuVNAK01YN7RueYBqqFeGsBjV9XmCAzAdgt+667bCl5kPh9EqKKDwnaPG1I7A== + +once@^1.3.1, once@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" + integrity sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w== + dependencies: + wrappy "1" + +p-cancelable@^2.0.0: + version "2.1.1" + resolved "https://registry.yarnpkg.com/p-cancelable/-/p-cancelable-2.1.1.tgz#aab7fbd416582fa32a3db49859c122487c5ed2cf" + integrity sha512-BZOr3nRQHOntUjTrH8+Lh54smKHoHyur8We1V8DSMVrl5A2malOOwuJRnKRDjSnkoeBh4at6BwEnb5I7Jl31wg== + +picocolors@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.0.0.tgz#cb5bdc74ff3f51892236eaf79d68bc44564ab81c" + integrity sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ== + +postcss@^8.4.27: + version "8.4.31" + resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.31.tgz#92b451050a9f914da6755af352bdc0192508656d" + integrity sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ== + dependencies: + nanoid "^3.3.6" + picocolors "^1.0.0" + source-map-js "^1.0.2" + +pump@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/pump/-/pump-3.0.0.tgz#b4a2116815bde2f4e1ea602354e8c75565107a64" + integrity sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww== + dependencies: + end-of-stream "^1.1.0" + once "^1.3.1" + +quick-lru@^5.1.1: + version "5.1.1" + resolved "https://registry.yarnpkg.com/quick-lru/-/quick-lru-5.1.1.tgz#366493e6b3e42a3a6885e2e99d18f80fb7a8c932" + integrity sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA== + +random-words@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/random-words/-/random-words-2.0.0.tgz#af1e1a75d506b5dec996094ab074bf2196272287" + integrity sha512-uqpnDqFnYrZajgmvgjmBrSZL2V1UA/9bNPGrilo12CmBeBszoff/avElutUlwWxG12gvmCk/8dUhvHefYxzYjw== + dependencies: + seedrandom "^3.0.5" + +react-dom@^18.2.0: + version "18.2.0" + resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-18.2.0.tgz#22aaf38708db2674ed9ada224ca4aa708d821e3d" + integrity sha512-6IMTriUmvsjHUjNtEDudZfuDQUoWXVxKHhlEGSk81n4YFS+r/Kl99wXiwlVXtPBtJenozv2P+hxDsw9eA7Xo6g== + dependencies: + loose-envify "^1.1.0" + scheduler "^0.23.0" + +react-refresh@^0.14.0: + version "0.14.0" + resolved "https://registry.yarnpkg.com/react-refresh/-/react-refresh-0.14.0.tgz#4e02825378a5f227079554d4284889354e5f553e" + integrity sha512-wViHqhAd8OHeLS/IRMJjTSDHF3U9eWi62F/MledQGPdJGDhodXJ9PBLNGr6WWL7qlH12Mt3TyTpbS+hGXMjCzQ== + +react@^18.2.0: + version "18.2.0" + resolved "https://registry.yarnpkg.com/react/-/react-18.2.0.tgz#555bd98592883255fa00de14f1151a917b5d77d5" + integrity sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ== + dependencies: + loose-envify "^1.1.0" + +resolve-alpn@^1.0.0: + version "1.2.1" + resolved "https://registry.yarnpkg.com/resolve-alpn/-/resolve-alpn-1.2.1.tgz#b7adbdac3546aaaec20b45e7d8265927072726f9" + integrity sha512-0a1F4l73/ZFZOakJnQ3FvkJ2+gSTQWz/r2KE5OdDY0TxPm5h4GkqkWWfM47T7HsbnOtcJVEF4epCVy6u7Q3K+g== + +responselike@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/responselike/-/responselike-2.0.1.tgz#9a0bc8fdc252f3fb1cca68b016591059ba1422bc" + integrity sha512-4gl03wn3hj1HP3yzgdI7d3lCkF95F21Pz4BPGvKHinyQzALR5CapwC8yIi0Rh58DEMQ/SguC03wFj2k0M/mHhw== + dependencies: + lowercase-keys "^2.0.0" + +rollup@^3.27.1: + version "3.29.4" + resolved "https://registry.yarnpkg.com/rollup/-/rollup-3.29.4.tgz#4d70c0f9834146df8705bfb69a9a19c9e1109981" + integrity sha512-oWzmBZwvYrU0iJHtDmhsm662rC15FRXmcjCk1xD771dFDx5jJ02ufAQQTn0etB2emNk4J9EZg/yWKpsn9BWGRw== + optionalDependencies: + fsevents "~2.3.2" + +scheduler@^0.23.0: + version "0.23.0" + resolved "https://registry.yarnpkg.com/scheduler/-/scheduler-0.23.0.tgz#ba8041afc3d30eb206a487b6b384002e4e61fdfe" + integrity sha512-CtuThmgHNg7zIZWAXi3AsyIzA3n4xx7aNyjwC2VJldO2LMVDhFK+63xGqq6CsJH4rTAt6/M+N4GhZiDYPx9eUw== + dependencies: + loose-envify "^1.1.0" + +seedrandom@^3.0.5: + version "3.0.5" + resolved "https://registry.yarnpkg.com/seedrandom/-/seedrandom-3.0.5.tgz#54edc85c95222525b0c7a6f6b3543d8e0b3aa0a7" + integrity sha512-8OwmbklUNzwezjGInmZ+2clQmExQPvomqjL7LFqOYqtmuxRgQYqOD3mHaU+MvZn5FLUeVxVfQjwLZW/n/JFuqg== + +semver@^6.3.1: + version "6.3.1" + resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.1.tgz#556d2ef8689146e46dcea4bfdd095f3434dffcb4" + integrity sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA== + +source-map-js@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/source-map-js/-/source-map-js-1.0.2.tgz#adbc361d9c62df380125e7f161f71c826f1e490c" + integrity sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw== + +supports-color@^5.3.0: + version "5.5.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f" + integrity sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow== + dependencies: + has-flag "^3.0.0" + +to-fast-properties@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-2.0.0.tgz#dc5e698cbd079265bc73e0377681a4e4e83f616e" + integrity sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog== + +to-utf8@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/to-utf8/-/to-utf8-0.0.1.tgz#d17aea72ff2fba39b9e43601be7b3ff72e089852" + integrity sha512-zks18/TWT1iHO3v0vFp5qLKOG27m67ycq/Y7a7cTiRuUNlc4gf3HGnkRgMv0NyhnfTamtkYBJl+YeD1/j07gBQ== + +typescript@5.2.2: + version "5.2.2" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.2.2.tgz#5ebb5e5a5b75f085f22bc3f8460fba308310fa78" + integrity sha512-mI4WrpHsbCIcwT9cF4FZvr80QUeKvsUsUvKDoR+X/7XHQH98xYD8YHZg7ANtz2GtZt/CBq2QJ0thkGJMHfqc1w== + +update-browserslist-db@^1.0.11: + version "1.0.11" + resolved "https://registry.yarnpkg.com/update-browserslist-db/-/update-browserslist-db-1.0.11.tgz#9a2a641ad2907ae7b3616506f4b977851db5b940" + integrity sha512-dCwEFf0/oT85M1fHBg4F0jtLwJrutGoHSQXCh7u4o2t1drG+c0a9Flnqww6XUKSfQMPpJBRjU8d4RXB09qtvaA== + dependencies: + escalade "^3.1.1" + picocolors "^1.0.0" + +vite@^4.4.9: + version "4.4.9" + resolved "https://registry.yarnpkg.com/vite/-/vite-4.4.9.tgz#1402423f1a2f8d66fd8d15e351127c7236d29d3d" + integrity sha512-2mbUn2LlUmNASWwSCNSJ/EG2HuSRTnVNaydp6vMCm5VIqJsjMfbIWtbH2kDuwUVW5mMUKKZvGPX/rqeqVvv1XA== + dependencies: + esbuild "^0.18.10" + postcss "^8.4.27" + rollup "^3.27.1" + optionalDependencies: + fsevents "~2.3.2" + +wrappy@1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" + integrity sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ== + +ws@^5.1: + version "5.2.3" + resolved "https://registry.yarnpkg.com/ws/-/ws-5.2.3.tgz#05541053414921bc29c63bee14b8b0dd50b07b3d" + integrity sha512-jZArVERrMsKUatIdnLzqvcfydI85dvd/Fp1u/VOpfdDWQ4c9qWXe+VIeAbQ5FrDwciAkr+lzofXLz3Kuf26AOA== + dependencies: + async-limiter "~1.0.0" + +yallist@^3.0.2: + version "3.1.1" + resolved "https://registry.yarnpkg.com/yallist/-/yallist-3.1.1.tgz#dbb7daf9bfd8bac9ab45ebf602b8cbad0d5d08fd" + integrity sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g== diff --git a/src/main.tsx b/src/main.tsx index b13d8c7..7fa513d 100644 --- a/src/main.tsx +++ b/src/main.tsx @@ -13,6 +13,8 @@ import EmojiReactions from "./routes/EmojiReactions"; import UserClaims from "./routes/UserClaims"; import MemberLocation from "./routes/MemberLocation"; import ComponentLocking from "./routes/ComponentLocking"; +// import VanillaAvatarStack from "./routes/VanillaAvatarStack"; +import ViteReactAvatarStack from "./routes/ViteReactAvatarStack"; import "./styles/global.css"; @@ -50,6 +52,8 @@ ReactDOM.createRoot(document.getElementById("root")!).render( /> } /> } /> + {/* } /> */} + } /> diff --git a/src/routes/Home.tsx b/src/routes/Home.tsx index 19f1f37..3a1167e 100644 --- a/src/routes/Home.tsx +++ b/src/routes/Home.tsx @@ -31,6 +31,12 @@ const Home = () => {
  • User Claims
  • + {/*
  • + Avatar Stack - Vanilla JS +
  • */} +
  • + Avatar Stack - React +
  • ); }; diff --git a/src/routes/JavascriptTemplate.tsx b/src/routes/JavascriptTemplate.tsx new file mode 100644 index 0000000..7784d12 --- /dev/null +++ b/src/routes/JavascriptTemplate.tsx @@ -0,0 +1,28 @@ +import { useEffect } from "react"; +import { useOutletContext } from "react-router-dom"; + +import type { ProjectInfo } from "../utils/types"; +import AvatarStack from "../../examples/vite-avatar-stack/src/App"; +import Spaces from "@ably/spaces"; + +const Project = ({ spaces }: { spaces: Spaces }) => { + const { setProjectInfo } = useOutletContext<{ + setProjectInfo: (projectInfo: ProjectInfo) => void; + }>(); + + useEffect(() => { + setProjectInfo({ + name: "Avatar stack", + docsLink: "https://ably.com/docs/spaces/avatar", + repoNameAndPath: "realtime-examples/tree/main/examples/vite-avatar-stack", + topic: "avatar-stack", + learnMore: true, + description: + "See your online presence in a space displayed as an Avatar. Open in a new window or share the link to see multiple users.", + }); + }, []); + + return ; +}; + +export default Project; diff --git a/src/routes/VanillaAvatarStack.tsx b/src/routes/VanillaAvatarStack.tsx new file mode 100644 index 0000000..00be853 --- /dev/null +++ b/src/routes/VanillaAvatarStack.tsx @@ -0,0 +1,11 @@ +const VanillaAvatarStack = () => { + return ( + + ); +}; + +export default VanillaAvatarStack; diff --git a/src/routes/ViteReactAvatarStack.tsx b/src/routes/ViteReactAvatarStack.tsx new file mode 100644 index 0000000..c834b9b --- /dev/null +++ b/src/routes/ViteReactAvatarStack.tsx @@ -0,0 +1,28 @@ +import { useEffect } from "react"; +import { useOutletContext } from "react-router-dom"; + +import type { ProjectInfo } from "../utils/types"; +import AvatarStack from "../../examples/vite-react-avatar-stack/src/App"; +import Spaces from "@ably/spaces"; + +const Project = ({ spaces }: { spaces: Spaces }) => { + const { setProjectInfo } = useOutletContext<{ + setProjectInfo: (projectInfo: ProjectInfo) => void; + }>(); + + useEffect(() => { + setProjectInfo({ + name: "React Avatar stack", + docsLink: "https://ably.com/docs/spaces/avatar", + repoNameAndPath: "realtime-examples/tree/main/examples/vite-react-avatar-stack", + topic: "avatar-stack", + learnMore: true, + description: + "See your online presence in a space displayed as an Avatar. Open in a new window or share the link to see multiple users.", + }); + }, []); + + return ; +}; + +export default Project; From 97f3b69472ff4812e4a65958f510047260c1fdec Mon Sep 17 00:00:00 2001 From: Greg Holmes Date: Tue, 25 Jun 2024 00:00:02 +0100 Subject: [PATCH 02/19] fixup! Introduced vite-react-avatar-stack --- .../src/components/AvatarStack.module.css | 4 ++-- .../vite-react-avatar-stack/src/components/AvatarStack.tsx | 2 +- .../vite-react-avatar-stack/src/components/Avatars.module.css | 2 +- examples/vite-react-avatar-stack/src/components/Avatars.tsx | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/examples/vite-react-avatar-stack/src/components/AvatarStack.module.css b/examples/vite-react-avatar-stack/src/components/AvatarStack.module.css index 33dbfa7..7b276ab 100644 --- a/examples/vite-react-avatar-stack/src/components/AvatarStack.module.css +++ b/examples/vite-react-avatar-stack/src/components/AvatarStack.module.css @@ -1,4 +1,4 @@ -.container { +.avatarStackContainer { width: 100%; display: flex; justify-content: center; @@ -6,4 +6,4 @@ position: relative; background-color: #f4f8fb; height: 100vh; - } +} diff --git a/examples/vite-react-avatar-stack/src/components/AvatarStack.tsx b/examples/vite-react-avatar-stack/src/components/AvatarStack.tsx index 076443c..a59cc38 100644 --- a/examples/vite-react-avatar-stack/src/components/AvatarStack.tsx +++ b/examples/vite-react-avatar-stack/src/components/AvatarStack.tsx @@ -41,7 +41,7 @@ const AvatarStack = () => { const { others, self } = useMembers(); return ( -
    +
    {/** 💡 Stack of first 5 user avatars including yourself.💡 */}
    diff --git a/examples/vite-react-avatar-stack/src/components/Avatars.module.css b/examples/vite-react-avatar-stack/src/components/Avatars.module.css index 3176879..3f1c256 100644 --- a/examples/vite-react-avatar-stack/src/components/Avatars.module.css +++ b/examples/vite-react-avatar-stack/src/components/Avatars.module.css @@ -1,6 +1,6 @@ /** AVATARS **/ -.container { +.avatarsContainer { position: relative; display: flex; } diff --git a/examples/vite-react-avatar-stack/src/components/Avatars.tsx b/examples/vite-react-avatar-stack/src/components/Avatars.tsx index e344585..ab412c8 100644 --- a/examples/vite-react-avatar-stack/src/components/Avatars.tsx +++ b/examples/vite-react-avatar-stack/src/components/Avatars.tsx @@ -189,7 +189,7 @@ const Avatars = ({ const totalWidth = calculateTotalWidth({ users: otherUsers }); return ( -
    +
    setHover(true)} From 46a886f2e6a48ee13773732952daa6d8bb6661ea Mon Sep 17 00:00:00 2001 From: Greg Holmes Date: Tue, 25 Jun 2024 00:01:16 +0100 Subject: [PATCH 03/19] Added first draft of vanilla JS version of avatar stack --- examples/vanilla-avatar-stack/.env.example | 2 + examples/vanilla-avatar-stack/index.html | 16 + examples/vanilla-avatar-stack/package.json | 25 + examples/vanilla-avatar-stack/script.js | 319 ++++++++++++ examples/vanilla-avatar-stack/styles.css | 471 ++++++++++++++++++ examples/vanilla-avatar-stack/tsconfig.json | 26 + .../vanilla-avatar-stack/tsconfig.node.json | 8 + examples/vanilla-avatar-stack/vite.config.ts | 7 + src/main.tsx | 4 +- src/routes/Home.tsx | 4 +- 10 files changed, 878 insertions(+), 4 deletions(-) create mode 100644 examples/vanilla-avatar-stack/.env.example create mode 100644 examples/vanilla-avatar-stack/index.html create mode 100644 examples/vanilla-avatar-stack/package.json create mode 100644 examples/vanilla-avatar-stack/script.js create mode 100644 examples/vanilla-avatar-stack/styles.css create mode 100644 examples/vanilla-avatar-stack/tsconfig.json create mode 100644 examples/vanilla-avatar-stack/tsconfig.node.json create mode 100644 examples/vanilla-avatar-stack/vite.config.ts diff --git a/examples/vanilla-avatar-stack/.env.example b/examples/vanilla-avatar-stack/.env.example new file mode 100644 index 0000000..dbcc501 --- /dev/null +++ b/examples/vanilla-avatar-stack/.env.example @@ -0,0 +1,2 @@ +# Use your own API KEY from Ably here: +VITE_ABLY_KEY= diff --git a/examples/vanilla-avatar-stack/index.html b/examples/vanilla-avatar-stack/index.html new file mode 100644 index 0000000..d95759d --- /dev/null +++ b/examples/vanilla-avatar-stack/index.html @@ -0,0 +1,16 @@ + + + + + + Avatar Stack + + + +
    +
    +
    +
    + + + diff --git a/examples/vanilla-avatar-stack/package.json b/examples/vanilla-avatar-stack/package.json new file mode 100644 index 0000000..cb0bfc7 --- /dev/null +++ b/examples/vanilla-avatar-stack/package.json @@ -0,0 +1,25 @@ +{ + "name": "vanilla-live-cursors", + "private": true, + "version": "0.0.0", + "type": "module", + "scripts": { + "dev": "vite", + "build": "tsc && vite build", + "preview": "vite preview" + }, + "dependencies": { + "@ably/spaces": "0.2.0", + "ably": "1.2.45", + "classnames": "^2.3.2", + "nanoid": "^5.0.1", + "random-words": "^2.0.0", + "react": "^18.0.0", + "react-dom": "^18.0.0" + }, + "devDependencies": { + "dotenv": "16.4.5", + "typescript": "^5.2.2", + "vite": "^5.2.13" + } +} diff --git a/examples/vanilla-avatar-stack/script.js b/examples/vanilla-avatar-stack/script.js new file mode 100644 index 0000000..6582da5 --- /dev/null +++ b/examples/vanilla-avatar-stack/script.js @@ -0,0 +1,319 @@ +import Spaces from '@ably/spaces' +import { Realtime } from 'ably' +import { nanoid } from 'nanoid' +import { generate } from "random-words"; +import classNames from "classnames"; +import dayjs from "dayjs"; + +const REMOVE_USER_AFTER_MILLIS = 120_000; +const MAX_USERS_BEFORE_LIST = 4; +const HORIZONTAL_SPACING_OFFSET = 40; +const OVERLAP_AMOUNT = 40; +const AVATAR_WIDTH = 48; + +const client = new Realtime.Promise({ + clientId: nanoid(), + key: import.meta.env.VITE_ABLY_KEY, +}) +const spaces = new Spaces(client) +// TODO: Update this to call getSpaceNameFromUrl() +const space = await spaces.get('avatar-stack') + +const avatarStack = document.getElementById('avatar-stack') + +function getSpaceNameFromUrl() { + const url = new URL(window.location.href); + const spaceNameInParams = url.searchParams.get("space"); + + if (spaceNameInParams) { + return spaceNameInParams; + } else { + const generatedName = generate({ exactly: 3, join: "-" }); + url.searchParams.set("space", generatedName); + window.history.replaceState({}, "", `?${url.searchParams.toString()}`); + return generatedName; + } +}; + +function calculateRightOffset(options) { + const { usersCount, index = 0 } = options; + + return usersCount > MAX_USERS_BEFORE_LIST + ? (index + 1) * HORIZONTAL_SPACING_OFFSET + : index * HORIZONTAL_SPACING_OFFSET; +} + +function calculateTotalWidth(users) { + return ( + AVATAR_WIDTH + + OVERLAP_AMOUNT * Math.min(users.length, MAX_USERS_BEFORE_LIST + 1) + ); +} + +const mockNames = [ + "Anum Reeve", + "Tiernan Stubbs", + "Hakim Hernandez", +] + +const mockColors = [ + "#9951F5", + "#1BF5C3", + "#F54A4A", +] + +await space.enter({ + name: mockNames[Math.floor(Math.random() * mockNames.length)], + memberColor: mockColors[Math.floor(Math.random() * mockColors.length)], +}).then(async () => { + const otherMembers = await space.members.getOthers(); + + await getMyAvatar() + getOtherAvatars(otherMembers.slice(0, MAX_USERS_BEFORE_LIST).reverse()) + getSurplusAvatars(otherMembers) +}).catch((err) => { + console.error('Error joining space:', err); +}) + +// Subscribe to member enters in a space +space.members.subscribe('enter', (member) => { + addAvatar(member, otherMembers.length) +}) + +// Subscribe to member leaves in a space +space.members.subscribe(['leave', 'remove'], (member) => { + const avatarElement = avatarStack.querySelector( + `.avatar[data-member-id="${member.clientId}"]` + ) + if (avatarElement) { + avatarElement.remove() + } +}) + +async function getMyAvatar() { + const self = await space.members.getSelf() + const initialsCSS = classNames( + { + ["textWhite"]: self.isConnected, + ["inactiveColor"]: !self.isConnected, + }, + "nameOthers", + ); + const statusIndicatorCSS = classNames( + { + ["statusIndicatorOnline"]: self.isConnected, + ["inactiveBackground"]: !self.isConnected, + }, + "statusIndicator", + ); + + const avatars = document.getElementById('avatars') + const avatar = document.createElement('div') + avatar.className = 'avatar' + avatar.style.backgroundColor = self.isConnected + ? self.profileData.memberColor + : "#C6CED9" + avatar.setAttribute('data-member-id', self.clientId); + + const popup = document.createElement('div'); + popup.className = 'popup'; + popup.style.display = 'none'; + + const userInfo = createUserInfo(self) + popup.appendChild(userInfo); + + avatar.appendChild(popup); + + avatar.addEventListener('mouseover', function() { + popup.style.display = 'block' + }); + + avatar.addEventListener('mouseleave', function() { + popup.style.display = 'none' + }); + + const initials = document.createElement('p') + initials.className = initialsCSS + initials.textContent = 'You' + + const statusIndicator = document.createElement('div') + statusIndicator.className = statusIndicatorCSS + statusIndicator.id = 'status-indicator' + + avatars.appendChild(avatar) + avatar.appendChild(initials) + avatar.appendChild(statusIndicator) +} + +async function addAvatar(user, usersCount, index = 0) { + const rightOffset = calculateRightOffset({ usersCount, index }); + const userInitials = user.profileData.name + .split(" ") + .map((word) => word.charAt(0)) + .join(""); + + const initialsCSS = classNames( + { + ["textWhite"]: user.isConnected, + ["inactiveColor"]: !user.isConnected, + }, + "nameOthers", + ); + + const statusIndicatorCSS = classNames( + { + ["statusIndicatorOnline"]: user.isConnected, + ["inactiveBackground"]: !user.isConnected, + }, + "statusIndicator", + ); + + const avatarsElement = document.getElementById('avatars') + avatarsElement.style.right = rightOffset + avatarsElement.style.zIndex = usersCount - index + + const avatar = document.createElement('div') + avatar.className = 'avatar' + avatar.style.backgroundColor = user.isConnected + ? user.profileData.memberColor + : "#C6CED9"; + avatar.setAttribute('data-member-id', user.clientId); + + const popup = document.createElement('div'); + popup.className = 'popup'; + popup.style.display = 'none'; + + const userInfo = createUserInfo(user) + popup.appendChild(userInfo); + + avatar.appendChild(popup); + + avatar.addEventListener('mouseover', function() { + popup.style.display = 'block' + }); + + avatar.addEventListener('mouseleave', function() { + popup.style.display = 'none' + }); + + const initials = document.createElement('p') + initials.className = initialsCSS + initials.textContent = userInitials + + const statusIndicator = document.createElement('div') + statusIndicator.className = statusIndicatorCSS + statusIndicator.id = 'status-indicator' + + avatarsElement.appendChild(avatar) + avatar.appendChild(initials) + avatar.appendChild(statusIndicator) +} + +async function getOtherAvatars(otherMembers) { + const usersCount = otherMembers.length + + {otherMembers.map((user, index) => { + addAvatar(user, usersCount, index) + })} +} + +function createUserInfo(user, isSelf = false) { + const userDiv = document.createElement('div') + userDiv.className = 'user' + + const wrapper = document.createElement('div'); + wrapper.className = 'wrapper'; + userDiv.appendChild(wrapper); + + const initials = user.profileData.name + .split(" ") + .map(word => word.charAt(0)) + .join(""); + + const statusIndicatorText = user.isConnected + ? "Online" + : "Last seen " + dayjs().to(user.lastEvent.timestamp); + + const name = isSelf + ? `${user.profileData.name} (You)` + : user.profileData.name; + + const userInfoContainer = document.createElement('div'); + userInfoContainer.className = 'userInfoContainer'; + userInfoContainer.style.backgroundColor = user.isConnected + ? user.profileData.memberColor + : "rgb(229 231 235)"; + userInfoContainer.id = 'avatar'; + wrapper.appendChild(userInfoContainer) + + const initialsElement = document.createElement('p'); + initialsElement.className = 'smallText'; + initialsElement.style.color = user.isConnected ? "#fff" : "rgb(156 163 175)"; + initialsElement.textContent = initials; + + userInfoContainer.appendChild(initialsElement); + + const userListContainer = document.createElement('div'); + userListContainer.className = 'userList'; + userListContainer.id = 'user-list'; + + const nameElement = document.createElement('p'); + nameElement.className = 'name'; + nameElement.textContent = name; + + const statusWrapper = document.createElement('div'); + statusWrapper.className = 'wrapper'; + + const statusIndicatorTextElement = document.createElement('p'); + statusIndicatorTextElement.className = 'statusIndicatorText'; + statusIndicatorTextElement.textContent = statusIndicatorText; + + statusWrapper.appendChild(statusIndicatorTextElement); + + userListContainer.appendChild(nameElement); + userListContainer.appendChild(statusWrapper); + + wrapper.appendChild(userInfoContainer); + wrapper.appendChild(userListContainer); + + return userDiv; +} + +async function getSurplusAvatars(otherUsers) { + let showList = false; + + if (otherUsers.length > MAX_USERS_BEFORE_LIST) { + const surplusContainer = document.createElement('div'); + surplusContainer.className = 'surplusContainer'; + + const badge = document.createElement('div'); + badge.className = 'badge'; + badge.style.zIndex = otherUsers.length + 50; + badge.textContent = `+${otherUsers.slice(MAX_USERS_BEFORE_LIST).length}`; + surplusContainer.appendChild(badge); + + const listContainer = document.createElement('div'); + listContainer.className = 'list'; + listContainer.style.display = 'none'; + otherUsers.slice(MAX_USERS_BEFORE_LIST).forEach(user => { + const userDiv = createUserInfo(user) + listContainer.appendChild(userDiv); + }); + surplusContainer.appendChild(listContainer); + + badge.addEventListener('mouseover', () => { + listContainer.style.display = 'block' + }); + + badge.addEventListener('mouseleave', () => { + listContainer.style.display = 'none' + }); + + if (otherUsers.length > MAX_USERS_BEFORE_LIST) { + document.getElementById("avatars").appendChild(surplusContainer); + } + } +} + +const otherMembers = await space.members.getOthers() +document.getElementById('avatars').style.width = calculateTotalWidth(otherMembers) diff --git a/examples/vanilla-avatar-stack/styles.css b/examples/vanilla-avatar-stack/styles.css new file mode 100644 index 0000000..04fdb63 --- /dev/null +++ b/examples/vanilla-avatar-stack/styles.css @@ -0,0 +1,471 @@ +html { + line-height: 1.5; + -webkit-text-size-adjust: 100%; + -moz-tab-size: 4; + -o-tab-size: 4; + tab-size: 4; + font-family: Inter, ui-sans-serif, system-ui; +} + +body { + margin: 0; + line-height: inherit; +} + +hr { + height: 0; + color: inherit; + border-top-width: 1px; +} + +abbr:where([title]) { + -webkit-text-decoration: underline dotted; + text-decoration: underline dotted; +} + +h1, +h2, +h3, +h4, +h5, +h6 { + font-size: inherit; + font-weight: inherit; +} + +a { + color: inherit; + text-decoration: inherit; +} + +b, +strong { + font-weight: bolder; +} + +code, +kbd, +samp, +pre { + font-family: + ui-monospace, + SFMono-Regular, + Menlo, + Monaco, + Consolas, + Liberation Mono, + Courier New, + monospace; + font-size: 1em; +} + +small { + font-size: 80%; +} + +sub, +sup { + font-size: 75%; + line-height: 0; + position: relative; + vertical-align: baseline; +} + +sub { + bottom: -0.25em; +} + +sup { + top: -0.5em; +} + +table { + text-indent: 0; + border-color: inherit; + border-collapse: collapse; +} + +button, +input, +optgroup, +select, +textarea { + font-family: inherit; + font-size: 100%; + font-weight: inherit; + line-height: inherit; + color: inherit; + margin: 0; + padding: 0; +} + +button, +select { + text-transform: none; +} + +button, +[type="button"], +[type="reset"], +[type="submit"] { + -webkit-appearance: button; + background-color: transparent; + background-image: none; +} + +:-moz-focusring { + outline: auto; +} + +:-moz-ui-invalid { + box-shadow: none; +} + +progress { + vertical-align: baseline; +} + +::-webkit-inner-spin-button, +::-webkit-outer-spin-button { + height: auto; +} + +[type="search"] { + -webkit-appearance: textfield; + outline-offset: -2px; +} + +::-webkit-search-decoration { + -webkit-appearance: none; +} + +::-webkit-file-upload-button { + -webkit-appearance: button; + font: inherit; +} + +summary { + display: list-item; +} + +blockquote, +dl, +dd, +h1, +h2, +h3, +h4, +h5, +h6, +hr, +figure, +p, +pre { + margin: 0; +} + +fieldset { + margin: 0; + padding: 0; +} + +legend { + padding: 0; +} + +ol, +ul, +menu { + list-style: none; + margin: 0; + padding: 0; +} + +textarea { + resize: vertical; +} + +input::-moz-placeholder, +textarea::-moz-placeholder { + opacity: 1; + color: #9ca3af; +} + +input::placeholder, +textarea::placeholder { + opacity: 1; + color: #9ca3af; +} + +button, +[role="button"] { + cursor: pointer; +} + +:disabled { + cursor: default; +} + +img, +svg, +video, +canvas, +audio, +iframe, +embed, +object { + display: block; + vertical-align: middle; +} + +img, +video { + max-width: 100%; + height: auto; +} + +*, +:before, +:after { + box-sizing: border-box; + border-width: 0; + border-style: solid; + border-color: currentColor; +} + + +/* #app { + display: flex; + justify-content: center; + align-items: center; + height: 100vh; +} + +#avatar-stack { + display: flex; + flex-wrap: wrap; + max-width: 300px; +} + +.avatar { + width: 40px; + height: 40px; + border-radius: 50%; + display: flex; + justify-content: center; + align-items: center; + color: white; + font-weight: bold; + margin: 5px; + box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2); +} */ + +/** AVATARS **/ + +.avatarsContainer { + position: relative; + display: flex; +} + +.avatarContainer { + position: absolute; + right: 0; + display: flex; + flex-direction: column; + align-items: center; +} + +.avatar { + background-color: rgb(234 88 12); + height: 3rem; + width: 3rem; + border-radius: 9999px; + display: flex; + align-items: center; + justify-content: center; + position: relative; + border: 2px solid #e2e7ef; +} + +.name { + font-size: 0.75rem; + line-height: 1rem; + color: rgb(255 255 255); +} + +.statusIndicator, +.statusIndicatorOnline { + width: 10px; + height: 10px; + border-radius: 9999px; + border: 1.5px solid #e2e7ef; + position: absolute; + bottom: 0.3rem; + left: -0.2rem; + transform: translateY(50%) translateX(50%); +} + +.popup { + position: absolute; + top: 4rem; + padding: 1rem; + background-color: #000; + border-radius: 8px; + color: #fff; + min-width: 240px; +} + +.nameOthers { + z-index: 20; + font-size: 0.75rem; +} + +.statusIndicatorOnline { + background-color: #10b981; +} + +.textWhite { + color: #fff; +} + +.inactiveColor { + color: rgb(156 163 175); +} + +.inactiveBackground { + background-color: rgb(156 163 175); +} + +/** END AVATARS **/ + +/** SURPLUS **/ + +.surplusContainer { + right: 0; + display: flex; + flex-direction: column; + align-items: center; + position: absolute; +} + +.badge { + display: flex; + justify-content: center; + align-items: center; + position: absolute; + right: 0; + color: #fff; + font-size: 0.875rem; + background-color: #718096; + border: 2px solid #cbd5e0; + height: 3rem; + width: 3rem; + border-radius: 9999px; + margin-bottom: 0.5rem; + user-select: none; +} + +.list { + max-height: 70px; + overflow-y: auto; + padding: 0.5rem; + position: relative; + top: 3.5rem; + left: 1.5rem; + min-width: 280px; + max-height: 250px; + left: 6rem; + background-color: #39414e; + border-radius: 8px; + color: #fff; +} + +.user { + padding: 0.5rem; +} + +.user:hover { + background-color: #4a5568; + border-radius: 8px; +} + +@media screen and (min-width: 768px) { + .user { + padding: 0.75rem; + } +} + +/** END SURPLUS **/ + +/** USER INFO **/ + +.userInfoContainer { + height: 2rem; + width: 2rem; + border-radius: 9999px; + display: flex; + flex-shrink: 0; + align-items: center; + justify-content: center; + position: relative; + border: 2px solid #cbd5e0; +} + +.statusIndicator { + width: 10px; + height: 10px; + border-radius: 9999px; +} + +.wrapper { + display: flex; + justify-content: flex-start; + align-items: center; +} + +.userList { + padding-left: 0.75rem; + width: 100%; +} + +.name { + display: block; + font-weight: 600; + font-size: 0.875rem; + margin: 0 0 2px 0; +} + +.statusIndicatorText { + font-weight: 500; + font-size: 0.75rem; + margin: 0 0 0 0.3rem; + color: #89929f; +} + +.smallText { + font-size: 0.75rem; +} + +/** END USER INFO **/ + +.example-container { + display: flex; + position: relative; + justify-content: center; + align-items: center; + border-radius: 1rem; + background-color: #f4f8fb; + height: auto; + width: 100%; +} + +.avatarStackContainer { + width: 100%; + display: flex; + justify-content: center; + align-items: center; + position: relative; + background-color: #f4f8fb; + height: 100vh; +} + diff --git a/examples/vanilla-avatar-stack/tsconfig.json b/examples/vanilla-avatar-stack/tsconfig.json new file mode 100644 index 0000000..bf03b41 --- /dev/null +++ b/examples/vanilla-avatar-stack/tsconfig.json @@ -0,0 +1,26 @@ +{ + "compilerOptions": { + "target": "ESNext", + "useDefineForClassFields": true, + "lib": ["DOM", "DOM.Iterable", "ESNext"], + "allowJs": false, + "skipLibCheck": true, + "esModuleInterop": false, + "allowSyntheticDefaultImports": true, + "strict": true, + "forceConsistentCasingInFileNames": true, + "module": "ESNext", + "moduleResolution": "Node", + "resolveJsonModule": true, + "isolatedModules": true, + "noEmit": true, + "jsx": "react-jsx" + }, + "types": ["vite/client"], + "include": ["src"], + "references": [ + { + "path": "./tsconfig.node.json" + } + ] + } diff --git a/examples/vanilla-avatar-stack/tsconfig.node.json b/examples/vanilla-avatar-stack/tsconfig.node.json new file mode 100644 index 0000000..cdd5821 --- /dev/null +++ b/examples/vanilla-avatar-stack/tsconfig.node.json @@ -0,0 +1,8 @@ +{ + "compilerOptions": { + "composite": true, + "module": "esnext", + "moduleResolution": "node" + }, + "include": ["vite.config.ts"] + } diff --git a/examples/vanilla-avatar-stack/vite.config.ts b/examples/vanilla-avatar-stack/vite.config.ts new file mode 100644 index 0000000..3c2f3df --- /dev/null +++ b/examples/vanilla-avatar-stack/vite.config.ts @@ -0,0 +1,7 @@ +import { defineConfig } from 'vite'; +import react from '@vitejs/plugin-react'; + +export default defineConfig({ + plugins: [react()], + publicDir: 'public', +}); diff --git a/src/main.tsx b/src/main.tsx index 7fa513d..d68ebf2 100644 --- a/src/main.tsx +++ b/src/main.tsx @@ -13,7 +13,7 @@ import EmojiReactions from "./routes/EmojiReactions"; import UserClaims from "./routes/UserClaims"; import MemberLocation from "./routes/MemberLocation"; import ComponentLocking from "./routes/ComponentLocking"; -// import VanillaAvatarStack from "./routes/VanillaAvatarStack"; +import VanillaAvatarStack from "./routes/VanillaAvatarStack"; import ViteReactAvatarStack from "./routes/ViteReactAvatarStack"; import "./styles/global.css"; @@ -52,7 +52,7 @@ ReactDOM.createRoot(document.getElementById("root")!).render( /> } /> } /> - {/* } /> */} + } /> } /> diff --git a/src/routes/Home.tsx b/src/routes/Home.tsx index 3a1167e..01204a6 100644 --- a/src/routes/Home.tsx +++ b/src/routes/Home.tsx @@ -31,9 +31,9 @@ const Home = () => {
  • User Claims
  • - {/*
  • +
  • Avatar Stack - Vanilla JS -
  • */} +
  • Avatar Stack - React
  • From 8f664fc20312109248bf362019f6b92918429de6 Mon Sep 17 00:00:00 2001 From: Greg Holmes Date: Thu, 27 Jun 2024 15:13:25 +0100 Subject: [PATCH 04/19] fixup! Introduced vite-react-avatar-stack --- src/routes/JavascriptTemplate.tsx | 28 ---------------------------- 1 file changed, 28 deletions(-) delete mode 100644 src/routes/JavascriptTemplate.tsx diff --git a/src/routes/JavascriptTemplate.tsx b/src/routes/JavascriptTemplate.tsx deleted file mode 100644 index 7784d12..0000000 --- a/src/routes/JavascriptTemplate.tsx +++ /dev/null @@ -1,28 +0,0 @@ -import { useEffect } from "react"; -import { useOutletContext } from "react-router-dom"; - -import type { ProjectInfo } from "../utils/types"; -import AvatarStack from "../../examples/vite-avatar-stack/src/App"; -import Spaces from "@ably/spaces"; - -const Project = ({ spaces }: { spaces: Spaces }) => { - const { setProjectInfo } = useOutletContext<{ - setProjectInfo: (projectInfo: ProjectInfo) => void; - }>(); - - useEffect(() => { - setProjectInfo({ - name: "Avatar stack", - docsLink: "https://ably.com/docs/spaces/avatar", - repoNameAndPath: "realtime-examples/tree/main/examples/vite-avatar-stack", - topic: "avatar-stack", - learnMore: true, - description: - "See your online presence in a space displayed as an Avatar. Open in a new window or share the link to see multiple users.", - }); - }, []); - - return ; -}; - -export default Project; From c4bd1b03ecaee080825cd1748ca839c4fcf79657 Mon Sep 17 00:00:00 2001 From: Greg Holmes Date: Wed, 31 Jul 2024 14:18:59 +0100 Subject: [PATCH 05/19] Updates to DR examples --- examples/vanilla-avatar-stack/script.js | 84 +------------------ examples/vanilla-avatar-stack/styles.css | 59 ------------- .../src/components/Avatars.tsx | 50 ----------- .../src/hooks/useClickOutsideList.ts | 34 -------- 4 files changed, 3 insertions(+), 224 deletions(-) delete mode 100644 examples/vite-react-avatar-stack/src/hooks/useClickOutsideList.ts diff --git a/examples/vanilla-avatar-stack/script.js b/examples/vanilla-avatar-stack/script.js index 6582da5..14ed0ad 100644 --- a/examples/vanilla-avatar-stack/script.js +++ b/examples/vanilla-avatar-stack/script.js @@ -1,11 +1,8 @@ import Spaces from '@ably/spaces' import { Realtime } from 'ably' import { nanoid } from 'nanoid' -import { generate } from "random-words"; import classNames from "classnames"; -import dayjs from "dayjs"; -const REMOVE_USER_AFTER_MILLIS = 120_000; const MAX_USERS_BEFORE_LIST = 4; const HORIZONTAL_SPACING_OFFSET = 40; const OVERLAP_AMOUNT = 40; @@ -15,26 +12,11 @@ const client = new Realtime.Promise({ clientId: nanoid(), key: import.meta.env.VITE_ABLY_KEY, }) + const spaces = new Spaces(client) -// TODO: Update this to call getSpaceNameFromUrl() const space = await spaces.get('avatar-stack') - const avatarStack = document.getElementById('avatar-stack') -function getSpaceNameFromUrl() { - const url = new URL(window.location.href); - const spaceNameInParams = url.searchParams.get("space"); - - if (spaceNameInParams) { - return spaceNameInParams; - } else { - const generatedName = generate({ exactly: 3, join: "-" }); - url.searchParams.set("space", generatedName); - window.history.replaceState({}, "", `?${url.searchParams.toString()}`); - return generatedName; - } -}; - function calculateRightOffset(options) { const { usersCount, index = 0 } = options; @@ -50,17 +32,8 @@ function calculateTotalWidth(users) { ); } -const mockNames = [ - "Anum Reeve", - "Tiernan Stubbs", - "Hakim Hernandez", -] - -const mockColors = [ - "#9951F5", - "#1BF5C3", - "#F54A4A", -] +const mockNames = ["Anum Reeve", "Tiernan Stubbs", "Hakim Hernandez"] +const mockColors = ["#9951F5", "#1BF5C3", "#F54A4A"] await space.enter({ name: mockNames[Math.floor(Math.random() * mockNames.length)], @@ -70,7 +43,6 @@ await space.enter({ await getMyAvatar() getOtherAvatars(otherMembers.slice(0, MAX_USERS_BEFORE_LIST).reverse()) - getSurplusAvatars(otherMembers) }).catch((err) => { console.error('Error joining space:', err); }) @@ -230,10 +202,6 @@ function createUserInfo(user, isSelf = false) { .map(word => word.charAt(0)) .join(""); - const statusIndicatorText = user.isConnected - ? "Online" - : "Last seen " + dayjs().to(user.lastEvent.timestamp); - const name = isSelf ? `${user.profileData.name} (You)` : user.profileData.name; @@ -261,17 +229,7 @@ function createUserInfo(user, isSelf = false) { nameElement.className = 'name'; nameElement.textContent = name; - const statusWrapper = document.createElement('div'); - statusWrapper.className = 'wrapper'; - - const statusIndicatorTextElement = document.createElement('p'); - statusIndicatorTextElement.className = 'statusIndicatorText'; - statusIndicatorTextElement.textContent = statusIndicatorText; - - statusWrapper.appendChild(statusIndicatorTextElement); - userListContainer.appendChild(nameElement); - userListContainer.appendChild(statusWrapper); wrapper.appendChild(userInfoContainer); wrapper.appendChild(userListContainer); @@ -279,41 +237,5 @@ function createUserInfo(user, isSelf = false) { return userDiv; } -async function getSurplusAvatars(otherUsers) { - let showList = false; - - if (otherUsers.length > MAX_USERS_BEFORE_LIST) { - const surplusContainer = document.createElement('div'); - surplusContainer.className = 'surplusContainer'; - - const badge = document.createElement('div'); - badge.className = 'badge'; - badge.style.zIndex = otherUsers.length + 50; - badge.textContent = `+${otherUsers.slice(MAX_USERS_BEFORE_LIST).length}`; - surplusContainer.appendChild(badge); - - const listContainer = document.createElement('div'); - listContainer.className = 'list'; - listContainer.style.display = 'none'; - otherUsers.slice(MAX_USERS_BEFORE_LIST).forEach(user => { - const userDiv = createUserInfo(user) - listContainer.appendChild(userDiv); - }); - surplusContainer.appendChild(listContainer); - - badge.addEventListener('mouseover', () => { - listContainer.style.display = 'block' - }); - - badge.addEventListener('mouseleave', () => { - listContainer.style.display = 'none' - }); - - if (otherUsers.length > MAX_USERS_BEFORE_LIST) { - document.getElementById("avatars").appendChild(surplusContainer); - } - } -} - const otherMembers = await space.members.getOthers() document.getElementById('avatars').style.width = calculateTotalWidth(otherMembers) diff --git a/examples/vanilla-avatar-stack/styles.css b/examples/vanilla-avatar-stack/styles.css index 04fdb63..9d51873 100644 --- a/examples/vanilla-avatar-stack/styles.css +++ b/examples/vanilla-avatar-stack/styles.css @@ -338,65 +338,6 @@ video { /** END AVATARS **/ -/** SURPLUS **/ - -.surplusContainer { - right: 0; - display: flex; - flex-direction: column; - align-items: center; - position: absolute; -} - -.badge { - display: flex; - justify-content: center; - align-items: center; - position: absolute; - right: 0; - color: #fff; - font-size: 0.875rem; - background-color: #718096; - border: 2px solid #cbd5e0; - height: 3rem; - width: 3rem; - border-radius: 9999px; - margin-bottom: 0.5rem; - user-select: none; -} - -.list { - max-height: 70px; - overflow-y: auto; - padding: 0.5rem; - position: relative; - top: 3.5rem; - left: 1.5rem; - min-width: 280px; - max-height: 250px; - left: 6rem; - background-color: #39414e; - border-radius: 8px; - color: #fff; -} - -.user { - padding: 0.5rem; -} - -.user:hover { - background-color: #4a5568; - border-radius: 8px; -} - -@media screen and (min-width: 768px) { - .user { - padding: 0.75rem; - } -} - -/** END SURPLUS **/ - /** USER INFO **/ .userInfoContainer { diff --git a/examples/vite-react-avatar-stack/src/components/Avatars.tsx b/examples/vite-react-avatar-stack/src/components/Avatars.tsx index ab412c8..3ebf98c 100644 --- a/examples/vite-react-avatar-stack/src/components/Avatars.tsx +++ b/examples/vite-react-avatar-stack/src/components/Avatars.tsx @@ -3,7 +3,6 @@ import classNames from "classnames"; import { FunctionComponent } from "react"; import dayjs from "dayjs"; import relativeTime from "dayjs/plugin/relativeTime"; -import useClickOutsideList from "../hooks/useClickOutsideList"; import { MAX_USERS_BEFORE_LIST, @@ -126,58 +125,11 @@ const UserInfo: FunctionComponent<{ user: Member; isSelf?: boolean }> = ({ {/* 💡 Display the name of the user from the `profileData` object 💡 */}

    {name}

    -
    -
    -

    {statusIndicatorText}

    -
    ); }; -const Surplus: FunctionComponent<{ otherUsers: Member[] }> = ({ - otherUsers, -}) => { - const [showList, setShowList] = useState(false); - const { listRef, plusButtonRef } = useClickOutsideList(() => - setShowList(false), - ); - - return otherUsers.length > MAX_USERS_BEFORE_LIST ? ( -
    -
    { - setShowList(!showList); - }} - > - +{otherUsers.slice(MAX_USERS_BEFORE_LIST).length} -
    - - {showList ? ( -
    - {otherUsers.slice(MAX_USERS_BEFORE_LIST).map((user) => ( -
    - -
    - ))} -
    - ) : null} -
    - ) : null; -}; - const Avatars = ({ otherUsers, self, @@ -208,8 +160,6 @@ const Avatars = ({ usersCount={otherUsers.length} users={otherUsers.slice(0, MAX_USERS_BEFORE_LIST).reverse()} /> - {/** 💡 Dropdown list of surplus users 💡 */} -
    ); }; diff --git a/examples/vite-react-avatar-stack/src/hooks/useClickOutsideList.ts b/examples/vite-react-avatar-stack/src/hooks/useClickOutsideList.ts deleted file mode 100644 index c30ad84..0000000 --- a/examples/vite-react-avatar-stack/src/hooks/useClickOutsideList.ts +++ /dev/null @@ -1,34 +0,0 @@ -import { useEffect, useRef } from "react"; - -const useClickOutsideList = (callback: () => void) => { - const listRef = useRef(null); - const plusButtonRef = useRef(null); - - // 💡 Handler to click outside user list - useEffect(() => { - const listener = (event: MouseEvent | TouchEvent) => { - if ( - !listRef.current || - listRef.current.contains(event.target as Node) || - !plusButtonRef.current || - plusButtonRef.current.contains(event.target as Node) - ) { - return; - } - - callback(); - }; - - document.addEventListener("mousedown", listener); - document.addEventListener("touchstart", listener); - - return () => { - document.removeEventListener("mousedown", listener); - document.removeEventListener("touchstart", listener); - }; - }, [listRef, plusButtonRef]); - - return { listRef, plusButtonRef }; -}; - -export default useClickOutsideList; From be5b90618acab02bb3bab833d7a5ff9e71f071ba Mon Sep 17 00:00:00 2001 From: Greg Holmes Date: Fri, 2 Aug 2024 09:16:37 +0100 Subject: [PATCH 06/19] Add second revision of react avatar stack example --- .../.codesandbox/Dockerfile | 1 + .../vite-react-avatar-stack-2/.env.example | 2 + examples/vite-react-avatar-stack-2/.gitignore | 26 + examples/vite-react-avatar-stack-2/README.md | 39 + .../vite-react-avatar-stack-2/favicon.ico | Bin 0 -> 3262 bytes .../images/avatar-stack.png | Bin 0 -> 29528 bytes examples/vite-react-avatar-stack-2/index.html | 24 + .../vite-react-avatar-stack-2/package.json | 29 + .../vite-react-avatar-stack-2/src/App.tsx | 74 ++ .../src/components/Avatar.tsx | 75 ++ .../vite-react-avatar-stack-2/src/env.d.ts | 5 + .../vite-react-avatar-stack-2/src/index.tsx | 25 + .../src/styles/avatars.css | 79 ++ .../src/styles/global.css | 234 ++++ .../tailwind.config.js | 132 +++ .../vite-react-avatar-stack-2/tsconfig.json | 26 + .../tsconfig.node.json | 8 + .../vite-react-avatar-stack-2/vite.config.ts | 7 + examples/vite-react-avatar-stack-2/yarn.lock | 996 ++++++++++++++++++ src/main.tsx | 2 + src/routes/ViteReactAvatarStack2.tsx | 28 + 21 files changed, 1812 insertions(+) create mode 100644 examples/vite-react-avatar-stack-2/.codesandbox/Dockerfile create mode 100644 examples/vite-react-avatar-stack-2/.env.example create mode 100644 examples/vite-react-avatar-stack-2/.gitignore create mode 100644 examples/vite-react-avatar-stack-2/README.md create mode 100644 examples/vite-react-avatar-stack-2/favicon.ico create mode 100644 examples/vite-react-avatar-stack-2/images/avatar-stack.png create mode 100644 examples/vite-react-avatar-stack-2/index.html create mode 100644 examples/vite-react-avatar-stack-2/package.json create mode 100644 examples/vite-react-avatar-stack-2/src/App.tsx create mode 100644 examples/vite-react-avatar-stack-2/src/components/Avatar.tsx create mode 100644 examples/vite-react-avatar-stack-2/src/env.d.ts create mode 100644 examples/vite-react-avatar-stack-2/src/index.tsx create mode 100644 examples/vite-react-avatar-stack-2/src/styles/avatars.css create mode 100644 examples/vite-react-avatar-stack-2/src/styles/global.css create mode 100644 examples/vite-react-avatar-stack-2/tailwind.config.js create mode 100644 examples/vite-react-avatar-stack-2/tsconfig.json create mode 100644 examples/vite-react-avatar-stack-2/tsconfig.node.json create mode 100644 examples/vite-react-avatar-stack-2/vite.config.ts create mode 100644 examples/vite-react-avatar-stack-2/yarn.lock create mode 100644 src/routes/ViteReactAvatarStack2.tsx diff --git a/examples/vite-react-avatar-stack-2/.codesandbox/Dockerfile b/examples/vite-react-avatar-stack-2/.codesandbox/Dockerfile new file mode 100644 index 0000000..3739923 --- /dev/null +++ b/examples/vite-react-avatar-stack-2/.codesandbox/Dockerfile @@ -0,0 +1 @@ +FROM node:18-bullseye \ No newline at end of file diff --git a/examples/vite-react-avatar-stack-2/.env.example b/examples/vite-react-avatar-stack-2/.env.example new file mode 100644 index 0000000..dbcc501 --- /dev/null +++ b/examples/vite-react-avatar-stack-2/.env.example @@ -0,0 +1,2 @@ +# Use your own API KEY from Ably here: +VITE_ABLY_KEY= diff --git a/examples/vite-react-avatar-stack-2/.gitignore b/examples/vite-react-avatar-stack-2/.gitignore new file mode 100644 index 0000000..26a3ac4 --- /dev/null +++ b/examples/vite-react-avatar-stack-2/.gitignore @@ -0,0 +1,26 @@ +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +pnpm-debug.log* +lerna-debug.log* + +.env + +node_modules +dist +dist-ssr +*.local + +# Editor directories and files +.vscode/* +!.vscode/extensions.json +.idea +.DS_Store +*.suo +*.ntvs* +*.njsproj +*.sln +*.sw? diff --git a/examples/vite-react-avatar-stack-2/README.md b/examples/vite-react-avatar-stack-2/README.md new file mode 100644 index 0000000..76a4c5a --- /dev/null +++ b/examples/vite-react-avatar-stack-2/README.md @@ -0,0 +1,39 @@ +## Overview + +![Avatar stack Start screen](./images/avatar-stack.png) + +This folder contains the code for the Avatar stack - a demo of how you can leverage [Ably Spaces](https://github.com/ably/spaces) to show a list of currently online users. + +Try out the [live demo](https://examples.ably.dev/avatar-stack) of the Avatar stack. + +## Running locally + +- Fork or clone the [example](https://github.com/ably-labs/realtime-examples/examples/vite-react-avatar-stack). +- Sign up for an account on [Ably](https://ably.com/sign-up?utm_source=ably-labs&utm_medium=github&utm_campaign=avatar-stack) and get an API KEY. +- Rename `.env.example` to `.env` and fill in your API KEY in the `VITE_ABLY_KEY` environment variable. +- Run `yarn` to install dependencies. +- Run `yarn dev` and go to http://localhost:5173 + +## Runtime Requirements + +- [Node.js](https://nodejs.org/en/) +- Ably API Key +- [Yarn](https://yarnpkg.com/) + +## Resources + +- Learn more about how to build your own [Avatar stack](https://ably.com/examples/avatar-stack?utm_source=ably-labs&utm_medium=github&utm_campaign=avatar-stack). +- To see what else is possible with Ably check out our other [realtime examples](https://ably.com/examples?utm_source=ably-labs&utm_medium=github&utm_campaign=avatar-stack). + +## Support, feedback and troubleshooting + +- [Create a GitHub Issue](https://github.com/ably-labs/realtime-examples/issues) +- [Ably Spaces On GitHub](https://github.com/ably/spaces) +- [Join our Discord server](https://discord.gg/q89gDHZcBK) +- [Follow us on Twitter](https://twitter.com/ablyrealtime) +- [Use our SDKs](https://github.com/ably/) +- [Visit our website](https://ably.com?utm_source=ably-labs&utm_medium=github&utm_campaign=avatar-stack) + +--- + +[![Ably logo](https://static.ably.dev/badge-black.svg?serverless-websockets-quest)](https://ably.com?utm_source=ably-labs&utm_medium=github&utm_campaign=avatar-stack) diff --git a/examples/vite-react-avatar-stack-2/favicon.ico b/examples/vite-react-avatar-stack-2/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..483a4b24839316fea296e21ba293daf7476412d1 GIT binary patch literal 3262 zcmeH{*-{fh6o!W+lgvJonL)uV5e34&3b>BDqJrSlcmisd zr#liz#(O;8vIrGD`#wpw~;FN;5L#iB%5dCQ$Vza@D74i1S{~D;Vt}hOG>7K^Cf+Y zbOZ4#MC(7zC)^`*MaaP|1z&_W2X_WmqkC7fEuOT=n@Havd5w4-)#r$wbth}zq6PTG zDzZ=V0$c@mr(jRO96hy*hNN3aH<7$Syn*Bu;+Ke@qxuxlV?+-nP96uX2$mImNyy$j z+<7=ta3|qRz;5*Ll_AvJCci-S*$MaqME4QgkrLiA!bNezCz-P6#S@?K2^9@EW3X?Y z62o0X6i@g%Vnr6sPn7IT$l*OX#E?zG6I5g|M3LQDc(ZV+d0fRPoSO)4bn{svAz2wx zCHxU0YNjoB75TPwh*(YK%4#`BVrO8_A*#b6d{ksxBXCD@;N(Xyl_4Y(s|=Az-F~X~ z#1L(@CeOm25)`o#Be1TksOR&AMskLbhTKJP8_sGwGrWc1*pL~pL)>Xt^RjByMYE9W zs9claWS=KeRtIZhh_}>94(T>!Ps5pnHQAXLz9wHqQkFiJx(qE6{PyFy;fxgT!u zGLGl(Drn8aC=bEB0CO-uEw_-zL!4HZu>pHb9PUjshhdU@QOKnQ4CP@Q3yJ9dkOt#D4w#953v{vO0b&j zqTou2{*eBw(s&GIbuq#K4e?N5I2f=oVEqMYK5>YiL%>%;rscw|Ihqe4j|__+C|pNj%wd(t?|Q3^Tpx*r-SC_ x{k`Vb%3kYzSZnQMwWDk&Lw1y**4o9Mj3#h!sK=KtfQ-WfJ(_z!>qAZ@;5!R|Ate9+ literal 0 HcmV?d00001 diff --git a/examples/vite-react-avatar-stack-2/images/avatar-stack.png b/examples/vite-react-avatar-stack-2/images/avatar-stack.png new file mode 100644 index 0000000000000000000000000000000000000000..59e203833dad0ef3c089f7e20274ce9bd2b788cc GIT binary patch literal 29528 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 KOOKqr{yzW{ffpqJ literal 0 HcmV?d00001 diff --git a/examples/vite-react-avatar-stack-2/index.html b/examples/vite-react-avatar-stack-2/index.html new file mode 100644 index 0000000..55a9f12 --- /dev/null +++ b/examples/vite-react-avatar-stack-2/index.html @@ -0,0 +1,24 @@ + + + + + + + + + + + Ably Realtime Examples - Avatar stack + + + +
    + + + diff --git a/examples/vite-react-avatar-stack-2/package.json b/examples/vite-react-avatar-stack-2/package.json new file mode 100644 index 0000000..3c81c26 --- /dev/null +++ b/examples/vite-react-avatar-stack-2/package.json @@ -0,0 +1,29 @@ +{ + "name": "@ably-labs/vite-react-avatar-stack", + "license": "Apache-2.0", + "version": "1.0.0", + "private": true, + "scripts": { + "dev": "vite", + "build": "tsc && vite build", + "preview": "vite preview", + "format": "prettier --write ." + }, + "dependencies": { + "@ably/spaces": "0.2.0", + "ably": "1.2.45", + "classnames": "^2.3.2", + "dayjs": "^1.11.4", + "nanoid": "^5.0.1", + "random-words": "^2.0.0", + "react": "^18.2.0", + "react-dom": "^18.2.0" + }, + "devDependencies": { + "@types/react": "^18.2.0", + "@types/react-dom": "^18.2.0", + "@vitejs/plugin-react": "^4.1.0", + "typescript": "5.2.2", + "vite": "^4.4.9" + } +} diff --git a/examples/vite-react-avatar-stack-2/src/App.tsx b/examples/vite-react-avatar-stack-2/src/App.tsx new file mode 100644 index 0000000..9e941b9 --- /dev/null +++ b/examples/vite-react-avatar-stack-2/src/App.tsx @@ -0,0 +1,74 @@ +import { useMemo, useEffect } from "react"; +import { SpaceProvider, SpacesProvider, useMembers, useSpace } from "@ably/spaces/react"; +import Spaces, { type SpaceMember } from "@ably/spaces"; +import { Avatar } from "./components/Avatar"; +import "./styles/avatars.css"; + +export type Member = Omit & { + profileData: { memberColor: string; name: string }; +}; + +const colors = ["#9951F5", "#f1c232", "#f44336"]; +const mockNames = [ + "Anum Reeve", + "Tiernan Stubbs", + "Hakim Hernandez", +]; + +function Example() { + const name = useMemo(() => { + return mockNames[Math.floor(Math.random() * mockNames.length)]; + }, []); + const memberColor = useMemo(() => { + return colors[Math.floor(Math.random() * colors.length)]; + }, []); + + const { space } = useSpace(); + + useEffect(() => { + space?.enter({ name, memberColor }); + }, [space]); + + const { others, self } = useMembers(); + const hasMoreUsers = others.length > 3; + + return ( +
    +
    + {self && ( +
    + +
    + )} + + {others.slice(0, 4).map(( other ) => { + return ( +
    + +
    + ); + })} + + {hasMoreUsers && +
    +

    +{others.length-4}

    +
    + } +
    +
    + ); +} + +const App = ({ spaces }: { spaces: Spaces }) => ( + + + + + +); + +export default App; diff --git a/examples/vite-react-avatar-stack-2/src/components/Avatar.tsx b/examples/vite-react-avatar-stack-2/src/components/Avatar.tsx new file mode 100644 index 0000000..d50b676 --- /dev/null +++ b/examples/vite-react-avatar-stack-2/src/components/Avatar.tsx @@ -0,0 +1,75 @@ +import { FunctionComponent, useState } from "react"; +import { type SpaceMember } from "@ably/spaces"; +import "../styles/avatars.css"; + +type Member = Omit & { + profileData: { memberColor: string; name: string }; +}; + +const UserInfo: FunctionComponent<{ user: Member; isSelf?: boolean }> = ({ + user, + isSelf, +}) => { + const initials = user.profileData.name + .split(" ") + .map((word: string) => word.charAt(0)) + .join(""); + + const name = isSelf + ? `${user.profileData.name} (You)` + : user.profileData.name; + + return ( +
    +
    +

    + {initials} +

    +
    + +
    +

    {name}

    +
    +
    + ); +}; + +export function Avatar({ user, isSelf }: { user: Member, isSelf: boolean }) { + const [hover, setHover] = useState(false); + + const userInitials = user.profileData.name + .split(" ") + .map((word: string) => word.charAt(0)) + .join(""); + + return ( +
    +
    setHover(true)} + onMouseLeave={() => setHover(true)} + id="avatar" + > +

    {userInitials}

    +
    + {hover && self ? ( +
    + +
    + ) : null} +
    + ); +} diff --git a/examples/vite-react-avatar-stack-2/src/env.d.ts b/examples/vite-react-avatar-stack-2/src/env.d.ts new file mode 100644 index 0000000..e8cfc0d --- /dev/null +++ b/examples/vite-react-avatar-stack-2/src/env.d.ts @@ -0,0 +1,5 @@ +/// + +interface ImportMetaEnv { + readonly VITE_ABLY_KEY: string; +} diff --git a/examples/vite-react-avatar-stack-2/src/index.tsx b/examples/vite-react-avatar-stack-2/src/index.tsx new file mode 100644 index 0000000..b67c491 --- /dev/null +++ b/examples/vite-react-avatar-stack-2/src/index.tsx @@ -0,0 +1,25 @@ +import ReactDOM from "react-dom/client"; +import { AblyProvider } from "ably/react"; +import Spaces from "@ably/spaces"; +import { nanoid } from "nanoid"; +import { Realtime } from "ably"; + +import App from "./App"; + +import "./styles/global.css"; + +const client = new Realtime.Promise({ + clientId: nanoid(), + key: import.meta.env.VITE_ABLY_KEY, +}); + +const spaces = new Spaces(client); + +ReactDOM.createRoot(document.getElementById("root")!).render( + // Mismatch between react-router-dom and latest react + // See https://github.com/remix-run/remix/issues/7514 + // @ts-ignore + + + , +); diff --git a/examples/vite-react-avatar-stack-2/src/styles/avatars.css b/examples/vite-react-avatar-stack-2/src/styles/avatars.css new file mode 100644 index 0000000..2d01f06 --- /dev/null +++ b/examples/vite-react-avatar-stack-2/src/styles/avatars.css @@ -0,0 +1,79 @@ +.avatarStackContainer { + width: 100%; + display: flex; + justify-content: center; + align-items: center; + position: relative; + background-color: #f4f8fb; + height: 100vh; +} + +.avatars { + display: inline-flex; +} + +.avatar { + background-color: rgb(234, 88, 12); + height: 3rem; + width: 3rem; + border-radius: 9999px; + display: flex; + align-items: center; + justify-content: center; + border: 2px solid #e2e7ef; + flex-shrink: 0; + position: relative; + margin-left: -7px; +} + +.name { + font-size: 0.75rem; + line-height: 1rem; + color: rgb(255, 255, 255); +} + +.textWhite { + color: #fff; +} + +.nameOthers { + z-index: 20; + font-size: 0.75rem; +} + +.popup { + position: absolute; + top: 4rem; + padding: 1rem; + background-color: #000; + border-radius: 8px; + color: #fff; + min-width: 240px; +} + +.wrapper { + display: flex; + justify-content: flex-start; + align-items: center; +} + +.userList { + padding-left: 0.75rem; + width: 100%; +} + +.userInfoContainer { + height: 2rem; + width: 2rem; + border-radius: 9999px; + display: flex; + flex-shrink: 0; + align-items: center; + justify-content: center; + position: relative; + border: 2px solid #cbd5e0; +} + +.smallText { + font-size: 0.75rem; +} diff --git a/examples/vite-react-avatar-stack-2/src/styles/global.css b/examples/vite-react-avatar-stack-2/src/styles/global.css new file mode 100644 index 0000000..68e0614 --- /dev/null +++ b/examples/vite-react-avatar-stack-2/src/styles/global.css @@ -0,0 +1,234 @@ +html { + line-height: 1.5; + -webkit-text-size-adjust: 100%; + -moz-tab-size: 4; + -o-tab-size: 4; + tab-size: 4; + font-family: Inter, ui-sans-serif, system-ui; +} + +body { + margin: 0; + line-height: inherit; +} + +hr { + height: 0; + color: inherit; + border-top-width: 1px; +} + +abbr:where([title]) { + -webkit-text-decoration: underline dotted; + text-decoration: underline dotted; +} + +h1, +h2, +h3, +h4, +h5, +h6 { + font-size: inherit; + font-weight: inherit; +} + +a { + color: inherit; + text-decoration: inherit; +} + +b, +strong { + font-weight: bolder; +} + +code, +kbd, +samp, +pre { + font-family: + ui-monospace, + SFMono-Regular, + Menlo, + Monaco, + Consolas, + Liberation Mono, + Courier New, + monospace; + font-size: 1em; +} + +small { + font-size: 80%; +} + +sub, +sup { + font-size: 75%; + line-height: 0; + position: relative; + vertical-align: baseline; +} + +sub { + bottom: -0.25em; +} + +sup { + top: -0.5em; +} + +table { + text-indent: 0; + border-color: inherit; + border-collapse: collapse; +} + +button, +input, +optgroup, +select, +textarea { + font-family: inherit; + font-size: 100%; + font-weight: inherit; + line-height: inherit; + color: inherit; + margin: 0; + padding: 0; +} + +button, +select { + text-transform: none; +} + +button, +[type="button"], +[type="reset"], +[type="submit"] { + -webkit-appearance: button; + background-color: transparent; + background-image: none; +} + +:-moz-focusring { + outline: auto; +} + +:-moz-ui-invalid { + box-shadow: none; +} + +progress { + vertical-align: baseline; +} + +::-webkit-inner-spin-button, +::-webkit-outer-spin-button { + height: auto; +} + +[type="search"] { + -webkit-appearance: textfield; + outline-offset: -2px; +} + +::-webkit-search-decoration { + -webkit-appearance: none; +} + +::-webkit-file-upload-button { + -webkit-appearance: button; + font: inherit; +} + +summary { + display: list-item; +} + +blockquote, +dl, +dd, +h1, +h2, +h3, +h4, +h5, +h6, +hr, +figure, +p, +pre { + margin: 0; +} + +fieldset { + margin: 0; + padding: 0; +} + +legend { + padding: 0; +} + +ol, +ul, +menu { + list-style: none; + margin: 0; + padding: 0; +} + +textarea { + resize: vertical; +} + +input::-moz-placeholder, +textarea::-moz-placeholder { + opacity: 1; + color: #9ca3af; +} + +input::placeholder, +textarea::placeholder { + opacity: 1; + color: #9ca3af; +} + +button, +[role="button"] { + cursor: pointer; +} + +:disabled { + cursor: default; +} + +img, +svg, +video, +canvas, +audio, +iframe, +embed, +object { + display: block; + vertical-align: middle; +} + +img, +video { + max-width: 100%; + height: auto; +} + +*, +:before, +:after { + box-sizing: border-box; + border-width: 0; + border-style: solid; + border-color: currentColor; +} diff --git a/examples/vite-react-avatar-stack-2/tailwind.config.js b/examples/vite-react-avatar-stack-2/tailwind.config.js new file mode 100644 index 0000000..27fa99a --- /dev/null +++ b/examples/vite-react-avatar-stack-2/tailwind.config.js @@ -0,0 +1,132 @@ +/** @type {import('tailwindcss').Config} */ + +module.exports = { + content: ["./index.html", "./src/**/*.{js,ts,jsx,tsx}"], + + safelist: [ + "border-[#9951F5]", + "border-[#7A1BF2]", + "border-[#5F0BC9]", + "border-[#460894]", + "border-[#00E80B]", + "border-[#00C008]", + "border-[#008E06]", + "border-[#FF17D2]", + "border-[#D400AB]", + "border-[#9C007E]", + "border-[#2CC0FF]", + "border-[#00A5EC]", + "border-[#0284CD]", + "border-[#E4B200]", + "border-[#AC8600]", + "bg-[#9951F5]", + "bg-[#7A1BF2]", + "bg-[#5F0BC9]", + "bg-[#460894]", + "bg-[#00E80B]", + "bg-[#00C008]", + "bg-[#008E06]", + "bg-[#FF17D2]", + "bg-[#D400AB]", + "bg-[#9C007E]", + "bg-[#2CC0FF]", + "bg-[#00A5EC]", + "bg-[#0284CD]", + "bg-[#E4B200]", + "bg-[#AC8600]", + ], + + theme: { + colors: { + white: "#FFFFFF", + black: "#000000", + "slate-50": "#F4F8FB", + "slate-100": "#f1f5f9", + "slate-150": "#EDF1F6", + "slate-200": "#e2e8f0", + "slate-250": "#E2E7EF", + "slate-300": "#cbd5e1", + "slate-400": "#94a3b8", + "slate-500": "#64748b", + "slate-600": "#475569", + "slate-700": "#334155", + "slate-800": "#1e293b", + "slate-900": "#0f172a", + "gray-100": "#f3f4f6", + "gray-200": "#e5e7eb", + "gray-300": "#d1d5db", + "gray-325": "#ADB6C2", + "gray-350": "#C6CED9", + "gray-400": "#9ca3af", + "gray-500": "#6b7280", + "gray-600": "#4b5563", + "gray-700": "#374151", + "gray-800": "#1f2937", + "gray-900": "#111827", + "orange-100": "#FFF5F1", + "orange-200": "#FFE3D8", + "orange-300": "#FFC4AE", + "orange-400": "#FF9B79", + "orange-500": "#FF723F", + "orange-600": "#FF5416", + "orange-700": "#FE372B", + "orange-800": "#E40000", + "orange-900": "#B82202", + "orange-1000": "#751500", + "orange-1100": "#2A0B00", + "yellow-100": "#FFFBEF", + "yellow-200": "#FFF0BA", + "yellow-300": "#FFE27C", + "yellow-400": "#FFD43D", + "yellow-500": "#FFC700", + "yellow-600": "#E4B200", + "yellow-700": "#AC8600", + "yellow-800": "#654F00", + "yellow-900": "#291C01", + "green-100": "#F1FFF1", + "green-200": "#B8FFBB", + "green-300": "#80FF85", + "green-400": "#08FF13", + "green-500": "#00E80B", + "green-600": "#00C008", + "green-700": "#008E06", + "green-800": "#005303", + "green-900": "#002A02", + "blue-100": "#F1FBFF", + "blue-200": "#B8EAFF", + "blue-300": "#80D9FF", + "blue-400": "#4AD4FF", + "blue-500": "#2CC0FF", + "blue-600": "#00A5EC", + "blue-700": "#0284CD", + "blue-800": "#004B75", + "blue-900": "#001B2A", + "purple-100": "#F7F2FE", + "purple-200": "#D8BCFB", + "purple-300": "#B986F8", + "purple-400": "#9951F5", + "purple-500": "#7A1BF2", + "purple-600": "#5F0BC9", + "purple-700": "#460894", + "purple-800": "#2D055E", + "purple-900": "#130228", + "pink-100": "#FFF1FC", + "pink-200": "#FFB8F1", + "pink-300": "#FF80E6", + "pink-400": "#FF47DB", + "pink-500": "#FF17D2", + "pink-600": "#D400AB", + "pink-700": "#9C007E", + "pink-800": "#630050", + "pink-900": "#2A0022", + "red-100": "#FFF1F1", + "red-600": "#E40000", + }, + extend: { + fontFamily: { + sans: ["Inter", "ui-sans-serif", "system-ui"], + }, + }, + }, + plugins: [], +}; diff --git a/examples/vite-react-avatar-stack-2/tsconfig.json b/examples/vite-react-avatar-stack-2/tsconfig.json new file mode 100644 index 0000000..b55c9e8 --- /dev/null +++ b/examples/vite-react-avatar-stack-2/tsconfig.json @@ -0,0 +1,26 @@ +{ + "compilerOptions": { + "target": "ESNext", + "useDefineForClassFields": true, + "lib": ["DOM", "DOM.Iterable", "ESNext"], + "allowJs": false, + "skipLibCheck": true, + "esModuleInterop": false, + "allowSyntheticDefaultImports": true, + "strict": true, + "forceConsistentCasingInFileNames": true, + "module": "ESNext", + "moduleResolution": "Node", + "resolveJsonModule": true, + "isolatedModules": true, + "noEmit": true, + "jsx": "react-jsx" + }, + "types": ["vite/client"], + "include": ["src"], + "references": [ + { + "path": "./tsconfig.node.json" + } + ] +} diff --git a/examples/vite-react-avatar-stack-2/tsconfig.node.json b/examples/vite-react-avatar-stack-2/tsconfig.node.json new file mode 100644 index 0000000..e993792 --- /dev/null +++ b/examples/vite-react-avatar-stack-2/tsconfig.node.json @@ -0,0 +1,8 @@ +{ + "compilerOptions": { + "composite": true, + "module": "esnext", + "moduleResolution": "node" + }, + "include": ["vite.config.ts"] +} diff --git a/examples/vite-react-avatar-stack-2/vite.config.ts b/examples/vite-react-avatar-stack-2/vite.config.ts new file mode 100644 index 0000000..9cc50ea --- /dev/null +++ b/examples/vite-react-avatar-stack-2/vite.config.ts @@ -0,0 +1,7 @@ +import { defineConfig } from "vite"; +import react from "@vitejs/plugin-react"; + +// https://vitejs.dev/config/ +export default defineConfig({ + plugins: [react()], +}); diff --git a/examples/vite-react-avatar-stack-2/yarn.lock b/examples/vite-react-avatar-stack-2/yarn.lock new file mode 100644 index 0000000..54f4c81 --- /dev/null +++ b/examples/vite-react-avatar-stack-2/yarn.lock @@ -0,0 +1,996 @@ +# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. +# yarn lockfile v1 + + +"@ably/msgpack-js@^0.4.0": + version "0.4.0" + resolved "https://registry.yarnpkg.com/@ably/msgpack-js/-/msgpack-js-0.4.0.tgz#aaaf5d8dffacf7aa253effd8c3488aa09130e6a2" + integrity sha512-IPt/BoiQwCWubqoNik1aw/6M/DleMdrxJOUpSja6xmMRbT2p1TA8oqKWgfZabqzrq8emRNeSl/+4XABPNnW5pQ== + dependencies: + bops "^1.0.1" + +"@ably/spaces@0.2.0": + version "0.2.0" + resolved "https://registry.yarnpkg.com/@ably/spaces/-/spaces-0.2.0.tgz#ba999c634421e98fb063d443846c8c8d059a77c0" + integrity sha512-s2QE4uzWoS67Sq0z0KTTWlRtvHbCg9FyN+0K/8Agv+hvPY9Fe2r0oozae/Lj2Q2i7oEUiRvoYl37rX9Xk9x+fQ== + dependencies: + nanoid "^5.0.2" + +"@ampproject/remapping@^2.2.0": + version "2.2.1" + resolved "https://registry.yarnpkg.com/@ampproject/remapping/-/remapping-2.2.1.tgz#99e8e11851128b8702cd57c33684f1d0f260b630" + integrity sha512-lFMjJTrFL3j7L9yBxwYfCq2k6qqwHyzuUl/XBnif78PWTJYyL/dfowQHWE3sp6U6ZzqWiiIZnpTMO96zhkjwtg== + dependencies: + "@jridgewell/gen-mapping" "^0.3.0" + "@jridgewell/trace-mapping" "^0.3.9" + +"@babel/code-frame@^7.22.13": + version "7.22.13" + resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.22.13.tgz#e3c1c099402598483b7a8c46a721d1038803755e" + integrity sha512-XktuhWlJ5g+3TJXc5upd9Ks1HutSArik6jf2eAjYFyIOf4ej3RN+184cZbzDvbPnuTJIUhPKKJE3cIsYTiAT3w== + dependencies: + "@babel/highlight" "^7.22.13" + chalk "^2.4.2" + +"@babel/compat-data@^7.22.9": + version "7.22.20" + resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.22.20.tgz#8df6e96661209623f1975d66c35ffca66f3306d0" + integrity sha512-BQYjKbpXjoXwFW5jGqiizJQQT/aC7pFm9Ok1OWssonuguICi264lbgMzRp2ZMmRSlfkX6DsWDDcsrctK8Rwfiw== + +"@babel/core@^7.22.20": + version "7.23.0" + resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.23.0.tgz#f8259ae0e52a123eb40f552551e647b506a94d83" + integrity sha512-97z/ju/Jy1rZmDxybphrBuI+jtJjFVoz7Mr9yUQVVVi+DNZE333uFQeMOqcCIy1x3WYBIbWftUSLmbNXNT7qFQ== + dependencies: + "@ampproject/remapping" "^2.2.0" + "@babel/code-frame" "^7.22.13" + "@babel/generator" "^7.23.0" + "@babel/helper-compilation-targets" "^7.22.15" + "@babel/helper-module-transforms" "^7.23.0" + "@babel/helpers" "^7.23.0" + "@babel/parser" "^7.23.0" + "@babel/template" "^7.22.15" + "@babel/traverse" "^7.23.0" + "@babel/types" "^7.23.0" + convert-source-map "^2.0.0" + debug "^4.1.0" + gensync "^1.0.0-beta.2" + json5 "^2.2.3" + semver "^6.3.1" + +"@babel/generator@^7.23.0": + version "7.23.0" + resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.23.0.tgz#df5c386e2218be505b34837acbcb874d7a983420" + integrity sha512-lN85QRR+5IbYrMWM6Y4pE/noaQtg4pNiqeNGX60eqOfo6gtEj6uw/JagelB8vVztSd7R6M5n1+PQkDbHbBRU4g== + dependencies: + "@babel/types" "^7.23.0" + "@jridgewell/gen-mapping" "^0.3.2" + "@jridgewell/trace-mapping" "^0.3.17" + jsesc "^2.5.1" + +"@babel/helper-compilation-targets@^7.22.15": + version "7.22.15" + resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.22.15.tgz#0698fc44551a26cf29f18d4662d5bf545a6cfc52" + integrity sha512-y6EEzULok0Qvz8yyLkCvVX+02ic+By2UdOhylwUOvOn9dvYc9mKICJuuU1n1XBI02YWsNsnrY1kc6DVbjcXbtw== + dependencies: + "@babel/compat-data" "^7.22.9" + "@babel/helper-validator-option" "^7.22.15" + browserslist "^4.21.9" + lru-cache "^5.1.1" + semver "^6.3.1" + +"@babel/helper-environment-visitor@^7.22.20": + version "7.22.20" + resolved "https://registry.yarnpkg.com/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.20.tgz#96159db61d34a29dba454c959f5ae4a649ba9167" + integrity sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA== + +"@babel/helper-function-name@^7.23.0": + version "7.23.0" + resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.23.0.tgz#1f9a3cdbd5b2698a670c30d2735f9af95ed52759" + integrity sha512-OErEqsrxjZTJciZ4Oo+eoZqeW9UIiOcuYKRJA4ZAgV9myA+pOXhhmpfNCKjEH/auVfEYVFJ6y1Tc4r0eIApqiw== + dependencies: + "@babel/template" "^7.22.15" + "@babel/types" "^7.23.0" + +"@babel/helper-hoist-variables@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/helper-hoist-variables/-/helper-hoist-variables-7.22.5.tgz#c01a007dac05c085914e8fb652b339db50d823bb" + integrity sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw== + dependencies: + "@babel/types" "^7.22.5" + +"@babel/helper-module-imports@^7.22.15": + version "7.22.15" + resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.22.15.tgz#16146307acdc40cc00c3b2c647713076464bdbf0" + integrity sha512-0pYVBnDKZO2fnSPCrgM/6WMc7eS20Fbok+0r88fp+YtWVLZrp4CkafFGIp+W0VKw4a22sgebPT99y+FDNMdP4w== + dependencies: + "@babel/types" "^7.22.15" + +"@babel/helper-module-transforms@^7.23.0": + version "7.23.0" + resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.23.0.tgz#3ec246457f6c842c0aee62a01f60739906f7047e" + integrity sha512-WhDWw1tdrlT0gMgUJSlX0IQvoO1eN279zrAUbVB+KpV2c3Tylz8+GnKOLllCS6Z/iZQEyVYxhZVUdPTqs2YYPw== + dependencies: + "@babel/helper-environment-visitor" "^7.22.20" + "@babel/helper-module-imports" "^7.22.15" + "@babel/helper-simple-access" "^7.22.5" + "@babel/helper-split-export-declaration" "^7.22.6" + "@babel/helper-validator-identifier" "^7.22.20" + +"@babel/helper-plugin-utils@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.22.5.tgz#dd7ee3735e8a313b9f7b05a773d892e88e6d7295" + integrity sha512-uLls06UVKgFG9QD4OeFYLEGteMIAa5kpTPcFL28yuCIIzsf6ZyKZMllKVOCZFhiZ5ptnwX4mtKdWCBE/uT4amg== + +"@babel/helper-simple-access@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/helper-simple-access/-/helper-simple-access-7.22.5.tgz#4938357dc7d782b80ed6dbb03a0fba3d22b1d5de" + integrity sha512-n0H99E/K+Bika3++WNL17POvo4rKWZ7lZEp1Q+fStVbUi8nxPQEBOlTmCOxW/0JsS56SKKQ+ojAe2pHKJHN35w== + dependencies: + "@babel/types" "^7.22.5" + +"@babel/helper-split-export-declaration@^7.22.6": + version "7.22.6" + resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.22.6.tgz#322c61b7310c0997fe4c323955667f18fcefb91c" + integrity sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g== + dependencies: + "@babel/types" "^7.22.5" + +"@babel/helper-string-parser@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/helper-string-parser/-/helper-string-parser-7.22.5.tgz#533f36457a25814cf1df6488523ad547d784a99f" + integrity sha512-mM4COjgZox8U+JcXQwPijIZLElkgEpO5rsERVDJTc2qfCDfERyob6k5WegS14SX18IIjv+XD+GrqNumY5JRCDw== + +"@babel/helper-validator-identifier@^7.22.19", "@babel/helper-validator-identifier@^7.22.20": + version "7.22.20" + resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz#c4ae002c61d2879e724581d96665583dbc1dc0e0" + integrity sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A== + +"@babel/helper-validator-option@^7.22.15": + version "7.22.15" + resolved "https://registry.yarnpkg.com/@babel/helper-validator-option/-/helper-validator-option-7.22.15.tgz#694c30dfa1d09a6534cdfcafbe56789d36aba040" + integrity sha512-bMn7RmyFjY/mdECUbgn9eoSY4vqvacUnS9i9vGAGttgFWesO6B4CYWA7XlpbWgBt71iv/hfbPlynohStqnu5hA== + +"@babel/helpers@^7.23.0": + version "7.23.1" + resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.23.1.tgz#44e981e8ce2b9e99f8f0b703f3326a4636c16d15" + integrity sha512-chNpneuK18yW5Oxsr+t553UZzzAs3aZnFm4bxhebsNTeshrC95yA7l5yl7GBAG+JG1rF0F7zzD2EixK9mWSDoA== + dependencies: + "@babel/template" "^7.22.15" + "@babel/traverse" "^7.23.0" + "@babel/types" "^7.23.0" + +"@babel/highlight@^7.22.13": + version "7.22.20" + resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.22.20.tgz#4ca92b71d80554b01427815e06f2df965b9c1f54" + integrity sha512-dkdMCN3py0+ksCgYmGG8jKeGA/8Tk+gJwSYYlFGxG5lmhfKNoAy004YpLxpS1W2J8m/EK2Ew+yOs9pVRwO89mg== + dependencies: + "@babel/helper-validator-identifier" "^7.22.20" + chalk "^2.4.2" + js-tokens "^4.0.0" + +"@babel/parser@^7.1.0", "@babel/parser@^7.20.7", "@babel/parser@^7.23.0": + version "7.23.0" + resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.23.0.tgz#da950e622420bf96ca0d0f2909cdddac3acd8719" + integrity sha512-vvPKKdMemU85V9WE/l5wZEmImpCtLqbnTvqDS2U1fJ96KrxoW7KrXhNsNCblQlg8Ck4b85yxdTyelsMUgFUXiw== + +"@babel/parser@^7.22.15": + version "7.22.16" + resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.22.16.tgz#180aead7f247305cce6551bea2720934e2fa2c95" + integrity sha512-+gPfKv8UWeKKeJTUxe59+OobVcrYHETCsORl61EmSkmgymguYk/X5bp7GuUIXaFsc6y++v8ZxPsLSSuujqDphA== + +"@babel/plugin-transform-react-jsx-self@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-jsx-self/-/plugin-transform-react-jsx-self-7.22.5.tgz#ca2fdc11bc20d4d46de01137318b13d04e481d8e" + integrity sha512-nTh2ogNUtxbiSbxaT4Ds6aXnXEipHweN9YRgOX/oNXdf0cCrGn/+2LozFa3lnPV5D90MkjhgckCPBrsoSc1a7g== + dependencies: + "@babel/helper-plugin-utils" "^7.22.5" + +"@babel/plugin-transform-react-jsx-source@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-jsx-source/-/plugin-transform-react-jsx-source-7.22.5.tgz#49af1615bfdf6ed9d3e9e43e425e0b2b65d15b6c" + integrity sha512-yIiRO6yobeEIaI0RTbIr8iAK9FcBHLtZq0S89ZPjDLQXBA4xvghaKqI0etp/tF3htTM0sazJKKLz9oEiGRtu7w== + dependencies: + "@babel/helper-plugin-utils" "^7.22.5" + +"@babel/template@^7.22.15": + version "7.22.15" + resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.22.15.tgz#09576efc3830f0430f4548ef971dde1350ef2f38" + integrity sha512-QPErUVm4uyJa60rkI73qneDacvdvzxshT3kksGqlGWYdOTIUOwJ7RDUL8sGqslY1uXWSL6xMFKEXDS3ox2uF0w== + dependencies: + "@babel/code-frame" "^7.22.13" + "@babel/parser" "^7.22.15" + "@babel/types" "^7.22.15" + +"@babel/traverse@^7.23.0": + version "7.23.2" + resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.23.2.tgz#329c7a06735e144a506bdb2cad0268b7f46f4ad8" + integrity sha512-azpe59SQ48qG6nu2CzcMLbxUudtN+dOM9kDbUqGq3HXUJRlo7i8fvPoxQUzYgLZ4cMVmuZgm8vvBpNeRhd6XSw== + dependencies: + "@babel/code-frame" "^7.22.13" + "@babel/generator" "^7.23.0" + "@babel/helper-environment-visitor" "^7.22.20" + "@babel/helper-function-name" "^7.23.0" + "@babel/helper-hoist-variables" "^7.22.5" + "@babel/helper-split-export-declaration" "^7.22.6" + "@babel/parser" "^7.23.0" + "@babel/types" "^7.23.0" + debug "^4.1.0" + globals "^11.1.0" + +"@babel/types@^7.0.0", "@babel/types@^7.20.7", "@babel/types@^7.23.0": + version "7.23.0" + resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.23.0.tgz#8c1f020c9df0e737e4e247c0619f58c68458aaeb" + integrity sha512-0oIyUfKoI3mSqMvsxBdclDwxXKXAUA8v/apZbc+iSyARYou1o8ZGDxbUYyLFoW2arqS2jDGqJuZvv1d/io1axg== + dependencies: + "@babel/helper-string-parser" "^7.22.5" + "@babel/helper-validator-identifier" "^7.22.20" + to-fast-properties "^2.0.0" + +"@babel/types@^7.22.15", "@babel/types@^7.22.5": + version "7.22.19" + resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.22.19.tgz#7425343253556916e440e662bb221a93ddb75684" + integrity sha512-P7LAw/LbojPzkgp5oznjE6tQEIWbp4PkkfrZDINTro9zgBRtI324/EYsiSI7lhPbpIQ+DCeR2NNmMWANGGfZsg== + dependencies: + "@babel/helper-string-parser" "^7.22.5" + "@babel/helper-validator-identifier" "^7.22.19" + to-fast-properties "^2.0.0" + +"@esbuild/android-arm64@0.18.20": + version "0.18.20" + resolved "https://registry.yarnpkg.com/@esbuild/android-arm64/-/android-arm64-0.18.20.tgz#984b4f9c8d0377443cc2dfcef266d02244593622" + integrity sha512-Nz4rJcchGDtENV0eMKUNa6L12zz2zBDXuhj/Vjh18zGqB44Bi7MBMSXjgunJgjRhCmKOjnPuZp4Mb6OKqtMHLQ== + +"@esbuild/android-arm@0.18.20": + version "0.18.20" + resolved "https://registry.yarnpkg.com/@esbuild/android-arm/-/android-arm-0.18.20.tgz#fedb265bc3a589c84cc11f810804f234947c3682" + integrity sha512-fyi7TDI/ijKKNZTUJAQqiG5T7YjJXgnzkURqmGj13C6dCqckZBLdl4h7bkhHt/t0WP+zO9/zwroDvANaOqO5Sw== + +"@esbuild/android-x64@0.18.20": + version "0.18.20" + resolved "https://registry.yarnpkg.com/@esbuild/android-x64/-/android-x64-0.18.20.tgz#35cf419c4cfc8babe8893d296cd990e9e9f756f2" + integrity sha512-8GDdlePJA8D6zlZYJV/jnrRAi6rOiNaCC/JclcXpB+KIuvfBN4owLtgzY2bsxnx666XjJx2kDPUmnTtR8qKQUg== + +"@esbuild/darwin-arm64@0.18.20": + version "0.18.20" + resolved "https://registry.yarnpkg.com/@esbuild/darwin-arm64/-/darwin-arm64-0.18.20.tgz#08172cbeccf95fbc383399a7f39cfbddaeb0d7c1" + integrity sha512-bxRHW5kHU38zS2lPTPOyuyTm+S+eobPUnTNkdJEfAddYgEcll4xkT8DB9d2008DtTbl7uJag2HuE5NZAZgnNEA== + +"@esbuild/darwin-x64@0.18.20": + version "0.18.20" + resolved "https://registry.yarnpkg.com/@esbuild/darwin-x64/-/darwin-x64-0.18.20.tgz#d70d5790d8bf475556b67d0f8b7c5bdff053d85d" + integrity sha512-pc5gxlMDxzm513qPGbCbDukOdsGtKhfxD1zJKXjCCcU7ju50O7MeAZ8c4krSJcOIJGFR+qx21yMMVYwiQvyTyQ== + +"@esbuild/freebsd-arm64@0.18.20": + version "0.18.20" + resolved "https://registry.yarnpkg.com/@esbuild/freebsd-arm64/-/freebsd-arm64-0.18.20.tgz#98755cd12707f93f210e2494d6a4b51b96977f54" + integrity sha512-yqDQHy4QHevpMAaxhhIwYPMv1NECwOvIpGCZkECn8w2WFHXjEwrBn3CeNIYsibZ/iZEUemj++M26W3cNR5h+Tw== + +"@esbuild/freebsd-x64@0.18.20": + version "0.18.20" + resolved "https://registry.yarnpkg.com/@esbuild/freebsd-x64/-/freebsd-x64-0.18.20.tgz#c1eb2bff03915f87c29cece4c1a7fa1f423b066e" + integrity sha512-tgWRPPuQsd3RmBZwarGVHZQvtzfEBOreNuxEMKFcd5DaDn2PbBxfwLcj4+aenoh7ctXcbXmOQIn8HI6mCSw5MQ== + +"@esbuild/linux-arm64@0.18.20": + version "0.18.20" + resolved "https://registry.yarnpkg.com/@esbuild/linux-arm64/-/linux-arm64-0.18.20.tgz#bad4238bd8f4fc25b5a021280c770ab5fc3a02a0" + integrity sha512-2YbscF+UL7SQAVIpnWvYwM+3LskyDmPhe31pE7/aoTMFKKzIc9lLbyGUpmmb8a8AixOL61sQ/mFh3jEjHYFvdA== + +"@esbuild/linux-arm@0.18.20": + version "0.18.20" + resolved "https://registry.yarnpkg.com/@esbuild/linux-arm/-/linux-arm-0.18.20.tgz#3e617c61f33508a27150ee417543c8ab5acc73b0" + integrity sha512-/5bHkMWnq1EgKr1V+Ybz3s1hWXok7mDFUMQ4cG10AfW3wL02PSZi5kFpYKrptDsgb2WAJIvRcDm+qIvXf/apvg== + +"@esbuild/linux-ia32@0.18.20": + version "0.18.20" + resolved "https://registry.yarnpkg.com/@esbuild/linux-ia32/-/linux-ia32-0.18.20.tgz#699391cccba9aee6019b7f9892eb99219f1570a7" + integrity sha512-P4etWwq6IsReT0E1KHU40bOnzMHoH73aXp96Fs8TIT6z9Hu8G6+0SHSw9i2isWrD2nbx2qo5yUqACgdfVGx7TA== + +"@esbuild/linux-loong64@0.18.20": + version "0.18.20" + resolved "https://registry.yarnpkg.com/@esbuild/linux-loong64/-/linux-loong64-0.18.20.tgz#e6fccb7aac178dd2ffb9860465ac89d7f23b977d" + integrity sha512-nXW8nqBTrOpDLPgPY9uV+/1DjxoQ7DoB2N8eocyq8I9XuqJ7BiAMDMf9n1xZM9TgW0J8zrquIb/A7s3BJv7rjg== + +"@esbuild/linux-mips64el@0.18.20": + version "0.18.20" + resolved "https://registry.yarnpkg.com/@esbuild/linux-mips64el/-/linux-mips64el-0.18.20.tgz#eeff3a937de9c2310de30622a957ad1bd9183231" + integrity sha512-d5NeaXZcHp8PzYy5VnXV3VSd2D328Zb+9dEq5HE6bw6+N86JVPExrA6O68OPwobntbNJ0pzCpUFZTo3w0GyetQ== + +"@esbuild/linux-ppc64@0.18.20": + version "0.18.20" + resolved "https://registry.yarnpkg.com/@esbuild/linux-ppc64/-/linux-ppc64-0.18.20.tgz#2f7156bde20b01527993e6881435ad79ba9599fb" + integrity sha512-WHPyeScRNcmANnLQkq6AfyXRFr5D6N2sKgkFo2FqguP44Nw2eyDlbTdZwd9GYk98DZG9QItIiTlFLHJHjxP3FA== + +"@esbuild/linux-riscv64@0.18.20": + version "0.18.20" + resolved "https://registry.yarnpkg.com/@esbuild/linux-riscv64/-/linux-riscv64-0.18.20.tgz#6628389f210123d8b4743045af8caa7d4ddfc7a6" + integrity sha512-WSxo6h5ecI5XH34KC7w5veNnKkju3zBRLEQNY7mv5mtBmrP/MjNBCAlsM2u5hDBlS3NGcTQpoBvRzqBcRtpq1A== + +"@esbuild/linux-s390x@0.18.20": + version "0.18.20" + resolved "https://registry.yarnpkg.com/@esbuild/linux-s390x/-/linux-s390x-0.18.20.tgz#255e81fb289b101026131858ab99fba63dcf0071" + integrity sha512-+8231GMs3mAEth6Ja1iK0a1sQ3ohfcpzpRLH8uuc5/KVDFneH6jtAJLFGafpzpMRO6DzJ6AvXKze9LfFMrIHVQ== + +"@esbuild/linux-x64@0.18.20": + version "0.18.20" + resolved "https://registry.yarnpkg.com/@esbuild/linux-x64/-/linux-x64-0.18.20.tgz#c7690b3417af318a9b6f96df3031a8865176d338" + integrity sha512-UYqiqemphJcNsFEskc73jQ7B9jgwjWrSayxawS6UVFZGWrAAtkzjxSqnoclCXxWtfwLdzU+vTpcNYhpn43uP1w== + +"@esbuild/netbsd-x64@0.18.20": + version "0.18.20" + resolved "https://registry.yarnpkg.com/@esbuild/netbsd-x64/-/netbsd-x64-0.18.20.tgz#30e8cd8a3dded63975e2df2438ca109601ebe0d1" + integrity sha512-iO1c++VP6xUBUmltHZoMtCUdPlnPGdBom6IrO4gyKPFFVBKioIImVooR5I83nTew5UOYrk3gIJhbZh8X44y06A== + +"@esbuild/openbsd-x64@0.18.20": + version "0.18.20" + resolved "https://registry.yarnpkg.com/@esbuild/openbsd-x64/-/openbsd-x64-0.18.20.tgz#7812af31b205055874c8082ea9cf9ab0da6217ae" + integrity sha512-e5e4YSsuQfX4cxcygw/UCPIEP6wbIL+se3sxPdCiMbFLBWu0eiZOJ7WoD+ptCLrmjZBK1Wk7I6D/I3NglUGOxg== + +"@esbuild/sunos-x64@0.18.20": + version "0.18.20" + resolved "https://registry.yarnpkg.com/@esbuild/sunos-x64/-/sunos-x64-0.18.20.tgz#d5c275c3b4e73c9b0ecd38d1ca62c020f887ab9d" + integrity sha512-kDbFRFp0YpTQVVrqUd5FTYmWo45zGaXe0X8E1G/LKFC0v8x0vWrhOWSLITcCn63lmZIxfOMXtCfti/RxN/0wnQ== + +"@esbuild/win32-arm64@0.18.20": + version "0.18.20" + resolved "https://registry.yarnpkg.com/@esbuild/win32-arm64/-/win32-arm64-0.18.20.tgz#73bc7f5a9f8a77805f357fab97f290d0e4820ac9" + integrity sha512-ddYFR6ItYgoaq4v4JmQQaAI5s7npztfV4Ag6NrhiaW0RrnOXqBkgwZLofVTlq1daVTQNhtI5oieTvkRPfZrePg== + +"@esbuild/win32-ia32@0.18.20": + version "0.18.20" + resolved "https://registry.yarnpkg.com/@esbuild/win32-ia32/-/win32-ia32-0.18.20.tgz#ec93cbf0ef1085cc12e71e0d661d20569ff42102" + integrity sha512-Wv7QBi3ID/rROT08SABTS7eV4hX26sVduqDOTe1MvGMjNd3EjOz4b7zeexIR62GTIEKrfJXKL9LFxTYgkyeu7g== + +"@esbuild/win32-x64@0.18.20": + version "0.18.20" + resolved "https://registry.yarnpkg.com/@esbuild/win32-x64/-/win32-x64-0.18.20.tgz#786c5f41f043b07afb1af37683d7c33668858f6d" + integrity sha512-kTdfRcSiDfQca/y9QIkng02avJ+NCaQvrMejlsB3RRv5sE9rRoeBPISaZpKxHELzRxZyLvNts1P27W3wV+8geQ== + +"@jridgewell/gen-mapping@^0.3.0", "@jridgewell/gen-mapping@^0.3.2": + version "0.3.3" + resolved "https://registry.yarnpkg.com/@jridgewell/gen-mapping/-/gen-mapping-0.3.3.tgz#7e02e6eb5df901aaedb08514203b096614024098" + integrity sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ== + dependencies: + "@jridgewell/set-array" "^1.0.1" + "@jridgewell/sourcemap-codec" "^1.4.10" + "@jridgewell/trace-mapping" "^0.3.9" + +"@jridgewell/resolve-uri@^3.1.0": + version "3.1.1" + resolved "https://registry.yarnpkg.com/@jridgewell/resolve-uri/-/resolve-uri-3.1.1.tgz#c08679063f279615a3326583ba3a90d1d82cc721" + integrity sha512-dSYZh7HhCDtCKm4QakX0xFpsRDqjjtZf/kjI/v3T3Nwt5r8/qz/M19F9ySyOqU94SXBmeG9ttTul+YnR4LOxFA== + +"@jridgewell/set-array@^1.0.1": + version "1.1.2" + resolved "https://registry.yarnpkg.com/@jridgewell/set-array/-/set-array-1.1.2.tgz#7c6cf998d6d20b914c0a55a91ae928ff25965e72" + integrity sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw== + +"@jridgewell/sourcemap-codec@^1.4.10", "@jridgewell/sourcemap-codec@^1.4.14": + version "1.4.15" + resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz#d7c6e6755c78567a951e04ab52ef0fd26de59f32" + integrity sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg== + +"@jridgewell/trace-mapping@^0.3.17", "@jridgewell/trace-mapping@^0.3.9": + version "0.3.19" + resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.19.tgz#f8a3249862f91be48d3127c3cfe992f79b4b8811" + integrity sha512-kf37QtfW+Hwx/buWGMPcR60iF9ziHa6r/CZJIHbmcm4+0qrXiVdxegAH0F6yddEVQ7zdkjcGCgCzUu+BcbhQxw== + dependencies: + "@jridgewell/resolve-uri" "^3.1.0" + "@jridgewell/sourcemap-codec" "^1.4.14" + +"@sindresorhus/is@^4.0.0": + version "4.6.0" + resolved "https://registry.yarnpkg.com/@sindresorhus/is/-/is-4.6.0.tgz#3c7c9c46e678feefe7a2e5bb609d3dbd665ffb3f" + integrity sha512-t09vSN3MdfsyCHoFcTRCH/iUtG7OJ0CsjzB8cjAmKc/va/kIgeDI/TxsigdncE/4be734m0cvIYwNaV4i2XqAw== + +"@szmarczak/http-timer@^4.0.5": + version "4.0.6" + resolved "https://registry.yarnpkg.com/@szmarczak/http-timer/-/http-timer-4.0.6.tgz#b4a914bb62e7c272d4e5989fe4440f812ab1d807" + integrity sha512-4BAffykYOgO+5nzBWYwE3W90sBgLJoUPRWWcL8wlyiM8IB8ipJz3UMJ9KXQd1RKQXpKp8Tutn80HZtWsu2u76w== + dependencies: + defer-to-connect "^2.0.0" + +"@types/babel__core@^7.20.2": + version "7.20.2" + resolved "https://registry.yarnpkg.com/@types/babel__core/-/babel__core-7.20.2.tgz#215db4f4a35d710256579784a548907237728756" + integrity sha512-pNpr1T1xLUc2l3xJKuPtsEky3ybxN3m4fJkknfIpTCTfIZCDW57oAg+EfCgIIp2rvCe0Wn++/FfodDS4YXxBwA== + dependencies: + "@babel/parser" "^7.20.7" + "@babel/types" "^7.20.7" + "@types/babel__generator" "*" + "@types/babel__template" "*" + "@types/babel__traverse" "*" + +"@types/babel__generator@*": + version "7.6.5" + resolved "https://registry.yarnpkg.com/@types/babel__generator/-/babel__generator-7.6.5.tgz#281f4764bcbbbc51fdded0f25aa587b4ce14da95" + integrity sha512-h9yIuWbJKdOPLJTbmSpPzkF67e659PbQDba7ifWm5BJ8xTv+sDmS7rFmywkWOvXedGTivCdeGSIIX8WLcRTz8w== + dependencies: + "@babel/types" "^7.0.0" + +"@types/babel__template@*": + version "7.4.2" + resolved "https://registry.yarnpkg.com/@types/babel__template/-/babel__template-7.4.2.tgz#843e9f1f47c957553b0c374481dc4772921d6a6b" + integrity sha512-/AVzPICMhMOMYoSx9MoKpGDKdBRsIXMNByh1PXSZoa+v6ZoLa8xxtsT/uLQ/NJm0XVAWl/BvId4MlDeXJaeIZQ== + dependencies: + "@babel/parser" "^7.1.0" + "@babel/types" "^7.0.0" + +"@types/babel__traverse@*": + version "7.20.2" + resolved "https://registry.yarnpkg.com/@types/babel__traverse/-/babel__traverse-7.20.2.tgz#4ddf99d95cfdd946ff35d2b65c978d9c9bf2645d" + integrity sha512-ojlGK1Hsfce93J0+kn3H5R73elidKUaZonirN33GSmgTUMpzI/MIFfSpF3haANe3G1bEBS9/9/QEqwTzwqFsKw== + dependencies: + "@babel/types" "^7.20.7" + +"@types/cacheable-request@^6.0.1": + version "6.0.3" + resolved "https://registry.yarnpkg.com/@types/cacheable-request/-/cacheable-request-6.0.3.tgz#a430b3260466ca7b5ca5bfd735693b36e7a9d183" + integrity sha512-IQ3EbTzGxIigb1I3qPZc1rWJnH0BmSKv5QYTalEwweFvyBDLSAe24zP0le/hyi7ecGfZVlIVAg4BZqb8WBwKqw== + dependencies: + "@types/http-cache-semantics" "*" + "@types/keyv" "^3.1.4" + "@types/node" "*" + "@types/responselike" "^1.0.0" + +"@types/http-cache-semantics@*": + version "4.0.2" + resolved "https://registry.yarnpkg.com/@types/http-cache-semantics/-/http-cache-semantics-4.0.2.tgz#abe102d06ccda1efdf0ed98c10ccf7f36a785a41" + integrity sha512-FD+nQWA2zJjh4L9+pFXqWOi0Hs1ryBCfI+985NjluQ1p8EYtoLvjLOKidXBtZ4/IcxDX4o8/E8qDS3540tNliw== + +"@types/keyv@^3.1.4": + version "3.1.4" + resolved "https://registry.yarnpkg.com/@types/keyv/-/keyv-3.1.4.tgz#3ccdb1c6751b0c7e52300bcdacd5bcbf8faa75b6" + integrity sha512-BQ5aZNSCpj7D6K2ksrRCTmKRLEpnPvWDiLPfoGyhZ++8YtiK9d/3DBKPJgry359X/P1PfruyYwvnvwFjuEiEIg== + dependencies: + "@types/node" "*" + +"@types/node@*": + version "20.6.2" + resolved "https://registry.yarnpkg.com/@types/node/-/node-20.6.2.tgz#a065925409f59657022e9063275cd0b9bd7e1b12" + integrity sha512-Y+/1vGBHV/cYk6OI1Na/LHzwnlNCAfU3ZNGrc1LdRe/LAIbdDPTTv/HU3M7yXN448aTVDq3eKRm2cg7iKLb8gw== + +"@types/prop-types@*": + version "15.7.6" + resolved "https://registry.yarnpkg.com/@types/prop-types/-/prop-types-15.7.6.tgz#bbf819813d6be21011b8f5801058498bec555572" + integrity sha512-RK/kBbYOQQHLYj9Z95eh7S6t7gq4Ojt/NT8HTk8bWVhA5DaF+5SMnxHKkP4gPNN3wAZkKP+VjAf0ebtYzf+fxg== + +"@types/react-dom@^18.2.0": + version "18.2.8" + resolved "https://registry.yarnpkg.com/@types/react-dom/-/react-dom-18.2.8.tgz#338f1b0a646c9f10e0a97208c1d26b9f473dffd6" + integrity sha512-bAIvO5lN/U8sPGvs1Xm61rlRHHaq5rp5N3kp9C+NJ/Q41P8iqjkXSu0+/qu8POsjH9pNWb0OYabFez7taP7omw== + dependencies: + "@types/react" "*" + +"@types/react@*": + version "18.2.22" + resolved "https://registry.yarnpkg.com/@types/react/-/react-18.2.22.tgz#abe778a1c95a07fa70df40a52d7300a40b949ccb" + integrity sha512-60fLTOLqzarLED2O3UQImc/lsNRgG0jE/a1mPW9KjMemY0LMITWEsbS4VvZ4p6rorEHd5YKxxmMKSDK505GHpA== + dependencies: + "@types/prop-types" "*" + "@types/scheduler" "*" + csstype "^3.0.2" + +"@types/react@^18.2.0": + version "18.2.23" + resolved "https://registry.yarnpkg.com/@types/react/-/react-18.2.23.tgz#60ad6cf4895e93bed858db0e03bcc4ff97d0410e" + integrity sha512-qHLW6n1q2+7KyBEYnrZpcsAmU/iiCh9WGCKgXvMxx89+TYdJWRjZohVIo9XTcoLhfX3+/hP0Pbulu3bCZQ9PSA== + dependencies: + "@types/prop-types" "*" + "@types/scheduler" "*" + csstype "^3.0.2" + +"@types/responselike@^1.0.0": + version "1.0.0" + resolved "https://registry.yarnpkg.com/@types/responselike/-/responselike-1.0.0.tgz#251f4fe7d154d2bad125abe1b429b23afd262e29" + integrity sha512-85Y2BjiufFzaMIlvJDvTTB8Fxl2xfLo4HgmHzVBz08w4wDePCTjYw66PdrolO0kzli3yam/YCgRufyo1DdQVTA== + dependencies: + "@types/node" "*" + +"@types/scheduler@*": + version "0.16.3" + resolved "https://registry.yarnpkg.com/@types/scheduler/-/scheduler-0.16.3.tgz#cef09e3ec9af1d63d2a6cc5b383a737e24e6dcf5" + integrity sha512-5cJ8CB4yAx7BH1oMvdU0Jh9lrEXyPkar6F9G/ERswkCuvP4KQZfZkSjcMbAICCpQTN4OuZn8tz0HiKv9TGZgrQ== + +"@vitejs/plugin-react@^4.1.0": + version "4.1.0" + resolved "https://registry.yarnpkg.com/@vitejs/plugin-react/-/plugin-react-4.1.0.tgz#e4f56f46fd737c5d386bb1f1ade86ba275fe09bd" + integrity sha512-rM0SqazU9iqPUraQ2JlIvReeaxOoRj6n+PzB1C0cBzIbd8qP336nC39/R9yPi3wVcah7E7j/kdU1uCUqMEU4OQ== + dependencies: + "@babel/core" "^7.22.20" + "@babel/plugin-transform-react-jsx-self" "^7.22.5" + "@babel/plugin-transform-react-jsx-source" "^7.22.5" + "@types/babel__core" "^7.20.2" + react-refresh "^0.14.0" + +ably@1.2.45: + version "1.2.45" + resolved "https://registry.yarnpkg.com/ably/-/ably-1.2.45.tgz#9da9b3faae18614160dd7ff1e5e93de948f984bd" + integrity sha512-8Jk8XT0dSPcLcZ8zSAF+mRtwMzaQR5dWHqGdx9Y859ZLhXiqf4gQb7P+4Elqy1l1IIRoDWgyt0fkyfo7ngUdMA== + dependencies: + "@ably/msgpack-js" "^0.4.0" + got "^11.8.5" + ws "^5.1" + +ansi-styles@^3.2.1: + version "3.2.1" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d" + integrity sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA== + dependencies: + color-convert "^1.9.0" + +async-limiter@~1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/async-limiter/-/async-limiter-1.0.1.tgz#dd379e94f0db8310b08291f9d64c3209766617fd" + integrity sha512-csOlWGAcRFJaI6m+F2WKdnMKr4HhdhFVBk0H/QbJFMCr+uO2kwohwXQPxw/9OCxp05r5ghVBFSyioixx3gfkNQ== + +base64-js@1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.0.2.tgz#474211c95e6cf2a547db461e4f6778b51d08fa65" + integrity sha512-ZXBDPMt/v/8fsIqn+Z5VwrhdR6jVka0bYobHdGia0Nxi7BJ9i/Uvml3AocHIBtIIBhZjBw5MR0aR4ROs/8+SNg== + +bops@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/bops/-/bops-1.0.1.tgz#502aaf00ee119db1dbae088e3df4bea2e241dbcc" + integrity sha512-qCMBuZKP36tELrrgXpAfM+gHzqa0nLsWZ+L37ncsb8txYlnAoxOPpVp+g7fK0sGkMXfA0wl8uQkESqw3v4HNag== + dependencies: + base64-js "1.0.2" + to-utf8 "0.0.1" + +browserslist@^4.21.9: + version "4.21.10" + resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.21.10.tgz#dbbac576628c13d3b2231332cb2ec5a46e015bb0" + integrity sha512-bipEBdZfVH5/pwrvqc+Ub0kUPVfGUhlKxbvfD+z1BDnPEO/X98ruXGA1WP5ASpAFKan7Qr6j736IacbZQuAlKQ== + dependencies: + caniuse-lite "^1.0.30001517" + electron-to-chromium "^1.4.477" + node-releases "^2.0.13" + update-browserslist-db "^1.0.11" + +cacheable-lookup@^5.0.3: + version "5.0.4" + resolved "https://registry.yarnpkg.com/cacheable-lookup/-/cacheable-lookup-5.0.4.tgz#5a6b865b2c44357be3d5ebc2a467b032719a7005" + integrity sha512-2/kNscPhpcxrOigMZzbiWF7dz8ilhb/nIHU3EyZiXWXpeq/au8qJ8VhdftMkty3n7Gj6HIGalQG8oiBNB3AJgA== + +cacheable-request@^7.0.2: + version "7.0.4" + resolved "https://registry.yarnpkg.com/cacheable-request/-/cacheable-request-7.0.4.tgz#7a33ebf08613178b403635be7b899d3e69bbe817" + integrity sha512-v+p6ongsrp0yTGbJXjgxPow2+DL93DASP4kXCDKb8/bwRtt9OEF3whggkkDkGNzgcWy2XaF4a8nZglC7uElscg== + dependencies: + clone-response "^1.0.2" + get-stream "^5.1.0" + http-cache-semantics "^4.0.0" + keyv "^4.0.0" + lowercase-keys "^2.0.0" + normalize-url "^6.0.1" + responselike "^2.0.0" + +caniuse-lite@^1.0.30001517: + version "1.0.30001538" + resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001538.tgz#9dbc6b9af1ff06b5eb12350c2012b3af56744f3f" + integrity sha512-HWJnhnID+0YMtGlzcp3T9drmBJUVDchPJ08tpUGFLs9CYlwWPH2uLgpHn8fND5pCgXVtnGS3H4QR9XLMHVNkHw== + +chalk@^2.4.2: + version "2.4.2" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424" + integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ== + dependencies: + ansi-styles "^3.2.1" + escape-string-regexp "^1.0.5" + supports-color "^5.3.0" + +classnames@^2.3.2: + version "2.3.2" + resolved "https://registry.yarnpkg.com/classnames/-/classnames-2.3.2.tgz#351d813bf0137fcc6a76a16b88208d2560a0d924" + integrity sha512-CSbhY4cFEJRe6/GQzIk5qXZ4Jeg5pcsP7b5peFSDpffpe1cqjASH/n9UTjBwOp6XpMSTwQ8Za2K5V02ueA7Tmw== + +clone-response@^1.0.2: + version "1.0.3" + resolved "https://registry.yarnpkg.com/clone-response/-/clone-response-1.0.3.tgz#af2032aa47816399cf5f0a1d0db902f517abb8c3" + integrity sha512-ROoL94jJH2dUVML2Y/5PEDNaSHgeOdSDicUyS7izcF63G6sTc/FTjLub4b8Il9S8S0beOfYt0TaA5qvFK+w0wA== + dependencies: + mimic-response "^1.0.0" + +color-convert@^1.9.0: + version "1.9.3" + resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8" + integrity sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg== + dependencies: + color-name "1.1.3" + +color-name@1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25" + integrity sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw== + +convert-source-map@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-2.0.0.tgz#4b560f649fc4e918dd0ab75cf4961e8bc882d82a" + integrity sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg== + +csstype@^3.0.2: + version "3.1.2" + resolved "https://registry.yarnpkg.com/csstype/-/csstype-3.1.2.tgz#1d4bf9d572f11c14031f0436e1c10bc1f571f50b" + integrity sha512-I7K1Uu0MBPzaFKg4nI5Q7Vs2t+3gWWW648spaF+Rg7pI9ds18Ugn+lvg4SHczUdKlHI5LWBXyqfS8+DufyBsgQ== + +dayjs@^1.11.4: + version "1.11.9" + resolved "https://registry.yarnpkg.com/dayjs/-/dayjs-1.11.9.tgz#9ca491933fadd0a60a2c19f6c237c03517d71d1a" + integrity sha512-QvzAURSbQ0pKdIye2txOzNaHmxtUBXerpY0FJsFXUMKbIZeFm5ht1LS/jFsrncjnmtv8HsG0W2g6c0zUjZWmpA== + +debug@^4.1.0: + version "4.3.4" + resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.4.tgz#1319f6579357f2338d3337d2cdd4914bb5dcc865" + integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ== + dependencies: + ms "2.1.2" + +decompress-response@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/decompress-response/-/decompress-response-6.0.0.tgz#ca387612ddb7e104bd16d85aab00d5ecf09c66fc" + integrity sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ== + dependencies: + mimic-response "^3.1.0" + +defer-to-connect@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/defer-to-connect/-/defer-to-connect-2.0.1.tgz#8016bdb4143e4632b77a3449c6236277de520587" + integrity sha512-4tvttepXG1VaYGrRibk5EwJd1t4udunSOVMdLSAL6mId1ix438oPwPZMALY41FCijukO1L0twNcGsdzS7dHgDg== + +electron-to-chromium@^1.4.477: + version "1.4.523" + resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.523.tgz#f82f99243c827df05c26776d49712cb284972df6" + integrity sha512-9AreocSUWnzNtvLcbpng6N+GkXnCcBR80IQkxRC9Dfdyg4gaWNUPBujAHUpKkiUkoSoR9UlhA4zD/IgBklmhzg== + +end-of-stream@^1.1.0: + version "1.4.4" + resolved "https://registry.yarnpkg.com/end-of-stream/-/end-of-stream-1.4.4.tgz#5ae64a5f45057baf3626ec14da0ca5e4b2431eb0" + integrity sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q== + dependencies: + once "^1.4.0" + +esbuild@^0.18.10: + version "0.18.20" + resolved "https://registry.yarnpkg.com/esbuild/-/esbuild-0.18.20.tgz#4709f5a34801b43b799ab7d6d82f7284a9b7a7a6" + integrity sha512-ceqxoedUrcayh7Y7ZX6NdbbDzGROiyVBgC4PriJThBKSVPWnnFHZAkfI1lJT8QFkOwH4qOS2SJkS4wvpGl8BpA== + optionalDependencies: + "@esbuild/android-arm" "0.18.20" + "@esbuild/android-arm64" "0.18.20" + "@esbuild/android-x64" "0.18.20" + "@esbuild/darwin-arm64" "0.18.20" + "@esbuild/darwin-x64" "0.18.20" + "@esbuild/freebsd-arm64" "0.18.20" + "@esbuild/freebsd-x64" "0.18.20" + "@esbuild/linux-arm" "0.18.20" + "@esbuild/linux-arm64" "0.18.20" + "@esbuild/linux-ia32" "0.18.20" + "@esbuild/linux-loong64" "0.18.20" + "@esbuild/linux-mips64el" "0.18.20" + "@esbuild/linux-ppc64" "0.18.20" + "@esbuild/linux-riscv64" "0.18.20" + "@esbuild/linux-s390x" "0.18.20" + "@esbuild/linux-x64" "0.18.20" + "@esbuild/netbsd-x64" "0.18.20" + "@esbuild/openbsd-x64" "0.18.20" + "@esbuild/sunos-x64" "0.18.20" + "@esbuild/win32-arm64" "0.18.20" + "@esbuild/win32-ia32" "0.18.20" + "@esbuild/win32-x64" "0.18.20" + +escalade@^3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.1.1.tgz#d8cfdc7000965c5a0174b4a82eaa5c0552742e40" + integrity sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw== + +escape-string-regexp@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" + integrity sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg== + +fsevents@~2.3.2: + version "2.3.3" + resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.3.tgz#cac6407785d03675a2a5e1a5305c697b347d90d6" + integrity sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw== + +gensync@^1.0.0-beta.2: + version "1.0.0-beta.2" + resolved "https://registry.yarnpkg.com/gensync/-/gensync-1.0.0-beta.2.tgz#32a6ee76c3d7f52d46b2b1ae5d93fea8580a25e0" + integrity sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg== + +get-stream@^5.1.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-5.2.0.tgz#4966a1795ee5ace65e706c4b7beb71257d6e22d3" + integrity sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA== + dependencies: + pump "^3.0.0" + +globals@^11.1.0: + version "11.12.0" + resolved "https://registry.yarnpkg.com/globals/-/globals-11.12.0.tgz#ab8795338868a0babd8525758018c2a7eb95c42e" + integrity sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA== + +got@^11.8.5: + version "11.8.6" + resolved "https://registry.yarnpkg.com/got/-/got-11.8.6.tgz#276e827ead8772eddbcfc97170590b841823233a" + integrity sha512-6tfZ91bOr7bOXnK7PRDCGBLa1H4U080YHNaAQ2KsMGlLEzRbk44nsZF2E1IeRc3vtJHPVbKCYgdFbaGO2ljd8g== + dependencies: + "@sindresorhus/is" "^4.0.0" + "@szmarczak/http-timer" "^4.0.5" + "@types/cacheable-request" "^6.0.1" + "@types/responselike" "^1.0.0" + cacheable-lookup "^5.0.3" + cacheable-request "^7.0.2" + decompress-response "^6.0.0" + http2-wrapper "^1.0.0-beta.5.2" + lowercase-keys "^2.0.0" + p-cancelable "^2.0.0" + responselike "^2.0.0" + +has-flag@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd" + integrity sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw== + +http-cache-semantics@^4.0.0: + version "4.1.1" + resolved "https://registry.yarnpkg.com/http-cache-semantics/-/http-cache-semantics-4.1.1.tgz#abe02fcb2985460bf0323be664436ec3476a6d5a" + integrity sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ== + +http2-wrapper@^1.0.0-beta.5.2: + version "1.0.3" + resolved "https://registry.yarnpkg.com/http2-wrapper/-/http2-wrapper-1.0.3.tgz#b8f55e0c1f25d4ebd08b3b0c2c079f9590800b3d" + integrity sha512-V+23sDMr12Wnz7iTcDeJr3O6AIxlnvT/bmaAAAP/Xda35C90p9599p0F1eHR/N1KILWSoWVAiOMFjBBXaXSMxg== + dependencies: + quick-lru "^5.1.1" + resolve-alpn "^1.0.0" + +"js-tokens@^3.0.0 || ^4.0.0", js-tokens@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" + integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ== + +jsesc@^2.5.1: + version "2.5.2" + resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-2.5.2.tgz#80564d2e483dacf6e8ef209650a67df3f0c283a4" + integrity sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA== + +json-buffer@3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/json-buffer/-/json-buffer-3.0.1.tgz#9338802a30d3b6605fbe0613e094008ca8c05a13" + integrity sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ== + +json5@^2.2.3: + version "2.2.3" + resolved "https://registry.yarnpkg.com/json5/-/json5-2.2.3.tgz#78cd6f1a19bdc12b73db5ad0c61efd66c1e29283" + integrity sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg== + +keyv@^4.0.0: + version "4.5.3" + resolved "https://registry.yarnpkg.com/keyv/-/keyv-4.5.3.tgz#00873d2b046df737963157bd04f294ca818c9c25" + integrity sha512-QCiSav9WaX1PgETJ+SpNnx2PRRapJ/oRSXM4VO5OGYGSjrxbKPVFVhB3l2OCbLCk329N8qyAtsJjSjvVBWzEug== + dependencies: + json-buffer "3.0.1" + +loose-envify@^1.1.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.4.0.tgz#71ee51fa7be4caec1a63839f7e682d8132d30caf" + integrity sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q== + dependencies: + js-tokens "^3.0.0 || ^4.0.0" + +lowercase-keys@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/lowercase-keys/-/lowercase-keys-2.0.0.tgz#2603e78b7b4b0006cbca2fbcc8a3202558ac9479" + integrity sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA== + +lru-cache@^5.1.1: + version "5.1.1" + resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-5.1.1.tgz#1da27e6710271947695daf6848e847f01d84b920" + integrity sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w== + dependencies: + yallist "^3.0.2" + +mimic-response@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/mimic-response/-/mimic-response-1.0.1.tgz#4923538878eef42063cb8a3e3b0798781487ab1b" + integrity sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ== + +mimic-response@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/mimic-response/-/mimic-response-3.1.0.tgz#2d1d59af9c1b129815accc2c46a022a5ce1fa3c9" + integrity sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ== + +ms@2.1.2: + version "2.1.2" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" + integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== + +nanoid@^3.3.6: + version "3.3.6" + resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.6.tgz#443380c856d6e9f9824267d960b4236ad583ea4c" + integrity sha512-BGcqMMJuToF7i1rt+2PWSNVnWIkGCU78jBG3RxO/bZlnZPK2Cmi2QaffxGO/2RvWi9sL+FAiRiXMgsyxQ1DIDA== + +nanoid@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-5.0.1.tgz#3e95d775a8bc8a98afbf0a237e2bbc6a71b0662e" + integrity sha512-vWeVtV5Cw68aML/QaZvqN/3QQXc6fBfIieAlu05m7FZW2Dgb+3f0xc0TTxuJW+7u30t7iSDTV/j3kVI0oJqIfQ== + +nanoid@^5.0.2: + version "5.0.2" + resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-5.0.2.tgz#97588ebc70166d0feaf73ccd2799bb4ceaebf692" + integrity sha512-2ustYUX1R2rL/Br5B/FMhi8d5/QzvkJ912rBYxskcpu0myTHzSZfTr1LAS2Sm7jxRUObRrSBFoyzwAhL49aVSg== + +node-releases@^2.0.13: + version "2.0.13" + resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.13.tgz#d5ed1627c23e3461e819b02e57b75e4899b1c81d" + integrity sha512-uYr7J37ae/ORWdZeQ1xxMJe3NtdmqMC/JZK+geofDrkLUApKRHPd18/TxtBOJ4A0/+uUIliorNrfYV6s1b02eQ== + +normalize-url@^6.0.1: + version "6.1.0" + resolved "https://registry.yarnpkg.com/normalize-url/-/normalize-url-6.1.0.tgz#40d0885b535deffe3f3147bec877d05fe4c5668a" + integrity sha512-DlL+XwOy3NxAQ8xuC0okPgK46iuVNAK01YN7RueYBqqFeGsBjV9XmCAzAdgt+667bCl5kPh9EqKKDwnaPG1I7A== + +once@^1.3.1, once@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" + integrity sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w== + dependencies: + wrappy "1" + +p-cancelable@^2.0.0: + version "2.1.1" + resolved "https://registry.yarnpkg.com/p-cancelable/-/p-cancelable-2.1.1.tgz#aab7fbd416582fa32a3db49859c122487c5ed2cf" + integrity sha512-BZOr3nRQHOntUjTrH8+Lh54smKHoHyur8We1V8DSMVrl5A2malOOwuJRnKRDjSnkoeBh4at6BwEnb5I7Jl31wg== + +picocolors@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.0.0.tgz#cb5bdc74ff3f51892236eaf79d68bc44564ab81c" + integrity sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ== + +postcss@^8.4.27: + version "8.4.31" + resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.31.tgz#92b451050a9f914da6755af352bdc0192508656d" + integrity sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ== + dependencies: + nanoid "^3.3.6" + picocolors "^1.0.0" + source-map-js "^1.0.2" + +pump@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/pump/-/pump-3.0.0.tgz#b4a2116815bde2f4e1ea602354e8c75565107a64" + integrity sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww== + dependencies: + end-of-stream "^1.1.0" + once "^1.3.1" + +quick-lru@^5.1.1: + version "5.1.1" + resolved "https://registry.yarnpkg.com/quick-lru/-/quick-lru-5.1.1.tgz#366493e6b3e42a3a6885e2e99d18f80fb7a8c932" + integrity sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA== + +random-words@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/random-words/-/random-words-2.0.0.tgz#af1e1a75d506b5dec996094ab074bf2196272287" + integrity sha512-uqpnDqFnYrZajgmvgjmBrSZL2V1UA/9bNPGrilo12CmBeBszoff/avElutUlwWxG12gvmCk/8dUhvHefYxzYjw== + dependencies: + seedrandom "^3.0.5" + +react-dom@^18.2.0: + version "18.2.0" + resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-18.2.0.tgz#22aaf38708db2674ed9ada224ca4aa708d821e3d" + integrity sha512-6IMTriUmvsjHUjNtEDudZfuDQUoWXVxKHhlEGSk81n4YFS+r/Kl99wXiwlVXtPBtJenozv2P+hxDsw9eA7Xo6g== + dependencies: + loose-envify "^1.1.0" + scheduler "^0.23.0" + +react-refresh@^0.14.0: + version "0.14.0" + resolved "https://registry.yarnpkg.com/react-refresh/-/react-refresh-0.14.0.tgz#4e02825378a5f227079554d4284889354e5f553e" + integrity sha512-wViHqhAd8OHeLS/IRMJjTSDHF3U9eWi62F/MledQGPdJGDhodXJ9PBLNGr6WWL7qlH12Mt3TyTpbS+hGXMjCzQ== + +react@^18.2.0: + version "18.2.0" + resolved "https://registry.yarnpkg.com/react/-/react-18.2.0.tgz#555bd98592883255fa00de14f1151a917b5d77d5" + integrity sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ== + dependencies: + loose-envify "^1.1.0" + +resolve-alpn@^1.0.0: + version "1.2.1" + resolved "https://registry.yarnpkg.com/resolve-alpn/-/resolve-alpn-1.2.1.tgz#b7adbdac3546aaaec20b45e7d8265927072726f9" + integrity sha512-0a1F4l73/ZFZOakJnQ3FvkJ2+gSTQWz/r2KE5OdDY0TxPm5h4GkqkWWfM47T7HsbnOtcJVEF4epCVy6u7Q3K+g== + +responselike@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/responselike/-/responselike-2.0.1.tgz#9a0bc8fdc252f3fb1cca68b016591059ba1422bc" + integrity sha512-4gl03wn3hj1HP3yzgdI7d3lCkF95F21Pz4BPGvKHinyQzALR5CapwC8yIi0Rh58DEMQ/SguC03wFj2k0M/mHhw== + dependencies: + lowercase-keys "^2.0.0" + +rollup@^3.27.1: + version "3.29.4" + resolved "https://registry.yarnpkg.com/rollup/-/rollup-3.29.4.tgz#4d70c0f9834146df8705bfb69a9a19c9e1109981" + integrity sha512-oWzmBZwvYrU0iJHtDmhsm662rC15FRXmcjCk1xD771dFDx5jJ02ufAQQTn0etB2emNk4J9EZg/yWKpsn9BWGRw== + optionalDependencies: + fsevents "~2.3.2" + +scheduler@^0.23.0: + version "0.23.0" + resolved "https://registry.yarnpkg.com/scheduler/-/scheduler-0.23.0.tgz#ba8041afc3d30eb206a487b6b384002e4e61fdfe" + integrity sha512-CtuThmgHNg7zIZWAXi3AsyIzA3n4xx7aNyjwC2VJldO2LMVDhFK+63xGqq6CsJH4rTAt6/M+N4GhZiDYPx9eUw== + dependencies: + loose-envify "^1.1.0" + +seedrandom@^3.0.5: + version "3.0.5" + resolved "https://registry.yarnpkg.com/seedrandom/-/seedrandom-3.0.5.tgz#54edc85c95222525b0c7a6f6b3543d8e0b3aa0a7" + integrity sha512-8OwmbklUNzwezjGInmZ+2clQmExQPvomqjL7LFqOYqtmuxRgQYqOD3mHaU+MvZn5FLUeVxVfQjwLZW/n/JFuqg== + +semver@^6.3.1: + version "6.3.1" + resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.1.tgz#556d2ef8689146e46dcea4bfdd095f3434dffcb4" + integrity sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA== + +source-map-js@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/source-map-js/-/source-map-js-1.0.2.tgz#adbc361d9c62df380125e7f161f71c826f1e490c" + integrity sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw== + +supports-color@^5.3.0: + version "5.5.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f" + integrity sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow== + dependencies: + has-flag "^3.0.0" + +to-fast-properties@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-2.0.0.tgz#dc5e698cbd079265bc73e0377681a4e4e83f616e" + integrity sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog== + +to-utf8@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/to-utf8/-/to-utf8-0.0.1.tgz#d17aea72ff2fba39b9e43601be7b3ff72e089852" + integrity sha512-zks18/TWT1iHO3v0vFp5qLKOG27m67ycq/Y7a7cTiRuUNlc4gf3HGnkRgMv0NyhnfTamtkYBJl+YeD1/j07gBQ== + +typescript@5.2.2: + version "5.2.2" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.2.2.tgz#5ebb5e5a5b75f085f22bc3f8460fba308310fa78" + integrity sha512-mI4WrpHsbCIcwT9cF4FZvr80QUeKvsUsUvKDoR+X/7XHQH98xYD8YHZg7ANtz2GtZt/CBq2QJ0thkGJMHfqc1w== + +update-browserslist-db@^1.0.11: + version "1.0.11" + resolved "https://registry.yarnpkg.com/update-browserslist-db/-/update-browserslist-db-1.0.11.tgz#9a2a641ad2907ae7b3616506f4b977851db5b940" + integrity sha512-dCwEFf0/oT85M1fHBg4F0jtLwJrutGoHSQXCh7u4o2t1drG+c0a9Flnqww6XUKSfQMPpJBRjU8d4RXB09qtvaA== + dependencies: + escalade "^3.1.1" + picocolors "^1.0.0" + +vite@^4.4.9: + version "4.4.9" + resolved "https://registry.yarnpkg.com/vite/-/vite-4.4.9.tgz#1402423f1a2f8d66fd8d15e351127c7236d29d3d" + integrity sha512-2mbUn2LlUmNASWwSCNSJ/EG2HuSRTnVNaydp6vMCm5VIqJsjMfbIWtbH2kDuwUVW5mMUKKZvGPX/rqeqVvv1XA== + dependencies: + esbuild "^0.18.10" + postcss "^8.4.27" + rollup "^3.27.1" + optionalDependencies: + fsevents "~2.3.2" + +wrappy@1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" + integrity sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ== + +ws@^5.1: + version "5.2.3" + resolved "https://registry.yarnpkg.com/ws/-/ws-5.2.3.tgz#05541053414921bc29c63bee14b8b0dd50b07b3d" + integrity sha512-jZArVERrMsKUatIdnLzqvcfydI85dvd/Fp1u/VOpfdDWQ4c9qWXe+VIeAbQ5FrDwciAkr+lzofXLz3Kuf26AOA== + dependencies: + async-limiter "~1.0.0" + +yallist@^3.0.2: + version "3.1.1" + resolved "https://registry.yarnpkg.com/yallist/-/yallist-3.1.1.tgz#dbb7daf9bfd8bac9ab45ebf602b8cbad0d5d08fd" + integrity sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g== diff --git a/src/main.tsx b/src/main.tsx index d68ebf2..1460794 100644 --- a/src/main.tsx +++ b/src/main.tsx @@ -15,6 +15,7 @@ import MemberLocation from "./routes/MemberLocation"; import ComponentLocking from "./routes/ComponentLocking"; import VanillaAvatarStack from "./routes/VanillaAvatarStack"; import ViteReactAvatarStack from "./routes/ViteReactAvatarStack"; +import ViteReactAvatarStack2 from "./routes/ViteReactAvatarStack2"; import "./styles/global.css"; @@ -54,6 +55,7 @@ ReactDOM.createRoot(document.getElementById("root")!).render( } /> } /> } /> + } /> diff --git a/src/routes/ViteReactAvatarStack2.tsx b/src/routes/ViteReactAvatarStack2.tsx new file mode 100644 index 0000000..7b62e44 --- /dev/null +++ b/src/routes/ViteReactAvatarStack2.tsx @@ -0,0 +1,28 @@ +import { useEffect } from "react"; +import { useOutletContext } from "react-router-dom"; + +import type { ProjectInfo } from "../utils/types"; +import AvatarStack from "../../examples/vite-react-avatar-stack-2/src/App"; +import Spaces from "@ably/spaces"; + +const Project = ({ spaces }: { spaces: Spaces }) => { + const { setProjectInfo } = useOutletContext<{ + setProjectInfo: (projectInfo: ProjectInfo) => void; + }>(); + + useEffect(() => { + setProjectInfo({ + name: "React Avatar stack Version 2", + docsLink: "https://ably.com/docs/spaces/avatar", + repoNameAndPath: "realtime-examples/tree/main/examples/vite-react-avatar-stack-2", + topic: "avatar-stack", + learnMore: true, + description: + "See your online presence in a space displayed as an Avatar. Open in a new window or share the link to see multiple users.", + }); + }, []); + + return ; +}; + +export default Project; From aa015e7be809b39f7f6538311b56585482849075 Mon Sep 17 00:00:00 2001 From: Greg Holmes Date: Fri, 2 Aug 2024 09:19:01 +0100 Subject: [PATCH 07/19] fixup! Add second revision of react avatar stack example --- examples/vite-react-avatar-stack-2/src/components/Avatar.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/vite-react-avatar-stack-2/src/components/Avatar.tsx b/examples/vite-react-avatar-stack-2/src/components/Avatar.tsx index d50b676..519fa06 100644 --- a/examples/vite-react-avatar-stack-2/src/components/Avatar.tsx +++ b/examples/vite-react-avatar-stack-2/src/components/Avatar.tsx @@ -60,7 +60,7 @@ export function Avatar({ user, isSelf }: { user: Member, isSelf: boolean }) { backgroundColor: user.profileData.memberColor }} onMouseOver={() => setHover(true)} - onMouseLeave={() => setHover(true)} + onMouseLeave={() => setHover(false)} id="avatar" >

    {userInitials}

    From ee1f0c78aca8ab9e06f061ad7c92104445c727d1 Mon Sep 17 00:00:00 2001 From: April Smith Date: Fri, 2 Aug 2024 09:40:50 +0100 Subject: [PATCH 08/19] chore: popup position on the top of the avatar --- .../vite-react-avatar-stack-2/src/components/Avatar.tsx | 2 +- examples/vite-react-avatar-stack-2/src/styles/avatars.css | 7 ++++++- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/examples/vite-react-avatar-stack-2/src/components/Avatar.tsx b/examples/vite-react-avatar-stack-2/src/components/Avatar.tsx index 519fa06..e70fe9d 100644 --- a/examples/vite-react-avatar-stack-2/src/components/Avatar.tsx +++ b/examples/vite-react-avatar-stack-2/src/components/Avatar.tsx @@ -52,7 +52,7 @@ export function Avatar({ user, isSelf }: { user: Member, isSelf: boolean }) { .join(""); return ( -
    +
    Date: Mon, 5 Aug 2024 10:34:33 +0100 Subject: [PATCH 09/19] Added comments to vite-react-avatar-stack-2 --- examples/vite-react-avatar-stack-2/src/App.tsx | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/examples/vite-react-avatar-stack-2/src/App.tsx b/examples/vite-react-avatar-stack-2/src/App.tsx index 9e941b9..1cc5730 100644 --- a/examples/vite-react-avatar-stack-2/src/App.tsx +++ b/examples/vite-react-avatar-stack-2/src/App.tsx @@ -15,7 +15,7 @@ const mockNames = [ "Hakim Hernandez", ]; -function Example() { +function AvatarStack() { const name = useMemo(() => { return mockNames[Math.floor(Math.random() * mockNames.length)]; }, []); @@ -23,24 +23,29 @@ function Example() { return colors[Math.floor(Math.random() * colors.length)]; }, []); + /** 💡 Get a handle on a space instance 💡 */ const { space } = useSpace(); + /** 💡 Enter the space as soon as it's available 💡 */ useEffect(() => { space?.enter({ name, memberColor }); }, [space]); + /** 💡 Get everybody except the local member in the space and the local member 💡 */ const { others, self } = useMembers(); const hasMoreUsers = others.length > 3; return (
    + {/** 💡 Add your avatar to the stack.💡 */} {self && (
    )} + {/** 💡 Stack of first 4 user avatars excluding yourself.💡 */} {others.slice(0, 4).map(( other ) => { return (
    @@ -66,7 +71,7 @@ function Example() { const App = ({ spaces }: { spaces: Spaces }) => ( - + ); From 9bfc0fb0b7718c607c640c9512fe5c215fb131c0 Mon Sep 17 00:00:00 2001 From: Greg Holmes Date: Mon, 5 Aug 2024 15:41:01 +0100 Subject: [PATCH 10/19] Corrected code comment --- examples/vite-react-avatar-stack-2/src/App.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/vite-react-avatar-stack-2/src/App.tsx b/examples/vite-react-avatar-stack-2/src/App.tsx index 1cc5730..62768f3 100644 --- a/examples/vite-react-avatar-stack-2/src/App.tsx +++ b/examples/vite-react-avatar-stack-2/src/App.tsx @@ -31,7 +31,7 @@ function AvatarStack() { space?.enter({ name, memberColor }); }, [space]); - /** 💡 Get everybody except the local member in the space and the local member 💡 */ + /** 💡 Get everybody in the space including the local member 💡 */ const { others, self } = useMembers(); const hasMoreUsers = others.length > 3; From 922491ee9188da703fe9c5ed2ab31973bfbd55b0 Mon Sep 17 00:00:00 2001 From: Greg Holmes Date: Mon, 5 Aug 2024 15:41:25 +0100 Subject: [PATCH 11/19] Added a second version of Vanilla JS Avatar Stack example --- examples/vanilla-avatar-stack-2/.env.example | 2 + examples/vanilla-avatar-stack-2/.gitignore | 2 + examples/vanilla-avatar-stack-2/index.html | 17 +++ examples/vanilla-avatar-stack-2/package.json | 27 ++++ examples/vanilla-avatar-stack-2/script.js | 129 ++++++++++++++++++ examples/vanilla-avatar-stack-2/styles.css | 84 ++++++++++++ examples/vanilla-avatar-stack-2/tsconfig.json | 26 ++++ .../vanilla-avatar-stack-2/tsconfig.node.json | 8 ++ .../vanilla-avatar-stack-2/vite.config.ts | 7 + src/main.tsx | 2 + src/routes/Home.tsx | 6 + src/routes/VanillaAvatarStack2.tsx | 11 ++ 12 files changed, 321 insertions(+) create mode 100644 examples/vanilla-avatar-stack-2/.env.example create mode 100644 examples/vanilla-avatar-stack-2/.gitignore create mode 100644 examples/vanilla-avatar-stack-2/index.html create mode 100644 examples/vanilla-avatar-stack-2/package.json create mode 100644 examples/vanilla-avatar-stack-2/script.js create mode 100644 examples/vanilla-avatar-stack-2/styles.css create mode 100644 examples/vanilla-avatar-stack-2/tsconfig.json create mode 100644 examples/vanilla-avatar-stack-2/tsconfig.node.json create mode 100644 examples/vanilla-avatar-stack-2/vite.config.ts create mode 100644 src/routes/VanillaAvatarStack2.tsx diff --git a/examples/vanilla-avatar-stack-2/.env.example b/examples/vanilla-avatar-stack-2/.env.example new file mode 100644 index 0000000..dbcc501 --- /dev/null +++ b/examples/vanilla-avatar-stack-2/.env.example @@ -0,0 +1,2 @@ +# Use your own API KEY from Ably here: +VITE_ABLY_KEY= diff --git a/examples/vanilla-avatar-stack-2/.gitignore b/examples/vanilla-avatar-stack-2/.gitignore new file mode 100644 index 0000000..713d500 --- /dev/null +++ b/examples/vanilla-avatar-stack-2/.gitignore @@ -0,0 +1,2 @@ +node_modules/ +.env diff --git a/examples/vanilla-avatar-stack-2/index.html b/examples/vanilla-avatar-stack-2/index.html new file mode 100644 index 0000000..419e579 --- /dev/null +++ b/examples/vanilla-avatar-stack-2/index.html @@ -0,0 +1,17 @@ + + + + + + Avatar Stack + + + +
    +
    +
    +
    +
    + + + diff --git a/examples/vanilla-avatar-stack-2/package.json b/examples/vanilla-avatar-stack-2/package.json new file mode 100644 index 0000000..21c00d8 --- /dev/null +++ b/examples/vanilla-avatar-stack-2/package.json @@ -0,0 +1,27 @@ +{ + "name": "vanilla-avatar-stack-2", + "version": "1.0.0", + "description": "", + "main": "index.js", + "author": "", + "license": "ISC", + "scripts": { + "dev": "vite", + "build": "tsc && vite build", + "preview": "vite preview" + }, + "dependencies": { + "@ably/spaces": "0.2.0", + "ably": "1.2.45", + "classnames": "^2.3.2", + "nanoid": "^5.0.1", + "random-words": "^2.0.0", + "react": "^18.0.0", + "react-dom": "^18.0.0" + }, + "devDependencies": { + "dotenv": "16.4.5", + "typescript": "^5.2.2", + "vite": "^5.2.13" + } +} diff --git a/examples/vanilla-avatar-stack-2/script.js b/examples/vanilla-avatar-stack-2/script.js new file mode 100644 index 0000000..d46cd54 --- /dev/null +++ b/examples/vanilla-avatar-stack-2/script.js @@ -0,0 +1,129 @@ +import Spaces from '@ably/spaces' +import { Realtime } from 'ably' +import { nanoid } from 'nanoid' + +const client = new Realtime.Promise({ + clientId: nanoid(), + key: import.meta.env.VITE_ABLY_KEY, +}) + +const spaces = new Spaces(client) +const space = await spaces.get('avatar-stack') + +const mockNames = ["Anum Reeve", "Tiernan Stubbs", "Hakim Hernandez"] +const mockColors = ["#9951F5", "#f1c232", "#f44336"]; + +/** 💡 Add every avatar that enters 💡 */ +space.members.subscribe('enter', (memberUpdate) => { + addAvatar(memberUpdate, true); +}); + +/** 💡 Enter the space as soon as it's available 💡 */ +await space.enter({ + name: mockNames[Math.floor(Math.random() * mockNames.length)], + memberColor: mockColors[Math.floor(Math.random() * mockColors.length)], +}).then(async () => { + const otherMembers = await space.members.getOthers(); + + /** 💡 Get first four except the local member in the space 💡 */ + {otherMembers.slice(0, 4).map((user) => { + addAvatar(user) + })} + + /** 💡 Get a count of the number exceeding four and display as a single tally 💡 */ + if (otherMembers.length > 4) { + const avatarsElement = document.getElementById('avatars') + const avatarElement = document.createElement('div') + avatarElement.className='avatar' + avatarElement.style.backgroundColor = '#595959' + + const nameElement = document.createElement('p') + nameElement.className='textWhite nameOthers' + nameElement.textContent = `+${otherMembers.length-4}` + + avatarsElement.appendChild(avatarElement) + avatarElement.appendChild(nameElement) + } +}).catch((err) => { + console.error('Error joining space:', err); +}) + +function createUserInfo(user, isSelf = false) { + const wrapper = document.createElement('div') + wrapper.className = 'wrapper' + + const userInfoContainer = document.createElement('div') + userInfoContainer.className = 'userInfoContainer' + userInfoContainer.style.backgroundColor = user.profileData.memberColor + userInfoContainer.id = 'avatar' + + const userInitials = user.profileData.name + .split(" ") + .map((word) => word.charAt(0)) + .join(""); + + const initials = document.createElement('p') + initials.className = 'smallText' + initials.textContent = userInitials + + userInfoContainer.appendChild(initials) + wrapper.appendChild(userInfoContainer) + + const userList = document.createElement('div') + userList.className = 'userList' + userList.id = 'user-list' + + const nameElement = document.createElement('p') + nameElement.className = 'name' + nameElement.textContent = isSelf ? user.profileData.name + ' (You)' : user.profileData.name + + userList.appendChild(nameElement) + wrapper.appendChild(userList) + + return wrapper; +} + +async function addAvatar(user, isSelf = false) { + const userInitials = user.profileData.name + .split(" ") + .map((word) => word.charAt(0)) + .join(""); + + const avatarsElement = document.getElementById('avatars') + const avatarElement = document.createElement('div') + avatarElement.className = isSelf ? 'selfAvatar' : 'otherAvatar' + + const avatarContainer = document.createElement('div') + avatarContainer.className = 'avatarContainer' + + const avatar = document.createElement('div') + avatar.className = 'avatar' + avatar.style.backgroundColor = user.profileData.memberColor + avatar.setAttribute('data-member-id', user.clientId) + avatar.setAttribute('key', user.clientId) + + const initials = document.createElement('p') + initials.className = "textWhite" + initials.textContent = userInitials + + avatar.appendChild(initials) + + const popup = document.createElement('div'); + popup.className = 'popup'; + popup.style.display = 'none'; + + const userInfo = createUserInfo(user, isSelf) + avatarsElement.appendChild(avatarElement) + avatarElement.appendChild(avatarContainer) + avatarContainer.appendChild(avatar) + popup.appendChild(userInfo); + avatar.appendChild(popup); + + avatar.addEventListener('mouseover', () => { + popup.style.display = 'block' + }); + + avatar.addEventListener('mouseleave', () => { + popup.style.display = 'none' + }); +} diff --git a/examples/vanilla-avatar-stack-2/styles.css b/examples/vanilla-avatar-stack-2/styles.css new file mode 100644 index 0000000..2fc5cbe --- /dev/null +++ b/examples/vanilla-avatar-stack-2/styles.css @@ -0,0 +1,84 @@ +.avatarStackContainer { + width: 100%; + display: flex; + justify-content: center; + align-items: center; + position: relative; + background-color: #f4f8fb; + height: 100vh; +} + +.avatars { + display: inline-flex; +} + +.avatarContainer { + position: relative; +} + +.avatar { + background-color: rgb(234, 88, 12); + height: 3rem; + width: 3rem; + border-radius: 9999px; + display: flex; + align-items: center; + justify-content: center; + border: 2px solid #e2e7ef; + flex-shrink: 0; + position: relative; + margin-left: -7px; +} + +.name { + font-size: 0.75rem; + line-height: 1rem; + color: rgb(255, 255, 255); +} + +.textWhite { + color: #fff; +} + +.nameOthers { + z-index: 20; + font-size: 0.75rem; +} + +.popup { + position: absolute; + left: -5rem; + top: -4.8rem; + padding: 1rem; + background-color: #000; + border-radius: 8px; + color: #fff; + min-width: 240px; +} + +.wrapper { + display: flex; + justify-content: flex-start; + align-items: center; +} + +.userList { + padding-left: 0.75rem; + width: 100%; +} + +.userInfoContainer { + height: 2rem; + width: 2rem; + border-radius: 9999px; + display: flex; + flex-shrink: 0; + align-items: center; + justify-content: center; + position: relative; + border: 2px solid #cbd5e0; +} + +.smallText { + font-size: 0.75rem; +} diff --git a/examples/vanilla-avatar-stack-2/tsconfig.json b/examples/vanilla-avatar-stack-2/tsconfig.json new file mode 100644 index 0000000..bf03b41 --- /dev/null +++ b/examples/vanilla-avatar-stack-2/tsconfig.json @@ -0,0 +1,26 @@ +{ + "compilerOptions": { + "target": "ESNext", + "useDefineForClassFields": true, + "lib": ["DOM", "DOM.Iterable", "ESNext"], + "allowJs": false, + "skipLibCheck": true, + "esModuleInterop": false, + "allowSyntheticDefaultImports": true, + "strict": true, + "forceConsistentCasingInFileNames": true, + "module": "ESNext", + "moduleResolution": "Node", + "resolveJsonModule": true, + "isolatedModules": true, + "noEmit": true, + "jsx": "react-jsx" + }, + "types": ["vite/client"], + "include": ["src"], + "references": [ + { + "path": "./tsconfig.node.json" + } + ] + } diff --git a/examples/vanilla-avatar-stack-2/tsconfig.node.json b/examples/vanilla-avatar-stack-2/tsconfig.node.json new file mode 100644 index 0000000..cdd5821 --- /dev/null +++ b/examples/vanilla-avatar-stack-2/tsconfig.node.json @@ -0,0 +1,8 @@ +{ + "compilerOptions": { + "composite": true, + "module": "esnext", + "moduleResolution": "node" + }, + "include": ["vite.config.ts"] + } diff --git a/examples/vanilla-avatar-stack-2/vite.config.ts b/examples/vanilla-avatar-stack-2/vite.config.ts new file mode 100644 index 0000000..3c2f3df --- /dev/null +++ b/examples/vanilla-avatar-stack-2/vite.config.ts @@ -0,0 +1,7 @@ +import { defineConfig } from 'vite'; +import react from '@vitejs/plugin-react'; + +export default defineConfig({ + plugins: [react()], + publicDir: 'public', +}); diff --git a/src/main.tsx b/src/main.tsx index 1460794..cd9c1d7 100644 --- a/src/main.tsx +++ b/src/main.tsx @@ -14,6 +14,7 @@ import UserClaims from "./routes/UserClaims"; import MemberLocation from "./routes/MemberLocation"; import ComponentLocking from "./routes/ComponentLocking"; import VanillaAvatarStack from "./routes/VanillaAvatarStack"; +import VanillaAvatarStack2 from "./routes/VanillaAvatarStack2"; import ViteReactAvatarStack from "./routes/ViteReactAvatarStack"; import ViteReactAvatarStack2 from "./routes/ViteReactAvatarStack2"; @@ -54,6 +55,7 @@ ReactDOM.createRoot(document.getElementById("root")!).render( } /> } /> } /> + } /> } /> } /> diff --git a/src/routes/Home.tsx b/src/routes/Home.tsx index 01204a6..05aebbf 100644 --- a/src/routes/Home.tsx +++ b/src/routes/Home.tsx @@ -34,9 +34,15 @@ const Home = () => {
  • Avatar Stack - Vanilla JS
  • +
  • + Avatar Stack - Vanilla JS (Revised) +
  • Avatar Stack - React
  • +
  • + Avatar Stack - React (Revised) +
  • ); }; diff --git a/src/routes/VanillaAvatarStack2.tsx b/src/routes/VanillaAvatarStack2.tsx new file mode 100644 index 0000000..13b5178 --- /dev/null +++ b/src/routes/VanillaAvatarStack2.tsx @@ -0,0 +1,11 @@ +const VanillaAvatarStack2 = () => { + return ( + + ); +}; + +export default VanillaAvatarStack2; From 6c35004ddb6b95c2d81ff4a8fcf4230fbd642acc Mon Sep 17 00:00:00 2001 From: Greg Holmes Date: Mon, 12 Aug 2024 10:26:47 +0100 Subject: [PATCH 12/19] Update ably dependencies to latest version --- examples/vanilla-avatar-stack-2/package.json | 4 +- examples/vanilla-avatar-stack-2/script.js | 2 +- .../vite-react-avatar-stack-2/package.json | 9 +-- .../vite-react-avatar-stack-2/src/App.tsx | 2 +- examples/vite-react-avatar-stack-2/yarn.lock | 57 ++++++++++--------- 5 files changed, 38 insertions(+), 36 deletions(-) diff --git a/examples/vanilla-avatar-stack-2/package.json b/examples/vanilla-avatar-stack-2/package.json index 21c00d8..beb84ae 100644 --- a/examples/vanilla-avatar-stack-2/package.json +++ b/examples/vanilla-avatar-stack-2/package.json @@ -11,8 +11,8 @@ "preview": "vite preview" }, "dependencies": { - "@ably/spaces": "0.2.0", - "ably": "1.2.45", + "@ably/spaces": "0.4.0", + "ably": "2.3.1", "classnames": "^2.3.2", "nanoid": "^5.0.1", "random-words": "^2.0.0", diff --git a/examples/vanilla-avatar-stack-2/script.js b/examples/vanilla-avatar-stack-2/script.js index d46cd54..32ccc57 100644 --- a/examples/vanilla-avatar-stack-2/script.js +++ b/examples/vanilla-avatar-stack-2/script.js @@ -2,7 +2,7 @@ import Spaces from '@ably/spaces' import { Realtime } from 'ably' import { nanoid } from 'nanoid' -const client = new Realtime.Promise({ +const client = new Realtime({ clientId: nanoid(), key: import.meta.env.VITE_ABLY_KEY, }) diff --git a/examples/vite-react-avatar-stack-2/package.json b/examples/vite-react-avatar-stack-2/package.json index 3c81c26..ddea839 100644 --- a/examples/vite-react-avatar-stack-2/package.json +++ b/examples/vite-react-avatar-stack-2/package.json @@ -1,5 +1,5 @@ { - "name": "@ably-labs/vite-react-avatar-stack", + "name": "@ably-labs/vite-react-avatar-stack-2", "license": "Apache-2.0", "version": "1.0.0", "private": true, @@ -10,12 +10,9 @@ "format": "prettier --write ." }, "dependencies": { - "@ably/spaces": "0.2.0", - "ably": "1.2.45", - "classnames": "^2.3.2", - "dayjs": "^1.11.4", + "@ably/spaces": "0.4.0", + "ably": "2.3.1", "nanoid": "^5.0.1", - "random-words": "^2.0.0", "react": "^18.2.0", "react-dom": "^18.2.0" }, diff --git a/examples/vite-react-avatar-stack-2/src/App.tsx b/examples/vite-react-avatar-stack-2/src/App.tsx index 62768f3..728a5ff 100644 --- a/examples/vite-react-avatar-stack-2/src/App.tsx +++ b/examples/vite-react-avatar-stack-2/src/App.tsx @@ -70,7 +70,7 @@ function AvatarStack() { const App = ({ spaces }: { spaces: Spaces }) => ( - + diff --git a/examples/vite-react-avatar-stack-2/yarn.lock b/examples/vite-react-avatar-stack-2/yarn.lock index 54f4c81..438e151 100644 --- a/examples/vite-react-avatar-stack-2/yarn.lock +++ b/examples/vite-react-avatar-stack-2/yarn.lock @@ -9,12 +9,12 @@ dependencies: bops "^1.0.1" -"@ably/spaces@0.2.0": - version "0.2.0" - resolved "https://registry.yarnpkg.com/@ably/spaces/-/spaces-0.2.0.tgz#ba999c634421e98fb063d443846c8c8d059a77c0" - integrity sha512-s2QE4uzWoS67Sq0z0KTTWlRtvHbCg9FyN+0K/8Agv+hvPY9Fe2r0oozae/Lj2Q2i7oEUiRvoYl37rX9Xk9x+fQ== +"@ably/spaces@0.4.0": + version "0.4.0" + resolved "https://registry.yarnpkg.com/@ably/spaces/-/spaces-0.4.0.tgz#766d748d79f3de3cd82939431daea99479150bbf" + integrity sha512-yehNgkv9DOHUBR1c46/5Q4BhkF3TJkKb00kLDhZFWTVJpFSW0Mkw0PUgHLkzAg9Bt9LJPcA0mgZq3mFeLQCrIg== dependencies: - nanoid "^5.0.2" + nanoid "^3.3.7" "@ampproject/remapping@^2.2.0": version "2.2.1" @@ -503,14 +503,16 @@ "@types/babel__core" "^7.20.2" react-refresh "^0.14.0" -ably@1.2.45: - version "1.2.45" - resolved "https://registry.yarnpkg.com/ably/-/ably-1.2.45.tgz#9da9b3faae18614160dd7ff1e5e93de948f984bd" - integrity sha512-8Jk8XT0dSPcLcZ8zSAF+mRtwMzaQR5dWHqGdx9Y859ZLhXiqf4gQb7P+4Elqy1l1IIRoDWgyt0fkyfo7ngUdMA== +ably@2.3.1: + version "2.3.1" + resolved "https://registry.yarnpkg.com/ably/-/ably-2.3.1.tgz#c3b02df6aa4262284b0b1ba130e5f85e0f423ef4" + integrity sha512-OQ9PUwQe0qehOUPqvLargmUTlPQsxCAdStIpLZE7pT68yDd3JF28R1Ap7C50DluCIa6NqXrieRSa2tcLNN95PA== dependencies: "@ably/msgpack-js" "^0.4.0" + fastestsmallesttextencoderdecoder "^1.0.22" got "^11.8.5" - ws "^5.1" + ulid "^2.3.0" + ws "^8.17.1" ansi-styles@^3.2.1: version "3.2.1" @@ -519,11 +521,6 @@ ansi-styles@^3.2.1: dependencies: color-convert "^1.9.0" -async-limiter@~1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/async-limiter/-/async-limiter-1.0.1.tgz#dd379e94f0db8310b08291f9d64c3209766617fd" - integrity sha512-csOlWGAcRFJaI6m+F2WKdnMKr4HhdhFVBk0H/QbJFMCr+uO2kwohwXQPxw/9OCxp05r5ghVBFSyioixx3gfkNQ== - base64-js@1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.0.2.tgz#474211c95e6cf2a547db461e4f6778b51d08fa65" @@ -687,6 +684,11 @@ escape-string-regexp@^1.0.5: resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" integrity sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg== +fastestsmallesttextencoderdecoder@^1.0.22: + version "1.0.22" + resolved "https://registry.yarnpkg.com/fastestsmallesttextencoderdecoder/-/fastestsmallesttextencoderdecoder-1.0.22.tgz#59b47e7b965f45258629cc6c127bf783281c5e93" + integrity sha512-Pb8d48e+oIuY4MaM64Cd7OW1gt4nxCHs7/ddPPZ/Ic3sg8yVGM7O9wDvZ7us6ScaUupzM+pfBolwtYhN1IxBIw== + fsevents@~2.3.2: version "2.3.3" resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.3.tgz#cac6407785d03675a2a5e1a5305c697b347d90d6" @@ -810,16 +812,16 @@ nanoid@^3.3.6: resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.6.tgz#443380c856d6e9f9824267d960b4236ad583ea4c" integrity sha512-BGcqMMJuToF7i1rt+2PWSNVnWIkGCU78jBG3RxO/bZlnZPK2Cmi2QaffxGO/2RvWi9sL+FAiRiXMgsyxQ1DIDA== +nanoid@^3.3.7: + version "3.3.7" + resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.7.tgz#d0c301a691bc8d54efa0a2226ccf3fe2fd656bd8" + integrity sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g== + nanoid@^5.0.1: version "5.0.1" resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-5.0.1.tgz#3e95d775a8bc8a98afbf0a237e2bbc6a71b0662e" integrity sha512-vWeVtV5Cw68aML/QaZvqN/3QQXc6fBfIieAlu05m7FZW2Dgb+3f0xc0TTxuJW+7u30t7iSDTV/j3kVI0oJqIfQ== -nanoid@^5.0.2: - version "5.0.2" - resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-5.0.2.tgz#97588ebc70166d0feaf73ccd2799bb4ceaebf692" - integrity sha512-2ustYUX1R2rL/Br5B/FMhi8d5/QzvkJ912rBYxskcpu0myTHzSZfTr1LAS2Sm7jxRUObRrSBFoyzwAhL49aVSg== - node-releases@^2.0.13: version "2.0.13" resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.13.tgz#d5ed1627c23e3461e819b02e57b75e4899b1c81d" @@ -959,6 +961,11 @@ typescript@5.2.2: resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.2.2.tgz#5ebb5e5a5b75f085f22bc3f8460fba308310fa78" integrity sha512-mI4WrpHsbCIcwT9cF4FZvr80QUeKvsUsUvKDoR+X/7XHQH98xYD8YHZg7ANtz2GtZt/CBq2QJ0thkGJMHfqc1w== +ulid@^2.3.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/ulid/-/ulid-2.3.0.tgz#93063522771a9774121a84d126ecd3eb9804071f" + integrity sha512-keqHubrlpvT6G2wH0OEfSW4mquYRcbe/J8NMmveoQOjUqmo+hXtO+ORCpWhdbZ7k72UtY61BL7haGxW6enBnjw== + update-browserslist-db@^1.0.11: version "1.0.11" resolved "https://registry.yarnpkg.com/update-browserslist-db/-/update-browserslist-db-1.0.11.tgz#9a2a641ad2907ae7b3616506f4b977851db5b940" @@ -983,12 +990,10 @@ wrappy@1: resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" integrity sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ== -ws@^5.1: - version "5.2.3" - resolved "https://registry.yarnpkg.com/ws/-/ws-5.2.3.tgz#05541053414921bc29c63bee14b8b0dd50b07b3d" - integrity sha512-jZArVERrMsKUatIdnLzqvcfydI85dvd/Fp1u/VOpfdDWQ4c9qWXe+VIeAbQ5FrDwciAkr+lzofXLz3Kuf26AOA== - dependencies: - async-limiter "~1.0.0" +ws@^8.17.1: + version "8.18.0" + resolved "https://registry.yarnpkg.com/ws/-/ws-8.18.0.tgz#0d7505a6eafe2b0e712d232b42279f53bc289bbc" + integrity sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw== yallist@^3.0.2: version "3.1.1" From 7105f318dc83a79c4c2b164f65549e8d10164e25 Mon Sep 17 00:00:00 2001 From: Greg Holmes Date: Mon, 12 Aug 2024 11:41:46 +0100 Subject: [PATCH 13/19] Revert "Update ably dependencies to latest version" This reverts commit 6c35004ddb6b95c2d81ff4a8fcf4230fbd642acc. --- examples/vanilla-avatar-stack-2/package.json | 4 +- examples/vanilla-avatar-stack-2/script.js | 2 +- .../vite-react-avatar-stack-2/package.json | 9 ++- .../vite-react-avatar-stack-2/src/App.tsx | 2 +- examples/vite-react-avatar-stack-2/yarn.lock | 57 +++++++++---------- 5 files changed, 36 insertions(+), 38 deletions(-) diff --git a/examples/vanilla-avatar-stack-2/package.json b/examples/vanilla-avatar-stack-2/package.json index beb84ae..21c00d8 100644 --- a/examples/vanilla-avatar-stack-2/package.json +++ b/examples/vanilla-avatar-stack-2/package.json @@ -11,8 +11,8 @@ "preview": "vite preview" }, "dependencies": { - "@ably/spaces": "0.4.0", - "ably": "2.3.1", + "@ably/spaces": "0.2.0", + "ably": "1.2.45", "classnames": "^2.3.2", "nanoid": "^5.0.1", "random-words": "^2.0.0", diff --git a/examples/vanilla-avatar-stack-2/script.js b/examples/vanilla-avatar-stack-2/script.js index 32ccc57..d46cd54 100644 --- a/examples/vanilla-avatar-stack-2/script.js +++ b/examples/vanilla-avatar-stack-2/script.js @@ -2,7 +2,7 @@ import Spaces from '@ably/spaces' import { Realtime } from 'ably' import { nanoid } from 'nanoid' -const client = new Realtime({ +const client = new Realtime.Promise({ clientId: nanoid(), key: import.meta.env.VITE_ABLY_KEY, }) diff --git a/examples/vite-react-avatar-stack-2/package.json b/examples/vite-react-avatar-stack-2/package.json index ddea839..3c81c26 100644 --- a/examples/vite-react-avatar-stack-2/package.json +++ b/examples/vite-react-avatar-stack-2/package.json @@ -1,5 +1,5 @@ { - "name": "@ably-labs/vite-react-avatar-stack-2", + "name": "@ably-labs/vite-react-avatar-stack", "license": "Apache-2.0", "version": "1.0.0", "private": true, @@ -10,9 +10,12 @@ "format": "prettier --write ." }, "dependencies": { - "@ably/spaces": "0.4.0", - "ably": "2.3.1", + "@ably/spaces": "0.2.0", + "ably": "1.2.45", + "classnames": "^2.3.2", + "dayjs": "^1.11.4", "nanoid": "^5.0.1", + "random-words": "^2.0.0", "react": "^18.2.0", "react-dom": "^18.2.0" }, diff --git a/examples/vite-react-avatar-stack-2/src/App.tsx b/examples/vite-react-avatar-stack-2/src/App.tsx index 728a5ff..62768f3 100644 --- a/examples/vite-react-avatar-stack-2/src/App.tsx +++ b/examples/vite-react-avatar-stack-2/src/App.tsx @@ -70,7 +70,7 @@ function AvatarStack() { const App = ({ spaces }: { spaces: Spaces }) => ( - + diff --git a/examples/vite-react-avatar-stack-2/yarn.lock b/examples/vite-react-avatar-stack-2/yarn.lock index 438e151..54f4c81 100644 --- a/examples/vite-react-avatar-stack-2/yarn.lock +++ b/examples/vite-react-avatar-stack-2/yarn.lock @@ -9,12 +9,12 @@ dependencies: bops "^1.0.1" -"@ably/spaces@0.4.0": - version "0.4.0" - resolved "https://registry.yarnpkg.com/@ably/spaces/-/spaces-0.4.0.tgz#766d748d79f3de3cd82939431daea99479150bbf" - integrity sha512-yehNgkv9DOHUBR1c46/5Q4BhkF3TJkKb00kLDhZFWTVJpFSW0Mkw0PUgHLkzAg9Bt9LJPcA0mgZq3mFeLQCrIg== +"@ably/spaces@0.2.0": + version "0.2.0" + resolved "https://registry.yarnpkg.com/@ably/spaces/-/spaces-0.2.0.tgz#ba999c634421e98fb063d443846c8c8d059a77c0" + integrity sha512-s2QE4uzWoS67Sq0z0KTTWlRtvHbCg9FyN+0K/8Agv+hvPY9Fe2r0oozae/Lj2Q2i7oEUiRvoYl37rX9Xk9x+fQ== dependencies: - nanoid "^3.3.7" + nanoid "^5.0.2" "@ampproject/remapping@^2.2.0": version "2.2.1" @@ -503,16 +503,14 @@ "@types/babel__core" "^7.20.2" react-refresh "^0.14.0" -ably@2.3.1: - version "2.3.1" - resolved "https://registry.yarnpkg.com/ably/-/ably-2.3.1.tgz#c3b02df6aa4262284b0b1ba130e5f85e0f423ef4" - integrity sha512-OQ9PUwQe0qehOUPqvLargmUTlPQsxCAdStIpLZE7pT68yDd3JF28R1Ap7C50DluCIa6NqXrieRSa2tcLNN95PA== +ably@1.2.45: + version "1.2.45" + resolved "https://registry.yarnpkg.com/ably/-/ably-1.2.45.tgz#9da9b3faae18614160dd7ff1e5e93de948f984bd" + integrity sha512-8Jk8XT0dSPcLcZ8zSAF+mRtwMzaQR5dWHqGdx9Y859ZLhXiqf4gQb7P+4Elqy1l1IIRoDWgyt0fkyfo7ngUdMA== dependencies: "@ably/msgpack-js" "^0.4.0" - fastestsmallesttextencoderdecoder "^1.0.22" got "^11.8.5" - ulid "^2.3.0" - ws "^8.17.1" + ws "^5.1" ansi-styles@^3.2.1: version "3.2.1" @@ -521,6 +519,11 @@ ansi-styles@^3.2.1: dependencies: color-convert "^1.9.0" +async-limiter@~1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/async-limiter/-/async-limiter-1.0.1.tgz#dd379e94f0db8310b08291f9d64c3209766617fd" + integrity sha512-csOlWGAcRFJaI6m+F2WKdnMKr4HhdhFVBk0H/QbJFMCr+uO2kwohwXQPxw/9OCxp05r5ghVBFSyioixx3gfkNQ== + base64-js@1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.0.2.tgz#474211c95e6cf2a547db461e4f6778b51d08fa65" @@ -684,11 +687,6 @@ escape-string-regexp@^1.0.5: resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" integrity sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg== -fastestsmallesttextencoderdecoder@^1.0.22: - version "1.0.22" - resolved "https://registry.yarnpkg.com/fastestsmallesttextencoderdecoder/-/fastestsmallesttextencoderdecoder-1.0.22.tgz#59b47e7b965f45258629cc6c127bf783281c5e93" - integrity sha512-Pb8d48e+oIuY4MaM64Cd7OW1gt4nxCHs7/ddPPZ/Ic3sg8yVGM7O9wDvZ7us6ScaUupzM+pfBolwtYhN1IxBIw== - fsevents@~2.3.2: version "2.3.3" resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.3.tgz#cac6407785d03675a2a5e1a5305c697b347d90d6" @@ -812,16 +810,16 @@ nanoid@^3.3.6: resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.6.tgz#443380c856d6e9f9824267d960b4236ad583ea4c" integrity sha512-BGcqMMJuToF7i1rt+2PWSNVnWIkGCU78jBG3RxO/bZlnZPK2Cmi2QaffxGO/2RvWi9sL+FAiRiXMgsyxQ1DIDA== -nanoid@^3.3.7: - version "3.3.7" - resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.7.tgz#d0c301a691bc8d54efa0a2226ccf3fe2fd656bd8" - integrity sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g== - nanoid@^5.0.1: version "5.0.1" resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-5.0.1.tgz#3e95d775a8bc8a98afbf0a237e2bbc6a71b0662e" integrity sha512-vWeVtV5Cw68aML/QaZvqN/3QQXc6fBfIieAlu05m7FZW2Dgb+3f0xc0TTxuJW+7u30t7iSDTV/j3kVI0oJqIfQ== +nanoid@^5.0.2: + version "5.0.2" + resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-5.0.2.tgz#97588ebc70166d0feaf73ccd2799bb4ceaebf692" + integrity sha512-2ustYUX1R2rL/Br5B/FMhi8d5/QzvkJ912rBYxskcpu0myTHzSZfTr1LAS2Sm7jxRUObRrSBFoyzwAhL49aVSg== + node-releases@^2.0.13: version "2.0.13" resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.13.tgz#d5ed1627c23e3461e819b02e57b75e4899b1c81d" @@ -961,11 +959,6 @@ typescript@5.2.2: resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.2.2.tgz#5ebb5e5a5b75f085f22bc3f8460fba308310fa78" integrity sha512-mI4WrpHsbCIcwT9cF4FZvr80QUeKvsUsUvKDoR+X/7XHQH98xYD8YHZg7ANtz2GtZt/CBq2QJ0thkGJMHfqc1w== -ulid@^2.3.0: - version "2.3.0" - resolved "https://registry.yarnpkg.com/ulid/-/ulid-2.3.0.tgz#93063522771a9774121a84d126ecd3eb9804071f" - integrity sha512-keqHubrlpvT6G2wH0OEfSW4mquYRcbe/J8NMmveoQOjUqmo+hXtO+ORCpWhdbZ7k72UtY61BL7haGxW6enBnjw== - update-browserslist-db@^1.0.11: version "1.0.11" resolved "https://registry.yarnpkg.com/update-browserslist-db/-/update-browserslist-db-1.0.11.tgz#9a2a641ad2907ae7b3616506f4b977851db5b940" @@ -990,10 +983,12 @@ wrappy@1: resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" integrity sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ== -ws@^8.17.1: - version "8.18.0" - resolved "https://registry.yarnpkg.com/ws/-/ws-8.18.0.tgz#0d7505a6eafe2b0e712d232b42279f53bc289bbc" - integrity sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw== +ws@^5.1: + version "5.2.3" + resolved "https://registry.yarnpkg.com/ws/-/ws-5.2.3.tgz#05541053414921bc29c63bee14b8b0dd50b07b3d" + integrity sha512-jZArVERrMsKUatIdnLzqvcfydI85dvd/Fp1u/VOpfdDWQ4c9qWXe+VIeAbQ5FrDwciAkr+lzofXLz3Kuf26AOA== + dependencies: + async-limiter "~1.0.0" yallist@^3.0.2: version "3.1.1" From 9772ea97912b79520e03b3b345b3241b4b72361c Mon Sep 17 00:00:00 2001 From: Greg Holmes Date: Mon, 12 Aug 2024 11:48:01 +0100 Subject: [PATCH 14/19] Fix name of package --- examples/vite-react-avatar-stack-2/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/vite-react-avatar-stack-2/package.json b/examples/vite-react-avatar-stack-2/package.json index 3c81c26..fef096b 100644 --- a/examples/vite-react-avatar-stack-2/package.json +++ b/examples/vite-react-avatar-stack-2/package.json @@ -1,5 +1,5 @@ { - "name": "@ably-labs/vite-react-avatar-stack", + "name": "@ably-labs/vite-react-avatar-stack-2", "license": "Apache-2.0", "version": "1.0.0", "private": true, From 61c89e3969b82f6d6fea7d626d730396436b0cde Mon Sep 17 00:00:00 2001 From: Greg Holmes Date: Mon, 12 Aug 2024 11:48:21 +0100 Subject: [PATCH 15/19] Fix name of react avatar stack 2 Space's name --- examples/vite-react-avatar-stack-2/src/App.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/vite-react-avatar-stack-2/src/App.tsx b/examples/vite-react-avatar-stack-2/src/App.tsx index 62768f3..728a5ff 100644 --- a/examples/vite-react-avatar-stack-2/src/App.tsx +++ b/examples/vite-react-avatar-stack-2/src/App.tsx @@ -70,7 +70,7 @@ function AvatarStack() { const App = ({ spaces }: { spaces: Spaces }) => ( - + From 63647709023a1d3bb8fe962693eafeb2887613bb Mon Sep 17 00:00:00 2001 From: Greg Holmes Date: Mon, 12 Aug 2024 17:03:43 +0100 Subject: [PATCH 16/19] Testing - broken commit --- examples/vanilla-avatar-stack-2/index.html | 4 +- examples/vanilla-avatar-stack-2/package.json | 2 +- examples/vanilla-avatar-stack-2/script.js | 129 -------- examples/vanilla-avatar-stack-2/src/script.ts | 160 +++++++++ examples/vanilla-avatar-stack-2/tsconfig.json | 2 +- examples/vanilla-avatar-stack-2/vite-env.d.ts | 8 + src/routes/VanillaAvatarStack2.tsx | 2 +- yarn.lock | 304 ++++++++++++++++++ 8 files changed, 477 insertions(+), 134 deletions(-) delete mode 100644 examples/vanilla-avatar-stack-2/script.js create mode 100644 examples/vanilla-avatar-stack-2/src/script.ts create mode 100644 examples/vanilla-avatar-stack-2/vite-env.d.ts diff --git a/examples/vanilla-avatar-stack-2/index.html b/examples/vanilla-avatar-stack-2/index.html index 419e579..af3e2cc 100644 --- a/examples/vanilla-avatar-stack-2/index.html +++ b/examples/vanilla-avatar-stack-2/index.html @@ -4,7 +4,7 @@ Avatar Stack - +
    @@ -12,6 +12,6 @@
    - + diff --git a/examples/vanilla-avatar-stack-2/package.json b/examples/vanilla-avatar-stack-2/package.json index 21c00d8..5ad9994 100644 --- a/examples/vanilla-avatar-stack-2/package.json +++ b/examples/vanilla-avatar-stack-2/package.json @@ -2,7 +2,7 @@ "name": "vanilla-avatar-stack-2", "version": "1.0.0", "description": "", - "main": "index.js", + "main": "src/index.js", "author": "", "license": "ISC", "scripts": { diff --git a/examples/vanilla-avatar-stack-2/script.js b/examples/vanilla-avatar-stack-2/script.js deleted file mode 100644 index d46cd54..0000000 --- a/examples/vanilla-avatar-stack-2/script.js +++ /dev/null @@ -1,129 +0,0 @@ -import Spaces from '@ably/spaces' -import { Realtime } from 'ably' -import { nanoid } from 'nanoid' - -const client = new Realtime.Promise({ - clientId: nanoid(), - key: import.meta.env.VITE_ABLY_KEY, -}) - -const spaces = new Spaces(client) -const space = await spaces.get('avatar-stack') - -const mockNames = ["Anum Reeve", "Tiernan Stubbs", "Hakim Hernandez"] -const mockColors = ["#9951F5", "#f1c232", "#f44336"]; - -/** 💡 Add every avatar that enters 💡 */ -space.members.subscribe('enter', (memberUpdate) => { - addAvatar(memberUpdate, true); -}); - -/** 💡 Enter the space as soon as it's available 💡 */ -await space.enter({ - name: mockNames[Math.floor(Math.random() * mockNames.length)], - memberColor: mockColors[Math.floor(Math.random() * mockColors.length)], -}).then(async () => { - const otherMembers = await space.members.getOthers(); - - /** 💡 Get first four except the local member in the space 💡 */ - {otherMembers.slice(0, 4).map((user) => { - addAvatar(user) - })} - - /** 💡 Get a count of the number exceeding four and display as a single tally 💡 */ - if (otherMembers.length > 4) { - const avatarsElement = document.getElementById('avatars') - const avatarElement = document.createElement('div') - avatarElement.className='avatar' - avatarElement.style.backgroundColor = '#595959' - - const nameElement = document.createElement('p') - nameElement.className='textWhite nameOthers' - nameElement.textContent = `+${otherMembers.length-4}` - - avatarsElement.appendChild(avatarElement) - avatarElement.appendChild(nameElement) - } -}).catch((err) => { - console.error('Error joining space:', err); -}) - -function createUserInfo(user, isSelf = false) { - const wrapper = document.createElement('div') - wrapper.className = 'wrapper' - - const userInfoContainer = document.createElement('div') - userInfoContainer.className = 'userInfoContainer' - userInfoContainer.style.backgroundColor = user.profileData.memberColor - userInfoContainer.id = 'avatar' - - const userInitials = user.profileData.name - .split(" ") - .map((word) => word.charAt(0)) - .join(""); - - const initials = document.createElement('p') - initials.className = 'smallText' - initials.textContent = userInitials - - userInfoContainer.appendChild(initials) - wrapper.appendChild(userInfoContainer) - - const userList = document.createElement('div') - userList.className = 'userList' - userList.id = 'user-list' - - const nameElement = document.createElement('p') - nameElement.className = 'name' - nameElement.textContent = isSelf ? user.profileData.name + ' (You)' : user.profileData.name - - userList.appendChild(nameElement) - wrapper.appendChild(userList) - - return wrapper; -} - -async function addAvatar(user, isSelf = false) { - const userInitials = user.profileData.name - .split(" ") - .map((word) => word.charAt(0)) - .join(""); - - const avatarsElement = document.getElementById('avatars') - const avatarElement = document.createElement('div') - avatarElement.className = isSelf ? 'selfAvatar' : 'otherAvatar' - - const avatarContainer = document.createElement('div') - avatarContainer.className = 'avatarContainer' - - const avatar = document.createElement('div') - avatar.className = 'avatar' - avatar.style.backgroundColor = user.profileData.memberColor - avatar.setAttribute('data-member-id', user.clientId) - avatar.setAttribute('key', user.clientId) - - const initials = document.createElement('p') - initials.className = "textWhite" - initials.textContent = userInitials - - avatar.appendChild(initials) - - const popup = document.createElement('div'); - popup.className = 'popup'; - popup.style.display = 'none'; - - const userInfo = createUserInfo(user, isSelf) - avatarsElement.appendChild(avatarElement) - avatarElement.appendChild(avatarContainer) - avatarContainer.appendChild(avatar) - popup.appendChild(userInfo); - avatar.appendChild(popup); - - avatar.addEventListener('mouseover', () => { - popup.style.display = 'block' - }); - - avatar.addEventListener('mouseleave', () => { - popup.style.display = 'none' - }); -} diff --git a/examples/vanilla-avatar-stack-2/src/script.ts b/examples/vanilla-avatar-stack-2/src/script.ts new file mode 100644 index 0000000..09785d9 --- /dev/null +++ b/examples/vanilla-avatar-stack-2/src/script.ts @@ -0,0 +1,160 @@ +import Spaces, { type SpaceMember } from "@ably/spaces"; +import { Realtime } from 'ably'; +import { nanoid } from 'nanoid'; + +export type Member = Omit & { + profileData: { memberColor: string; name: string }; +}; + +const client = new Realtime.Promise({ + clientId: nanoid(), + key: import.meta.env.VITE_ABLY_KEY as string, +}); + +const spaces = new Spaces(client); +const space = await spaces.get('avatar-stack'); + +const mockNames: string[] = ["Anum Reeve", "Tiernan Stubbs", "Hakim Hernandez"]; +const mockColors: string[] = ["#9951F5", "#f1c232", "#f44336"]; + +/** 💡 Add every avatar that enters 💡 */ +space.members.subscribe('enter', (memberUpdate: SpaceMember) => { + const member: Member = { + ...memberUpdate, + profileData: { + memberColor: (memberUpdate.profileData as any).memberColor, + name: (memberUpdate.profileData as any).name, + } + }; + addAvatar(member, true); +}); + +/** 💡 Enter the space as soon as it's available 💡 */ +await space.enter({ + name: mockNames[Math.floor(Math.random() * mockNames.length)], + memberColor: mockColors[Math.floor(Math.random() * mockColors.length)], +}).then(async () => { + const otherMembers = await space.members.getOthers(); + + /** 💡 Get first four except the local member in the space 💡 */ + space.members.subscribe('enter', (memberUpdate: SpaceMember) => { + if (memberUpdate.profileData && typeof memberUpdate.profileData === 'object' && + typeof (memberUpdate.profileData as any).memberColor === 'string' && + typeof (memberUpdate.profileData as any).name === 'string') { + + const member: Member = { + ...memberUpdate, + profileData: { + memberColor: (memberUpdate.profileData as any).memberColor, + name: (memberUpdate.profileData as any).name, + } + }; + + addAvatar(member, true); + } else { + console.warn('Received a member with invalid profile data:', memberUpdate); + } + }); + + /** 💡 Get a count of the number exceeding four and display as a single tally 💡 */ + if (otherMembers.length > 4) { + const avatarsElement = document.getElementById('avatars'); + if (avatarsElement) { + const avatarElement = document.createElement('div'); + avatarElement.className = 'avatar'; + avatarElement.style.backgroundColor = '#595959'; + + const nameElement = document.createElement('p'); + nameElement.className = 'textWhite nameOthers'; + nameElement.textContent = `+${otherMembers.length - 4}`; + + avatarElement.appendChild(nameElement); + avatarsElement.appendChild(avatarElement); + } + } +}).catch((err) => { + console.error('Error joining space:', err); +}); + +function createUserInfo(user: Member, isSelf: boolean = false): HTMLDivElement { + const wrapper = document.createElement('div'); + wrapper.className = 'wrapper'; + + const userInfoContainer = document.createElement('div'); + userInfoContainer.className = 'userInfoContainer'; + userInfoContainer.style.backgroundColor = user.profileData.memberColor; + userInfoContainer.id = 'avatar'; + + const userInitials = user.profileData.name + .split(" ") + .map((word: string) => word.charAt(0)) + .join(""); + + const initials = document.createElement('p'); + initials.className = 'smallText'; + initials.textContent = userInitials; + + userInfoContainer.appendChild(initials); + wrapper.appendChild(userInfoContainer); + + const userList = document.createElement('div'); + userList.className = 'userList'; + userList.id = 'user-list'; + + const nameElement = document.createElement('p'); + nameElement.className = 'name'; + nameElement.textContent = isSelf ? user.profileData.name + ' (You)' : user.profileData.name; + + userList.appendChild(nameElement); + wrapper.appendChild(userList); + + return wrapper; +} + +async function addAvatar(user: Member, isSelf: boolean = false): Promise { + const userInitials = user.profileData.name + .split(" ") + .map((word: string) => word.charAt(0)) + .join(""); + + const avatarsElement = document.getElementById('avatars'); + if (avatarsElement) { + const avatarElement = document.createElement('div'); + avatarElement.className = isSelf ? 'selfAvatar' : 'otherAvatar'; + + const avatarContainer = document.createElement('div'); + avatarContainer.className = 'avatarContainer'; + + const avatar = document.createElement('div'); + avatar.className = 'avatar'; + avatar.style.backgroundColor = user.profileData.memberColor; + avatar.setAttribute('data-member-id', user.clientId); + avatar.setAttribute('key', user.clientId); + + const initials = document.createElement('p'); + initials.className = "textWhite"; + initials.textContent = userInitials; + + avatar.appendChild(initials); + + const popup = document.createElement('div'); + popup.className = 'popup'; + popup.style.display = 'none'; + + const userInfo = createUserInfo(user, isSelf); + avatarElement.appendChild(avatarContainer); + avatarContainer.appendChild(avatar); + popup.appendChild(userInfo); + avatar.appendChild(popup); + + avatarsElement.appendChild(avatarElement); + + avatar.addEventListener('mouseover', () => { + popup.style.display = 'block'; + }); + + avatar.addEventListener('mouseleave', () => { + popup.style.display = 'none'; + }); + } +} diff --git a/examples/vanilla-avatar-stack-2/tsconfig.json b/examples/vanilla-avatar-stack-2/tsconfig.json index bf03b41..d334f83 100644 --- a/examples/vanilla-avatar-stack-2/tsconfig.json +++ b/examples/vanilla-avatar-stack-2/tsconfig.json @@ -17,7 +17,7 @@ "jsx": "react-jsx" }, "types": ["vite/client"], - "include": ["src"], + "include": ["src", "vite-env.d.ts"], "references": [ { "path": "./tsconfig.node.json" diff --git a/examples/vanilla-avatar-stack-2/vite-env.d.ts b/examples/vanilla-avatar-stack-2/vite-env.d.ts new file mode 100644 index 0000000..449e61a --- /dev/null +++ b/examples/vanilla-avatar-stack-2/vite-env.d.ts @@ -0,0 +1,8 @@ +interface ImportMetaEnv { + readonly VITE_ABLY_KEY: string; + // Add other environment variables here if needed +} + +interface ImportMeta { + readonly env: ImportMetaEnv; +} diff --git a/src/routes/VanillaAvatarStack2.tsx b/src/routes/VanillaAvatarStack2.tsx index 13b5178..b035cd4 100644 --- a/src/routes/VanillaAvatarStack2.tsx +++ b/src/routes/VanillaAvatarStack2.tsx @@ -1,7 +1,7 @@ const VanillaAvatarStack2 = () => { return ( diff --git a/yarn.lock b/yarn.lock index c554ea5..6ae87ea 100644 --- a/yarn.lock +++ b/yarn.lock @@ -229,116 +229,231 @@ "@babel/helper-validator-identifier" "^7.22.20" to-fast-properties "^2.0.0" +"@esbuild/aix-ppc64@0.21.5": + version "0.21.5" + resolved "https://registry.yarnpkg.com/@esbuild/aix-ppc64/-/aix-ppc64-0.21.5.tgz#c7184a326533fcdf1b8ee0733e21c713b975575f" + integrity sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ== + "@esbuild/android-arm64@0.18.20": version "0.18.20" resolved "https://registry.yarnpkg.com/@esbuild/android-arm64/-/android-arm64-0.18.20.tgz#984b4f9c8d0377443cc2dfcef266d02244593622" integrity sha512-Nz4rJcchGDtENV0eMKUNa6L12zz2zBDXuhj/Vjh18zGqB44Bi7MBMSXjgunJgjRhCmKOjnPuZp4Mb6OKqtMHLQ== +"@esbuild/android-arm64@0.21.5": + version "0.21.5" + resolved "https://registry.yarnpkg.com/@esbuild/android-arm64/-/android-arm64-0.21.5.tgz#09d9b4357780da9ea3a7dfb833a1f1ff439b4052" + integrity sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A== + "@esbuild/android-arm@0.18.20": version "0.18.20" resolved "https://registry.yarnpkg.com/@esbuild/android-arm/-/android-arm-0.18.20.tgz#fedb265bc3a589c84cc11f810804f234947c3682" integrity sha512-fyi7TDI/ijKKNZTUJAQqiG5T7YjJXgnzkURqmGj13C6dCqckZBLdl4h7bkhHt/t0WP+zO9/zwroDvANaOqO5Sw== +"@esbuild/android-arm@0.21.5": + version "0.21.5" + resolved "https://registry.yarnpkg.com/@esbuild/android-arm/-/android-arm-0.21.5.tgz#9b04384fb771926dfa6d7ad04324ecb2ab9b2e28" + integrity sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg== + "@esbuild/android-x64@0.18.20": version "0.18.20" resolved "https://registry.yarnpkg.com/@esbuild/android-x64/-/android-x64-0.18.20.tgz#35cf419c4cfc8babe8893d296cd990e9e9f756f2" integrity sha512-8GDdlePJA8D6zlZYJV/jnrRAi6rOiNaCC/JclcXpB+KIuvfBN4owLtgzY2bsxnx666XjJx2kDPUmnTtR8qKQUg== +"@esbuild/android-x64@0.21.5": + version "0.21.5" + resolved "https://registry.yarnpkg.com/@esbuild/android-x64/-/android-x64-0.21.5.tgz#29918ec2db754cedcb6c1b04de8cd6547af6461e" + integrity sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA== + "@esbuild/darwin-arm64@0.18.20": version "0.18.20" resolved "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.18.20.tgz" integrity sha512-bxRHW5kHU38zS2lPTPOyuyTm+S+eobPUnTNkdJEfAddYgEcll4xkT8DB9d2008DtTbl7uJag2HuE5NZAZgnNEA== +"@esbuild/darwin-arm64@0.21.5": + version "0.21.5" + resolved "https://registry.yarnpkg.com/@esbuild/darwin-arm64/-/darwin-arm64-0.21.5.tgz#e495b539660e51690f3928af50a76fb0a6ccff2a" + integrity sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ== + "@esbuild/darwin-x64@0.18.20": version "0.18.20" resolved "https://registry.yarnpkg.com/@esbuild/darwin-x64/-/darwin-x64-0.18.20.tgz#d70d5790d8bf475556b67d0f8b7c5bdff053d85d" integrity sha512-pc5gxlMDxzm513qPGbCbDukOdsGtKhfxD1zJKXjCCcU7ju50O7MeAZ8c4krSJcOIJGFR+qx21yMMVYwiQvyTyQ== +"@esbuild/darwin-x64@0.21.5": + version "0.21.5" + resolved "https://registry.yarnpkg.com/@esbuild/darwin-x64/-/darwin-x64-0.21.5.tgz#c13838fa57372839abdddc91d71542ceea2e1e22" + integrity sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw== + "@esbuild/freebsd-arm64@0.18.20": version "0.18.20" resolved "https://registry.yarnpkg.com/@esbuild/freebsd-arm64/-/freebsd-arm64-0.18.20.tgz#98755cd12707f93f210e2494d6a4b51b96977f54" integrity sha512-yqDQHy4QHevpMAaxhhIwYPMv1NECwOvIpGCZkECn8w2WFHXjEwrBn3CeNIYsibZ/iZEUemj++M26W3cNR5h+Tw== +"@esbuild/freebsd-arm64@0.21.5": + version "0.21.5" + resolved "https://registry.yarnpkg.com/@esbuild/freebsd-arm64/-/freebsd-arm64-0.21.5.tgz#646b989aa20bf89fd071dd5dbfad69a3542e550e" + integrity sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g== + "@esbuild/freebsd-x64@0.18.20": version "0.18.20" resolved "https://registry.yarnpkg.com/@esbuild/freebsd-x64/-/freebsd-x64-0.18.20.tgz#c1eb2bff03915f87c29cece4c1a7fa1f423b066e" integrity sha512-tgWRPPuQsd3RmBZwarGVHZQvtzfEBOreNuxEMKFcd5DaDn2PbBxfwLcj4+aenoh7ctXcbXmOQIn8HI6mCSw5MQ== +"@esbuild/freebsd-x64@0.21.5": + version "0.21.5" + resolved "https://registry.yarnpkg.com/@esbuild/freebsd-x64/-/freebsd-x64-0.21.5.tgz#aa615cfc80af954d3458906e38ca22c18cf5c261" + integrity sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ== + "@esbuild/linux-arm64@0.18.20": version "0.18.20" resolved "https://registry.yarnpkg.com/@esbuild/linux-arm64/-/linux-arm64-0.18.20.tgz#bad4238bd8f4fc25b5a021280c770ab5fc3a02a0" integrity sha512-2YbscF+UL7SQAVIpnWvYwM+3LskyDmPhe31pE7/aoTMFKKzIc9lLbyGUpmmb8a8AixOL61sQ/mFh3jEjHYFvdA== +"@esbuild/linux-arm64@0.21.5": + version "0.21.5" + resolved "https://registry.yarnpkg.com/@esbuild/linux-arm64/-/linux-arm64-0.21.5.tgz#70ac6fa14f5cb7e1f7f887bcffb680ad09922b5b" + integrity sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q== + "@esbuild/linux-arm@0.18.20": version "0.18.20" resolved "https://registry.yarnpkg.com/@esbuild/linux-arm/-/linux-arm-0.18.20.tgz#3e617c61f33508a27150ee417543c8ab5acc73b0" integrity sha512-/5bHkMWnq1EgKr1V+Ybz3s1hWXok7mDFUMQ4cG10AfW3wL02PSZi5kFpYKrptDsgb2WAJIvRcDm+qIvXf/apvg== +"@esbuild/linux-arm@0.21.5": + version "0.21.5" + resolved "https://registry.yarnpkg.com/@esbuild/linux-arm/-/linux-arm-0.21.5.tgz#fc6fd11a8aca56c1f6f3894f2bea0479f8f626b9" + integrity sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA== + "@esbuild/linux-ia32@0.18.20": version "0.18.20" resolved "https://registry.yarnpkg.com/@esbuild/linux-ia32/-/linux-ia32-0.18.20.tgz#699391cccba9aee6019b7f9892eb99219f1570a7" integrity sha512-P4etWwq6IsReT0E1KHU40bOnzMHoH73aXp96Fs8TIT6z9Hu8G6+0SHSw9i2isWrD2nbx2qo5yUqACgdfVGx7TA== +"@esbuild/linux-ia32@0.21.5": + version "0.21.5" + resolved "https://registry.yarnpkg.com/@esbuild/linux-ia32/-/linux-ia32-0.21.5.tgz#3271f53b3f93e3d093d518d1649d6d68d346ede2" + integrity sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg== + "@esbuild/linux-loong64@0.18.20": version "0.18.20" resolved "https://registry.yarnpkg.com/@esbuild/linux-loong64/-/linux-loong64-0.18.20.tgz#e6fccb7aac178dd2ffb9860465ac89d7f23b977d" integrity sha512-nXW8nqBTrOpDLPgPY9uV+/1DjxoQ7DoB2N8eocyq8I9XuqJ7BiAMDMf9n1xZM9TgW0J8zrquIb/A7s3BJv7rjg== +"@esbuild/linux-loong64@0.21.5": + version "0.21.5" + resolved "https://registry.yarnpkg.com/@esbuild/linux-loong64/-/linux-loong64-0.21.5.tgz#ed62e04238c57026aea831c5a130b73c0f9f26df" + integrity sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg== + "@esbuild/linux-mips64el@0.18.20": version "0.18.20" resolved "https://registry.yarnpkg.com/@esbuild/linux-mips64el/-/linux-mips64el-0.18.20.tgz#eeff3a937de9c2310de30622a957ad1bd9183231" integrity sha512-d5NeaXZcHp8PzYy5VnXV3VSd2D328Zb+9dEq5HE6bw6+N86JVPExrA6O68OPwobntbNJ0pzCpUFZTo3w0GyetQ== +"@esbuild/linux-mips64el@0.21.5": + version "0.21.5" + resolved "https://registry.yarnpkg.com/@esbuild/linux-mips64el/-/linux-mips64el-0.21.5.tgz#e79b8eb48bf3b106fadec1ac8240fb97b4e64cbe" + integrity sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg== + "@esbuild/linux-ppc64@0.18.20": version "0.18.20" resolved "https://registry.yarnpkg.com/@esbuild/linux-ppc64/-/linux-ppc64-0.18.20.tgz#2f7156bde20b01527993e6881435ad79ba9599fb" integrity sha512-WHPyeScRNcmANnLQkq6AfyXRFr5D6N2sKgkFo2FqguP44Nw2eyDlbTdZwd9GYk98DZG9QItIiTlFLHJHjxP3FA== +"@esbuild/linux-ppc64@0.21.5": + version "0.21.5" + resolved "https://registry.yarnpkg.com/@esbuild/linux-ppc64/-/linux-ppc64-0.21.5.tgz#5f2203860a143b9919d383ef7573521fb154c3e4" + integrity sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w== + "@esbuild/linux-riscv64@0.18.20": version "0.18.20" resolved "https://registry.yarnpkg.com/@esbuild/linux-riscv64/-/linux-riscv64-0.18.20.tgz#6628389f210123d8b4743045af8caa7d4ddfc7a6" integrity sha512-WSxo6h5ecI5XH34KC7w5veNnKkju3zBRLEQNY7mv5mtBmrP/MjNBCAlsM2u5hDBlS3NGcTQpoBvRzqBcRtpq1A== +"@esbuild/linux-riscv64@0.21.5": + version "0.21.5" + resolved "https://registry.yarnpkg.com/@esbuild/linux-riscv64/-/linux-riscv64-0.21.5.tgz#07bcafd99322d5af62f618cb9e6a9b7f4bb825dc" + integrity sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA== + "@esbuild/linux-s390x@0.18.20": version "0.18.20" resolved "https://registry.yarnpkg.com/@esbuild/linux-s390x/-/linux-s390x-0.18.20.tgz#255e81fb289b101026131858ab99fba63dcf0071" integrity sha512-+8231GMs3mAEth6Ja1iK0a1sQ3ohfcpzpRLH8uuc5/KVDFneH6jtAJLFGafpzpMRO6DzJ6AvXKze9LfFMrIHVQ== +"@esbuild/linux-s390x@0.21.5": + version "0.21.5" + resolved "https://registry.yarnpkg.com/@esbuild/linux-s390x/-/linux-s390x-0.21.5.tgz#b7ccf686751d6a3e44b8627ababc8be3ef62d8de" + integrity sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A== + "@esbuild/linux-x64@0.18.20": version "0.18.20" resolved "https://registry.yarnpkg.com/@esbuild/linux-x64/-/linux-x64-0.18.20.tgz#c7690b3417af318a9b6f96df3031a8865176d338" integrity sha512-UYqiqemphJcNsFEskc73jQ7B9jgwjWrSayxawS6UVFZGWrAAtkzjxSqnoclCXxWtfwLdzU+vTpcNYhpn43uP1w== +"@esbuild/linux-x64@0.21.5": + version "0.21.5" + resolved "https://registry.yarnpkg.com/@esbuild/linux-x64/-/linux-x64-0.21.5.tgz#6d8f0c768e070e64309af8004bb94e68ab2bb3b0" + integrity sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ== + "@esbuild/netbsd-x64@0.18.20": version "0.18.20" resolved "https://registry.yarnpkg.com/@esbuild/netbsd-x64/-/netbsd-x64-0.18.20.tgz#30e8cd8a3dded63975e2df2438ca109601ebe0d1" integrity sha512-iO1c++VP6xUBUmltHZoMtCUdPlnPGdBom6IrO4gyKPFFVBKioIImVooR5I83nTew5UOYrk3gIJhbZh8X44y06A== +"@esbuild/netbsd-x64@0.21.5": + version "0.21.5" + resolved "https://registry.yarnpkg.com/@esbuild/netbsd-x64/-/netbsd-x64-0.21.5.tgz#bbe430f60d378ecb88decb219c602667387a6047" + integrity sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg== + "@esbuild/openbsd-x64@0.18.20": version "0.18.20" resolved "https://registry.yarnpkg.com/@esbuild/openbsd-x64/-/openbsd-x64-0.18.20.tgz#7812af31b205055874c8082ea9cf9ab0da6217ae" integrity sha512-e5e4YSsuQfX4cxcygw/UCPIEP6wbIL+se3sxPdCiMbFLBWu0eiZOJ7WoD+ptCLrmjZBK1Wk7I6D/I3NglUGOxg== +"@esbuild/openbsd-x64@0.21.5": + version "0.21.5" + resolved "https://registry.yarnpkg.com/@esbuild/openbsd-x64/-/openbsd-x64-0.21.5.tgz#99d1cf2937279560d2104821f5ccce220cb2af70" + integrity sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow== + "@esbuild/sunos-x64@0.18.20": version "0.18.20" resolved "https://registry.yarnpkg.com/@esbuild/sunos-x64/-/sunos-x64-0.18.20.tgz#d5c275c3b4e73c9b0ecd38d1ca62c020f887ab9d" integrity sha512-kDbFRFp0YpTQVVrqUd5FTYmWo45zGaXe0X8E1G/LKFC0v8x0vWrhOWSLITcCn63lmZIxfOMXtCfti/RxN/0wnQ== +"@esbuild/sunos-x64@0.21.5": + version "0.21.5" + resolved "https://registry.yarnpkg.com/@esbuild/sunos-x64/-/sunos-x64-0.21.5.tgz#08741512c10d529566baba837b4fe052c8f3487b" + integrity sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg== + "@esbuild/win32-arm64@0.18.20": version "0.18.20" resolved "https://registry.yarnpkg.com/@esbuild/win32-arm64/-/win32-arm64-0.18.20.tgz#73bc7f5a9f8a77805f357fab97f290d0e4820ac9" integrity sha512-ddYFR6ItYgoaq4v4JmQQaAI5s7npztfV4Ag6NrhiaW0RrnOXqBkgwZLofVTlq1daVTQNhtI5oieTvkRPfZrePg== +"@esbuild/win32-arm64@0.21.5": + version "0.21.5" + resolved "https://registry.yarnpkg.com/@esbuild/win32-arm64/-/win32-arm64-0.21.5.tgz#675b7385398411240735016144ab2e99a60fc75d" + integrity sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A== + "@esbuild/win32-ia32@0.18.20": version "0.18.20" resolved "https://registry.yarnpkg.com/@esbuild/win32-ia32/-/win32-ia32-0.18.20.tgz#ec93cbf0ef1085cc12e71e0d661d20569ff42102" integrity sha512-Wv7QBi3ID/rROT08SABTS7eV4hX26sVduqDOTe1MvGMjNd3EjOz4b7zeexIR62GTIEKrfJXKL9LFxTYgkyeu7g== +"@esbuild/win32-ia32@0.21.5": + version "0.21.5" + resolved "https://registry.yarnpkg.com/@esbuild/win32-ia32/-/win32-ia32-0.21.5.tgz#1bfc3ce98aa6ca9a0969e4d2af72144c59c1193b" + integrity sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA== + "@esbuild/win32-x64@0.18.20": version "0.18.20" resolved "https://registry.yarnpkg.com/@esbuild/win32-x64/-/win32-x64-0.18.20.tgz#786c5f41f043b07afb1af37683d7c33668858f6d" integrity sha512-kTdfRcSiDfQca/y9QIkng02avJ+NCaQvrMejlsB3RRv5sE9rRoeBPISaZpKxHELzRxZyLvNts1P27W3wV+8geQ== +"@esbuild/win32-x64@0.21.5": + version "0.21.5" + resolved "https://registry.yarnpkg.com/@esbuild/win32-x64/-/win32-x64-0.21.5.tgz#acad351d582d157bb145535db2a6ff53dd514b5c" + integrity sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw== + "@heroicons/react@^2.0.18": version "2.0.18" resolved "https://registry.npmjs.org/@heroicons/react/-/react-2.0.18.tgz" @@ -414,6 +529,86 @@ resolved "https://registry.npmjs.org/@remix-run/router/-/router-1.10.0.tgz" integrity sha512-Lm+fYpMfZoEucJ7cMxgt4dYt8jLfbpwRCzAjm9UgSLOkmlqo9gupxt6YX3DY0Fk155NT9l17d/ydi+964uS9Lw== +"@rollup/rollup-android-arm-eabi@4.20.0": + version "4.20.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.20.0.tgz#c3f5660f67030c493a981ac1d34ee9dfe1d8ec0f" + integrity sha512-TSpWzflCc4VGAUJZlPpgAJE1+V60MePDQnBd7PPkpuEmOy8i87aL6tinFGKBFKuEDikYpig72QzdT3QPYIi+oA== + +"@rollup/rollup-android-arm64@4.20.0": + version "4.20.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.20.0.tgz#64161f0b67050023a3859e723570af54a82cff5c" + integrity sha512-u00Ro/nok7oGzVuh/FMYfNoGqxU5CPWz1mxV85S2w9LxHR8OoMQBuSk+3BKVIDYgkpeOET5yXkx90OYFc+ytpQ== + +"@rollup/rollup-darwin-arm64@4.20.0": + version "4.20.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.20.0.tgz#25f3d57b1da433097cfebc89341b355901615763" + integrity sha512-uFVfvzvsdGtlSLuL0ZlvPJvl6ZmrH4CBwLGEFPe7hUmf7htGAN+aXo43R/V6LATyxlKVC/m6UsLb7jbG+LG39Q== + +"@rollup/rollup-darwin-x64@4.20.0": + version "4.20.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.20.0.tgz#d8ddaffb636cc2f59222c50316e27771e48966df" + integrity sha512-xbrMDdlev53vNXexEa6l0LffojxhqDTBeL+VUxuuIXys4x6xyvbKq5XqTXBCEUA8ty8iEJblHvFaWRJTk/icAQ== + +"@rollup/rollup-linux-arm-gnueabihf@4.20.0": + version "4.20.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.20.0.tgz#41bd4fcffa20fb84f3dbac6c5071638f46151885" + integrity sha512-jMYvxZwGmoHFBTbr12Xc6wOdc2xA5tF5F2q6t7Rcfab68TT0n+r7dgawD4qhPEvasDsVpQi+MgDzj2faOLsZjA== + +"@rollup/rollup-linux-arm-musleabihf@4.20.0": + version "4.20.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.20.0.tgz#842077c5113a747eb5686f19f2f18c33ecc0acc8" + integrity sha512-1asSTl4HKuIHIB1GcdFHNNZhxAYEdqML/MW4QmPS4G0ivbEcBr1JKlFLKsIRqjSwOBkdItn3/ZDlyvZ/N6KPlw== + +"@rollup/rollup-linux-arm64-gnu@4.20.0": + version "4.20.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.20.0.tgz#65d1d5b6778848f55b7823958044bf3e8737e5b7" + integrity sha512-COBb8Bkx56KldOYJfMf6wKeYJrtJ9vEgBRAOkfw6Ens0tnmzPqvlpjZiLgkhg6cA3DGzCmLmmd319pmHvKWWlQ== + +"@rollup/rollup-linux-arm64-musl@4.20.0": + version "4.20.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.20.0.tgz#50eef7d6e24d0fe3332200bb666cad2be8afcf86" + integrity sha512-+it+mBSyMslVQa8wSPvBx53fYuZK/oLTu5RJoXogjk6x7Q7sz1GNRsXWjn6SwyJm8E/oMjNVwPhmNdIjwP135Q== + +"@rollup/rollup-linux-powerpc64le-gnu@4.20.0": + version "4.20.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.20.0.tgz#8837e858f53c84607f05ad0602943e96d104c6b4" + integrity sha512-yAMvqhPfGKsAxHN8I4+jE0CpLWD8cv4z7CK7BMmhjDuz606Q2tFKkWRY8bHR9JQXYcoLfopo5TTqzxgPUjUMfw== + +"@rollup/rollup-linux-riscv64-gnu@4.20.0": + version "4.20.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.20.0.tgz#c894ade2300caa447757ddf45787cca246e816a4" + integrity sha512-qmuxFpfmi/2SUkAw95TtNq/w/I7Gpjurx609OOOV7U4vhvUhBcftcmXwl3rqAek+ADBwSjIC4IVNLiszoj3dPA== + +"@rollup/rollup-linux-s390x-gnu@4.20.0": + version "4.20.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.20.0.tgz#5841e5390d4c82dd5cdf7b2c95a830e3c2f47dd3" + integrity sha512-I0BtGXddHSHjV1mqTNkgUZLnS3WtsqebAXv11D5BZE/gfw5KoyXSAXVqyJximQXNvNzUo4GKlCK/dIwXlz+jlg== + +"@rollup/rollup-linux-x64-gnu@4.20.0": + version "4.20.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.20.0.tgz#cc1f26398bf777807a99226dc13f47eb0f6c720d" + integrity sha512-y+eoL2I3iphUg9tN9GB6ku1FA8kOfmF4oUEWhztDJ4KXJy1agk/9+pejOuZkNFhRwHAOxMsBPLbXPd6mJiCwew== + +"@rollup/rollup-linux-x64-musl@4.20.0": + version "4.20.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.20.0.tgz#1507465d9056e0502a590d4c1a00b4d7b1fda370" + integrity sha512-hM3nhW40kBNYUkZb/r9k2FKK+/MnKglX7UYd4ZUy5DJs8/sMsIbqWK2piZtVGE3kcXVNj3B2IrUYROJMMCikNg== + +"@rollup/rollup-win32-arm64-msvc@4.20.0": + version "4.20.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.20.0.tgz#86a221f01a2c248104dd0defb4da119f2a73642e" + integrity sha512-psegMvP+Ik/Bg7QRJbv8w8PAytPA7Uo8fpFjXyCRHWm6Nt42L+JtoqH8eDQ5hRP7/XW2UiIriy1Z46jf0Oa1kA== + +"@rollup/rollup-win32-ia32-msvc@4.20.0": + version "4.20.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.20.0.tgz#8bc8f77e02760aa664694b4286d6fbea7f1331c5" + integrity sha512-GabekH3w4lgAJpVxkk7hUzUf2hICSQO0a/BLFA11/RMxQT92MabKAqyubzDZmMOC/hcJNlc+rrypzNzYl4Dx7A== + +"@rollup/rollup-win32-x64-msvc@4.20.0": + version "4.20.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.20.0.tgz#601fffee719a1e8447f908aca97864eec23b2784" + integrity sha512-aJ1EJSuTdGnM6qbVC4B5DSmozPTqIag9fSzXRNNo+humQLG89XpPgdt16Ia56ORD7s+H8Pmyx44uczDQ0yDzpg== + "@sindresorhus/is@^4.0.0": version "4.6.0" resolved "https://registry.npmjs.org/@sindresorhus/is/-/is-4.6.0.tgz" @@ -469,6 +664,11 @@ "@types/node" "*" "@types/responselike" "*" +"@types/estree@1.0.5": + version "1.0.5" + resolved "https://registry.yarnpkg.com/@types/estree/-/estree-1.0.5.tgz#a6ce3e556e00fd9895dd872dd172ad0d4bd687f4" + integrity sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw== + "@types/http-cache-semantics@*": version "4.0.1" resolved "https://registry.npmjs.org/@types/http-cache-semantics/-/http-cache-semantics-4.0.1.tgz" @@ -837,6 +1037,11 @@ dlv@^1.1.3: resolved "https://registry.npmjs.org/dlv/-/dlv-1.1.3.tgz" integrity sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA== +dotenv@16.4.5: + version "16.4.5" + resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-16.4.5.tgz#cdd3b3b604cb327e286b4762e13502f717cb099f" + integrity sha512-ZmdL2rui+eB2YwhsWzjInR8LldtZHGDoQ1ugH85ppHKwpUHL7j7rN0Ti9NCnGiQbhaZ11FpR+7ao1dNsmduNUg== + electron-to-chromium@^1.4.535: version "1.4.566" resolved "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.566.tgz" @@ -877,6 +1082,35 @@ esbuild@^0.18.10: "@esbuild/win32-ia32" "0.18.20" "@esbuild/win32-x64" "0.18.20" +esbuild@^0.21.3: + version "0.21.5" + resolved "https://registry.yarnpkg.com/esbuild/-/esbuild-0.21.5.tgz#9ca301b120922959b766360d8ac830da0d02997d" + integrity sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw== + optionalDependencies: + "@esbuild/aix-ppc64" "0.21.5" + "@esbuild/android-arm" "0.21.5" + "@esbuild/android-arm64" "0.21.5" + "@esbuild/android-x64" "0.21.5" + "@esbuild/darwin-arm64" "0.21.5" + "@esbuild/darwin-x64" "0.21.5" + "@esbuild/freebsd-arm64" "0.21.5" + "@esbuild/freebsd-x64" "0.21.5" + "@esbuild/linux-arm" "0.21.5" + "@esbuild/linux-arm64" "0.21.5" + "@esbuild/linux-ia32" "0.21.5" + "@esbuild/linux-loong64" "0.21.5" + "@esbuild/linux-mips64el" "0.21.5" + "@esbuild/linux-ppc64" "0.21.5" + "@esbuild/linux-riscv64" "0.21.5" + "@esbuild/linux-s390x" "0.21.5" + "@esbuild/linux-x64" "0.21.5" + "@esbuild/netbsd-x64" "0.21.5" + "@esbuild/openbsd-x64" "0.21.5" + "@esbuild/sunos-x64" "0.21.5" + "@esbuild/win32-arm64" "0.21.5" + "@esbuild/win32-ia32" "0.21.5" + "@esbuild/win32-x64" "0.21.5" + escalade@^3.1.1: version "3.1.1" resolved "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz" @@ -976,6 +1210,11 @@ fsevents@~2.3.2: resolved "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz" integrity sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA== +fsevents@~2.3.3: + version "2.3.3" + resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.3.tgz#cac6407785d03675a2a5e1a5305c697b347d90d6" + integrity sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw== + function-bind@^1.1.1: version "1.1.1" resolved "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz" @@ -1253,6 +1492,11 @@ nanoid@^3.3.6: resolved "https://registry.npmjs.org/nanoid/-/nanoid-3.3.6.tgz" integrity sha512-BGcqMMJuToF7i1rt+2PWSNVnWIkGCU78jBG3RxO/bZlnZPK2Cmi2QaffxGO/2RvWi9sL+FAiRiXMgsyxQ1DIDA== +nanoid@^3.3.7: + version "3.3.7" + resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.7.tgz#d0c301a691bc8d54efa0a2226ccf3fe2fd656bd8" + integrity sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g== + nanoid@^4.0.2: version "4.0.2" resolved "https://registry.npmjs.org/nanoid/-/nanoid-4.0.2.tgz" @@ -1358,6 +1602,11 @@ picocolors@^1.0.0: resolved "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz" integrity sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ== +picocolors@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.0.1.tgz#a8ad579b571952f0e5d25892de5445bcfe25aaa1" + integrity sha512-anP1Z8qwhkbmu7MFP5iTt+wQKXgwzf7zTyGlcdzabySa9vd0Xt392U0rVmz9poOaBj0uHJKyyo9/upk0HrEQew== + picomatch@^2.0.4, picomatch@^2.2.1, picomatch@^2.3.1: version "2.3.1" resolved "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz" @@ -1421,6 +1670,15 @@ postcss@^8.4.14, postcss@^8.4.27: picocolors "^1.0.0" source-map-js "^1.0.2" +postcss@^8.4.31, postcss@^8.4.40: + version "8.4.41" + resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.41.tgz#d6104d3ba272d882fe18fc07d15dc2da62fa2681" + integrity sha512-TesUflQ0WKZqAvg52PWL6kHgLKP6xB6heTOdoYM0Wt2UHyxNa4K25EZZMgKns3BH1RLVbZCREPpLY0rhnNoHVQ== + dependencies: + nanoid "^3.3.7" + picocolors "^1.0.1" + source-map-js "^1.2.0" + prettier-linter-helpers@^1.0.0: version "1.0.0" resolved "https://registry.npmjs.org/prettier-linter-helpers/-/prettier-linter-helpers-1.0.0.tgz" @@ -1540,6 +1798,31 @@ rollup@^3.27.1: optionalDependencies: fsevents "~2.3.2" +rollup@^4.13.0: + version "4.20.0" + resolved "https://registry.yarnpkg.com/rollup/-/rollup-4.20.0.tgz#f9d602161d29e178f0bf1d9f35f0a26f83939492" + integrity sha512-6rbWBChcnSGzIlXeIdNIZTopKYad8ZG8ajhl78lGRLsI2rX8IkaotQhVas2Ma+GPxJav19wrSzvRvuiv0YKzWw== + dependencies: + "@types/estree" "1.0.5" + optionalDependencies: + "@rollup/rollup-android-arm-eabi" "4.20.0" + "@rollup/rollup-android-arm64" "4.20.0" + "@rollup/rollup-darwin-arm64" "4.20.0" + "@rollup/rollup-darwin-x64" "4.20.0" + "@rollup/rollup-linux-arm-gnueabihf" "4.20.0" + "@rollup/rollup-linux-arm-musleabihf" "4.20.0" + "@rollup/rollup-linux-arm64-gnu" "4.20.0" + "@rollup/rollup-linux-arm64-musl" "4.20.0" + "@rollup/rollup-linux-powerpc64le-gnu" "4.20.0" + "@rollup/rollup-linux-riscv64-gnu" "4.20.0" + "@rollup/rollup-linux-s390x-gnu" "4.20.0" + "@rollup/rollup-linux-x64-gnu" "4.20.0" + "@rollup/rollup-linux-x64-musl" "4.20.0" + "@rollup/rollup-win32-arm64-msvc" "4.20.0" + "@rollup/rollup-win32-ia32-msvc" "4.20.0" + "@rollup/rollup-win32-x64-msvc" "4.20.0" + fsevents "~2.3.2" + run-applescript@^5.0.0: version "5.0.0" resolved "https://registry.npmjs.org/run-applescript/-/run-applescript-5.0.0.tgz" @@ -1593,6 +1876,11 @@ source-map-js@^1.0.2: resolved "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz" integrity sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw== +source-map-js@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/source-map-js/-/source-map-js-1.2.0.tgz#16b809c162517b5b8c3e7dcd315a2a5c2612b2af" + integrity sha512-itJW8lvSA0TXEphiRoawsCksnlf8SyvmFzIhltqAHluXd88pkCd+cXJVHTDwdCr0IzwptSm035IHQktUu1QUMg== + strip-final-newline@^2.0.0: version "2.0.0" resolved "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz" @@ -1683,6 +1971,11 @@ typescript@5.2.2: resolved "https://registry.npmjs.org/typescript/-/typescript-5.2.2.tgz" integrity sha512-mI4WrpHsbCIcwT9cF4FZvr80QUeKvsUsUvKDoR+X/7XHQH98xYD8YHZg7ANtz2GtZt/CBq2QJ0thkGJMHfqc1w== +typescript@^5.2.2: + version "5.5.4" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.5.4.tgz#d9852d6c82bad2d2eda4fd74a5762a8f5909e9ba" + integrity sha512-Mtq29sKDAEYP7aljRgtPOpTvOfbwRWlS6dPRzwjdE+C0R4brX/GUyhHSecbHMFLNBLcJIPt9nl9yG5TZ1weH+Q== + untildify@^4.0.0: version "4.0.0" resolved "https://registry.npmjs.org/untildify/-/untildify-4.0.0.tgz" @@ -1717,6 +2010,17 @@ vite@^4.4.9: optionalDependencies: fsevents "~2.3.2" +vite@^5.2.13: + version "5.4.0" + resolved "https://registry.yarnpkg.com/vite/-/vite-5.4.0.tgz#11dca8a961369ba8b5cae42d068c7ad684d5370f" + integrity sha512-5xokfMX0PIiwCMCMb9ZJcMyh5wbBun0zUzKib+L65vAZ8GY9ePZMXxFrHbr/Kyll2+LSCY7xtERPpxkBDKngwg== + dependencies: + esbuild "^0.21.3" + postcss "^8.4.40" + rollup "^4.13.0" + optionalDependencies: + fsevents "~2.3.3" + which@^2.0.1: version "2.0.2" resolved "https://registry.npmjs.org/which/-/which-2.0.2.tgz" From 19db753bb59502159eb5d8e8a2e078980d63e5b3 Mon Sep 17 00:00:00 2001 From: Greg Holmes Date: Tue, 13 Aug 2024 11:53:31 +0100 Subject: [PATCH 17/19] Added space.leave in react example effect clean up --- examples/vite-react-avatar-stack-2/src/App.tsx | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/examples/vite-react-avatar-stack-2/src/App.tsx b/examples/vite-react-avatar-stack-2/src/App.tsx index 728a5ff..d875d88 100644 --- a/examples/vite-react-avatar-stack-2/src/App.tsx +++ b/examples/vite-react-avatar-stack-2/src/App.tsx @@ -29,6 +29,10 @@ function AvatarStack() { /** 💡 Enter the space as soon as it's available 💡 */ useEffect(() => { space?.enter({ name, memberColor }); + + return () => { + space?.leave(); + }; }, [space]); /** 💡 Get everybody in the space including the local member 💡 */ From 0a461fa82e5994e0d259bec379f8aeda2d2b3998 Mon Sep 17 00:00:00 2001 From: Greg Holmes Date: Tue, 13 Aug 2024 12:03:51 +0100 Subject: [PATCH 18/19] Update vanilla-avatar-stack-2 to be TypeScript --- examples/vanilla-avatar-stack-2/index.html | 4 +- examples/vanilla-avatar-stack-2/package.json | 2 +- examples/vanilla-avatar-stack-2/src/script.ts | 128 ++-- .../{ => src}/styles.css | 0 examples/vanilla-avatar-stack-2/tsconfig.json | 47 +- .../vanilla-avatar-stack-2/vite.config.ts | 3 + examples/vanilla-avatar-stack-2/yarn.lock | 624 ++++++++++++++++++ 7 files changed, 716 insertions(+), 92 deletions(-) rename examples/vanilla-avatar-stack-2/{ => src}/styles.css (100%) create mode 100644 examples/vanilla-avatar-stack-2/yarn.lock diff --git a/examples/vanilla-avatar-stack-2/index.html b/examples/vanilla-avatar-stack-2/index.html index af3e2cc..a84fae5 100644 --- a/examples/vanilla-avatar-stack-2/index.html +++ b/examples/vanilla-avatar-stack-2/index.html @@ -4,7 +4,7 @@ Avatar Stack - +
    @@ -12,6 +12,6 @@
    - + diff --git a/examples/vanilla-avatar-stack-2/package.json b/examples/vanilla-avatar-stack-2/package.json index 5ad9994..8dc5063 100644 --- a/examples/vanilla-avatar-stack-2/package.json +++ b/examples/vanilla-avatar-stack-2/package.json @@ -11,7 +11,7 @@ "preview": "vite preview" }, "dependencies": { - "@ably/spaces": "0.2.0", + "@ably/spaces": "^0.4.0", "ably": "1.2.45", "classnames": "^2.3.2", "nanoid": "^5.0.1", diff --git a/examples/vanilla-avatar-stack-2/src/script.ts b/examples/vanilla-avatar-stack-2/src/script.ts index 09785d9..86d3f89 100644 --- a/examples/vanilla-avatar-stack-2/src/script.ts +++ b/examples/vanilla-avatar-stack-2/src/script.ts @@ -5,87 +5,75 @@ import { nanoid } from 'nanoid'; export type Member = Omit & { profileData: { memberColor: string; name: string }; }; +const mockNames: string[] = ["Anum Reeve", "Tiernan Stubbs", "Hakim Hernandez"]; +const mockColors: string[] = ["#9951F5", "#f1c232", "#f44336"]; -const client = new Realtime.Promise({ - clientId: nanoid(), - key: import.meta.env.VITE_ABLY_KEY as string, -}); +connect() -const spaces = new Spaces(client); -const space = await spaces.get('avatar-stack'); +async function connect() { + const client = new Realtime.Promise({ + clientId: nanoid(), + key: import.meta.env.VITE_ABLY_KEY as string, + }); -const mockNames: string[] = ["Anum Reeve", "Tiernan Stubbs", "Hakim Hernandez"]; -const mockColors: string[] = ["#9951F5", "#f1c232", "#f44336"]; + const spaces = new Spaces(client); + const space = await spaces.get('avatar-stack'); -/** 💡 Add every avatar that enters 💡 */ -space.members.subscribe('enter', (memberUpdate: SpaceMember) => { - const member: Member = { - ...memberUpdate, - profileData: { - memberColor: (memberUpdate.profileData as any).memberColor, - name: (memberUpdate.profileData as any).name, - } - }; - addAvatar(member, true); -}); - -/** 💡 Enter the space as soon as it's available 💡 */ -await space.enter({ - name: mockNames[Math.floor(Math.random() * mockNames.length)], - memberColor: mockColors[Math.floor(Math.random() * mockColors.length)], -}).then(async () => { - const otherMembers = await space.members.getOthers(); - - /** 💡 Get first four except the local member in the space 💡 */ + /** 💡 Add every avatar that enters 💡 */ space.members.subscribe('enter', (memberUpdate: SpaceMember) => { - if (memberUpdate.profileData && typeof memberUpdate.profileData === 'object' && - typeof (memberUpdate.profileData as any).memberColor === 'string' && - typeof (memberUpdate.profileData as any).name === 'string') { - - const member: Member = { - ...memberUpdate, - profileData: { - memberColor: (memberUpdate.profileData as any).memberColor, - name: (memberUpdate.profileData as any).name, - } - }; - - addAvatar(member, true); - } else { - console.warn('Received a member with invalid profile data:', memberUpdate); - } + const member: Member = { + ...memberUpdate, + profileData: { + memberColor: (memberUpdate.profileData as any).memberColor, + name: (memberUpdate.profileData as any).name, + } + }; + renderAvatar(member, true); }); - /** 💡 Get a count of the number exceeding four and display as a single tally 💡 */ - if (otherMembers.length > 4) { - const avatarsElement = document.getElementById('avatars'); - if (avatarsElement) { - const avatarElement = document.createElement('div'); - avatarElement.className = 'avatar'; - avatarElement.style.backgroundColor = '#595959'; + /** 💡 Enter the space as soon as it's available 💡 */ + space.enter({ + name: mockNames[Math.floor(Math.random() * mockNames.length)], + memberColor: mockColors[Math.floor(Math.random() * mockColors.length)], + }).then(async () => { + const otherMembers = await space.members.getOthers(); - const nameElement = document.createElement('p'); - nameElement.className = 'textWhite nameOthers'; - nameElement.textContent = `+${otherMembers.length - 4}`; + /** 💡 Get first four except the local member in the space 💡 */ + otherMembers.slice(0, 4).forEach((member) => { + renderAvatar(member as Member); + }); - avatarElement.appendChild(nameElement); - avatarsElement.appendChild(avatarElement); + /** 💡 Get a count of the number exceeding four and display as a single tally 💡 */ + if (otherMembers.length > 4) { + const avatarsElement = document.getElementById('avatars'); + if (avatarsElement) { + const avatarElement = document.createElement('div'); + avatarElement.className = 'avatar'; + avatarElement.style.backgroundColor = '#595959'; + + const nameElement = document.createElement('p'); + nameElement.className = 'textWhite nameOthers'; + nameElement.textContent = `+${otherMembers.length - 4}`; + + avatarElement.appendChild(nameElement); + avatarsElement.appendChild(avatarElement); + } } - } -}).catch((err) => { - console.error('Error joining space:', err); -}); + }).catch((err) => { + console.error('Error joining space:', err); + }); +} -function createUserInfo(user: Member, isSelf: boolean = false): HTMLDivElement { +function buildUserInfo(member: Member, isSelf: boolean = false): HTMLDivElement { const wrapper = document.createElement('div'); wrapper.className = 'wrapper'; const userInfoContainer = document.createElement('div'); userInfoContainer.className = 'userInfoContainer'; - userInfoContainer.style.backgroundColor = user.profileData.memberColor; + userInfoContainer.style.backgroundColor = member.profileData.memberColor; userInfoContainer.id = 'avatar'; - const userInitials = user.profileData.name + const userInitials = member.profileData.name .split(" ") .map((word: string) => word.charAt(0)) .join(""); @@ -103,7 +91,7 @@ function createUserInfo(user: Member, isSelf: boolean = false): HTMLDivElement { const nameElement = document.createElement('p'); nameElement.className = 'name'; - nameElement.textContent = isSelf ? user.profileData.name + ' (You)' : user.profileData.name; + nameElement.textContent = isSelf ? member.profileData.name + ' (You)' : member.profileData.name; userList.appendChild(nameElement); wrapper.appendChild(userList); @@ -111,8 +99,8 @@ function createUserInfo(user: Member, isSelf: boolean = false): HTMLDivElement { return wrapper; } -async function addAvatar(user: Member, isSelf: boolean = false): Promise { - const userInitials = user.profileData.name +async function renderAvatar(member: Member, isSelf: boolean = false): Promise { + const userInitials = member.profileData.name .split(" ") .map((word: string) => word.charAt(0)) .join(""); @@ -127,9 +115,9 @@ async function addAvatar(user: Member, isSelf: boolean = false): Promise { const avatar = document.createElement('div'); avatar.className = 'avatar'; - avatar.style.backgroundColor = user.profileData.memberColor; - avatar.setAttribute('data-member-id', user.clientId); - avatar.setAttribute('key', user.clientId); + avatar.style.backgroundColor = member.profileData.memberColor; + avatar.setAttribute('data-member-id', member['clientId']); + avatar.setAttribute('key', member['clientId']); const initials = document.createElement('p'); initials.className = "textWhite"; @@ -141,7 +129,7 @@ async function addAvatar(user: Member, isSelf: boolean = false): Promise { popup.className = 'popup'; popup.style.display = 'none'; - const userInfo = createUserInfo(user, isSelf); + const userInfo = buildUserInfo(member, isSelf); avatarElement.appendChild(avatarContainer); avatarContainer.appendChild(avatar); popup.appendChild(userInfo); diff --git a/examples/vanilla-avatar-stack-2/styles.css b/examples/vanilla-avatar-stack-2/src/styles.css similarity index 100% rename from examples/vanilla-avatar-stack-2/styles.css rename to examples/vanilla-avatar-stack-2/src/styles.css diff --git a/examples/vanilla-avatar-stack-2/tsconfig.json b/examples/vanilla-avatar-stack-2/tsconfig.json index d334f83..e842734 100644 --- a/examples/vanilla-avatar-stack-2/tsconfig.json +++ b/examples/vanilla-avatar-stack-2/tsconfig.json @@ -1,26 +1,35 @@ { "compilerOptions": { + "lib": [ + "es2021", + "DOM", + "DOM.Iterable", + ], + "module": "ESNext", "target": "ESNext", - "useDefineForClassFields": true, - "lib": ["DOM", "DOM.Iterable", "ESNext"], - "allowJs": false, - "skipLibCheck": true, - "esModuleInterop": false, - "allowSyntheticDefaultImports": true, "strict": true, - "forceConsistentCasingInFileNames": true, - "module": "ESNext", + "esModuleInterop": true, "moduleResolution": "Node", - "resolveJsonModule": true, - "isolatedModules": true, - "noEmit": true, - "jsx": "react-jsx" + "skipLibCheck": true, + "forceConsistentCasingInFileNames": true, + "allowUnusedLabels": false, + "allowUnreachableCode": false, + "exactOptionalPropertyTypes": true, + "noFallthroughCasesInSwitch": true, + "noImplicitOverride": true, + "noImplicitReturns": true, + "noPropertyAccessFromIndexSignature": true, + "noUncheckedIndexedAccess": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "checkJs": true, + // Everything below are custom changes for this app + "allowJs": true, + "outDir": "dist" }, - "types": ["vite/client"], - "include": ["src", "vite-env.d.ts"], - "references": [ - { - "path": "./tsconfig.node.json" - } + "include": [ + "./src/**/*", + "./__tests__/**/*", + "vite-env.d.ts" ] - } +} diff --git a/examples/vanilla-avatar-stack-2/vite.config.ts b/examples/vanilla-avatar-stack-2/vite.config.ts index 3c2f3df..9519f73 100644 --- a/examples/vanilla-avatar-stack-2/vite.config.ts +++ b/examples/vanilla-avatar-stack-2/vite.config.ts @@ -4,4 +4,7 @@ import react from '@vitejs/plugin-react'; export default defineConfig({ plugins: [react()], publicDir: 'public', + build: { + outDir: 'dist', + }, }); diff --git a/examples/vanilla-avatar-stack-2/yarn.lock b/examples/vanilla-avatar-stack-2/yarn.lock new file mode 100644 index 0000000..e708896 --- /dev/null +++ b/examples/vanilla-avatar-stack-2/yarn.lock @@ -0,0 +1,624 @@ +# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. +# yarn lockfile v1 + + +"@ably/msgpack-js@^0.4.0": + version "0.4.0" + resolved "https://registry.yarnpkg.com/@ably/msgpack-js/-/msgpack-js-0.4.0.tgz#aaaf5d8dffacf7aa253effd8c3488aa09130e6a2" + integrity sha512-IPt/BoiQwCWubqoNik1aw/6M/DleMdrxJOUpSja6xmMRbT2p1TA8oqKWgfZabqzrq8emRNeSl/+4XABPNnW5pQ== + dependencies: + bops "^1.0.1" + +"@ably/spaces@^0.4.0": + version "0.4.0" + resolved "https://registry.yarnpkg.com/@ably/spaces/-/spaces-0.4.0.tgz#766d748d79f3de3cd82939431daea99479150bbf" + integrity sha512-yehNgkv9DOHUBR1c46/5Q4BhkF3TJkKb00kLDhZFWTVJpFSW0Mkw0PUgHLkzAg9Bt9LJPcA0mgZq3mFeLQCrIg== + dependencies: + nanoid "^3.3.7" + +"@esbuild/aix-ppc64@0.21.5": + version "0.21.5" + resolved "https://registry.yarnpkg.com/@esbuild/aix-ppc64/-/aix-ppc64-0.21.5.tgz#c7184a326533fcdf1b8ee0733e21c713b975575f" + integrity sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ== + +"@esbuild/android-arm64@0.21.5": + version "0.21.5" + resolved "https://registry.yarnpkg.com/@esbuild/android-arm64/-/android-arm64-0.21.5.tgz#09d9b4357780da9ea3a7dfb833a1f1ff439b4052" + integrity sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A== + +"@esbuild/android-arm@0.21.5": + version "0.21.5" + resolved "https://registry.yarnpkg.com/@esbuild/android-arm/-/android-arm-0.21.5.tgz#9b04384fb771926dfa6d7ad04324ecb2ab9b2e28" + integrity sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg== + +"@esbuild/android-x64@0.21.5": + version "0.21.5" + resolved "https://registry.yarnpkg.com/@esbuild/android-x64/-/android-x64-0.21.5.tgz#29918ec2db754cedcb6c1b04de8cd6547af6461e" + integrity sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA== + +"@esbuild/darwin-arm64@0.21.5": + version "0.21.5" + resolved "https://registry.yarnpkg.com/@esbuild/darwin-arm64/-/darwin-arm64-0.21.5.tgz#e495b539660e51690f3928af50a76fb0a6ccff2a" + integrity sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ== + +"@esbuild/darwin-x64@0.21.5": + version "0.21.5" + resolved "https://registry.yarnpkg.com/@esbuild/darwin-x64/-/darwin-x64-0.21.5.tgz#c13838fa57372839abdddc91d71542ceea2e1e22" + integrity sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw== + +"@esbuild/freebsd-arm64@0.21.5": + version "0.21.5" + resolved "https://registry.yarnpkg.com/@esbuild/freebsd-arm64/-/freebsd-arm64-0.21.5.tgz#646b989aa20bf89fd071dd5dbfad69a3542e550e" + integrity sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g== + +"@esbuild/freebsd-x64@0.21.5": + version "0.21.5" + resolved "https://registry.yarnpkg.com/@esbuild/freebsd-x64/-/freebsd-x64-0.21.5.tgz#aa615cfc80af954d3458906e38ca22c18cf5c261" + integrity sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ== + +"@esbuild/linux-arm64@0.21.5": + version "0.21.5" + resolved "https://registry.yarnpkg.com/@esbuild/linux-arm64/-/linux-arm64-0.21.5.tgz#70ac6fa14f5cb7e1f7f887bcffb680ad09922b5b" + integrity sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q== + +"@esbuild/linux-arm@0.21.5": + version "0.21.5" + resolved "https://registry.yarnpkg.com/@esbuild/linux-arm/-/linux-arm-0.21.5.tgz#fc6fd11a8aca56c1f6f3894f2bea0479f8f626b9" + integrity sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA== + +"@esbuild/linux-ia32@0.21.5": + version "0.21.5" + resolved "https://registry.yarnpkg.com/@esbuild/linux-ia32/-/linux-ia32-0.21.5.tgz#3271f53b3f93e3d093d518d1649d6d68d346ede2" + integrity sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg== + +"@esbuild/linux-loong64@0.21.5": + version "0.21.5" + resolved "https://registry.yarnpkg.com/@esbuild/linux-loong64/-/linux-loong64-0.21.5.tgz#ed62e04238c57026aea831c5a130b73c0f9f26df" + integrity sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg== + +"@esbuild/linux-mips64el@0.21.5": + version "0.21.5" + resolved "https://registry.yarnpkg.com/@esbuild/linux-mips64el/-/linux-mips64el-0.21.5.tgz#e79b8eb48bf3b106fadec1ac8240fb97b4e64cbe" + integrity sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg== + +"@esbuild/linux-ppc64@0.21.5": + version "0.21.5" + resolved "https://registry.yarnpkg.com/@esbuild/linux-ppc64/-/linux-ppc64-0.21.5.tgz#5f2203860a143b9919d383ef7573521fb154c3e4" + integrity sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w== + +"@esbuild/linux-riscv64@0.21.5": + version "0.21.5" + resolved "https://registry.yarnpkg.com/@esbuild/linux-riscv64/-/linux-riscv64-0.21.5.tgz#07bcafd99322d5af62f618cb9e6a9b7f4bb825dc" + integrity sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA== + +"@esbuild/linux-s390x@0.21.5": + version "0.21.5" + resolved "https://registry.yarnpkg.com/@esbuild/linux-s390x/-/linux-s390x-0.21.5.tgz#b7ccf686751d6a3e44b8627ababc8be3ef62d8de" + integrity sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A== + +"@esbuild/linux-x64@0.21.5": + version "0.21.5" + resolved "https://registry.yarnpkg.com/@esbuild/linux-x64/-/linux-x64-0.21.5.tgz#6d8f0c768e070e64309af8004bb94e68ab2bb3b0" + integrity sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ== + +"@esbuild/netbsd-x64@0.21.5": + version "0.21.5" + resolved "https://registry.yarnpkg.com/@esbuild/netbsd-x64/-/netbsd-x64-0.21.5.tgz#bbe430f60d378ecb88decb219c602667387a6047" + integrity sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg== + +"@esbuild/openbsd-x64@0.21.5": + version "0.21.5" + resolved "https://registry.yarnpkg.com/@esbuild/openbsd-x64/-/openbsd-x64-0.21.5.tgz#99d1cf2937279560d2104821f5ccce220cb2af70" + integrity sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow== + +"@esbuild/sunos-x64@0.21.5": + version "0.21.5" + resolved "https://registry.yarnpkg.com/@esbuild/sunos-x64/-/sunos-x64-0.21.5.tgz#08741512c10d529566baba837b4fe052c8f3487b" + integrity sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg== + +"@esbuild/win32-arm64@0.21.5": + version "0.21.5" + resolved "https://registry.yarnpkg.com/@esbuild/win32-arm64/-/win32-arm64-0.21.5.tgz#675b7385398411240735016144ab2e99a60fc75d" + integrity sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A== + +"@esbuild/win32-ia32@0.21.5": + version "0.21.5" + resolved "https://registry.yarnpkg.com/@esbuild/win32-ia32/-/win32-ia32-0.21.5.tgz#1bfc3ce98aa6ca9a0969e4d2af72144c59c1193b" + integrity sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA== + +"@esbuild/win32-x64@0.21.5": + version "0.21.5" + resolved "https://registry.yarnpkg.com/@esbuild/win32-x64/-/win32-x64-0.21.5.tgz#acad351d582d157bb145535db2a6ff53dd514b5c" + integrity sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw== + +"@rollup/rollup-android-arm-eabi@4.20.0": + version "4.20.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.20.0.tgz#c3f5660f67030c493a981ac1d34ee9dfe1d8ec0f" + integrity sha512-TSpWzflCc4VGAUJZlPpgAJE1+V60MePDQnBd7PPkpuEmOy8i87aL6tinFGKBFKuEDikYpig72QzdT3QPYIi+oA== + +"@rollup/rollup-android-arm64@4.20.0": + version "4.20.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.20.0.tgz#64161f0b67050023a3859e723570af54a82cff5c" + integrity sha512-u00Ro/nok7oGzVuh/FMYfNoGqxU5CPWz1mxV85S2w9LxHR8OoMQBuSk+3BKVIDYgkpeOET5yXkx90OYFc+ytpQ== + +"@rollup/rollup-darwin-arm64@4.20.0": + version "4.20.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.20.0.tgz#25f3d57b1da433097cfebc89341b355901615763" + integrity sha512-uFVfvzvsdGtlSLuL0ZlvPJvl6ZmrH4CBwLGEFPe7hUmf7htGAN+aXo43R/V6LATyxlKVC/m6UsLb7jbG+LG39Q== + +"@rollup/rollup-darwin-x64@4.20.0": + version "4.20.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.20.0.tgz#d8ddaffb636cc2f59222c50316e27771e48966df" + integrity sha512-xbrMDdlev53vNXexEa6l0LffojxhqDTBeL+VUxuuIXys4x6xyvbKq5XqTXBCEUA8ty8iEJblHvFaWRJTk/icAQ== + +"@rollup/rollup-linux-arm-gnueabihf@4.20.0": + version "4.20.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.20.0.tgz#41bd4fcffa20fb84f3dbac6c5071638f46151885" + integrity sha512-jMYvxZwGmoHFBTbr12Xc6wOdc2xA5tF5F2q6t7Rcfab68TT0n+r7dgawD4qhPEvasDsVpQi+MgDzj2faOLsZjA== + +"@rollup/rollup-linux-arm-musleabihf@4.20.0": + version "4.20.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.20.0.tgz#842077c5113a747eb5686f19f2f18c33ecc0acc8" + integrity sha512-1asSTl4HKuIHIB1GcdFHNNZhxAYEdqML/MW4QmPS4G0ivbEcBr1JKlFLKsIRqjSwOBkdItn3/ZDlyvZ/N6KPlw== + +"@rollup/rollup-linux-arm64-gnu@4.20.0": + version "4.20.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.20.0.tgz#65d1d5b6778848f55b7823958044bf3e8737e5b7" + integrity sha512-COBb8Bkx56KldOYJfMf6wKeYJrtJ9vEgBRAOkfw6Ens0tnmzPqvlpjZiLgkhg6cA3DGzCmLmmd319pmHvKWWlQ== + +"@rollup/rollup-linux-arm64-musl@4.20.0": + version "4.20.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.20.0.tgz#50eef7d6e24d0fe3332200bb666cad2be8afcf86" + integrity sha512-+it+mBSyMslVQa8wSPvBx53fYuZK/oLTu5RJoXogjk6x7Q7sz1GNRsXWjn6SwyJm8E/oMjNVwPhmNdIjwP135Q== + +"@rollup/rollup-linux-powerpc64le-gnu@4.20.0": + version "4.20.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.20.0.tgz#8837e858f53c84607f05ad0602943e96d104c6b4" + integrity sha512-yAMvqhPfGKsAxHN8I4+jE0CpLWD8cv4z7CK7BMmhjDuz606Q2tFKkWRY8bHR9JQXYcoLfopo5TTqzxgPUjUMfw== + +"@rollup/rollup-linux-riscv64-gnu@4.20.0": + version "4.20.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.20.0.tgz#c894ade2300caa447757ddf45787cca246e816a4" + integrity sha512-qmuxFpfmi/2SUkAw95TtNq/w/I7Gpjurx609OOOV7U4vhvUhBcftcmXwl3rqAek+ADBwSjIC4IVNLiszoj3dPA== + +"@rollup/rollup-linux-s390x-gnu@4.20.0": + version "4.20.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.20.0.tgz#5841e5390d4c82dd5cdf7b2c95a830e3c2f47dd3" + integrity sha512-I0BtGXddHSHjV1mqTNkgUZLnS3WtsqebAXv11D5BZE/gfw5KoyXSAXVqyJximQXNvNzUo4GKlCK/dIwXlz+jlg== + +"@rollup/rollup-linux-x64-gnu@4.20.0": + version "4.20.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.20.0.tgz#cc1f26398bf777807a99226dc13f47eb0f6c720d" + integrity sha512-y+eoL2I3iphUg9tN9GB6ku1FA8kOfmF4oUEWhztDJ4KXJy1agk/9+pejOuZkNFhRwHAOxMsBPLbXPd6mJiCwew== + +"@rollup/rollup-linux-x64-musl@4.20.0": + version "4.20.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.20.0.tgz#1507465d9056e0502a590d4c1a00b4d7b1fda370" + integrity sha512-hM3nhW40kBNYUkZb/r9k2FKK+/MnKglX7UYd4ZUy5DJs8/sMsIbqWK2piZtVGE3kcXVNj3B2IrUYROJMMCikNg== + +"@rollup/rollup-win32-arm64-msvc@4.20.0": + version "4.20.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.20.0.tgz#86a221f01a2c248104dd0defb4da119f2a73642e" + integrity sha512-psegMvP+Ik/Bg7QRJbv8w8PAytPA7Uo8fpFjXyCRHWm6Nt42L+JtoqH8eDQ5hRP7/XW2UiIriy1Z46jf0Oa1kA== + +"@rollup/rollup-win32-ia32-msvc@4.20.0": + version "4.20.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.20.0.tgz#8bc8f77e02760aa664694b4286d6fbea7f1331c5" + integrity sha512-GabekH3w4lgAJpVxkk7hUzUf2hICSQO0a/BLFA11/RMxQT92MabKAqyubzDZmMOC/hcJNlc+rrypzNzYl4Dx7A== + +"@rollup/rollup-win32-x64-msvc@4.20.0": + version "4.20.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.20.0.tgz#601fffee719a1e8447f908aca97864eec23b2784" + integrity sha512-aJ1EJSuTdGnM6qbVC4B5DSmozPTqIag9fSzXRNNo+humQLG89XpPgdt16Ia56ORD7s+H8Pmyx44uczDQ0yDzpg== + +"@sindresorhus/is@^4.0.0": + version "4.6.0" + resolved "https://registry.yarnpkg.com/@sindresorhus/is/-/is-4.6.0.tgz#3c7c9c46e678feefe7a2e5bb609d3dbd665ffb3f" + integrity sha512-t09vSN3MdfsyCHoFcTRCH/iUtG7OJ0CsjzB8cjAmKc/va/kIgeDI/TxsigdncE/4be734m0cvIYwNaV4i2XqAw== + +"@szmarczak/http-timer@^4.0.5": + version "4.0.6" + resolved "https://registry.yarnpkg.com/@szmarczak/http-timer/-/http-timer-4.0.6.tgz#b4a914bb62e7c272d4e5989fe4440f812ab1d807" + integrity sha512-4BAffykYOgO+5nzBWYwE3W90sBgLJoUPRWWcL8wlyiM8IB8ipJz3UMJ9KXQd1RKQXpKp8Tutn80HZtWsu2u76w== + dependencies: + defer-to-connect "^2.0.0" + +"@types/cacheable-request@^6.0.1": + version "6.0.3" + resolved "https://registry.yarnpkg.com/@types/cacheable-request/-/cacheable-request-6.0.3.tgz#a430b3260466ca7b5ca5bfd735693b36e7a9d183" + integrity sha512-IQ3EbTzGxIigb1I3qPZc1rWJnH0BmSKv5QYTalEwweFvyBDLSAe24zP0le/hyi7ecGfZVlIVAg4BZqb8WBwKqw== + dependencies: + "@types/http-cache-semantics" "*" + "@types/keyv" "^3.1.4" + "@types/node" "*" + "@types/responselike" "^1.0.0" + +"@types/estree@1.0.5": + version "1.0.5" + resolved "https://registry.yarnpkg.com/@types/estree/-/estree-1.0.5.tgz#a6ce3e556e00fd9895dd872dd172ad0d4bd687f4" + integrity sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw== + +"@types/http-cache-semantics@*": + version "4.0.4" + resolved "https://registry.yarnpkg.com/@types/http-cache-semantics/-/http-cache-semantics-4.0.4.tgz#b979ebad3919799c979b17c72621c0bc0a31c6c4" + integrity sha512-1m0bIFVc7eJWyve9S0RnuRgcQqF/Xd5QsUZAZeQFr1Q3/p9JWoQQEqmVy+DPTNpGXwhgIetAoYF8JSc33q29QA== + +"@types/keyv@^3.1.4": + version "3.1.4" + resolved "https://registry.yarnpkg.com/@types/keyv/-/keyv-3.1.4.tgz#3ccdb1c6751b0c7e52300bcdacd5bcbf8faa75b6" + integrity sha512-BQ5aZNSCpj7D6K2ksrRCTmKRLEpnPvWDiLPfoGyhZ++8YtiK9d/3DBKPJgry359X/P1PfruyYwvnvwFjuEiEIg== + dependencies: + "@types/node" "*" + +"@types/node@*": + version "22.2.0" + resolved "https://registry.yarnpkg.com/@types/node/-/node-22.2.0.tgz#7cf046a99f0ba4d628ad3088cb21f790df9b0c5b" + integrity sha512-bm6EG6/pCpkxDf/0gDNDdtDILMOHgaQBVOJGdwsqClnxA3xL6jtMv76rLBc006RVMWbmaf0xbmom4Z/5o2nRkQ== + dependencies: + undici-types "~6.13.0" + +"@types/responselike@^1.0.0": + version "1.0.3" + resolved "https://registry.yarnpkg.com/@types/responselike/-/responselike-1.0.3.tgz#cc29706f0a397cfe6df89debfe4bf5cea159db50" + integrity sha512-H/+L+UkTV33uf49PH5pCAUBVPNj2nDBXTN+qS1dOwyyg24l3CcicicCA7ca+HMvJBZcFgl5r8e+RR6elsb4Lyw== + dependencies: + "@types/node" "*" + +ably@1.2.45: + version "1.2.45" + resolved "https://registry.yarnpkg.com/ably/-/ably-1.2.45.tgz#9da9b3faae18614160dd7ff1e5e93de948f984bd" + integrity sha512-8Jk8XT0dSPcLcZ8zSAF+mRtwMzaQR5dWHqGdx9Y859ZLhXiqf4gQb7P+4Elqy1l1IIRoDWgyt0fkyfo7ngUdMA== + dependencies: + "@ably/msgpack-js" "^0.4.0" + got "^11.8.5" + ws "^5.1" + +async-limiter@~1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/async-limiter/-/async-limiter-1.0.1.tgz#dd379e94f0db8310b08291f9d64c3209766617fd" + integrity sha512-csOlWGAcRFJaI6m+F2WKdnMKr4HhdhFVBk0H/QbJFMCr+uO2kwohwXQPxw/9OCxp05r5ghVBFSyioixx3gfkNQ== + +base64-js@1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.0.2.tgz#474211c95e6cf2a547db461e4f6778b51d08fa65" + integrity sha512-ZXBDPMt/v/8fsIqn+Z5VwrhdR6jVka0bYobHdGia0Nxi7BJ9i/Uvml3AocHIBtIIBhZjBw5MR0aR4ROs/8+SNg== + +bops@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/bops/-/bops-1.0.1.tgz#502aaf00ee119db1dbae088e3df4bea2e241dbcc" + integrity sha512-qCMBuZKP36tELrrgXpAfM+gHzqa0nLsWZ+L37ncsb8txYlnAoxOPpVp+g7fK0sGkMXfA0wl8uQkESqw3v4HNag== + dependencies: + base64-js "1.0.2" + to-utf8 "0.0.1" + +cacheable-lookup@^5.0.3: + version "5.0.4" + resolved "https://registry.yarnpkg.com/cacheable-lookup/-/cacheable-lookup-5.0.4.tgz#5a6b865b2c44357be3d5ebc2a467b032719a7005" + integrity sha512-2/kNscPhpcxrOigMZzbiWF7dz8ilhb/nIHU3EyZiXWXpeq/au8qJ8VhdftMkty3n7Gj6HIGalQG8oiBNB3AJgA== + +cacheable-request@^7.0.2: + version "7.0.4" + resolved "https://registry.yarnpkg.com/cacheable-request/-/cacheable-request-7.0.4.tgz#7a33ebf08613178b403635be7b899d3e69bbe817" + integrity sha512-v+p6ongsrp0yTGbJXjgxPow2+DL93DASP4kXCDKb8/bwRtt9OEF3whggkkDkGNzgcWy2XaF4a8nZglC7uElscg== + dependencies: + clone-response "^1.0.2" + get-stream "^5.1.0" + http-cache-semantics "^4.0.0" + keyv "^4.0.0" + lowercase-keys "^2.0.0" + normalize-url "^6.0.1" + responselike "^2.0.0" + +classnames@^2.3.2: + version "2.5.1" + resolved "https://registry.yarnpkg.com/classnames/-/classnames-2.5.1.tgz#ba774c614be0f016da105c858e7159eae8e7687b" + integrity sha512-saHYOzhIQs6wy2sVxTM6bUDsQO4F50V9RQ22qBpEdCW+I+/Wmke2HOl6lS6dTpdxVhb88/I6+Hs+438c3lfUow== + +clone-response@^1.0.2: + version "1.0.3" + resolved "https://registry.yarnpkg.com/clone-response/-/clone-response-1.0.3.tgz#af2032aa47816399cf5f0a1d0db902f517abb8c3" + integrity sha512-ROoL94jJH2dUVML2Y/5PEDNaSHgeOdSDicUyS7izcF63G6sTc/FTjLub4b8Il9S8S0beOfYt0TaA5qvFK+w0wA== + dependencies: + mimic-response "^1.0.0" + +decompress-response@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/decompress-response/-/decompress-response-6.0.0.tgz#ca387612ddb7e104bd16d85aab00d5ecf09c66fc" + integrity sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ== + dependencies: + mimic-response "^3.1.0" + +defer-to-connect@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/defer-to-connect/-/defer-to-connect-2.0.1.tgz#8016bdb4143e4632b77a3449c6236277de520587" + integrity sha512-4tvttepXG1VaYGrRibk5EwJd1t4udunSOVMdLSAL6mId1ix438oPwPZMALY41FCijukO1L0twNcGsdzS7dHgDg== + +dotenv@16.4.5: + version "16.4.5" + resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-16.4.5.tgz#cdd3b3b604cb327e286b4762e13502f717cb099f" + integrity sha512-ZmdL2rui+eB2YwhsWzjInR8LldtZHGDoQ1ugH85ppHKwpUHL7j7rN0Ti9NCnGiQbhaZ11FpR+7ao1dNsmduNUg== + +end-of-stream@^1.1.0: + version "1.4.4" + resolved "https://registry.yarnpkg.com/end-of-stream/-/end-of-stream-1.4.4.tgz#5ae64a5f45057baf3626ec14da0ca5e4b2431eb0" + integrity sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q== + dependencies: + once "^1.4.0" + +esbuild@^0.21.3: + version "0.21.5" + resolved "https://registry.yarnpkg.com/esbuild/-/esbuild-0.21.5.tgz#9ca301b120922959b766360d8ac830da0d02997d" + integrity sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw== + optionalDependencies: + "@esbuild/aix-ppc64" "0.21.5" + "@esbuild/android-arm" "0.21.5" + "@esbuild/android-arm64" "0.21.5" + "@esbuild/android-x64" "0.21.5" + "@esbuild/darwin-arm64" "0.21.5" + "@esbuild/darwin-x64" "0.21.5" + "@esbuild/freebsd-arm64" "0.21.5" + "@esbuild/freebsd-x64" "0.21.5" + "@esbuild/linux-arm" "0.21.5" + "@esbuild/linux-arm64" "0.21.5" + "@esbuild/linux-ia32" "0.21.5" + "@esbuild/linux-loong64" "0.21.5" + "@esbuild/linux-mips64el" "0.21.5" + "@esbuild/linux-ppc64" "0.21.5" + "@esbuild/linux-riscv64" "0.21.5" + "@esbuild/linux-s390x" "0.21.5" + "@esbuild/linux-x64" "0.21.5" + "@esbuild/netbsd-x64" "0.21.5" + "@esbuild/openbsd-x64" "0.21.5" + "@esbuild/sunos-x64" "0.21.5" + "@esbuild/win32-arm64" "0.21.5" + "@esbuild/win32-ia32" "0.21.5" + "@esbuild/win32-x64" "0.21.5" + +fsevents@~2.3.2, fsevents@~2.3.3: + version "2.3.3" + resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.3.tgz#cac6407785d03675a2a5e1a5305c697b347d90d6" + integrity sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw== + +get-stream@^5.1.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-5.2.0.tgz#4966a1795ee5ace65e706c4b7beb71257d6e22d3" + integrity sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA== + dependencies: + pump "^3.0.0" + +got@^11.8.5: + version "11.8.6" + resolved "https://registry.yarnpkg.com/got/-/got-11.8.6.tgz#276e827ead8772eddbcfc97170590b841823233a" + integrity sha512-6tfZ91bOr7bOXnK7PRDCGBLa1H4U080YHNaAQ2KsMGlLEzRbk44nsZF2E1IeRc3vtJHPVbKCYgdFbaGO2ljd8g== + dependencies: + "@sindresorhus/is" "^4.0.0" + "@szmarczak/http-timer" "^4.0.5" + "@types/cacheable-request" "^6.0.1" + "@types/responselike" "^1.0.0" + cacheable-lookup "^5.0.3" + cacheable-request "^7.0.2" + decompress-response "^6.0.0" + http2-wrapper "^1.0.0-beta.5.2" + lowercase-keys "^2.0.0" + p-cancelable "^2.0.0" + responselike "^2.0.0" + +http-cache-semantics@^4.0.0: + version "4.1.1" + resolved "https://registry.yarnpkg.com/http-cache-semantics/-/http-cache-semantics-4.1.1.tgz#abe02fcb2985460bf0323be664436ec3476a6d5a" + integrity sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ== + +http2-wrapper@^1.0.0-beta.5.2: + version "1.0.3" + resolved "https://registry.yarnpkg.com/http2-wrapper/-/http2-wrapper-1.0.3.tgz#b8f55e0c1f25d4ebd08b3b0c2c079f9590800b3d" + integrity sha512-V+23sDMr12Wnz7iTcDeJr3O6AIxlnvT/bmaAAAP/Xda35C90p9599p0F1eHR/N1KILWSoWVAiOMFjBBXaXSMxg== + dependencies: + quick-lru "^5.1.1" + resolve-alpn "^1.0.0" + +"js-tokens@^3.0.0 || ^4.0.0": + version "4.0.0" + resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" + integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ== + +json-buffer@3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/json-buffer/-/json-buffer-3.0.1.tgz#9338802a30d3b6605fbe0613e094008ca8c05a13" + integrity sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ== + +keyv@^4.0.0: + version "4.5.4" + resolved "https://registry.yarnpkg.com/keyv/-/keyv-4.5.4.tgz#a879a99e29452f942439f2a405e3af8b31d4de93" + integrity sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw== + dependencies: + json-buffer "3.0.1" + +loose-envify@^1.1.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.4.0.tgz#71ee51fa7be4caec1a63839f7e682d8132d30caf" + integrity sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q== + dependencies: + js-tokens "^3.0.0 || ^4.0.0" + +lowercase-keys@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/lowercase-keys/-/lowercase-keys-2.0.0.tgz#2603e78b7b4b0006cbca2fbcc8a3202558ac9479" + integrity sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA== + +mimic-response@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/mimic-response/-/mimic-response-1.0.1.tgz#4923538878eef42063cb8a3e3b0798781487ab1b" + integrity sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ== + +mimic-response@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/mimic-response/-/mimic-response-3.1.0.tgz#2d1d59af9c1b129815accc2c46a022a5ce1fa3c9" + integrity sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ== + +nanoid@^3.3.7: + version "3.3.7" + resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.7.tgz#d0c301a691bc8d54efa0a2226ccf3fe2fd656bd8" + integrity sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g== + +nanoid@^5.0.1: + version "5.0.7" + resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-5.0.7.tgz#6452e8c5a816861fd9d2b898399f7e5fd6944cc6" + integrity sha512-oLxFY2gd2IqnjcYyOXD8XGCftpGtZP2AbHbOkthDkvRywH5ayNtPVy9YlOPcHckXzbLTCHpkb7FB+yuxKV13pQ== + +normalize-url@^6.0.1: + version "6.1.0" + resolved "https://registry.yarnpkg.com/normalize-url/-/normalize-url-6.1.0.tgz#40d0885b535deffe3f3147bec877d05fe4c5668a" + integrity sha512-DlL+XwOy3NxAQ8xuC0okPgK46iuVNAK01YN7RueYBqqFeGsBjV9XmCAzAdgt+667bCl5kPh9EqKKDwnaPG1I7A== + +once@^1.3.1, once@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" + integrity sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w== + dependencies: + wrappy "1" + +p-cancelable@^2.0.0: + version "2.1.1" + resolved "https://registry.yarnpkg.com/p-cancelable/-/p-cancelable-2.1.1.tgz#aab7fbd416582fa32a3db49859c122487c5ed2cf" + integrity sha512-BZOr3nRQHOntUjTrH8+Lh54smKHoHyur8We1V8DSMVrl5A2malOOwuJRnKRDjSnkoeBh4at6BwEnb5I7Jl31wg== + +picocolors@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.0.1.tgz#a8ad579b571952f0e5d25892de5445bcfe25aaa1" + integrity sha512-anP1Z8qwhkbmu7MFP5iTt+wQKXgwzf7zTyGlcdzabySa9vd0Xt392U0rVmz9poOaBj0uHJKyyo9/upk0HrEQew== + +postcss@^8.4.40: + version "8.4.41" + resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.41.tgz#d6104d3ba272d882fe18fc07d15dc2da62fa2681" + integrity sha512-TesUflQ0WKZqAvg52PWL6kHgLKP6xB6heTOdoYM0Wt2UHyxNa4K25EZZMgKns3BH1RLVbZCREPpLY0rhnNoHVQ== + dependencies: + nanoid "^3.3.7" + picocolors "^1.0.1" + source-map-js "^1.2.0" + +pump@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/pump/-/pump-3.0.0.tgz#b4a2116815bde2f4e1ea602354e8c75565107a64" + integrity sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww== + dependencies: + end-of-stream "^1.1.0" + once "^1.3.1" + +quick-lru@^5.1.1: + version "5.1.1" + resolved "https://registry.yarnpkg.com/quick-lru/-/quick-lru-5.1.1.tgz#366493e6b3e42a3a6885e2e99d18f80fb7a8c932" + integrity sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA== + +random-words@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/random-words/-/random-words-2.0.1.tgz#cc4564385d040c9fad2b817621a0041a1ecc90f6" + integrity sha512-nZNJAmgcFmtJMTDDIUCm/iK4R6RydC6NvALvWhYItXQrgYGk1F7Gww416LpVROFQtfVd5TaLEf4WuSsko03N7w== + dependencies: + seedrandom "^3.0.5" + +react-dom@^18.0.0: + version "18.3.1" + resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-18.3.1.tgz#c2265d79511b57d479b3dd3fdfa51536494c5cb4" + integrity sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw== + dependencies: + loose-envify "^1.1.0" + scheduler "^0.23.2" + +react@^18.0.0: + version "18.3.1" + resolved "https://registry.yarnpkg.com/react/-/react-18.3.1.tgz#49ab892009c53933625bd16b2533fc754cab2891" + integrity sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ== + dependencies: + loose-envify "^1.1.0" + +resolve-alpn@^1.0.0: + version "1.2.1" + resolved "https://registry.yarnpkg.com/resolve-alpn/-/resolve-alpn-1.2.1.tgz#b7adbdac3546aaaec20b45e7d8265927072726f9" + integrity sha512-0a1F4l73/ZFZOakJnQ3FvkJ2+gSTQWz/r2KE5OdDY0TxPm5h4GkqkWWfM47T7HsbnOtcJVEF4epCVy6u7Q3K+g== + +responselike@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/responselike/-/responselike-2.0.1.tgz#9a0bc8fdc252f3fb1cca68b016591059ba1422bc" + integrity sha512-4gl03wn3hj1HP3yzgdI7d3lCkF95F21Pz4BPGvKHinyQzALR5CapwC8yIi0Rh58DEMQ/SguC03wFj2k0M/mHhw== + dependencies: + lowercase-keys "^2.0.0" + +rollup@^4.13.0: + version "4.20.0" + resolved "https://registry.yarnpkg.com/rollup/-/rollup-4.20.0.tgz#f9d602161d29e178f0bf1d9f35f0a26f83939492" + integrity sha512-6rbWBChcnSGzIlXeIdNIZTopKYad8ZG8ajhl78lGRLsI2rX8IkaotQhVas2Ma+GPxJav19wrSzvRvuiv0YKzWw== + dependencies: + "@types/estree" "1.0.5" + optionalDependencies: + "@rollup/rollup-android-arm-eabi" "4.20.0" + "@rollup/rollup-android-arm64" "4.20.0" + "@rollup/rollup-darwin-arm64" "4.20.0" + "@rollup/rollup-darwin-x64" "4.20.0" + "@rollup/rollup-linux-arm-gnueabihf" "4.20.0" + "@rollup/rollup-linux-arm-musleabihf" "4.20.0" + "@rollup/rollup-linux-arm64-gnu" "4.20.0" + "@rollup/rollup-linux-arm64-musl" "4.20.0" + "@rollup/rollup-linux-powerpc64le-gnu" "4.20.0" + "@rollup/rollup-linux-riscv64-gnu" "4.20.0" + "@rollup/rollup-linux-s390x-gnu" "4.20.0" + "@rollup/rollup-linux-x64-gnu" "4.20.0" + "@rollup/rollup-linux-x64-musl" "4.20.0" + "@rollup/rollup-win32-arm64-msvc" "4.20.0" + "@rollup/rollup-win32-ia32-msvc" "4.20.0" + "@rollup/rollup-win32-x64-msvc" "4.20.0" + fsevents "~2.3.2" + +scheduler@^0.23.2: + version "0.23.2" + resolved "https://registry.yarnpkg.com/scheduler/-/scheduler-0.23.2.tgz#414ba64a3b282892e944cf2108ecc078d115cdc3" + integrity sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ== + dependencies: + loose-envify "^1.1.0" + +seedrandom@^3.0.5: + version "3.0.5" + resolved "https://registry.yarnpkg.com/seedrandom/-/seedrandom-3.0.5.tgz#54edc85c95222525b0c7a6f6b3543d8e0b3aa0a7" + integrity sha512-8OwmbklUNzwezjGInmZ+2clQmExQPvomqjL7LFqOYqtmuxRgQYqOD3mHaU+MvZn5FLUeVxVfQjwLZW/n/JFuqg== + +source-map-js@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/source-map-js/-/source-map-js-1.2.0.tgz#16b809c162517b5b8c3e7dcd315a2a5c2612b2af" + integrity sha512-itJW8lvSA0TXEphiRoawsCksnlf8SyvmFzIhltqAHluXd88pkCd+cXJVHTDwdCr0IzwptSm035IHQktUu1QUMg== + +to-utf8@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/to-utf8/-/to-utf8-0.0.1.tgz#d17aea72ff2fba39b9e43601be7b3ff72e089852" + integrity sha512-zks18/TWT1iHO3v0vFp5qLKOG27m67ycq/Y7a7cTiRuUNlc4gf3HGnkRgMv0NyhnfTamtkYBJl+YeD1/j07gBQ== + +typescript@^5.2.2: + version "5.5.4" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.5.4.tgz#d9852d6c82bad2d2eda4fd74a5762a8f5909e9ba" + integrity sha512-Mtq29sKDAEYP7aljRgtPOpTvOfbwRWlS6dPRzwjdE+C0R4brX/GUyhHSecbHMFLNBLcJIPt9nl9yG5TZ1weH+Q== + +undici-types@~6.13.0: + version "6.13.0" + resolved "https://registry.yarnpkg.com/undici-types/-/undici-types-6.13.0.tgz#e3e79220ab8c81ed1496b5812471afd7cf075ea5" + integrity sha512-xtFJHudx8S2DSoujjMd1WeWvn7KKWFRESZTMeL1RptAYERu29D6jphMjjY+vn96jvN3kVPDNxU/E13VTaXj6jg== + +vite@^5.2.13: + version "5.4.0" + resolved "https://registry.yarnpkg.com/vite/-/vite-5.4.0.tgz#11dca8a961369ba8b5cae42d068c7ad684d5370f" + integrity sha512-5xokfMX0PIiwCMCMb9ZJcMyh5wbBun0zUzKib+L65vAZ8GY9ePZMXxFrHbr/Kyll2+LSCY7xtERPpxkBDKngwg== + dependencies: + esbuild "^0.21.3" + postcss "^8.4.40" + rollup "^4.13.0" + optionalDependencies: + fsevents "~2.3.3" + +wrappy@1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" + integrity sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ== + +ws@^5.1: + version "5.2.4" + resolved "https://registry.yarnpkg.com/ws/-/ws-5.2.4.tgz#c7bea9f1cfb5f410de50e70e82662e562113f9a7" + integrity sha512-fFCejsuC8f9kOSu9FYaOw8CdO68O3h5v0lg4p74o8JqWpwTf9tniOD+nOB78aWoVSS6WptVUmDrp/KPsMVBWFQ== + dependencies: + async-limiter "~1.0.0" From 005b1c5a37a787b0b4241128496708704b2c9b0a Mon Sep 17 00:00:00 2001 From: Greg Holmes Date: Tue, 13 Aug 2024 17:11:38 +0100 Subject: [PATCH 19/19] Update: Abstracted code into a function for cleaner reading --- examples/vanilla-avatar-stack-2/src/script.ts | 37 +++++++++++-------- 1 file changed, 22 insertions(+), 15 deletions(-) diff --git a/examples/vanilla-avatar-stack-2/src/script.ts b/examples/vanilla-avatar-stack-2/src/script.ts index 86d3f89..0c4230a 100644 --- a/examples/vanilla-avatar-stack-2/src/script.ts +++ b/examples/vanilla-avatar-stack-2/src/script.ts @@ -44,21 +44,7 @@ async function connect() { }); /** 💡 Get a count of the number exceeding four and display as a single tally 💡 */ - if (otherMembers.length > 4) { - const avatarsElement = document.getElementById('avatars'); - if (avatarsElement) { - const avatarElement = document.createElement('div'); - avatarElement.className = 'avatar'; - avatarElement.style.backgroundColor = '#595959'; - - const nameElement = document.createElement('p'); - nameElement.className = 'textWhite nameOthers'; - nameElement.textContent = `+${otherMembers.length - 4}`; - - avatarElement.appendChild(nameElement); - avatarsElement.appendChild(avatarElement); - } - } + renderExceedingCounter(otherMembers) }).catch((err) => { console.error('Error joining space:', err); }); @@ -146,3 +132,24 @@ async function renderAvatar(member: Member, isSelf: boolean = false): Promise 4) { + const avatarsElement = document.getElementById('avatars'); + + if (avatarsElement) { + const avatarElement = document.createElement('div'); + avatarElement.className = 'avatar'; + avatarElement.style.backgroundColor = '#595959'; + + const nameElement = document.createElement('p'); + nameElement.className = 'textWhite nameOthers'; + nameElement.textContent = `+${otherMembers.length - 4}`; + + avatarElement.appendChild(nameElement); + avatarsElement.appendChild(avatarElement); + } + } +}