feat: basic mobile support (#64)
* feat: add mobile navigation with responsive layout and theme controls * feat: prevent workspace owners from removing themselves and update workspace dropdown styling * feat: add useClickOutside hook and event listener utilities for improved UI interactions * chore: improve mobile UI styling * refactor: improve UI layout and buttons in boards/members views feat: adjust /members layout * fix: standardize layout containers and improve mobile navigation styling * feat: update card view layout * feat: add responsive layout to board view * feat: readjust boards page layout * feat: enhance table view on mobile for members page * feat: extend mobile support with sliding side panels * fix: prevent two panels from being open at the same time * feat: close panels when clicking outside * fix: adjust font-sizing for import source --------- Co-authored-by: Henry <henry_ball@hotmail.co.uk>
This commit is contained in:
59
apps/web/src/hooks/useClickOutside.ts
Normal file
59
apps/web/src/hooks/useClickOutside.ts
Normal file
@@ -0,0 +1,59 @@
|
||||
import type { RefObject } from "react";
|
||||
|
||||
import { useEventListener } from "./useEventListener";
|
||||
|
||||
/** Supported event types. */
|
||||
type EventType =
|
||||
| "mousedown"
|
||||
| "mouseup"
|
||||
| "touchstart"
|
||||
| "touchend"
|
||||
| "focusin"
|
||||
| "focusout";
|
||||
|
||||
/**
|
||||
* Custom hook that handles clicks outside a specified element.
|
||||
* @template T - The type of the element's reference.
|
||||
* @param {RefObject<T> | RefObject<T>[]} ref - The React ref object(s) representing the element(s) to watch for outside clicks.
|
||||
* @param {(event: MouseEvent | TouchEvent | FocusEvent) => void} handler - The callback function to be executed when a click outside the element occurs.
|
||||
* @param {EventType} [eventType] - The mouse event type to listen for (optional, default is 'mousedown').
|
||||
* @param {?AddEventListenerOptions} [eventListenerOptions] - The options object to be passed to the `addEventListener` method (optional).
|
||||
* @returns {void}
|
||||
* @example
|
||||
* ```tsx
|
||||
* const containerRef = useRef(null);
|
||||
* useClickOutside([containerRef], () => {
|
||||
* // Handle clicks outside the container.
|
||||
* });
|
||||
* ```
|
||||
*/
|
||||
export function useClickOutside<T extends HTMLElement = HTMLElement>(
|
||||
ref: RefObject<T> | RefObject<T>[],
|
||||
handler: (event: MouseEvent | TouchEvent | FocusEvent) => void,
|
||||
eventType: EventType = "mousedown",
|
||||
eventListenerOptions: AddEventListenerOptions = {},
|
||||
): void {
|
||||
useEventListener(
|
||||
eventType,
|
||||
(event) => {
|
||||
const target = event.target as Node;
|
||||
|
||||
// Do nothing if the target is not connected element with document
|
||||
if (!target.isConnected) {
|
||||
return;
|
||||
}
|
||||
|
||||
const isOutside = Array.isArray(ref)
|
||||
? ref
|
||||
.filter((r) => Boolean(r.current))
|
||||
.every((r) => r.current && !r.current.contains(target))
|
||||
: ref.current && !ref.current.contains(target);
|
||||
|
||||
if (isOutside) {
|
||||
handler(event);
|
||||
}
|
||||
},
|
||||
undefined,
|
||||
eventListenerOptions,
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user