UNPKG

@logux/client

Version:

Logux base components to build web client

181 lines (171 loc) 4.44 kB
import type { LoguxNotFoundError, SyncMapValues } from '@logux/actions' import type { StoreValue } from 'nanostores' import { Component } from 'preact' import type { ComponentChild, ComponentType, Context as PreactContext } from 'preact' import type { Client } from '../client/index.js' import type { AuthStore } from '../create-auth/index.js' import type { Filter, FilterOptions, FilterStore } from '../create-filter/index.js' import type { ChannelDeniedError, ChannelError, ChannelNotFoundError } from '../logux-undo-error/index.js' import type { SyncMapTemplate, SyncMapTemplateLike, SyncMapValue } from '../sync-map-template/index.js' /** * Context to send Logux Client or object space to components deep in the tree. * * ```js * import { ClientContext, ChannelErrors } from '@logux/client/preact' * import { CrossTabClient } from '@logux/client' * * let client = new CrossTabClient(…) * * render( * <ClientContext.Provider value={client}> * <ChannelErrors NotFound={Page404} AccessDenied={Page403}> * <App /> * </ChannelErrors> * </ClientContext.Provider>, * document.body * ) * ``` */ export const ClientContext: PreactContext<Client> /** * Hook to return Logux client, which you set by `<ClientContext.Provider>`. * * ```js * import { useClient } from '@logux/client/preact' * * import { User } from '../stores/user' * * export const NewUserForm = () => { * let client = useClient() * let onAdd = data => { * User.create(client, data) * } * } * ``` */ export function useClient(): Client interface PreactErrorHandlers { AccessDenied?: ComponentType<{ error: ChannelDeniedError }> Error?: ComponentType<{ error: ChannelError }> NotFound?: ComponentType<{ error: ChannelNotFoundError | LoguxNotFoundError }> } /** * Context to pass error handlers from `ChannelErrors`. */ export const ErrorsContext: PreactContext<PreactErrorHandlers> /** * Show error message to user on subscription errors in components * deep in the tree. * * ```js * import { ChannelErrors } from '@logux/client/preact' * * export const App: FC = () => { * return <> * <SideMenu /> * <ChannelErrors * NotFound={NotFoundPage} * AccessDenied={AccessDeniedPage} * Error={ServerErrorPage} * > * <Layout /> * </ChannelErrors> * <> * } * ``` */ export class ChannelErrors extends Component<PreactErrorHandlers> { render(): ComponentChild } /** * Create store by ID, subscribe and get store’s value. * * ```js * import { useSync } from '@logux/client/preact' * * import { User } from '../stores/user' * * export const UserPage: FC = ({ id }) => { * let user = useSync(User, id) * if (user.isLoading) { * return <Loader /> * } else { * return <h1>{user.name}</h1> * } * } * ``` * * @param Template Store template. * @param id Store ID. * @param args Other store arguments. * @returns Store value. */ export function useSync<Value extends SyncMapValues>( Template: SyncMapTemplate<Value> | SyncMapTemplateLike<Value>, id: string ): SyncMapValue<Value> export function useSync<Value extends object, Args extends any[]>( Template: SyncMapTemplate<Value> | SyncMapTemplateLike<Value, Args>, id: string, ...args: Args ): Value /** * The way to {@link createFilter} in React. * * ```js * import { useFilter } from '@logux/client/preact' * * import { User } from '../stores/user' * * export const Users = ({ projectId }) => { * let users = useFilter(User, { projectId }) * return <div> * {users.list.map(user => <User user={user} />)} * {users.isLoading && <Loader />} * </div> * } * ``` * * @param Template Store class. * @param filter Key-value filter for stores. * @param opts Filter options. * @returns Filter store to use with map. */ export function useFilter<Value extends SyncMapValues>( Template: SyncMapTemplate<Value> | SyncMapTemplateLike<Value>, filter?: Filter<Value>, opts?: FilterOptions ): StoreValue<FilterStore<Value>> /** * Hook to return user's current authentication state and ID. * * ```js * import { useAuth } from '@logux/client/preact' * * export const UserPage = () => { * let { isAuthenticated, userId } = useAuth() * if (isAuthenticated) { * return <User id={userId} /> * } else { * return <Loader /> * } * } * ``` */ export function useAuth(): StoreValue<AuthStore>