@oxyhq/services 0.0.23 → 0.0.24

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (63) hide show
  1. package/dist/assets/dot-icon.d.ts +3 -0
  2. package/dist/assets/dot-icon.d.ts.map +1 -0
  3. package/dist/assets/dot-icon.js +6 -0
  4. package/dist/assets/verified-icon.d.ts +3 -0
  5. package/dist/assets/verified-icon.d.ts.map +1 -0
  6. package/dist/assets/verified-icon.js +9 -0
  7. package/dist/components/auth/AccountSwitcherModal.d.ts +5 -0
  8. package/dist/components/auth/AccountSwitcherModal.d.ts.map +1 -0
  9. package/dist/components/auth/AccountSwitcherModal.js +29 -0
  10. package/dist/components/auth/SessionOwnerButton.d.ts +3 -0
  11. package/dist/components/auth/SessionOwnerButton.d.ts.map +1 -0
  12. package/dist/components/auth/SessionOwnerButton.js +32 -0
  13. package/dist/components/elements/button/components/button.d.ts +7 -0
  14. package/dist/components/elements/button/components/button.d.ts.map +1 -0
  15. package/dist/components/elements/button/components/button.js +6 -0
  16. package/dist/components/elements/button/index.d.ts +2 -0
  17. package/dist/components/elements/button/index.d.ts.map +1 -0
  18. package/dist/components/elements/button/index.js +1 -0
  19. package/dist/components/elements/ellipsis-wrapper/components/ellipsis-wrapper.d.ts +5 -0
  20. package/dist/components/elements/ellipsis-wrapper/components/ellipsis-wrapper.d.ts.map +1 -0
  21. package/dist/components/elements/ellipsis-wrapper/components/ellipsis-wrapper.js +4 -0
  22. package/dist/components/elements/ellipsis-wrapper/index.d.ts +2 -0
  23. package/dist/components/elements/ellipsis-wrapper/index.d.ts.map +1 -0
  24. package/dist/components/elements/ellipsis-wrapper/index.js +1 -0
  25. package/dist/components/elements/modal/components/confirmation-modal.d.ts +12 -0
  26. package/dist/components/elements/modal/components/confirmation-modal.d.ts.map +1 -0
  27. package/dist/components/elements/modal/components/confirmation-modal.js +21 -0
  28. package/dist/components/elements/modal/components/modal.d.ts +13 -0
  29. package/dist/components/elements/modal/components/modal.d.ts.map +1 -0
  30. package/dist/components/elements/modal/components/modal.js +111 -0
  31. package/dist/components/elements/modal/hooks/use-track-position.d.ts +5 -0
  32. package/dist/components/elements/modal/hooks/use-track-position.d.ts.map +1 -0
  33. package/dist/components/elements/modal/hooks/use-track-position.js +35 -0
  34. package/dist/components/elements/modal/index.d.ts +4 -0
  35. package/dist/components/elements/modal/index.d.ts.map +1 -0
  36. package/dist/components/elements/modal/index.js +3 -0
  37. package/dist/config/index.d.ts +1 -1
  38. package/dist/config/index.d.ts.map +1 -1
  39. package/dist/features/profile/components/avatar.d.ts +10 -0
  40. package/dist/features/profile/components/avatar.d.ts.map +1 -0
  41. package/dist/features/profile/components/avatar.js +7 -0
  42. package/dist/features/profile/components/user-name.d.ts +7 -0
  43. package/dist/features/profile/components/user-name.d.ts.map +1 -0
  44. package/dist/features/profile/components/user-name.js +8 -0
  45. package/dist/features/profile/components/user-username.d.ts +5 -0
  46. package/dist/features/profile/components/user-username.d.ts.map +1 -0
  47. package/dist/features/profile/components/user-username.js +7 -0
  48. package/dist/features/profile/index.d.ts +4 -0
  49. package/dist/features/profile/index.d.ts.map +1 -0
  50. package/dist/features/profile/index.js +3 -0
  51. package/dist/hooks/get-user.d.ts +2 -0
  52. package/dist/hooks/get-user.d.ts.map +1 -0
  53. package/dist/hooks/get-user.js +27 -0
  54. package/dist/hooks/use-user.d.ts +14 -0
  55. package/dist/hooks/use-user.d.ts.map +1 -0
  56. package/dist/hooks/use-user.js +17 -0
  57. package/dist/index.d.ts +3 -3
  58. package/dist/index.d.ts.map +1 -1
  59. package/dist/index.js +3 -3
  60. package/dist/utils/cn.d.ts +3 -0
  61. package/dist/utils/cn.d.ts.map +1 -0
  62. package/dist/utils/cn.js +5 -0
  63. package/package.json +5 -1
