Hooks
Shelf comes with a few utility hooks that will make your usage of shelf easier.
NOTE
Not all hooks are documented. If you find a hook that is missing in the documentation, feel free to add your contribution by explaining what the hook does, using the same formatting as we typically use.
useViewportHeight
The useViewportHeight
hook is a utility hook that provides the current viewport height, excluding the URL bar, in pixels. This is useful for creating full-screen experiences on mobile devices where the URL bar can show and hide dynamically.
The hook returns an object with two properties:
vh
: The current viewport height in pixels.isMd
: A boolean indicating whether the viewport width is at least 768px.
Usage
Here's an example of how to use the useViewportHeight
hook:
import { useViewportHeight } from "./useViewportHeight"; // adjust the path as needed
const MyComponent = () => {
const { vh, isMd } = useViewportHeight();
const height = isMd ? vh - 132 : vh - 167;
return <div style={{ height: `${height}px` }}>{/* Your content here */}</div>;
};
useFetcherWithReset
The useFetcherWithReset
hook is a utility hook that extends the functionality of the useFetcher
hook from Remix. It provides a reset
function that allows you to manually reset the data fetched by the fetcher.
The hook returns an object that includes all properties of the original fetcher, plus a reset
function and a data
property of a specified type.
Usage
Here's an example of how to use the useFetcherWithReset
hook:
import useFetcherWithReset from './useFetcherWithReset'; // adjust the path as needed
const MyComponent = () => {
const fetcher = useFetcherWithReset<MyDataType>();
const handleReset = () => {
fetcher.reset();
};
// Use fetcher to fetch data...
return (
<div>
{/* Display fetched data */}
<button onClick={handleReset}>Reset data</button>
</div>
);
};
useBookingStatus
The useBookingStatus
hook is a utility hook that provides various status flags related to a booking. It's useful for determining the current state of a booking and the presence of certain types of assets within the booking.
The hook returns an object with the following properties:
hasAssets
: A boolean indicating whether the booking has any assets.hasUnavailableAssets
: A boolean indicating whether the booking has any assets that are currently unavailable.isDraft
: A boolean indicating whether the booking is in the draft state.isReserved
: A boolean indicating whether the booking is in the reserved state.isOngoing
: A boolean indicating whether the booking is ongoing.isCompleted
: A boolean indicating whether the booking has been completed.isArchived
: A boolean indicating whether the booking has been archived.isOverdue
: A boolean indicating whether the booking is overdue.isCancelled
: A boolean indicating whether the booking has been cancelled.hasCheckedOutAssets
: A boolean indicating whether any assets in the booking have been checked out.hasAlreadyBookedAssets
: A boolean indicating whether any assets in the booking have been booked previously.hasAssetsInCustody
: A boolean indicating whether any assets in the booking are currently in custody.
Usage
Here's an example of how to use the useBookingStatus
hook:
import useBookingStatus from './useBookingStatus'; // adjust the path as needed
const MyComponent = ({ booking }) => {
const bookingStatus = useBookingStatus(booking);
return (
<div>
{/* Display booking status */}
{bookingStatus.isReserved && <div>The booking is reserved.</div>}
</div>
);
};
useVideoDevices
The useVideoDevices
hook manages video device access and permissions for camera-dependent features like QR scanning. It provides device status, error handling, and permission management.
Returns
devices
: Array of available video input devices (MediaDeviceInfo[]
) ornull
error
: Error object if device access fails ornull
loading
: Boolean indicating if device enumeration is in progressrequestPermissions
: Function to request device accessDevicesPermissionComponent
: React component for rendering permission/error UI states
Usage
const QRScanner = () => {
const { devices, DevicesPermissionComponent } = useVideoDevices();
return (
<div>
{devices ? (
<Scanner videoMediaDevices={devices} />
) : (
<DevicesPermissionComponent />
)}
</div>
);
};
## `useDisabled`
The `useDisabled` hook is used to determine if a button should be disabled during navigation. By default, it operates with the navigation state, but it can optionally accept a fetcher to use as the state.
**Usage:**
```typescript
/** Without fetcher, using default navigation */
const isDisabled = useDisabled();
/** Without fetcher */
const isDisabled = useDisabled(fetcher);
Parameters:
fetcher
(optional): An object that contains the state to be used. If not provided, the navigation state will be used.
Returns:
boolean
: Returnstrue
if the form is processing and the button should be disabled, otherwisefalse
.
Example:
import { useDisabled } from './path/to/hooks';
const MyComponent = () => {
const fetcher = useFetcher();
const isDisabled = useDisabled(fetcher);
return (
<button disabled={isDisabled}>
Submit
</button>
);
};
Dependencies:
useNavigation
: A hook that provides the current navigation state.isFormProcessing
: A function that checks if the form is currently processing based on the state.
useUserRoleHelper
The useUserRoleHelper
hook is helps you to always know the roles of the current user and also returns some helper boolean values to make it easier to check for specific roles.
The useUserRoleHelper function returns an object(roles) and helper boolean attributes:
roles
: enum that provides role of the current userisAdministrator
: A boolean value indicating whether the user has the 'ADMIN' role.isOwner
: A boolean value indicating whether the user has the OWNER role.isAdministratorOrOwner
: A boolean value indicating whether the user has either the 'ADMIN' or 'OWNER'role.isSelfService
: A boolean value indicating whether the user has the 'SELF_SERVICE' role.isBase
: A boolean value indicating whether the user has the 'BASE' role.isBaseOrSelfService
: A boolean value indicating whether the user has either the BASE or 'SELF_SERVICE' role.
Usage: The "New Asset" button is rendered only if isAdministratorOrOwner is true.
import React from 'react';
import { useUserRoleHelper } from '~/hooks/user-user-role-helper';
export default function AssetIndexPage() {
const { isAdministratorOrOwner } = useUserRoleHelper();
return (
<div>
<header>
{isAdministratorOrOwner && (
<button>
New Asset
</button>
)}
</header>
</div>
);
}
Dependencies:
useRouteLoaderData
: hook from@remix-run/react
that returns the loader data for a given route by ID.
useUserData
The useUserData
hook is used to access the current user's data from within any component in the application, particularly those nested under the _layout
route.
Overview
This hook simplifies the process of retrieving user data that is loaded in the _layout
route. It uses the useRouteLoaderData
hook from Remix to access the loader data, making it easy to get user information without prop drilling.
Returns
user
: The user data object from the_layout
route loader. This typically includes properties likeemail
and possibly other user-related information.
Usage:
Here's an example of how to use the useUserData
hook in a component:
import React from 'react';
import { useUserData } from '~/hooks/use-user-data';
export const RequestDeleteUser = () => {
const user = useUserData();
return (
<form>
{/* Other form elements */}
<input type="hidden" name="email" value={user?.email} />
{/* Rest of the component */}
</form>
);
}
In this example, the useUserData
hook is used to retrieve the current user's email address, which is then used in a hidden form field.
Dependencies
useRouteLoaderData
: A hook from@remix-run/react
that returns the loader data for a given route by ID.loader
type from~/routes/_layout+/_layout
: Used to type the loader data.
useTableIsOverflowing
Overview
The useTableIsOverflowing
hook is used to handle the table's right-side scroll fade effect. It checks whether the table is overflowing and determines if the fade effect should be applied.
Returns:
containerRef
: A reference to the table container element.isOverflowing
: A boolean indicating whether the table is overflowing and has not reached the end.
Usage:
import React from "react";
import { useTableIsOverflowing } from "~/hooks/use-table-overflow";
import { tw } from "~/utils/tw";
export function Table({
children,
className,
}: {
children: React.ReactNode;
className?: string;
}) {
const { containerRef, isOverflowing } = useTableIsOverflowing();
return (
<div className={`relative ${isOverflowing ? "overflowing" : ""}`}>
<div className="fixed-gradient"></div>
<div
ref={containerRef}
className="scrollbar-top scrollbar-always-visible"
>
<table className={tw("w-full table-auto border-collapse", className)}>
{children}
</table>
</div>
</div>
);
}
In this example hook detects if the table content exceeds the container's width. When it does, isOverflowing becomes true, adding the overflowing class to the outer div. This class can trigger visual indicators like gradients to show users there's more content to scroll through.