tinybase
Version:
A reactive data store and sync engine.
1,437 lines (1,414 loc) • 627 kB
TypeScript
/**
* The ui-react module of the TinyBase project provides both hooks and
* components to make it easy to create reactive apps with Store objects.
*
* The hooks in this module provide access to the data and structures exposed by
* other modules in the project. As well as immediate access, they all register
* listeners such that components using those hooks are selectively re-rendered
* when data changes.
*
* The components in this module provide a further abstraction over those hooks
* to ease the composition of user interfaces that use TinyBase.
* @see Building UIs guides
* @see Building UIs With Metrics guide
* @see Building UIs With Indexes guide
* @see Building UIs With Relationships guide
* @see Building UIs With Queries guide
* @see Building UIs With Checkpoints guide
* @see Countries demo
* @see Todo App demos
* @see Drawing demo
* @packageDocumentation
* @module ui-react
* @since v1.0.0
*/
import type {
AllCellIdFromSchema,
CellIdFromSchema,
DefaultedValueFromSchema,
NoInfer,
TableIdFromSchema,
ValueIdFromSchema,
} from '../../_internal/store/with-schemas/index.d.ts';
import type {
BackwardCheckpointsProps,
CellProps,
CheckpointProps,
CheckpointsOrCheckpointsId,
ComponentReturnType,
CurrentCheckpointProps,
ExtraProps,
ForwardCheckpointsProps,
GetId,
IndexProps,
IndexesOrIndexesId,
LinkedRowsProps,
LocalRowsProps,
MetricProps,
MetricsOrMetricsId,
PersisterOrPersisterId,
ProviderProps,
QueriesOrQueriesId,
RelationshipsOrRelationshipsId,
RemoteRowProps,
ResultCellProps,
ResultRowProps,
ResultSortedTableProps,
ResultTableProps,
RowProps,
SliceProps,
SortedTableProps,
StoreOrStoreId,
SynchronizerOrSynchronizerId,
TableProps,
TablesProps,
UndoOrRedoInformation,
ValueProps,
ValuesProps,
} from '../../_internal/ui-react/with-schemas/index.d.ts';
import type {
CheckpointIds,
CheckpointIdsListener,
CheckpointListener,
Checkpoints,
} from '../../checkpoints/with-schemas/index.d.ts';
import type {
Callback,
Id,
IdOrNull,
Ids,
ParameterizedCallback,
} from '../../common/with-schemas/index.d.ts';
import type {
Indexes,
SliceIdsListener,
SliceRowIdsListener,
} from '../../indexes/with-schemas/index.d.ts';
import type {MergeableStore} from '../../mergeable-store/with-schemas/index.d.ts';
import type {
MetricListener,
Metrics,
} from '../../metrics/with-schemas/index.d.ts';
import type {
AnyPersister,
PersistedStore,
Persister,
Persists,
Status,
StatusListener,
} from '../../persisters/with-schemas/index.d.ts';
import type {
Queries,
ResultCell,
ResultCellIdsListener,
ResultCellListener,
ResultRow,
ResultRowCountListener,
ResultRowIdsListener,
ResultRowListener,
ResultSortedRowIdsListener,
ResultTable,
ResultTableCellIdsListener,
ResultTableListener,
} from '../../queries/with-schemas/index.d.ts';
import type {
LinkedRowIdsListener,
LocalRowIdsListener,
Relationships,
RemoteRowIdListener,
} from '../../relationships/with-schemas/index.d.ts';
import type {
Cell,
CellIdsListener,
CellListener,
CellOrUndefined,
HasCellListener,
HasRowListener,
HasTableCellListener,
HasTableListener,
HasTablesListener,
HasValueListener,
HasValuesListener,
MapCell,
MapValue,
OptionalSchemas,
Row,
RowCountListener,
RowIdsListener,
RowListener,
SortedRowIdsListener,
Store,
Table,
TableCellIdsListener,
TableIdsListener,
TableListener,
Tables,
TablesListener,
TransactionListener,
Value,
ValueIdsListener,
ValueListener,
Values,
ValuesListener,
} from '../../store/with-schemas/index.d.ts';
import type {Synchronizer} from '../../synchronizers/with-schemas/index.d.ts';
import type {ReactElement} from 'react';
export type WithSchemas<Schemas extends OptionalSchemas> = {
/**
* The StoreOrStoreId type is used when you need to refer to a Store in a React
* hook or component.
*
* This has schema-based typing. The following is a simplified representation:
*
* ```ts override
* Store | Id;
* ```
*
* In some simple cases you will already have a direct reference to the Store.
*
* This module also includes a Provider component that can be used to wrap
* multiple Store objects into a context that can be used throughout the app. In
* this case you will want to refer to a Store by its Id in that context.
*
* Many hooks and components in this ui-react module take this type as a
* parameter or a prop, allowing you to pass in either the Store or its Id.
* @category Identity
* @since v1.0.0
*/
StoreOrStoreId: StoreOrStoreId<Schemas>;
/**
* The MetricsOrMetricsId type is used when you need to refer to a Metrics
* object in a React hook or component.
*
* This has schema-based typing. The following is a simplified representation:
*
* ```ts override
* Metrics | Id;
* ```
*
* In some simple cases you will already have a direct reference to the Metrics
* object.
*
* This module also includes a Provider component that can be used to wrap
* multiple Metrics objects into a context that can be used throughout the app.
* In this case you will want to refer to a Metrics object by its Id in that
* context.
*
* Many hooks and components in this ui-react module take this type as a
* parameter or a prop, allowing you to pass in either the Metrics object or its
* Id.
* @category Identity
* @since v1.0.0
*/
MetricsOrMetricsId: MetricsOrMetricsId<Schemas>;
/**
* The IndexesOrIndexesId type is used when you need to refer to an Indexes
* object in a React hook or component.
*
* This has schema-based typing. The following is a simplified representation:
*
* ```ts override
* Indexes | Id;
* ```
*
* In some simple cases you will already have a direct reference to the Indexes
* object.
*
* This module also includes a Provider component that can be used to wrap
* multiple Indexes objects into a context that can be used throughout the app.
* In this case you will want to refer to an Indexes object by its Id in that
* context.
*
* Many hooks and components in this ui-react module take this type as a
* parameter or a prop, allowing you to pass in either the Indexes object or its
* Id.
* @category Identity
* @since v1.0.0
*/
IndexesOrIndexesId: IndexesOrIndexesId<Schemas>;
/**
* The RelationshipsOrRelationshipsId type is used when you need to refer to a
* Relationships object in a React hook or component.
*
* This has schema-based typing. The following is a simplified representation:
*
* ```ts override
* Relationships | Id;
* ```
*
* In some simple cases you will already have a direct reference to the
* Relationships object.
*
* This module also includes a Provider component that can be used to wrap
* multiple Relationships objects into a context that can be used throughout the
* app. In this case you will want to refer to a Relationships object by its Id
* in that context.
*
* Many hooks and components in this ui-react module take this type as a
* parameter or a prop, allowing you to pass in either the Relationships object
* or its Id.
* @category Identity
* @since v1.0.0
*/
RelationshipsOrRelationshipsId: RelationshipsOrRelationshipsId<Schemas>;
/**
* The QueriesOrQueriesId type is used when you need to refer to a Queries
* object in a React hook or component.
*
* This has schema-based typing. The following is a simplified representation:
*
* ```ts override
* Queries | Id;
* ```
*
* In some simple cases you will already have a direct reference to the Queries
* object.
*
* This module also includes a Provider component that can be used to wrap
* multiple Queries objects into a context that can be used throughout the app.
* In this case you will want to refer to a Queries object by its Id in that
* context.
*
* Many hooks and components in this ui-react module take this type as a
* parameter or a prop, allowing you to pass in either the Queries object or its
* Id.
* @category Identity
* @since v2.0.0
*/
QueriesOrQueriesId: QueriesOrQueriesId<Schemas>;
/**
* The CheckpointsOrCheckpointsId type is used when you need to refer to a
* Checkpoints object in a React hook or component.
*
* This has schema-based typing. The following is a simplified representation:
*
* ```ts override
* Checkpoints | Id;
* ```
*
* In some simple cases you will already have a direct reference to the
* Checkpoints object.
*
* This module also includes a Provider component that can be used to wrap
* multiple Checkpoints objects into a context that can be used throughout the
* app. In this case you will want to refer to a Checkpoints object by its Id in
* that context.
*
* Many hooks and components in this ui-react module take this type as a
* parameter or a prop, allowing you to pass in either the Checkpoints object or
* its Id.
* @category Identity
* @since v1.0.0
*/
CheckpointsOrCheckpointsId: CheckpointsOrCheckpointsId<Schemas>;
/**
* The PersisterOrPersisterId type is used when you need to refer to a Persister
* object in a React hook or component.
*
* This has schema-based typing. The following is a simplified representation:
*
* ```ts override
* AnyPersister | Id;
* ```
*
* In some simple cases you will already have a direct reference to the
* Persister object.
*
* This module also includes a Provider component that can be used to wrap
* multiple Persister objects into a context that can be used throughout the
* app. In this case you will want to refer to a Persister object by its Id in
* that context.
*
* Many hooks and components in this ui-react module take this type as a
* parameter or a prop, allowing you to pass in either the Persister or its Id.
* @category Identity
* @since v5.3.0
*/
PersisterOrPersisterId: PersisterOrPersisterId<Schemas>;
/**
* The SynchronizerOrSynchronizerId type is used when you need to refer to a
* Synchronizer object in a React hook or component.
*
* This has schema-based typing. The following is a simplified representation:
*
* ```ts override
* Synchronizer | Id;
* ```
*
* In some simple cases you will already have a direct reference to the
* Synchronizer object.
*
* This module also includes a Provider component that can be used to wrap
* multiple Synchronizer objects into a context that can be used throughout the
* app. In this case you will want to refer to a Synchronizer object by its Id
* in that context.
*
* Many hooks and components in this ui-react module take this type as a
* parameter or a prop, allowing you to pass in either the Synchronizer or its
* Id.
* @category Identity
* @since v5.3.0
*/
SynchronizerOrSynchronizerId: SynchronizerOrSynchronizerId<Schemas>;
/**
* The UndoOrRedoInformation type is an array that you can fetch from a
* Checkpoints object to that indicates if and how you can move the state of the
* underlying Store forward or backward.
*
* This type is useful if you are building undo or redo buttons. See the
* useUndoInformation hook and the useRedoInformation hook for more details and
* examples.
* @category Checkpoints
* @since v1.0.0
*/
UndoOrRedoInformation: UndoOrRedoInformation;
/**
* The useCreateStore hook is used to create a Store within a React application
* with convenient memoization.
*
* This has schema-based typing. The following is a simplified representation:
*
* ```ts override
* useCreateStore(
* create: () => Store,
* createDeps?: React.DependencyList,
* ): Store;
* ```
*
* It is possible to create a Store outside of the React app with the regular
* createStore function and pass it in, but you may prefer to create it within
* the app, perhaps inside the top-level component. To prevent a new Store being
* created every time the app renders or re-renders, the useCreateStore hook
* wraps the creation in a memoization.
*
* The useCreateStore hook is a very thin wrapper around the React `useMemo`
* hook, defaulting to an empty array for its dependencies, so that by default,
* the creation only occurs once.
*
* If your `create` function contains other dependencies, the changing of which
* should cause the Store to be recreated, you can provide them in an array in
* the optional second parameter, just as you would for any React hook with
* dependencies.
* @param create A function for performing the creation of the Store, plus any
* additional steps such as adding data or listeners, and returning it.
* @param createDeps An optional array of dependencies for the `create`
* function, which, if any change, result in its rerun. This parameter defaults
* to an empty array.
* @returns A reference to the Store.
* @example
* This example creates an empty Store at the top level of a React application.
* Even though the App component is rendered twice, the Store creation only
* occurs once by default.
*
* ```jsx
* import React from 'react';
* import {createRoot} from 'react-dom/client';
* import {createStore} from 'tinybase';
* import {useCreateStore} from 'tinybase/ui-react';
*
* const App = () => {
* const store = useCreateStore(() => {
* console.log('Store created');
* return createStore().setTables({pets: {fido: {species: 'dog'}}});
* });
* return <span>{store.getCell('pets', 'fido', 'species')}</span>;
* };
*
* const app = document.createElement('div');
* const root = createRoot(app);
* root.render(<App />); // !act
* // -> 'Store created'
*
* root.render(<App />); // !act
* // No second Store creation
*
* console.log(app.innerHTML);
* // -> '<span>dog</span>'
* ```
* @example
* This example creates an empty Store at the top level of a React application.
* The App component is rendered twice, each with a different top-level prop.
* The useCreateStore hook takes the `fidoSpecies` prop as a dependency, and so
* the Store is created again on the second render.
*
* ```jsx
* import React from 'react';
* import {createRoot} from 'react-dom/client';
* import {createStore} from 'tinybase';
* import {useCreateStore} from 'tinybase/ui-react';
*
* const App = ({fidoSpecies}) => {
* const store = useCreateStore(() => {
* console.log(`Store created for fido as ${fidoSpecies}`);
* return createStore().setTables({pets: {fido: {species: fidoSpecies}}});
* }, [fidoSpecies]);
* return <span>{store.getCell('pets', 'fido', 'species')}</span>;
* };
*
* const app = document.createElement('div');
* const root = createRoot(app);
* root.render(<App fidoSpecies="dog" />); // !act
* // -> 'Store created for fido as dog'
*
* console.log(app.innerHTML);
* // -> '<span>dog</span>'
*
* root.render(<App fidoSpecies="cat" />); // !act
* // -> 'Store created for fido as cat'
*
* console.log(app.innerHTML);
* // -> '<span>cat</span>'
* ```
* @category Store hooks
* @since v1.0.0
*/
useCreateStore: (
create: () => Store<Schemas>,
createDeps?: React.DependencyList,
) => Store<Schemas>;
/**
* The useCreateMergeableStore hook.
* @category Store hooks
* @since v1.0.0
*/
useCreateMergeableStore: (
create: () => MergeableStore<Schemas>,
createDeps?: React.DependencyList,
) => MergeableStore<Schemas>;
/**
* The useStoreIds hook is used to retrieve the Ids of all the named Store
* objects present in the current Provider component context.
* @returns A list of the Ids in the context.
* @example
* This example adds two named Store objects to a Provider context and an inner
* component accesses their Ids.
*
* ```jsx
* import React from 'react';
* import {createRoot} from 'react-dom/client';
* import {createStore} from 'tinybase';
* import {Provider, useCreateStore, useStoreIds} from 'tinybase/ui-react';
*
* const App = () => {
* const store1 = useCreateStore(createStore);
* const store2 = useCreateStore(createStore);
* return (
* <Provider storesById={{store1, store2}}>
* <Pane />
* </Provider>
* );
* };
* const Pane = () => <span>{JSON.stringify(useStoreIds())}</span>;
*
* const app = document.createElement('div');
* createRoot(app).render(<App />); // !act
* console.log(app.innerHTML);
* // -> '<span>["store1","store2"]</span>'
* ```
* @category Store hooks
* @since v4.1.0
*/
useStoreIds: () => Ids;
/**
* The useStore hook is used to get a reference to a Store from within a
* Provider component context.
*
* This has schema-based typing. The following is a simplified representation:
*
* ```ts override
* useStore(id?: Id): Store | undefined;
* ```
*
* A Provider component is used to wrap part of an application in a context. It
* can contain a default Store (or a set of Store objects named by Id) that can
* be easily accessed without having to be passed down as props through every
* component.
*
* The useStore hook lets you either get a reference to the default Store (when
* called without a parameter), or one of the Store objects that are named by Id
* (when called with an Id parameter).
* @param id An optional Id for accessing a Store that was named with an Id in
* the Provider.
* @returns A reference to the Store (or `undefined` if not within a Provider
* context, or if the requested Store does not exist).
* @example
* This example creates a Provider context into which a default Store is
* provided. A component within it then uses the useStore hook to get a
* reference to the Store again, without the need to have it passed as a prop.
*
* ```jsx
* import React from 'react';
* import {createRoot} from 'react-dom/client';
* import {createStore} from 'tinybase';
* import {Provider, useStore} from 'tinybase/ui-react';
*
* const App = ({store}) => (
* <Provider store={store}>
* <Pane />
* </Provider>
* );
* const Pane = () => <span>{useStore().getListenerStats().tables}</span>;
*
* const store = createStore();
* const app = document.createElement('div');
* createRoot(app).render(<App store={store} />); // !act
* console.log(app.innerHTML);
* // -> '<span>0</span>'
* ```
* @example
* This example creates a Provider context into which a Store is provided, named
* by Id. A component within it then uses the useStore hook with that Id to get
* a reference to the Store again, without the need to have it passed as a prop.
*
* ```jsx
* import React from 'react';
* import {createRoot} from 'react-dom/client';
* import {createStore} from 'tinybase';
* import {Provider, useStore} from 'tinybase/ui-react';
*
* const App = ({store}) => (
* <Provider storesById={{petStore: store}}>
* <Pane />
* </Provider>
* );
* const Pane = () => (
* <span>{useStore('petStore').getListenerStats().tables}</span>
* );
*
* const store = createStore();
* const app = document.createElement('div');
* createRoot(app).render(<App store={store} />); // !act
* console.log(app.innerHTML);
* // -> '<span>0</span>'
* ```
* @category Store hooks
* @since v1.0.0
*/
useStore: (id?: Id) => Store<Schemas> | undefined;
/**
* The useStores hook is used to get a reference to all the Store objects named
* by Id within a Provider component context.
*
* This has schema-based typing. The following is a simplified representation:
*
* ```ts override
* useStores(): {[storeId: Id]: Store};
* ```
*
* A Provider component is used to wrap part of an application in a context. It
* can contain a default Store (or a set of Store objects named by Id) that can
* be easily accessed without having to be passed down as props through every
* component.
*
* The useStores hook lets you get a reference to the latter as an object.
* @returns An object containing all the Store objects named by Id.
* @example
* This example creates a Provider context into which a Store is provided, named
* by Id. A component within it then uses the useStores hook to get a reference
* to the Store again.
*
* ```jsx
* import React from 'react';
* import {createRoot} from 'react-dom/client';
* import {createStore} from 'tinybase';
* import {Provider, useStores} from 'tinybase/ui-react';
*
* const App = ({store}) => (
* <Provider storesById={{petStore: store}}>
* <Pane />
* </Provider>
* );
* const Pane = () => (
* <span>{useStores()['petStore'].getListenerStats().tables}</span>
* );
*
* const store = createStore();
* const app = document.createElement('div');
* createRoot(app).render(<App store={store} />); // !act
* console.log(app.innerHTML);
* // -> '<span>0</span>'
* ```
* @category Store hooks
* @since v5.4.1
*/
useStores: () => {[storeId: Id]: Store<OptionalSchemas>};
/**
* The useStoreOrStoreById hook is used to get a reference to a Store object
* from within a Provider component context, _or_ have it passed directly to
* this hook.
*
* This has schema-based typing. The following is a simplified representation:
*
* ```ts override
* useStoreOrStoreById(
* storeOrStoreId?: StoreOrStoreId,
* ): Store | undefined;
* ```
*
* This is mostly of use when you are developing a component that needs a Store
* object and which might have been passed in explicitly to the component or is
* to be picked up from the context by Id (a common pattern for Store-based
* components).
*
* This is unlikely to be used often. For most situations, you will want to use
* the useStore hook.
* @param storeOrStoreId Either an Id for accessing a Store object that was
* named with an Id in the Provider, or the Store object itself.
* @returns A reference to the Store object (or `undefined` if not within a
* Provider context, or if the requested Store object does not exist).
* @example
* This example creates a Provider context into which a default Store object is
* provided. A component within it then uses the useStoreOrStoreById hook to get
* a reference to the Store object again, without the need to have it passed as
* a prop. Note however, that unlike the useStore hook example, this component
* would also work if you were to pass the Store object directly into it, making
* it more portable.
*
* ```jsx
* import React from 'react';
* import {createRoot} from 'react-dom/client';
* import {createStore} from 'tinybase';
* import {Provider, useStoreOrStoreById} from 'tinybase/ui-react';
*
* const App = ({store}) => (
* <Provider store={store}>
* <Pane />
* </Provider>
* );
* const Pane = ({store}) => (
* <span>{JSON.stringify(useStoreOrStoreById(store).getTableIds())}</span>
* );
*
* const store = createStore().setCell('pets', 'fido', 'color', 'brown');
* const app = document.createElement('div');
* const root = createRoot(app);
* root.render(<App store={store} />); // !act
* console.log(app.innerHTML);
* // -> '<span>["pets"]</span>'
* ```
* @category Store hooks
* @since v4.1.0
*/
useStoreOrStoreById: (
storeOrStoreId?: StoreOrStoreId<Schemas>,
) => Store<Schemas> | undefined;
/**
* The useProvideStore hook is used to add a Store object by Id to a Provider
* component, but imperatively from a component within it.
*
* This has schema-based typing. The following is a simplified representation:
*
* ```ts override
* useProvideStore(storeId: Id, store: Store): void;
* ```
*
* Normally you will register a Store by Id in a context by using the
* `storesById` prop of the top-level Provider component. This hook, however,
* lets you dynamically add a new Store to the context, from within a descendent
* component. This is useful for applications where the set of Stores is not
* known at the time of the first render of the root Provider.
*
* A Store added to the Provider context in this way will be available to other
* components within the context (using the useStore hook and so on). If you use
* the same Id as an existing Store registration, the new one will take priority
* over one provided by the `storesById` prop.
*
* Note that other components that consume a Store registered like this should
* defend against it being undefined at first. On the first render, the other
* component will likely not yet have completed the registration. In the example
* below, we use the null-safe `useStore('petStore')?` to do this.
* @param storeId The Id of the Store object to be registered with the Provider.
* @param store The Store object to be registered.
* @example
* This example creates a Provider context. A child component registers a Store
* into it which is then consumable by a peer child component.
* ```jsx
* import React from 'react';
* import {createRoot} from 'react-dom/client';
* import {createStore} from 'tinybase';
* import {
* Provider,
* useCreateStore,
* useProvideStore,
* useStore,
* } from 'tinybase/ui-react';
*
* const App = () => (
* <Provider>
* <RegisterStore />
* <ConsumeStore />
* </Provider>
* );
* const RegisterStore = () => {
* const store = useCreateStore(() =>
* createStore().setCell('pets', 'fido', 'color', 'brown'),
* );
* useProvideStore('petStore', store);
* return null;
* };
* const ConsumeStore = () => (
* <span>{JSON.stringify(useStore('petStore')?.getTableIds())}</span>
* );
*
* const app = document.createElement('div');
* const root = createRoot(app);
* root.render(<App />); // !act
* console.log(app.innerHTML);
* // -> '<span>["pets"]</span>'
* ```
* @category Store hooks
* @since v4.4.2
*/
useProvideStore: (storeId: Id, store: Store<Schemas>) => void;
/**
* The useHasTables hook returns a boolean indicating whether any Table objects
* exist in the Store, and registers a listener so that any changes to that
* result will cause a re-render.
*
* This has schema-based typing. The following is a simplified representation:
*
* ```ts override
* useHasTables(storeOrStoreId?: StoreOrStoreId): boolean;
* ```
*
* A Provider component is used to wrap part of an application in a context, and
* it can contain a default Store or a set of Store objects named by Id. The
* useHasTables hook lets you indicate which Store to get data for: omit the
* optional parameter for the default context Store, provide an Id for a named
* context Store, or provide a Store explicitly by reference.
*
* When first rendered, this hook will create a listener so that changes to the
* Tables will cause a re-render. When the component containing this hook is
* unmounted, the listener will be automatically removed.
* @param storeOrStoreId The Store to be accessed: omit for the default context
* Store, provide an Id for a named context Store, or provide an explicit
* reference.
* @returns Whether any Tables exist.
* @example
* This example creates a Store outside the application, which is used in the
* useHasTables hook by reference. A change to the data in the Store re-renders
* the component.
*
* ```jsx
* import React from 'react';
* import {createRoot} from 'react-dom/client';
* import {createStore} from 'tinybase';
* import {useHasTables} from 'tinybase/ui-react';
*
* const store = createStore().setCell('pets', 'fido', 'color', 'brown');
* const App = () => <span>{JSON.stringify(useHasTables(store))}</span>;
*
* const app = document.createElement('div');
* const root = createRoot(app);
* root.render(<App />); // !act
* console.log(app.innerHTML);
* // -> '<span>true</span>'
*
* store.delTable('pets'); // !act
* console.log(app.innerHTML);
* // -> '<span>false</span>'
* ```
* @example
* This example creates a Provider context into which a default Store is
* provided. A component within it then uses the useHasTables hook.
*
* ```jsx
* import React from 'react';
* import {createRoot} from 'react-dom/client';
* import {createStore} from 'tinybase';
* import {Provider, useHasTables} from 'tinybase/ui-react';
*
* const App = ({store}) => (
* <Provider store={store}>
* <Pane />
* </Provider>
* );
* const Pane = () => <span>{JSON.stringify(useHasTables())}</span>;
*
* const store = createStore().setCell('pets', 'fido', 'color', 'brown');
* const app = document.createElement('div');
* createRoot(app).render(<App store={store} />); // !act
* console.log(app.innerHTML);
* // -> '<span>true</span>'
* ```
* @example
* This example creates a Provider context into which a Store is provided, named
* by Id. A component within it then uses the useHasTables hook.
*
* ```jsx
* import React from 'react';
* import {createRoot} from 'react-dom/client';
* import {createStore} from 'tinybase';
* import {Provider, useHasTables} from 'tinybase/ui-react';
*
* const App = ({store}) => (
* <Provider storesById={{petStore: store}}>
* <Pane />
* </Provider>
* );
* const Pane = () => <span>{JSON.stringify(useHasTables('petStore'))}</span>;
*
* const store = createStore().setCell('pets', 'fido', 'color', 'brown');
* const app = document.createElement('div');
* createRoot(app).render(<App store={store} />); // !act
* console.log(app.innerHTML);
* // -> '<span>true</span>'
* ```
* @category Store hooks
* @since v4.4.0
*/
useHasTables: (storeOrStoreId?: StoreOrStoreId<Schemas>) => boolean;
/**
* The useTables hook returns a Tables object containing the tabular data of a
* Store, and registers a listener so that any changes to that result will cause
* a re-render.
*
* This has schema-based typing. The following is a simplified representation:
*
* ```ts override
* useTables(storeOrStoreId?: StoreOrStoreId): Tables;
* ```
*
* A Provider component is used to wrap part of an application in a context, and
* it can contain a default Store or a set of Store objects named by Id. The
* useTables hook lets you indicate which Store to get data for: omit the
* optional parameter for the default context Store, provide an Id for a named
* context Store, or provide a Store explicitly by reference.
*
* When first rendered, this hook will create a listener so that changes to the
* Tables will cause a re-render. When the component containing this hook is
* unmounted, the listener will be automatically removed.
* @param storeOrStoreId The Store to be accessed: omit for the default context
* Store, provide an Id for a named context Store, or provide an explicit
* reference.
* @returns A Tables object containing the tabular data of the Store.
* @example
* This example creates a Store outside the application, which is used in the
* useTables hook by reference. A change to the data in the Store re-renders the
* component.
*
* ```jsx
* import React from 'react';
* import {createRoot} from 'react-dom/client';
* import {createStore} from 'tinybase';
* import {useTables} from 'tinybase/ui-react';
*
* const store = createStore().setCell('pets', 'fido', 'color', 'brown');
* const App = () => <span>{JSON.stringify(useTables(store))}</span>;
*
* const app = document.createElement('div');
* const root = createRoot(app);
* root.render(<App />); // !act
* console.log(app.innerHTML);
* // -> '<span>{"pets":{"fido":{"color":"brown"}}}</span>'
*
* store.setCell('pets', 'fido', 'color', 'walnut'); // !act
* console.log(app.innerHTML);
* // -> '<span>{"pets":{"fido":{"color":"walnut"}}}</span>'
* ```
* @example
* This example creates a Provider context into which a default Store is
* provided. A component within it then uses the useTables hook.
*
* ```jsx
* import React from 'react';
* import {createRoot} from 'react-dom/client';
* import {createStore} from 'tinybase';
* import {Provider, useTables} from 'tinybase/ui-react';
*
* const App = ({store}) => (
* <Provider store={store}>
* <Pane />
* </Provider>
* );
* const Pane = () => <span>{JSON.stringify(useTables())}</span>;
*
* const store = createStore().setCell('pets', 'fido', 'color', 'brown');
* const app = document.createElement('div');
* createRoot(app).render(<App store={store} />); // !act
* console.log(app.innerHTML);
* // -> '<span>{"pets":{"fido":{"color":"brown"}}}</span>'
* ```
* @example
* This example creates a Provider context into which a Store is provided, named
* by Id. A component within it then uses the useTables hook.
*
* ```jsx
* import React from 'react';
* import {createRoot} from 'react-dom/client';
* import {createStore} from 'tinybase';
* import {Provider, useTables} from 'tinybase/ui-react';
*
* const App = ({store}) => (
* <Provider storesById={{petStore: store}}>
* <Pane />
* </Provider>
* );
* const Pane = () => <span>{JSON.stringify(useTables('petStore'))}</span>;
*
* const store = createStore().setCell('pets', 'fido', 'color', 'brown');
* const app = document.createElement('div');
* createRoot(app).render(<App store={store} />); // !act
* console.log(app.innerHTML);
* // -> '<span>{"pets":{"fido":{"color":"brown"}}}</span>'
* ```
* @category Store hooks
* @since v1.0.0
*/
useTables: (storeOrStoreId?: StoreOrStoreId<Schemas>) => Tables<Schemas[0]>;
/**
* The useTableIds hook returns the Ids of every Table in a Store, and registers
* a listener so that any changes to that result will cause a re-render.
*
* This has schema-based typing. The following is a simplified representation:
*
* ```ts override
* useTableIds(storeOrStoreId?: StoreOrStoreId): Ids;
* ```
*
* A Provider component is used to wrap part of an application in a context, and
* it can contain a default Store or a set of Store objects named by Id. The
* useTableIds hook lets you indicate which Store to get data for: omit the
* optional parameter for the default context Store, provide an Id for a named
* context Store, or provide a Store explicitly by reference.
*
* When first rendered, this hook will create a listener so that changes to the
* Table Ids will cause a re-render. When the component containing this hook is
* unmounted, the listener will be automatically removed.
* @param storeOrStoreId The Store to be accessed: omit for the default context
* Store, provide an Id for a named context Store, or provide an explicit
* reference.
* @returns An array of the Ids of every Table in the Store.
* @example
* This example creates a Store outside the application, which is used in the
* useTableIds hook by reference. A change to the data in the Store re-renders
* the component.
*
* ```jsx
* import React from 'react';
* import {createRoot} from 'react-dom/client';
* import {createStore} from 'tinybase';
* import {useTableIds} from 'tinybase/ui-react';
*
* const store = createStore().setCell('pets', 'fido', 'color', 'brown');
* const App = () => <span>{JSON.stringify(useTableIds(store))}</span>;
*
* const app = document.createElement('div');
* createRoot(app).render(<App />); // !act
* console.log(app.innerHTML);
* // -> '<span>["pets"]</span>'
*
* store.setCell('species', 'dog', 'price', 5); // !act
* console.log(app.innerHTML);
* // -> '<span>["pets","species"]</span>'
* ```
* @example
* This example creates a Provider context into which a default Store is
* provided. A component within it then uses the useTableIds hook.
*
* ```jsx
* import React from 'react';
* import {createRoot} from 'react-dom/client';
* import {createStore} from 'tinybase';
* import {Provider, useTableIds} from 'tinybase/ui-react';
*
* const App = ({store}) => (
* <Provider store={store}>
* <Pane />
* </Provider>
* );
* const Pane = () => <span>{JSON.stringify(useTableIds())}</span>;
*
* const store = createStore().setCell('pets', 'fido', 'color', 'brown');
* const app = document.createElement('div');
* createRoot(app).render(<App store={store} />); // !act
* console.log(app.innerHTML);
* // -> '<span>["pets"]</span>'
* ```
* @example
* This example creates a Provider context into which a Store is provided, named
* by Id. A component within it then uses the useTableIds hook.
*
* ```jsx
* import React from 'react';
* import {createRoot} from 'react-dom/client';
* import {createStore} from 'tinybase';
* import {Provider, useTableIds} from 'tinybase/ui-react';
*
* const App = ({store}) => (
* <Provider storesById={{petStore: store}}>
* <Pane />
* </Provider>
* );
* const Pane = () => <span>{JSON.stringify(useTableIds('petStore'))}</span>;
*
* const store = createStore().setCell('pets', 'fido', 'color', 'brown');
* const app = document.createElement('div');
* createRoot(app).render(<App store={store} />); // !act
* console.log(app.innerHTML);
* // -> '<span>["pets"]</span>'
* ```
* @category Store hooks
* @since v1.0.0
*/
useTableIds: (
storeOrStoreId?: StoreOrStoreId<Schemas>,
) => TableIdFromSchema<Schemas[0]>[];
/**
* The useHasTable hook returns a boolean indicating whether a given Table
* exists in the Store, and registers a listener so that any changes to that
* result will cause a re-render.
*
* This has schema-based typing. The following is a simplified representation:
*
* ```ts override
* useHasTable(
* tableId: Id,
* storeOrStoreId?: StoreOrStoreId,
* ): boolean;
* ```
*
* A Provider component is used to wrap part of an application in a context, and
* it can contain a default Store or a set of Store objects named by Id. The
* useHasTable hook lets you indicate which Store to get data for: omit the
* optional parameter for the default context Store, provide an Id for a named
* context Store, or provide a Store explicitly by reference.
*
* When first rendered, this hook will create a listener so that changes to the
* Table will cause a re-render. When the component containing this hook is
* unmounted, the listener will be automatically removed.
* @param tableId The Id of the Table in the Store.
* @param storeOrStoreId The Store to be accessed: omit for the default context
* Store, provide an Id for a named context Store, or provide an explicit
* reference.
* @returns Whether a Table with that Id exists.
* @example
* This example creates a Store outside the application, which is used in the
* useHasTable hook by reference. A change to the data in the Store re-renders
* the component.
*
* ```jsx
* import React from 'react';
* import {createRoot} from 'react-dom/client';
* import {createStore} from 'tinybase';
* import {useHasTable} from 'tinybase/ui-react';
*
* const store = createStore().setCell('pets', 'fido', 'color', 'brown');
* const App = () => (
* <span>{JSON.stringify(useHasTable('pets', store))}</span>
* );
*
* const app = document.createElement('div');
* const root = createRoot(app);
* root.render(<App />); // !act
* console.log(app.innerHTML);
* // -> '<span>true</span>'
*
* store.delTable('pets'); // !act
* console.log(app.innerHTML);
* // -> '<span>false</span>'
* ```
* @example
* This example creates a Provider context into which a default Store is
* provided. A component within it then uses the useHasTable hook.
*
* ```jsx
* import React from 'react';
* import {createRoot} from 'react-dom/client';
* import {createStore} from 'tinybase';
* import {Provider, useHasTable} from 'tinybase/ui-react';
*
* const App = ({store}) => (
* <Provider store={store}>
* <Pane />
* </Provider>
* );
* const Pane = () => <span>{JSON.stringify(useHasTable('pets'))}</span>;
*
* const store = createStore().setCell('pets', 'fido', 'color', 'brown');
* const app = document.createElement('div');
* createRoot(app).render(<App store={store} />); // !act
* console.log(app.innerHTML);
* // -> '<span>true</span>'
* ```
* @example
* This example creates a Provider context into which a Store is provided, named
* by Id. A component within it then uses the useHasTable hook.
*
* ```jsx
* import React from 'react';
* import {createRoot} from 'react-dom/client';
* import {createStore} from 'tinybase';
* import {Provider, useHasTable} from 'tinybase/ui-react';
*
* const App = ({store}) => (
* <Provider storesById={{petStore: store}}>
* <Pane />
* </Provider>
* );
* const Pane = () => (
* <span>{JSON.stringify(useHasTable('pets', 'petStore'))}</span>
* );
*
* const store = createStore().setCell('pets', 'fido', 'color', 'brown');
* const app = document.createElement('div');
* createRoot(app).render(<App store={store} />); // !act
* console.log(app.innerHTML);
* // -> '<span>true</span>'
* ```
* @category Store hooks
* @since v4.4.0
*/
useHasTable: <TableId extends TableIdFromSchema<Schemas[0]>>(
tableId: TableId,
storeOrStoreId?: StoreOrStoreId<Schemas>,
) => boolean;
/**
* The useTable hook returns an object containing the data of a single Table in
* a Store, and registers a listener so that any changes to that result will
* cause a re-render.
*
* This has schema-based typing. The following is a simplified representation:
*
* ```ts override
* useTable(tableId: Id, storeOrStoreId?: StoreOrStoreId): Table;
* ```
*
* A Provider component is used to wrap part of an application in a context, and
* it can contain a default Store or a set of Store objects named by Id. The
* useTable hook lets you indicate which Store to get data for: omit the final
* optional final parameter for the default context Store, provide an Id for a
* named context Store, or provide a Store explicitly by reference.
*
* When first rendered, this hook will create a listener so that changes to the
* Table will cause a re-render. When the component containing this hook is
* unmounted, the listener will be automatically removed.
* @param tableId The Id of the Table in the Store.
* @param storeOrStoreId The Store to be accessed: omit for the default context
* Store, provide an Id for a named context Store, or provide an explicit
* reference.
* @returns An object containing the entire data of the Table.
* @example
* This example creates a Store outside the application, which is used in the
* useTable hook by reference. A change to the data in the Store re-renders the
* component.
*
* ```jsx
* import React from 'react';
* import {createRoot} from 'react-dom/client';
* import {createStore} from 'tinybase';
* import {useTable} from 'tinybase/ui-react';
*
* const store = createStore().setCell('pets', 'fido', 'color', 'brown');
* const App = () => <span>{JSON.stringify(useTable('pets', store))}</span>;
*
* const app = document.createElement('div');
* createRoot(app).render(<App />); // !act
* console.log(app.innerHTML);
* // -> '<span>{"fido":{"color":"brown"}}</span>'
*
* store.setCell('pets', 'fido', 'color', 'walnut'); // !act
* console.log(app.innerHTML);
* // -> '<span>{"fido":{"color":"walnut"}}</span>'
* ```
* @example
* This example creates a Provider context into which a default Store is
* provided. A component within it then uses the useTable hook.
*
* ```jsx
* import React from 'react';
* import {createRoot} from 'react-dom/client';
* import {createStore} from 'tinybase';
* import {Provider, useTable} from 'tinybase/ui-react';
*
* const App = ({store}) => (
* <Provider store={store}>
* <Pane />
* </Provider>
* );
* const Pane = () => <span>{JSON.stringify(useTable('pets'))}</span>;
*
* const store = createStore().setCell('pets', 'fido', 'color', 'brown');
* const app = document.createElement('div');
* createRoot(app).render(<App store={store} />); // !act
* console.log(app.innerHTML);
* // -> '<span>{"fido":{"color":"brown"}}</span>'
* ```
* @example
* This example creates a Provider context into which a Store is provided, named
* by Id. A component within it then uses the useTable hook.
*
* ```jsx
* import React from 'react';
* import {createRoot} from 'react-dom/client';
* import {createStore} from 'tinybase';
* import {Provider, useTable} from 'tinybase/ui-react';
*
* const App = ({store}) => (
* <Provider storesById={{petStore: store}}>
* <Pane />
* </Provider>
* );
* const Pane = () => (
* <span>{JSON.stringify(useTable('pets', 'petStore'))}</span>
* );
*
* const store = createStore().setCell('pets', 'fido', 'color', 'brown');
* const app = document.createElement('div');
* createRoot(app).render(<App store={store} />); // !act
* console.log(app.innerHTML);
* // -> '<span>{"fido":{"color":"brown"}}</span>'
* ```
* @category Store hooks
* @since v1.0.0
*/
useTable: <TableId extends TableIdFromSchema<Schemas[0]>>(
tableId: TableId,
storeOrStoreId?: StoreOrStoreId<Schemas>,
) => Table<Schemas[0], TableId>;
/**
* The useTableCellIds hook returns the Ids of every Cell used across the whole
* Table, and registers a listener so that any changes to that result will cause
* a re-render.
*
* This has schema-based typing. The following is a simplified representation:
*
* ```ts override
* useTableCellIds(
* tableId: Id,
* storeOrStoreId?: StoreOrStoreId,
* ): Ids;
* ```
*
* A Provider component is used to wrap part of an application in a context, and
* it can contain a default Store or a set of Store objects named by Id. The
* useTableCellIds hook lets you indicate which Store to get data for: omit the
* optional final parameter for the default context Store, provide an Id for a
* named context Store, or provide a Store explicitly by reference.
*
* When first rendered, this hook will create a listener so that changes to the
* Table Cell Ids will cause a re-render. When the component containing this
* hook is unmounted, the listener will be automatically removed.
* @param tableId The Id of the Table in the Store.
* @param storeOrStoreId The Store to be accessed: omit for the default context
* Store, provide an Id for a named context Store, or provide an explicit
* reference.
* @returns An array of the Ids of every Cell used across the whole Table.
* @example
* This example creates a Store outside the application, which is used in the
* useTableCellIds hook by reference. A change to the data in the Store
* re-renders the component.
*
* ```jsx
* import React from 'react';
* import {createRoot} from 'react-dom/client';
* import {createStore} from 'tinybase';
* import {useTableCellIds} from 'tinybase/ui-react';
*
* const store = createStore().setCell('pets', 'fido', 'color', 'brown');
* const App = () => (
* <span>{JSON.stringify(useTableCellIds('pets', store))}</span>
* );
*
* const app = document.createElement('div');
* createRoot(app).render(<App />); // !act
* console.log(app.innerHTML);
* // -> '<span>["color"]</span>'
*
* store.setCell('pets', 'felix', 'species', 'cat'); // !act
* console.log(app.innerHTML);
* // -> '<span>["color","species"]</span>'
* ```
* @example
* This example creates a Provider context into which a default Store is
* provided. A component within it then uses the useTableCellIds hook.
*
* ```jsx
* import React from 'react';
* import {createRoot} from 'react-dom/client';
* import {createStore} from 'tinybase';
* import {Provider, useTableCellIds} from 'tinybase/ui-react';
*
* const App = ({store}) => (
* <Provider store={store}>
* <Pane />
* </Provider>
* );
* const Pane = () => <span>{JSON.stringify(useTableCellIds('pets'))}</span>;
*
* const store = createStore().setCell('pets', 'fido', 'color', 'brown');
* const app = document.createElement('div');
* createRoot(app).render(<App store={store} />); // !act
* console.log(app.innerHTML);
* // -> '<span>["color"]</span>'
* ```
* @example
* This example creates a Provider context into which a Store is provided, named
* by Id. A component within it then uses the useTableCellIds hook.
*
* ```jsx
* import React from 'react';
* import {createRoot} from 'react-dom/client';
* import {createStore} from 'tinybase';
* import {Provider, useTableCellIds} from 'tinybase/ui-react';
*
* const App = ({store}) => (
* <Provider storesById={{petStore: store}}>
* <Pane />
* </Provider>
* );
* const Pane = () => (
* <span>{JSON.stringify(useTableCellIds('pets', 'petStore'))}</span>
* );
*
* const store = createStore().setCell('pets', 'fido', 'color', 'brown');
* const app = document.createElement('div');
* createRoot(app).render(<App store={store} />); // !act
* console.log(app.innerHTML);
* // -> '<span>["color"]</span>'
* ```
* @category Store hooks
* @since v3.3.0
*/
useTableCellIds: <TableId extends TableIdFromSchema<Schemas[0]>>(
tableId: TableId,
storeOrStoreId?: StoreOrStoreId<Schemas>,
) => CellIdFromSchema<Schemas[0], TableId>[];
/**
* The useHasTableCell hook returns a boolean indicating whether a given Cell
* exists anywhere in a Table, not just in a specific Row, and registers a
* listener so that any changes to that result will cause a re-render.
*
* This has schema-based typing. The following is a simplified representation:
*
* ```ts override
* useHasTableCell(
* tableId: Id,
* cellId: Id,
* storeOrStoreId?: StoreOrStoreId,
* ): boolean;
* ```
*
* A Provider component is used to wrap part of an application in a context, and
* it can contain a default Store or a set of Store objects named by Id. The
* useHasTableCell hook lets you indicate which Store to get data for: omit the
* optional parameter for the default context Store, provide an Id for a named
* context Store, or provide a Store explicitly by reference.
*
* When first rendered, this hook will create a listener so that changes to the
* Table will cause a re-render. When the component containing this hook is
* unmounted, the listener will be automatically removed.
* @param tableId The Id of the Table in the Store.
* @param cellId The Id of the Cell in the Table.
* @param storeOrStoreId The Store to be accessed: omit for the default context
* Store, provide an Id for a named context Store, or provide an explicit
* reference.
* @returns Whether a Cell with that Id exists anywhere in that Table.
* @example
* This example creates a Store outside the application, which is used in the
* useHasTableCell hook by reference. A change to the data in the Store
* re-renders the component.
*
* ```jsx
* import React from 'react';
* import {createRoot} from 'react-dom/cl