@@ -0,0 +1,3 @@
1
+ import * as React from "react";
2
+ export declare const DotIcon: () => React.JSX.Element;
3
+ //# sourceMappingURL=dot-icon.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dot-icon.d.ts","sourceRoot":"","sources":["../../src/assets/dot-icon.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAE/B,eAAO,MAAM,OAAO,yBAQnB,CAAC"}
@@ -0,0 +1,6 @@
1
+ import * as React from "react";
2
+ export const DotIcon = () => {
3
+ return (React.createElement("svg", { viewBox: "0 0 24 24", "aria-hidden": "true" },
4
+ React.createElement("g", null,
5
+ React.createElement("path", { d: "M3 12c0-1.1.9-2 2-2s2 .9 2 2-.9 2-2 2-2-.9-2-2zm9 2c1.1 0 2-.9 2-2s-.9-2-2-2-2 .9-2 2 .9 2 2 2zm7 0c1.1 0 2-.9 2-2s-.9-2-2-2-2 .9-2 2 .9 2 2 2z" }))));
6
+ };
@@ -0,0 +1,3 @@
1
+ /// <reference types="react" />
2
+ export declare const VerifiedIcon: () => import("react").JSX.Element;
3
+ //# sourceMappingURL=verified-icon.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"verified-icon.d.ts","sourceRoot":"","sources":["../../src/assets/verified-icon.tsx"],"names":[],"mappings":";AAAA,eAAO,MAAM,YAAY,mCAiBxB,CAAC"}
@@ -0,0 +1,9 @@
1
+ export const VerifiedIcon = () => {
2
+ return (React.createElement("svg", { style: {
3
+ fill: "var(--clr-primary)",
4
+ height: "var(--verified-icon-width)",
5
+ marginLeft: "2px",
6
+ }, viewBox: "0 0 24 24", "aria-label": "Verified account", role: "img" },
7
+ React.createElement("g", null,
8
+ React.createElement("path", { d: "M22.25 12c0-1.43-.88-2.67-2.19-3.34.46-1.39.2-2.9-.81-3.91s-2.52-1.27-3.91-.81c-.66-1.31-1.91-2.19-3.34-2.19s-2.67.88-3.33 2.19c-1.4-.46-2.91-.2-3.92.81s-1.26 2.52-.8 3.91c-1.31.67-2.2 1.91-2.2 3.34s.89 2.67 2.2 3.34c-.46 1.39-.21 2.9.8 3.91s2.52 1.26 3.91.81c.67 1.31 1.91 2.19 3.34 2.19s2.68-.88 3.34-2.19c1.39.45 2.9.2 3.91-.81s1.27-2.52.81-3.91c1.31-.67 2.19-1.91 2.19-3.34zm-11.71 4.2L6.8 12.46l1.41-1.42 2.26 2.26 4.8-5.23 1.47 1.36-6.2 6.77z" }))));
9
+ };
@@ -0,0 +1,5 @@
1
+ import * as React from "react";
2
+ export declare const AccountSwitcherModal: React.ForwardRefExoticComponent<{
3
+ onClose: () => void;
4
+ } & React.RefAttributes<HTMLButtonElement>>;
5
+ //# sourceMappingURL=AccountSwitcherModal.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"AccountSwitcherModal.d.ts","sourceRoot":"","sources":["../../../src/components/auth/AccountSwitcherModal.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAU/B,eAAO,MAAM,oBAAoB;aAEpB,MAAM,IAAI;2CAmCrB,CAAC"}
@@ -0,0 +1,29 @@
1
+ "use client";
2
+ import * as React from "react";
3
+ import { motion } from "framer-motion";
4
+ import Link from "next/link";
5
+ import useOxySession from "../../hooks/useOxySession";
6
+ import { forwardRef } from "react";
7
+ import { useUser } from "../../hooks/use-user";
8
+ import styles from "./styles/session-owner-modal.module.scss";
9
+ export const AccountSwitcherModal = forwardRef(({ onClose }, ref) => {
10
+ const { session } = useOxySession();
11
+ const { data: user } = useUser({ id: session?.user?.id });
12
+ const style = {
13
+ position: "fixed",
14
+ top: "50%",
15
+ left: "50%",
16
+ transform: "translate(-50%, -50%)",
17
+ };
18
+ if (!session)
19
+ return null;
20
+ return (React.createElement(motion.div, { initial: { opacity: 0, y: "100%" }, animate: { opacity: 1, y: 0 }, exit: { opacity: 0, y: "100%" }, transition: {
21
+ ease: "easeInOut",
22
+ duration: 0.2,
23
+ }, className: styles.container, style: style, role: "group" },
24
+ React.createElement(Link, { href: `/auth/signin`, role: "menuitem", onClick: onClose }, "Add an existing account"),
25
+ React.createElement(Link, { href: `/auth/signout`, role: "menuitem", onClick: onClose },
26
+ "Log out @",
27
+ user?.username)));
28
+ });
29
+ AccountSwitcherModal.displayName = "AccountSwitcherModal";
@@ -0,0 +1,3 @@
1
+ import * as React from "react";
2
+ export declare const SessionOwnerButton: () => React.JSX.Element;
3
+ //# sourceMappingURL=SessionOwnerButton.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SessionOwnerButton.d.ts","sourceRoot":"","sources":["../../../src/components/auth/SessionOwnerButton.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAe/B,eAAO,MAAM,kBAAkB,yBAoD9B,CAAC"}
@@ -0,0 +1,32 @@
1
+ "use client";
2
+ import * as React from "react";
3
+ import { AnimatePresence } from "framer-motion";
4
+ import useOxySession from "../../hooks/useOxySession";
5
+ import { useRef, useState } from "react";
6
+ import { useUser } from "../../hooks/use-user";
7
+ import { DotIcon } from "../../assets/dot-icon";
8
+ import { Button } from "../../components/elements/button";
9
+ import { EllipsisWrapper } from "../../components/elements/ellipsis-wrapper";
10
+ import { Modal } from "../../components/elements/modal";
11
+ import { Avatar, UserName, UserUsername } from "../../features/profile";
12
+ import { AccountSwitcherModal } from "./AccountSwitcherModal";
13
+ export const SessionOwnerButton = () => {
14
+ const { session } = useOxySession();
15
+ const { data: user } = useUser({ id: session?.user?.id });
16
+ const [isModalOpen, setIsModalOpen] = useState(false);
17
+ const buttonRef = useRef(null);
18
+ const openModal = () => {
19
+ setIsModalOpen(true);
20
+ };
21
+ return (React.createElement(React.Fragment, null,
22
+ React.createElement(Button, { "aria-label": "Account menu", onClick: openModal, ref: buttonRef, "aria-haspopup": "menu", "aria-expanded": isModalOpen, className: "p-[0.75em] hover:bg-neutral-500 focus-visible:bg-neutral-500 focus-visible:outline-secondary-100 active:bg-neutral-600 xxl:flex xxl:w-full xxl:gap-3" },
23
+ React.createElement(Avatar, { userImage: session?.user?.avatar }),
24
+ React.createElement("div", { className: "hidden flex-1 flex-col xxl:flex" },
25
+ React.createElement(UserName, { name: session?.user?.name, isVerified: session?.user?.verified }),
26
+ React.createElement(EllipsisWrapper, null,
27
+ React.createElement(UserUsername, { username: user?.username }))),
28
+ React.createElement("div", { className: "hidden fill-secondary-100 xxl:inline [&>svg]:size-h2" },
29
+ React.createElement(DotIcon, null))),
30
+ React.createElement(AnimatePresence, null, isModalOpen && (React.createElement(Modal, { onClose: () => setIsModalOpen(false), background: "none", minViewportWidth: 500 },
31
+ React.createElement(AccountSwitcherModal, { ref: buttonRef, onClose: () => setIsModalOpen(false) }))))));
32
+ };
@@ -0,0 +1,7 @@
1
+ import React from "react";
2
+ interface IButton extends React.ButtonHTMLAttributes<HTMLButtonElement> {
3
+ children: React.ReactNode;
4
+ }
5
+ export declare const Button: React.ForwardRefExoticComponent<IButton & React.RefAttributes<HTMLButtonElement>>;
6
+ export {};
7
+ //# sourceMappingURL=button.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"button.d.ts","sourceRoot":"","sources":["../../../../../src/components/elements/button/components/button.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAqB,MAAM,OAAO,CAAC;AAI1C,UAAU,OAAQ,SAAQ,KAAK,CAAC,oBAAoB,CAAC,iBAAiB,CAAC;IACrE,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC;CAC3B;AAED,eAAO,MAAM,MAAM,mFAoBlB,CAAC"}
@@ -0,0 +1,6 @@
1
+ import React, { forwardRef } from "react";
2
+ import { cn } from "../../../../utils/cn";
3
+ export const Button = forwardRef(({ children, className, ...props }, ref) => {
4
+ return (React.createElement("button", { ref: ref, ...props, className: cn("grid cursor-pointer place-items-center rounded-full", "transition-colors duration-200 ease-in-out", "fill-secondary-100 p-[0.5em]", "focus-visible:outline focus-visible:outline-2 focus-visible:outline-primary-100", "fill-secondary-100 [&>svg]:w-h2", "disabled-button", className) }, children));
5
+ });
6
+ Button.displayName = "Button";
@@ -0,0 +1,2 @@
1
+ export { Button } from "./components/button";
2
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/components/elements/button/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,qBAAqB,CAAC"}
@@ -0,0 +1 @@
1
+ export { Button } from "./components/button";
@@ -0,0 +1,5 @@
1
+ import React from "react";
2
+ export declare const EllipsisWrapper: ({ children, }: {
3
+ children: React.ReactNode;
4
+ }) => React.JSX.Element;
5
+ //# sourceMappingURL=ellipsis-wrapper.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ellipsis-wrapper.d.ts","sourceRoot":"","sources":["../../../../../src/components/elements/ellipsis-wrapper/components/ellipsis-wrapper.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAG1B,eAAO,MAAM,eAAe,kBAEzB;IACD,QAAQ,EAAE,MAAM,SAAS,CAAC;CAC3B,sBAUA,CAAC"}
@@ -0,0 +1,4 @@
1
+ import React from "react";
2
+ export const EllipsisWrapper = ({ children, }) => {
3
+ return (React.createElement("div", { "aria-hidden": true, role: "presentation", className: "grid grid-flow-col [&>*]:truncate" }, children));
4
+ };
@@ -0,0 +1,2 @@
1
+ export * from "./components/ellipsis-wrapper";
2
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/components/elements/ellipsis-wrapper/index.ts"],"names":[],"mappings":"AAAA,cAAc,+BAA+B,CAAC"}
@@ -0,0 +1 @@
1
+ export * from "./components/ellipsis-wrapper";
@@ -0,0 +1,12 @@
1
+ import React from "react";
2
+ export declare const ConfirmationModal: ({ heading, paragraph, confirmButtonText, confirmButtonClick, confirmButtonStyle, cancelButtonText, cancelButtonClick, logo, }: {
3
+ heading: string;
4
+ paragraph: string;
5
+ confirmButtonText: string;
6
+ confirmButtonClick: () => void;
7
+ confirmButtonStyle: "delete" | "unfollow" | "logout";
8
+ cancelButtonText: string;
9
+ cancelButtonClick: () => void;
10
+ logo?: React.ReactNode;
11
+ }) => React.JSX.Element;
12
+ //# sourceMappingURL=confirmation-modal.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"confirmation-modal.d.ts","sourceRoot":"","sources":["../../../../../src/components/elements/modal/components/confirmation-modal.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAoB,MAAM,OAAO,CAAC;AAIzC,eAAO,MAAM,iBAAiB,kIAS3B;IACD,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,kBAAkB,EAAE,MAAM,IAAI,CAAC;IAC/B,kBAAkB,EAAE,QAAQ,GAAG,UAAU,GAAG,QAAQ,CAAC;IACrD,gBAAgB,EAAE,MAAM,CAAC;IACzB,iBAAiB,EAAE,MAAM,IAAI,CAAC;IAC9B,IAAI,CAAC,EAAE,MAAM,SAAS,CAAC;CACxB,sBAuCA,CAAC"}
@@ -0,0 +1,21 @@
1
+ import React, { useEffect } from "react";
2
+ import { motion } from "framer-motion";
3
+ import styles from "./styles/confirmation-modal.module.scss";
4
+ export const ConfirmationModal = ({ heading, paragraph, confirmButtonText, confirmButtonClick, confirmButtonStyle = "delete", cancelButtonText, cancelButtonClick, logo, }) => {
5
+ useEffect(() => {
6
+ document.body.style.overflow = "hidden";
7
+ document.body.style.paddingRight = "11px";
8
+ return () => {
9
+ document.body.style.overflow = "unset";
10
+ document.body.style.paddingRight = "0";
11
+ };
12
+ }, []);
13
+ return (React.createElement(motion.div, { initial: { opacity: 0, y: 50 }, animate: { opacity: 1, y: 0 }, exit: { opacity: 0, y: 50 }, transition: { duration: 0.2 }, className: styles.container },
14
+ logo && React.createElement("div", { className: styles.logo }, logo),
15
+ React.createElement("h1", null, heading),
16
+ React.createElement("p", null, paragraph),
17
+ React.createElement("div", { className: styles.buttons },
18
+ React.createElement("button", { onClick: confirmButtonClick, className: `${styles.confirm} ${styles[confirmButtonStyle]}
19
+ }` }, confirmButtonText),
20
+ React.createElement("button", { onClick: cancelButtonClick, className: styles.cancel }, cancelButtonText))));
21
+ };
@@ -0,0 +1,13 @@
1
+ import React from "react";
2
+ export declare const Modal: ({ children, onClose, closeOnBackdropClick, background, minViewportWidth, maxViewportWidth, disableScroll, focusOnElement, focusAfterClose, }: {
3
+ children: React.ReactNode;
4
+ onClose: () => void;
5
+ closeOnBackdropClick?: boolean;
6
+ background?: string;
7
+ minViewportWidth?: number | null;
8
+ maxViewportWidth?: number | null;
9
+ disableScroll?: boolean;
10
+ focusOnElement?: string | null;
11
+ focusAfterClose?: string | null;
12
+ }) => React.ReactPortal;
13
+ //# sourceMappingURL=modal.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"modal.d.ts","sourceRoot":"","sources":["../../../../../src/components/elements/modal/components/modal.tsx"],"names":[],"mappings":"AAKA,OAAO,KAA+C,MAAM,OAAO,CAAC;AAKpE,eAAO,MAAM,KAAK,iJAUf;IACD,QAAQ,EAAE,MAAM,SAAS,CAAC;IAC1B,OAAO,EAAE,MAAM,IAAI,CAAC;IACpB,oBAAoB,CAAC,EAAE,OAAO,CAAC;IAC/B,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,gBAAgB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACjC,gBAAgB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACjC,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,cAAc,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC/B,eAAe,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CACjC,sBAuJA,CAAC"}
@@ -0,0 +1,111 @@
1
+ /* eslint-disable jsx-a11y/no-static-element-interactions */
2
+ /* eslint-disable jsx-a11y/click-events-have-key-events */
3
+ /* eslint-disable jsx-a11y/no-noninteractive-element-interactions */
4
+ "use client";
5
+ import { motion } from "framer-motion";
6
+ import React, { useCallback, useLayoutEffect, useRef } from "react";
7
+ import { createPortal } from "react-dom";
8
+ import styles from "./styles/modal.module.scss";
9
+ export const Modal = ({ children, onClose, closeOnBackdropClick = true, background, minViewportWidth = null, maxViewportWidth = null, disableScroll = false, focusOnElement = null, focusAfterClose = null, }) => {
10
+ const modalRef = useRef(null);
11
+ const previouslyFocusedElementRef = useRef(null);
12
+ const handleKeyDown = useCallback((e) => {
13
+ if (e.key === "Escape") {
14
+ onClose();
15
+ }
16
+ if (e.key === "Tab") {
17
+ const modal = modalRef.current;
18
+ if (!modal)
19
+ return;
20
+ const focusableElements = Array.from(modal.querySelectorAll('a[href]:not([disabled]), button:not([disabled]), textarea:not([disabled]), input[type="text"]:not([disabled]), input[type="radio"]:not([disabled]), input[type="checkbox"]:not([disabled]), select:not([disabled])'));
21
+ const firstFocusableElement = focusableElements[0];
22
+ const lastFocusableElement = focusableElements[focusableElements.length - 1];
23
+ if (e.shiftKey) {
24
+ if (document.activeElement === firstFocusableElement) {
25
+ lastFocusableElement.focus();
26
+ e.preventDefault();
27
+ }
28
+ }
29
+ else {
30
+ if (document.activeElement === lastFocusableElement) {
31
+ firstFocusableElement.focus();
32
+ e.preventDefault();
33
+ }
34
+ }
35
+ }
36
+ }, [onClose]);
37
+ const handleScroll = useCallback((e) => {
38
+ if (disableScroll) {
39
+ e.preventDefault();
40
+ }
41
+ }, [disableScroll]);
42
+ const handleDisplay = useCallback(() => {
43
+ const modal = modalRef.current;
44
+ if (!modal)
45
+ return;
46
+ const viewportWidth = window.innerWidth;
47
+ if ((minViewportWidth && viewportWidth < minViewportWidth) ||
48
+ (maxViewportWidth && viewportWidth > maxViewportWidth)) {
49
+ onClose();
50
+ }
51
+ }, [onClose, minViewportWidth, maxViewportWidth]);
52
+ useLayoutEffect(() => {
53
+ const modal = modalRef.current;
54
+ if (!modal)
55
+ return;
56
+ const focusableElements = Array.from(modal.querySelectorAll('a[href]:not([disabled]), button:not([disabled]), textarea:not([disabled]), input[type="text"]:not([disabled]), input[type="radio"]:not([disabled]), input[type="checkbox"]:not([disabled]), select:not([disabled])'));
57
+ const firstFocusableElement = focusableElements?.[0];
58
+ previouslyFocusedElementRef.current = document.activeElement;
59
+ modal?.addEventListener("keydown", handleKeyDown);
60
+ if (focusOnElement) {
61
+ const elementToFocus = modal.querySelector(focusOnElement);
62
+ elementToFocus?.focus();
63
+ }
64
+ else {
65
+ firstFocusableElement?.focus();
66
+ }
67
+ if (disableScroll) {
68
+ document.body.style.overflow = "hidden";
69
+ document.body.style.paddingRight = "11px";
70
+ window.addEventListener("scroll", handleScroll);
71
+ }
72
+ if (minViewportWidth || maxViewportWidth) {
73
+ handleDisplay();
74
+ }
75
+ return () => {
76
+ modal?.removeEventListener("keydown", handleKeyDown);
77
+ if (focusAfterClose) {
78
+ const elementToFocus = document.querySelector(focusAfterClose);
79
+ elementToFocus?.focus();
80
+ }
81
+ else {
82
+ previouslyFocusedElementRef.current?.focus();
83
+ }
84
+ if (disableScroll) {
85
+ document.body.style.overflow = "";
86
+ document.body.style.paddingRight = "";
87
+ window.removeEventListener("scroll", handleScroll);
88
+ }
89
+ };
90
+ }, [
91
+ onClose,
92
+ disableScroll,
93
+ handleKeyDown,
94
+ handleScroll,
95
+ handleDisplay,
96
+ minViewportWidth,
97
+ maxViewportWidth,
98
+ focusOnElement,
99
+ focusAfterClose,
100
+ ]);
101
+ const backdropStyle = {
102
+ backgroundColor: background === "none" ? "transparent" : "var(--clr-modal-background)",
103
+ };
104
+ return createPortal(React.createElement(motion.div, { initial: { opacity: 0 }, animate: { opacity: 1 }, exit: { opacity: 0 }, onClick: (e) => {
105
+ e.stopPropagation();
106
+ if (e.currentTarget === e.target && closeOnBackdropClick)
107
+ onClose();
108
+ }, onKeyDown: (e) => {
109
+ e.stopPropagation();
110
+ }, ref: modalRef, className: `${styles.container}`, style: backdropStyle, id: "dialog", role: "dialog", "aria-modal": "true" }, children), document.body);
111
+ };
@@ -0,0 +1,5 @@
1
+ export declare const useTrackPosition: ({ buttonRef, trackScroll, }: {
2
+ buttonRef: React.RefObject<HTMLButtonElement>;
3
+ trackScroll?: boolean;
4
+ }) => DOMRect | null;
5
+ //# sourceMappingURL=use-track-position.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"use-track-position.d.ts","sourceRoot":"","sources":["../../../../../src/components/elements/modal/hooks/use-track-position.ts"],"names":[],"mappings":"AAGA,eAAO,MAAM,gBAAgB,gCAG1B;IACD,SAAS,EAAE,MAAM,SAAS,CAAC,iBAAiB,CAAC,CAAC;IAC9C,WAAW,CAAC,EAAE,OAAO,CAAC;CACvB,mBAuCA,CAAC"}
@@ -0,0 +1,35 @@
1
+ "use client";
2
+ import { useState, useLayoutEffect } from "react";
3
+ export const useTrackPosition = ({ buttonRef, trackScroll = false, }) => {
4
+ const [buttonBoundaries, setButtonBoundaries] = useState(buttonRef?.current?.getBoundingClientRect() ?? null);
5
+ useLayoutEffect(() => {
6
+ const handleResize = () => {
7
+ if (buttonRef?.current) {
8
+ setButtonBoundaries(buttonRef.current.getBoundingClientRect());
9
+ }
10
+ };
11
+ window.addEventListener("resize", handleResize);
12
+ if (trackScroll) {
13
+ window.addEventListener("scroll", handleResize);
14
+ }
15
+ return () => {
16
+ window.removeEventListener("resize", handleResize);
17
+ if (trackScroll) {
18
+ window.removeEventListener("scroll", handleResize);
19
+ }
20
+ };
21
+ }, [
22
+ buttonRef,
23
+ buttonRef.current?.getBoundingClientRect,
24
+ trackScroll,
25
+ setButtonBoundaries,
26
+ ]);
27
+ useLayoutEffect(() => {
28
+ setButtonBoundaries(buttonRef.current?.getBoundingClientRect() ?? null);
29
+ }, [
30
+ buttonRef,
31
+ buttonRef.current?.getBoundingClientRect,
32
+ setButtonBoundaries,
33
+ ]);
34
+ return buttonBoundaries;
35
+ };
@@ -0,0 +1,4 @@
1
+ export * from "./components/modal";
2
+ export * from "./components/confirmation-modal";
3
+ export * from "./hooks/use-track-position";
4
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/components/elements/modal/index.ts"],"names":[],"mappings":"AAAA,cAAc,oBAAoB,CAAC;AACnC,cAAc,iCAAiC,CAAC;AAChD,cAAc,4BAA4B,CAAC"}
@@ -0,0 +1,3 @@
1
+ export * from "./components/modal";
2
+ export * from "./components/confirmation-modal";
3
+ export * from "./hooks/use-track-position";
@@ -15,7 +15,7 @@ declare global {
15
15
  }
16
16
  }
17
17
  }
18
- export declare const NODE_ENV: "development" | "production" | "test";
18
+ export declare const NODE_ENV: "development" | "production";
19
19
  export declare const OXY_AUTH_URL: string;
20
20
  export {};
21
21
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/config/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,QAAA,MAAM,SAAS;;;;;;;;;EAGb,CAAC;AAEH,OAAO,CAAC,MAAM,CAAC;IAEb,UAAU,MAAM,CAAC;QACf,UAAU,UAAW,SAAQ,CAAC,CAAC,KAAK,CAAC,OAAO,SAAS,CAAC;SAAG;KAC1D;CACF;AAED,eAAO,MAAM,QAAQ,uCAAuB,CAAC;AAC7C,eAAO,MAAM,YAAY,QACoD,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/config/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,QAAA,MAAM,SAAS;;;;;;;;;EAGb,CAAC;AAEH,OAAO,CAAC,MAAM,CAAC;IAEb,UAAU,MAAM,CAAC;QACf,UAAU,UAAW,SAAQ,CAAC,CAAC,KAAK,CAAC,OAAO,SAAS,CAAC;SAAG;KAC1D;CACF;AAED,eAAO,MAAM,QAAQ,8BAAuB,CAAC;AAC7C,eAAO,MAAM,YAAY,QACoD,CAAC"}
@@ -0,0 +1,10 @@
1
+ import React from "react";
2
+ interface IAvatar extends React.ImgHTMLAttributes<HTMLImageElement> {
3
+ userImage: string | null | undefined;
4
+ className?: string;
5
+ width?: number;
6
+ height?: number;
7
+ }
8
+ export declare const Avatar: ({ userImage, className, ...props }: IAvatar) => React.JSX.Element;
9
+ export {};
10
+ //# sourceMappingURL=avatar.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"avatar.d.ts","sourceRoot":"","sources":["../../../../src/features/profile/components/avatar.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,MAAM,OAAO,CAAC;AAI1B,UAAU,OAAQ,SAAQ,KAAK,CAAC,iBAAiB,CAAC,gBAAgB,CAAC;IACjE,SAAS,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,CAAC;IACrC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,eAAO,MAAM,MAAM,uCAAwC,OAAO,sBAiBjE,CAAC"}
@@ -0,0 +1,7 @@
1
+ import Image from "next/image";
2
+ import React from "react";
3
+ import { cn } from "../../../utils/cn";
4
+ export const Avatar = ({ userImage, className, ...props }) => {
5
+ return (React.createElement("div", { className: cn("relative aspect-square w-[calc(var(--tw-fs-kilo)+9px)] overflow-hidden rounded-full", className) },
6
+ React.createElement(Image, { ...props, src: userImage || `/user_placeholder.png`, alt: "profile picture", fill: true, className: "block size-full object-cover" })));
7
+ };
@@ -0,0 +1,7 @@
1
+ import React from "react";
2
+ export declare const UserName: ({ name, isVerified, hover, }: {
3
+ name: string | undefined;
4
+ isVerified?: boolean | undefined;
5
+ hover?: boolean | undefined;
6
+ }) => React.JSX.Element;
7
+ //# sourceMappingURL=user-name.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"user-name.d.ts","sourceRoot":"","sources":["../../../../src/features/profile/components/user-name.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAK1B,eAAO,MAAM,QAAQ,iCAIlB;IACD,IAAI,EAAE,MAAM,GAAG,SAAS,CAAC;IACzB,UAAU,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;IACjC,KAAK,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;CAC7B,sBAOA,CAAC"}
@@ -0,0 +1,8 @@
1
+ import React from "react";
2
+ import { VerifiedIcon } from "../../../assets/verified-icon";
3
+ import styles from "./styles/user-name.module.scss";
4
+ export const UserName = ({ name, isVerified = false, hover = false, }) => {
5
+ return (React.createElement("div", { className: `${styles.container} ${hover ? styles.hover : ""}` },
6
+ name && React.createElement("span", null, name),
7
+ isVerified && React.createElement(VerifiedIcon, null)));
8
+ };
@@ -0,0 +1,5 @@
1
+ import React from "react";
2
+ export declare const UserUsername: ({ username, }: {
3
+ username: string | undefined;
4
+ }) => React.JSX.Element;
5
+ //# sourceMappingURL=user-username.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"user-username.d.ts","sourceRoot":"","sources":["../../../../src/features/profile/components/user-username.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAG1B,eAAO,MAAM,YAAY,kBAEtB;IACD,QAAQ,EAAE,MAAM,GAAG,SAAS,CAAC;CAC9B,sBAEA,CAAC"}
@@ -0,0 +1,7 @@
1
+ import React from "react";
2
+ import styles from "./styles/user-username.module.scss";
3
+ export const UserUsername = ({ username, }) => {
4
+ return React.createElement("span", { className: styles.container },
5
+ "@",
6
+ username);
7
+ };
@@ -0,0 +1,4 @@
1
+ export * from "./components/avatar";
2
+ export * from "./components/user-name";
3
+ export * from "./components/user-username";
4
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/features/profile/index.ts"],"names":[],"mappings":"AAAA,cAAc,qBAAqB,CAAC;AACpC,cAAc,wBAAwB,CAAC;AACvC,cAAc,4BAA4B,CAAC"}
@@ -0,0 +1,3 @@
1
+ export * from "./components/avatar";
2
+ export * from "./components/user-name";
3
+ export * from "./components/user-username";
@@ -0,0 +1,2 @@
1
+ export declare const getUser: (id: string | undefined) => Promise<any>;
2
+ //# sourceMappingURL=get-user.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"get-user.d.ts","sourceRoot":"","sources":["../../src/hooks/get-user.ts"],"names":[],"mappings":"AAEA,eAAO,MAAM,OAAO,OAAc,MAAM,GAAG,SAAS,iBAsBnD,CAAC"}
@@ -0,0 +1,27 @@
1
+ import axios from "axios";
2
+ export const getUser = async (id) => {
3
+ try {
4
+ const response = await axios.get(`/api/users/${id}`);
5
+ return response.data;
6
+ }
7
+ catch (error) {
8
+ if (error.response) {
9
+ // The request was made and the server responded with a status code
10
+ // that falls out of the range of 2xx
11
+ console.log(error.response.data);
12
+ console.log(error.response.status);
13
+ console.log(error.response.headers);
14
+ }
15
+ else if (error.request) {
16
+ // The request was made but no response was received
17
+ // `error.request` is an instance of XMLHttpRequest in the browser and an instance of
18
+ // http.ClientRequest in node.js
19
+ console.log(error.request);
20
+ }
21
+ else {
22
+ // Something happened in setting up the request that triggered an Error
23
+ console.log("Error", error.message);
24
+ }
25
+ console.log(error.config);
26
+ }
27
+ };
@@ -0,0 +1,14 @@
1
+ export interface IUser {
2
+ id: string;
3
+ username: string;
4
+ name: string;
5
+ email: string;
6
+ role: string;
7
+ avatar: string;
8
+ color: string;
9
+ }
10
+ export declare const useUser: ({ id, initialData, }: {
11
+ id: string | undefined;
12
+ initialData?: IUser;
13
+ }) => import("@tanstack/react-query").UseQueryResult<IUser, Error>;
14
+ //# sourceMappingURL=use-user.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"use-user.d.ts","sourceRoot":"","sources":["../../src/hooks/use-user.ts"],"names":[],"mappings":"AAIA,MAAM,WAAW,KAAK;IACpB,EAAE,EAAE,MAAM,CAAC;IACX,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;CACf;AAED,eAAO,MAAM,OAAO,yBAGjB;IACD,EAAE,EAAE,MAAM,GAAG,SAAS,CAAC;IACvB,WAAW,CAAC,EAAE,KAAK,CAAC;CACrB,iEAcA,CAAC"}
@@ -0,0 +1,17 @@
1
+ import { useQuery } from "@tanstack/react-query";
2
+ import { getUser } from "./get-user";
3
+ export const useUser = ({ id, initialData, }) => {
4
+ return useQuery({
5
+ queryKey: ["users", id],
6
+ queryFn: async () => {
7
+ if (!id) {
8
+ // Return a default value or null when id is not provided
9
+ return null;
10
+ }
11
+ return getUser(id);
12
+ },
13
+ refetchOnWindowFocus: false,
14
+ initialData: initialData ?? undefined,
15
+ enabled: !!id, // Only run the query if the id is provided
16
+ });
17
+ };
package/dist/index.d.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  import useOxySession from "./hooks/useOxySession";
2
2
  import getUserById from "./hooks/getUserById";
3
3
  import SignInButton from "./components/auth/SignInButton";
4
- import AccountSwitcher from "./components/auth/AccountSwitcher";
5
- import OAvatar from "./components/auth/OAvatar";
6
- export { useOxySession, getUserById, SignInButton, AccountSwitcher, OAvatar };
4
+ import { AccountSwitcherModal } from "./components/auth/AccountSwitcherModal";
5
+ import { SessionOwnerButton } from "./components/auth/SessionOwnerButton";
6
+ export { useOxySession, getUserById, SignInButton, AccountSwitcherModal, SessionOwnerButton, };
7
7
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,aAAa,MAAM,uBAAuB,CAAC;AAClD,OAAO,WAAW,MAAM,qBAAqB,CAAC;AAC9C,OAAO,YAAY,MAAM,gCAAgC,CAAC;AAC1D,OAAO,eAAe,MAAM,mCAAmC,CAAC;AAChE,OAAO,OAAO,MAAM,2BAA2B,CAAC;AAEhD,OAAO,EAAE,aAAa,EAAE,WAAW,EAAE,YAAY,EAAE,eAAe,EAAE,OAAO,EAAE,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,aAAa,MAAM,uBAAuB,CAAC;AAClD,OAAO,WAAW,MAAM,qBAAqB,CAAC;AAC9C,OAAO,YAAY,MAAM,gCAAgC,CAAC;AAC1D,OAAO,EAAE,oBAAoB,EAAE,MAAM,wCAAwC,CAAC;AAC9E,OAAO,EAAE,kBAAkB,EAAE,MAAM,sCAAsC,CAAC;AAE1E,OAAO,EACL,aAAa,EACb,WAAW,EACX,YAAY,EACZ,oBAAoB,EACpB,kBAAkB,GACnB,CAAC"}
package/dist/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import useOxySession from "./hooks/useOxySession";
2
2
  import getUserById from "./hooks/getUserById";
3
3
  import SignInButton from "./components/auth/SignInButton";
4
- import AccountSwitcher from "./components/auth/AccountSwitcher";
5
- import OAvatar from "./components/auth/OAvatar";
6
- export { useOxySession, getUserById, SignInButton, AccountSwitcher, OAvatar };
4
+ import { AccountSwitcherModal } from "./components/auth/AccountSwitcherModal";
5
+ import { SessionOwnerButton } from "./components/auth/SessionOwnerButton";
6
+ export { useOxySession, getUserById, SignInButton, AccountSwitcherModal, SessionOwnerButton, };
@@ -0,0 +1,3 @@
1
+ import { type ClassValue } from "clsx";
2
+ export declare const cn: (...inputs: ClassValue[]) => string;
3
+ //# sourceMappingURL=cn.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cn.d.ts","sourceRoot":"","sources":["../../src/utils/cn.ts"],"names":[],"mappings":"AAAA,OAAO,EAAQ,KAAK,UAAU,EAAE,MAAM,MAAM,CAAC;AAG7C,eAAO,MAAM,EAAE,cAAe,UAAU,EAAE,WAEzC,CAAC"}
@@ -0,0 +1,5 @@
1
+ import { clsx } from "clsx";
2
+ import { twMerge } from "tailwind-merge";
3
+ export const cn = (...inputs) => {
4
+ return twMerge(clsx(inputs));
5
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@oxyhq/services",
3
- "version": "0.0.23",
3
+ "version": "0.0.24",
4
4
  "description": "",
5
5
  "homepage": "https://oxy.so/",
6
6
  "main": "./dist/index.js",
@@ -39,11 +39,15 @@
39
39
  "typescript": "^5.4.5"
40
40
  },
41
41
  "dependencies": {
42
+ "@tanstack/react-query": "^5.40.0",
42
43
  "axios": "^1.6.8",
44
+ "clsx": "^2.1.1",
43
45
  "dotenv": "^16.4.5",
46
+ "framer-motion": "^11.2.9",
44
47
  "localforage": "^1.10.0",
45
48
  "react": "^18.3.1",
46
49
  "react-dom": "^18.3.1",
50
+ "tailwind-merge": "^2.3.0",
47
51
  "zod": "^3.23.8",
48
52
  "zustand": "^4.5.2"
49
53
  }