/**
 * The ui-react-inspector module of the TinyBase project provides a component to
 * help debug the state of your TinyBase stores and other objects.
 *
 * The component in this module uses the react-dom module and so is not
 * appropriate for environments like React Native.
 * @see <Inspector /> demo
 * @packageDocumentation
 * @module ui-react-inspector
 * @since v5.0.0
 */
import type {ComponentType} from 'react';
import type {
  CellIdFromSchema,
  TableIdFromSchema,
} from '../../_internal/store/with-schemas/index.d.ts';
import type {
  CellProps,
  CellPropsForTableIdAndCellId,
  ComponentReturnType,
  ExtraProps,
  IndexesOrIndexesId,
  QueriesOrQueriesId,
  RelationshipsOrRelationshipsId,
  ResultCellProps,
  StoreOrStoreId,
  ValueProps,
} from '../../_internal/ui-react/with-schemas/index.d.ts';
import type {Id, Ids} from '../../common/with-schemas/index.d.ts';
import type {NoSchemas} from '../../store/index.d.ts';
import type {OptionalSchemas} from '../../store/with-schemas/index.d.ts';

/**
 * The CustomCell object is used to configure custom cell rendering in an HTML
 * table.
 * @category Configuration
 * @since v4.1.0
 */
export type CustomCell<
  Schemas extends OptionalSchemas,
  TableId extends TableIdFromSchema<Schemas[0]>,
  CellId extends CellIdFromSchema<Schemas[0], TableId>,
> = {
  /**
   * An optional string that will be used as the label at the top of the table
   * column for this Cell.
   * @category Prop
   * @since v4.1.0
   */
  label?: string;
  /**
   * An optional custom component for rendering each Cell in the Table (to
   * override the default CellView component).
   * @category Prop
   * @since v4.1.0
   */
  component?: ComponentType<
    CellPropsForTableIdAndCellId<Schemas, TableId, CellId>
  >;
  /**
   * An optional function for generating extra props for each custom Cell
   * component based on Row and Cell Id.
   * @category Prop
   * @since v4.1.0
   */
  getComponentProps?: (rowId: Id, cellId: CellId) => ExtraProps;
};

/**
 * The CustomResultCell object is used to configure custom cell rendering for
 * query results in an HTML table.
 * @category Configuration
 * @since v4.1.0
 */
export type CustomResultCell<Schemas extends OptionalSchemas> = {
  /**
   * An optional string that will be used as the label at the top of the table
   * column for this Cell.
   * @category Prop
   * @since v4.1.0
   */
  label?: string;
  /**
   * An optional custom component for rendering each Cell in the ResultTable (to
   * override the default ResultCellView component).
   * @category Prop
   * @since v4.1.0
   */
  component?: ComponentType<ResultCellProps<Schemas>>;
  /**
   * An optional function for generating extra props for each custom Cell
   * component based on Row and Cell Id.
   * @category Prop
   * @since v4.1.0
   */
  getComponentProps?: (rowId: Id, cellId: Id) => ExtraProps;
};

/**
 * HtmlTableProps props are used for components that will render in an HTML
 * table, such as the TableInHtmlTable component or SortedTableInHtmlTable
 * component.
 * @category Props
 * @since v4.1.0
 */
export type HtmlTableProps = {
  /**
   * A string className to use on the root of the resulting element.
   * @category Prop
   * @since v4.1.0
   */
  readonly className?: string;
  /**
   * Whether a header row should be rendered at the top of the table, defaulting
   * to `true`.
   * @category Prop
   * @since v4.1.0
   */
  readonly headerRow?: boolean;
  /**
   * Whether an Id column should be rendered on the left of the table,
   * defaulting to `true`.
   * @category Prop
   * @since v4.1.0
   */
  readonly idColumn?: boolean;
};

/**
 * TableInHtmlTableProps props are used for components that will render a Table
 * in an HTML table, such as the TableInHtmlTable component.
 * @category Props
 * @since v4.1.0
 */
export type TableInHtmlTableProps<
  Schemas extends OptionalSchemas,
  TableIds extends TableIdFromSchema<Schemas[0]> = TableIdFromSchema<
    Schemas[0]
  >,
> = TableIds extends infer TableId
  ? TableId extends TableIdFromSchema<Schemas[0]>
    ? {
        /**
   * The Id of the Table in the Store to be rendered.
   * @category Prop
   * @since v4.1.0
   */
        readonly tableId: TableId;
        /**
   * The Store to be accessed: omit for the default context Store, provide an Id
   * for a named context Store, or provide an explicit reference.
   * @category Prop
   * @since v4.1.0
   */
        readonly store?: StoreOrStoreId<Schemas>;
        /**
   * Whether the Cells should be editable. This affects the default CellView
   * component (to use the EditableCellView component instead) but of course
   * will not affect custom Cell components if you have set them.
   * @category Prop
   * @since v4.1.0
   */
        readonly editable?: boolean;
        /**
   * An optional list of Cell Ids to use for rendering a prescribed set of the
   * Table's Cells in a given order. This can also be an object with the desired
   * Cell Ids as keys, and with a value that can either be a string label to
   * show in the column header, or a CustomCell object to further configure the
   * column.
   * @category Prop
   * @since v4.1.0
   */
        readonly customCells?:
          | CellIdFromSchema<Schemas[0], TableId>[]
          | {
              [CellId in CellIdFromSchema<Schemas[0], TableId>]?:
                | string
                | CustomCell<Schemas, TableId, CellId>;
            };
      }
    : never
  : never;

/**
 * SortedTableInHtmlTableProps props are used for components that will render a
 * sorted Table in an HTML table, such as the SortedTableInHtmlTable component.
 * @category Props
 * @since v4.1.0
 */
export type SortedTableInHtmlTableProps<
  Schemas extends OptionalSchemas,
  TableIds extends TableIdFromSchema<Schemas[0]> = TableIdFromSchema<
    Schemas[0]
  >,
> = TableIds extends infer TableId
  ? TableId extends TableIdFromSchema<Schemas[0]>
    ? {
        /**
   * The Id of the Table in the Store to be rendered.
   * @category Prop
   * @since v4.1.0
   */
        readonly tableId: TableId;
        /**
   * The Id of the Cell whose values are used for the sorting. If omitted, the
   * view will sort the Row Id itself.
   * @category Prop
   * @since v4.1.0
   */
        readonly cellId?: CellIdFromSchema<Schemas[0], TableId>;
        /**
   * Whether the sorting should be in descending order.
   * @category Prop
   * @since v4.1.0
   */
        readonly descending?: boolean;
        /**
   * The number of Row Ids to skip for pagination purposes.
   * @category Prop
   * @since v4.1.0
   */
        readonly offset?: number;
        /**
   * The maximum number of Row Ids to return.
   * @category Prop
   * @since v4.1.0
   */
        readonly limit?: number;
        /**
   * The Store to be accessed: omit for the default context Store, provide an Id
   * for a named context Store, or provide an explicit reference.
   * @category Prop
   * @since v4.1.0
   */
        readonly store?: StoreOrStoreId<Schemas>;
        /**
   * Whether the Cells should be editable. This affects the default CellView
   * component (to use the EditableCellView component instead) but of course
   * will not affect custom Cell components if you have set them.
   * @category Prop
   * @since v4.1.0
   */
        readonly editable?: boolean;
        /**
   * An optional list of Cell Ids to use for rendering a prescribed set of the
   * Table's Cells in a given order. This can also be an object with the desired
   * Cell Ids as keys, and with a value that can either be a string label to
   * show in the column header, or a CustomCell object to further configure the
   * column.
   * @category Prop
   * @since v4.1.0
   */
        readonly customCells?:
          | CellIdFromSchema<Schemas[0], TableId>[]
          | {
              [CellId in CellIdFromSchema<Schemas[0], TableId>]?:
                | string
                | CustomCell<Schemas, TableId, CellId>;
            };
        /**
   * Whether the table should be interactive such that clicking a header changes
   * the sorting and/or direction.
   * @category Prop
   * @since v4.1.0
   */
        readonly sortOnClick?: boolean;
        /**
   * Either `true` to show the default SortedTablePaginator for the Table, or
   * provide your own paginator component that takes SortedTablePaginatorProps.
   * @category Prop
   * @since v4.1.0
   */
        readonly paginator?: boolean | ComponentType<SortedTablePaginatorProps>;
        /**
   * A function that is called whenever the sorting or pagination of the Table
   * is changed by the user, invoked with the sorted Cell Id, whether descending
   * or not, and the offset of the pagination.
   * @category Prop
   * @since v4.1.0
   */
        readonly onChange?: (
          sortAndOffset: [
            cellId: CellIdFromSchema<Schemas[0], TableId> | undefined,
            descending: boolean,
            offset: number,
          ],
        ) => void;
      }
    : never
  : never;

/**
 * ValuesInHtmlTableProps props are used for components that will render Values
 * in an HTML table, such as the ValuesInHtmlTable component.
 * @category Props
 * @since v4.1.0
 */
export type ValuesInHtmlTableProps<Schemas extends OptionalSchemas> = {
  /**
   * The Store to be accessed: omit for the default context Store, provide an Id
   * for a named context Store, or provide an explicit reference.
   * @category Prop
   * @since v4.1.0
   */
  readonly store?: StoreOrStoreId<Schemas>;
  /**
   * Whether the Values should be editable. This affects the default ValueView
   * component (to use the EditableValueView component instead) but of course
   * will not affect a custom valueComponent if you have set one.
   * @category Prop
   * @since v4.1.0
   */
  readonly editable?: boolean;
  /**
   * A custom component for rendering each Value in the Store (to override the
   * default ValueView component).
   * @category Prop
   * @since v4.1.0
   */
  readonly valueComponent?: ComponentType<ValueProps<Schemas>>;
  /**
   * A function for generating extra props for each custom Value component based
   * on its Id.
   * @category Prop
   * @since v4.1.0
   */
  readonly getValueComponentProps?: (valueId: Id) => ExtraProps;
};

/**
 * SliceInHtmlTableProps props are used for components that will render an Index
 * Slice in an HTML table, such as the SliceInHtmlTable component.
 * @category Props
 * @since v4.1.0
 */
export type SliceInHtmlTableProps<Schemas extends OptionalSchemas> = {
  /**
   * The Id of the Index in the Indexes object.
   * @category Prop
   * @since v4.1.0
   */
  readonly indexId: Id;
  /**
   * The Id of the Slice in the Index to be rendered.
   * @category Prop
   * @since v4.1.0
   */
  readonly sliceId: Id;
  /**
   * The Indexes object to be accessed: omit for the default context Indexes
   * object, provide an Id for a named context Indexes object, or provide an
   * explicit reference.
   * @category Prop
   * @since v4.1.0
   */
  readonly indexes?: IndexesOrIndexesId<Schemas>;
  /**
   * Whether the Cells should be editable. This affects the default CellView
   * component (to use the EditableCellView component instead) but of course
   * will not affect custom Cell components if you have set them.
   * @category Prop
   * @since v4.1.0
   */
  readonly editable?: boolean;
  /**
   * An optional list of Cell Ids to use for rendering a prescribed set of the
   * Slice's Cells in a given order. This can also be an object with the desired
   * Cell Ids as keys, and with a value that can either be a string label to
   * show in the column header, or a CustomCell object to further configure the
   * column.
   * @category Prop
   * @since v4.1.0
   */
  readonly customCells?:
    | Ids
    | {[cellId: Id]: string | CustomCell<NoSchemas, Id, Id>};
};

/**
 * RelationshipInHtmlTableProps props are used for components that will render
 * the contents of the two Tables linked by a Relationship as an HTML table,
 * such as the RelationshipInHtmlTable component.
 *
 * Note the use of dotted 'tableId.cellId' string pairs when specifying custom
 * rendering for the cells in this table, since Cells from both the
 * relationship's 'local' and 'remote' Table objects can be rendered and need to
 * be distinguished.
 * @category Props
 * @since v4.1.0
 */
export type RelationshipInHtmlTableProps<Schemas extends OptionalSchemas> = {
  /**
   * The Id of the relationship in the Relationships object for which the
   * relationship Table Rows will be rendered.
   * @category Prop
   * @since v4.1.0
   */
  readonly relationshipId: Id;
  /**
   * The Relationships object to be accessed: omit for the default context
   * Relationships object, provide an Id for a named context Relationships
   * object, or provide an explicit reference.
   * @category Prop
   * @since v4.1.0
   */
  readonly relationships?: RelationshipsOrRelationshipsId<Schemas>;
  /**
   * Whether the Cells should be editable. This affects the default CellView
   * component (to use the EditableCellView component instead) but of course
   * will not affect custom Cell components if you have set them.
   * @category Prop
   * @since v4.1.0
   */
  readonly editable?: boolean;
  /**
   * An optional list of dotted 'tableId.cellId' string pairs to use for
   * rendering a prescribed set of the relationship Tables' Cells in a given
   * order. This can also be an object with the desired 'tableId.cellId' string
   * pairs as keys, and with a value that can either be a string label to show
   * in the column header, or a CustomCell object to further configure the
   * column.
   * @category Prop
   * @since v4.1.0
   */
  readonly customCells?:
    | Ids
    | {[cellId: Id]: string | CustomCell<NoSchemas, Id, Id>};
};

/**
 * ResultTableInHtmlTableProps props are used for components that will render a
 * ResultTable in an HTML table, such as the ResultTableInHtmlTable component.
 * @category Props
 * @since v4.1.0
 */
export type ResultTableInHtmlTableProps<Schemas extends OptionalSchemas> = {
  /**
   * The Id of the query in the Queries object for which the ResultTable will be
   * rendered.
   * @category Prop
   * @since v4.1.0
   */
  readonly queryId: Id;
  /**
   * The Queries object to be accessed: omit for the default context Queries
   * object, provide an Id for a named context Queries object, or provide an
   * explicit reference.
   * @category Prop
   * @since v4.1.0
   */
  readonly queries?: QueriesOrQueriesId<Schemas>;
  /**
   * An optional list of Cell Ids to use for rendering a prescribed set of the
   * ResultTable's Cells in a given order. This can also be an object with the
   * desired Cell Ids as keys, and with a value that can either be a string
   * label to show in the column header, or a ResultCustomCell object to further
   * configure the column.
   * @category Prop
   * @since v4.1.0
   */
  readonly customCells?:
    | Ids
    | {[cellId: Id]: string | CustomResultCell<Schemas>};
};

/**
 * ResultSortedTableInHtmlTableProps props are used for components that will
 * render a sorted Table in an HTML table, such as the SortedTableInHtmlTable
 * component.
 * @category Props
 * @since v4.1.0
 */
export type ResultSortedTableInHtmlTableProps<Schemas extends OptionalSchemas> =
  {
    /**
   * The Id of the query in the Queries object for which the ResultTable will be
   * rendered.
   * @category Prop
   * @since v4.1.0
   */
    readonly queryId: Id;
    /**
   * The Id of the Cell whose values are used for the sorting. If omitted, the
   * view will sort the Row Id itself.
   * @category Prop
   * @since v4.1.0
   */
    readonly cellId?: Id;
    /**
   * Whether the sorting should be in descending order.
   * @category Prop
   * @since v4.1.0
   */
    readonly descending?: boolean;
    /**
   * The number of Row Ids to skip for pagination purposes.
   * @category Prop
   * @since v4.1.0
   */
    readonly offset?: number;
    /**
   * The maximum number of Row Ids to return.
   * @category Prop
   * @since v4.1.0
   */
    readonly limit?: number;
    /**
   * The Queries object to be accessed: omit for the default context Queries
   * object, provide an Id for a named context Queries object, or provide an
   * explicit reference.
   * @category Prop
   * @since v4.1.0
   */
    readonly queries?: QueriesOrQueriesId<Schemas>;
    /**
   * An optional list of Cell Ids to use for rendering a prescribed set of the
   * ResultTable's Cells in a given order. This can also be an object with the
   * desired Cell Ids as keys, and with a value that can either be a string
   * label to show in the column header, or a ResultCustomCell object to further
   * configure the column.
   * @category Prop
   * @since v4.1.0
   */
    readonly customCells?:
      | Ids
      | {[cellId: Id]: string | CustomResultCell<Schemas>};
    /**
   * Whether the table should be interactive such that clicking a header changes
   * the sorting and/or direction.
   * @category Prop
   * @since v4.1.0
   */
    readonly sortOnClick?: boolean;
    /**
   * Either `true` to show the default SortedTablePaginator for the ResultTable,
   * or provide your own paginator component that takes
   * SortedTablePaginatorProps.
   * @category Prop
   * @since v4.1.0
   */
    readonly paginator?: boolean | ComponentType<SortedTablePaginatorProps>;
    /**
   * A function that is called whenever the sorting or pagination of the
   * ResultTable is changed by the user, invoked with the sorted Cell Id,
   * whether descending or not, and the offset of the pagination.
   * @category Prop
   * @since v4.1.0
   */
    readonly onChange?: (
      sortAndOffset: [
        cellId: Id | undefined,
        descending: boolean,
        offset: number,
      ],
    ) => void;
  };

/**
 * SortedTablePaginatorProps props are used for components that will be used as
 * a table paginator, such as the SortedTablePaginator component.
 * @category Props
 * @since v4.1.0
 */
export type SortedTablePaginatorProps = {
  /**
   * An event that will fire when the offset is updated, called with the new
   * offset.
   * @category Prop
   * @since v4.1.0
   */
  readonly onChange: (offset: number) => void;
  /**
   * The number of Row Ids to skip for pagination.
   * @category Prop
   * @since v4.1.0
   */
  readonly offset?: number;
  /**
   * The maximum number of Row Ids being returned.
   * @category Prop
   * @since v4.1.0
   */
  readonly limit?: number;
  /**
   * The total number of Row Ids in the paginated table.
   * @category Prop
   * @since v4.1.0
   */
  readonly total: number;
  /**
   * A noun to use in the pagination label for a single row, defaulting to
   * 'row'.
   * @category Prop
   * @since v4.1.0
   */
  readonly singular?: string;
  /**
   * A noun to use in the pagination label for multiple rows, defaulting to the
   * value of the singular noun suffixed with the letter 's'.
   * @category Prop
   * @since v4.1.0
   */
  readonly plural?: string;
};

/**
 * InspectorProps props are used to configure the Inspector component.
 * @category Props
 * @since v5.0.0
 */
export type InspectorProps = {
  /**
   * An optional string to indicate where you want the inspector to first
   * appear.
   * @category Prop
   * @since v5.0.0
   */
  readonly position?: 'top' | 'right' | 'bottom' | 'left' | 'full';
  /**
   * An optional boolean to indicate whether the inspector should start in the
   * opened state.
   * @category Prop
   * @since v5.0.0
   */
  readonly open?: boolean;
};

export type WithSchemas<Schemas extends OptionalSchemas> = {
  /**
 * The TableInHtmlTable component renders the contents of a single Table in a
 * Store as an HTML <table> element, and registers a listener so that any
 * changes to that result will cause a re-render.
 *
 * See the <TableInHtmlTable /> demo for this component in action.
 *
 * The component's props identify which Table to render based on Table Id, and
 * Store (which is either the default context Store, a named context Store, or
 * by explicit reference).
 *
 * This component renders a Table by iterating over its Row objects. By default
 * the Cells are in turn rendered with the CellView component, but you can
 * override this behavior by providing a `component` for each Cell in the
 * `customCells` prop. You can pass additional props to that custom component
 * with the `getComponentProps` callback. See the CustomCell type for more
 * details.
 *
 * This component uses the useRowIds hook under the covers, which means that any
 * changes to the structure of the Table will cause a re-render.
 *
 * You can use the `headerRow` and `idColumn` props to control whether the Ids
 * appear in a <th> element at the top of the table, and the start of each row.
 * @param props The props for this component.
 * @returns A rendering of the Table in a <table> element.
 * @example
 * This example creates a Provider context into which a default Store is
 * provided. The TableInHtmlTable component within it then renders the Table in
 * a <table> element with a CSS class.
 *
 * ```jsx
 * import React from 'react';
 * import {createRoot} from 'react-dom/client';
 * import {createStore} from 'tinybase';
 * import {Provider} from 'tinybase/ui-react';
 * import {TableInHtmlTable} from 'tinybase/ui-react-dom';
 *
 * const App = ({store}) => (
 *   <Provider store={store}>
 *     <Pane />
 *   </Provider>
 * );
 * const Pane = () => <TableInHtmlTable tableId="pets" className="table" />;
 *
 * const store = createStore().setTable('pets', {
 *   fido: {species: 'dog'},
 *   felix: {species: 'cat'},
 * });
 * const app = document.createElement('div');
 * createRoot(app).render(<App store={store} />); // !act
 * console.log(app.innerHTML);
 * // ->
 * `
 * <table class="table">
 *   <thead>
 *     <tr>
 *       <th>Id</th>
 *       <th>species</th>
 *     </tr>
 *   </thead>
 *   <tbody>
 *     <tr>
 *       <th>fido</th>
 *       <td>dog</td>
 *     </tr>
 *     <tr>
 *       <th>felix</th>
 *       <td>cat</td>
 *     </tr>
 *   </tbody>
 * </table>
 * `;
 * ```
 * @example
 * This example creates a Provider context into which a default Store is
 * provided. The TableInHtmlTable component within it then renders the Table
 * with a custom component and a custom props callback for the `species` Cell.
 * The header row at the top of the table and the Id column at the start of each
 * row is removed.
 *
 * ```jsx
 * import React from 'react';
 * import {createRoot} from 'react-dom/client';
 * import {createStore} from 'tinybase';
 * import {CellView, Provider} from 'tinybase/ui-react';
 * import {TableInHtmlTable} from 'tinybase/ui-react-dom';
 *
 * const App = ({store}) => (
 *   <Provider store={store}>
 *     <Pane />
 *   </Provider>
 * );
 * const Pane = () => (
 *   <TableInHtmlTable
 *     tableId="pets"
 *     customCells={customCells}
 *     headerRow={false}
 *     idColumn={false}
 *   />
 * );
 *
 * const FormattedCellView = ({tableId, rowId, cellId, bold}) => (
 *   <>
 *     {bold ? <b>{rowId}</b> : rowId}:
 *     <CellView tableId={tableId} rowId={rowId} cellId={cellId} />
 *   </>
 * );
 * const customCells = {
 *   species: {
 *     component: FormattedCellView,
 *     getComponentProps: (rowId) => ({bold: rowId == 'fido'}),
 *   },
 * };
 *
 * const store = createStore().setTable('pets', {
 *   fido: {species: 'dog'},
 *   felix: {species: 'cat'},
 * });
 * const app = document.createElement('div');
 * createRoot(app).render(<App store={store} />); // !act
 * console.log(app.innerHTML);
 * // ->
 * `
 * <table>
 *   <tbody>
 *     <tr>
 *       <td><b>fido</b>:dog</td>
 *     </tr>
 *     <tr>
 *       <td>felix:cat</td>
 *     </tr>
 *   </tbody>
 * </table>
 * `;
 * ```
 * @category Store components
 * @since v4.1.0
 */
  TableInHtmlTable: (
    props: TableInHtmlTableProps<Schemas> & HtmlTableProps,
  ) => ComponentReturnType;

  /**
 * The SortedTableInHtmlTable component renders the contents of a single sorted
 * Table in a Store, as an HTML <table> element, and registers a listener so
 * that any changes to that result will cause a re-render.
 *
 * See the <SortedTableInHtmlTable /> demo for this component in action.
 *
 * The component's props identify which Table to render based on Table Id, and
 * Store (which is either the default context Store, a named context Store, or
 * by explicit reference). It also takes a Cell Id to sort by and a boolean to
 * indicate that the sorting should be in descending order. The `offset` and
 * `limit` props are used to paginate results, but default to `0` and
 * `undefined` to return all available Row Ids if not specified.
 *
 * This component renders a ResultTable by iterating over its Row objects, in
 * the order dictated by the sort parameters. By default the Cells are in turn
 * rendered with the CellView component, but you can override this behavior by
 * providing a `component` for each Cell in the `customCells` prop. You can pass
 * additional props to that custom component with the `getComponentProps`
 * callback. See the CustomCell type for more details.
 *
 * This component uses the useSortedRowIds hook under the covers, which means
 * that any changes to the structure or sorting of the Table will cause a
 * re-render.
 *
 * You can use the `headerRow` and `idColumn` props to control whether the Ids
 * appear in a <th> element at the top of the table, and the start of each row.
 *
 * The `sortOnClick` prop makes the table's sorting interactive such that the
 * user can click on a column heading to sort by that column. The style classes
 * `sorted` and `ascending` (or `descending`) are added so that you can provide
 * hints to the user how the sorting is being applied.
 *
 * Provide a paginator component for the Table with the `paginator` prop. Set to
 * `true` to use the default SortedTablePaginator, or provide your own component
 * that accepts SortedTablePaginatorProps.
 *
 * Finally, the `onChange` prop lets you listen to a user's changes to the
 * Table's sorting or pagination.
 * @param props The props for this component.
 * @returns A rendering of the Table in a <table> element.
 * @example
 * This example creates a Provider context into which a default Store is
 * provided. The SortedTableInHtmlTable component within it then renders the
 * Table in a <table> element with a CSS class.
 *
 * ```jsx
 * import React from 'react';
 * import {createRoot} from 'react-dom/client';
 * import {createStore} from 'tinybase';
 * import {Provider} from 'tinybase/ui-react';
 * import {SortedTableInHtmlTable} from 'tinybase/ui-react-dom';
 *
 * const App = ({store}) => (
 *   <Provider store={store}>
 *     <Pane />
 *   </Provider>
 * );
 * const Pane = () => (
 *   <SortedTableInHtmlTable
 *     tableId="pets"
 *     cellId="species"
 *     className="table"
 *   />
 * );
 *
 * const store = createStore().setTables({
 *   pets: {
 *     fido: {species: 'dog'},
 *     felix: {species: 'cat'},
 *   },
 * });
 * const app = document.createElement('div');
 * createRoot(app).render(<App store={store} />); // !act
 * console.log(app.innerHTML);
 * // ->
 * `
 * <table class="table">
 *   <thead>
 *     <tr>
 *       <th>Id</th>
 *       <th class="sorted ascending">↑ species</th>
 *     </tr>
 *   </thead>
 *   <tbody>
 *     <tr>
 *       <th>felix</th>
 *       <td>cat</td>
 *     </tr>
 *     <tr>
 *       <th>fido</th>
 *       <td>dog</td>
 *     </tr>
 *   </tbody>
 * </table>
 * `;
 * ```
 * @example
 * This example creates a Provider context into which a default Store is
 * provided. The SortedTableInHtmlTable component within it then renders the
 * Table with a custom component and a custom props callback for the `species`
 * Cell. The header row at the top of the table and the Id column at the start
 * of each row is removed.
 *
 * ```jsx
 * import React from 'react';
 * import {createRoot} from 'react-dom/client';
 * import {createStore} from 'tinybase';
 * import {CellView, Provider} from 'tinybase/ui-react';
 * import {SortedTableInHtmlTable} from 'tinybase/ui-react-dom';
 *
 * const App = ({store}) => (
 *   <Provider store={store}>
 *     <Pane />
 *   </Provider>
 * );
 *
 * const Pane = () => (
 *   <SortedTableInHtmlTable
 *     tableId="pets"
 *     cellId="species"
 *     customCells={customCells}
 *     headerRow={false}
 *     idColumn={false}
 *   />
 * );
 *
 * const FormattedCellView = ({tableId, rowId, cellId, bold}) => (
 *   <>
 *     {bold ? <b>{rowId}</b> : rowId}:
 *     <CellView tableId={tableId} rowId={rowId} cellId={cellId} />
 *   </>
 * );
 * const customCells = {
 *   species: {
 *     component: FormattedCellView,
 *     getComponentProps: (rowId) => ({bold: rowId == 'fido'}),
 *   },
 * };
 *
 * const store = createStore().setTables({
 *   pets: {
 *     fido: {species: 'dog'},
 *     felix: {species: 'cat'},
 *   },
 * });
 * const app = document.createElement('div');
 * createRoot(app).render(<App store={store} />); // !act
 * console.log(app.innerHTML);
 * // ->
 * `
 * <table>
 *   <tbody>
 *     <tr>
 *       <td>felix:cat</td>
 *     </tr>
 *     <tr>
 *       <td><b>fido</b>:dog</td>
 *     </tr>
 *   </tbody>
 * </table>
 * `;
 * ```
 * @category Store components
 * @since v4.1.0
 */
  SortedTableInHtmlTable: (
    props: SortedTableInHtmlTableProps<Schemas> & HtmlTableProps,
  ) => ComponentReturnType;

  /**
 * The ValuesInHtmlTable component renders the keyed value contents of a Store
 * as an HTML <table> element, and registers a listener so that any changes to
 * that result will cause a re-render.
 *
 * See the <ValuesInHtmlTable /> demo for this component in action.
 *
 * The component's props identify which Row to render based on Table Id, Row Id,
 * and Store (which is either the default context Store, a named context Store,
 * or an explicit reference).
 *
 * This component renders a Store by iterating over its Value objects. By
 * default the Values are in turn rendered with the ValueView component, but you
 * can override this behavior by providing a `valueComponent` prop, a custom
 * component of your own that will render a Value based on ValueProps. You can
 * also pass additional props to your custom component with the
 * `getValueComponentProps` callback prop.
 *
 * This component uses the useValueIds hook under the covers, which means that
 * any changes to the structure of the Values in the Store will cause a
 * re-render.
 *
 * You can use the `headerRow` and `idColumn` props to control whether labels
 * and Ids appear in a <th> element at the top of the table, and the start of
 * each row.
 * @param props The props for this component.
 * @returns A rendering of the Values in a <table> element.
 * @example
 * This example creates a Provider context into which a default Store is
 * provided. The ValuesInHtmlTable component within it then renders the Values
 * in a <table> element with a CSS class.
 *
 * ```jsx
 * import React from 'react';
 * import {createRoot} from 'react-dom/client';
 * import {createStore} from 'tinybase';
 * import {Provider} from 'tinybase/ui-react';
 * import {ValuesInHtmlTable} from 'tinybase/ui-react-dom';
 *
 * const App = ({store}) => (
 *   <Provider store={store}>
 *     <Pane />
 *   </Provider>
 * );
 * const Pane = () => <ValuesInHtmlTable className="values" />;
 *
 * const store = createStore().setValues({open: true, employees: 3});
 * const app = document.createElement('div');
 * createRoot(app).render(<App store={store} />); // !act
 * console.log(app.innerHTML);
 * // ->
 * `
 * <table class="values">
 *   <thead>
 *     <tr>
 *       <th>Id</th>
 *       <th>Value</th>
 *     </tr>
 *   </thead>
 *   <tbody>
 *     <tr>
 *       <th>open</th>
 *       <td>true</td>
 *     </tr>
 *     <tr>
 *       <th>employees</th>
 *       <td>3</td>
 *     </tr>
 *   </tbody>
 * </table>
 * `;
 * ```
 * @example
 * This example creates a Provider context into which a default Store is
 * provided. The ValuesInHtmlTable component within it then renders the Row
 * with a custom Cell component and a custom props callback. The header row at
 * the top of the table and the Id column at the start of each row is removed.
 *
 * ```jsx
 * import React from 'react';
 * import {createRoot} from 'react-dom/client';
 * import {createStore} from 'tinybase';
 * import {Provider, ValueView} from 'tinybase/ui-react';
 * import {ValuesInHtmlTable} from 'tinybase/ui-react-dom';
 *
 * const App = ({store}) => (
 *   <Provider store={store}>
 *     <Pane />
 *   </Provider>
 * );
 * const getBoldProp = (valueId) => ({bold: valueId == 'open'});
 * const Pane = () => (
 *   <ValuesInHtmlTable
 *     valueComponent={FormattedValueView}
 *     getValueComponentProps={getBoldProp}
 *     headerRow={false}
 *     idColumn={false}
 *   />
 * );
 * const FormattedValueView = ({valueId, bold}) => (
 *   <>
 *     {bold ? <b>{valueId}</b> : valueId}
 *     {': '}
 *     <ValueView valueId={valueId} />
 *   </>
 * );
 *
 * const store = createStore().setValues({open: true, employees: 3});
 * const app = document.createElement('div');
 * createRoot(app).render(<App store={store} />); // !act
 * console.log(app.innerHTML);
 * // ->
 * `
 * <table>
 *   <tbody>
 *     <tr><td><b>open</b>: true</td></tr>
 *     <tr><td>employees: 3</td></tr>
 *   </tbody>
 * </table>
 * `;
 * ```
 * @category Store components
 * @since v4.1.0
 */
  ValuesInHtmlTable: (
    props: ValuesInHtmlTableProps<Schemas> & HtmlTableProps,
  ) => ComponentReturnType;

  /**
 * The SliceInHtmlTable component renders the contents of a Slice as an HTML
 * <table> element, and registers a listener so that any changes to that result
 * will cause a re-render.
 *
 * See the <SliceInHtmlTable /> demo for this component in action.
 *
 * The component's props identify which Slice to render based on Index Id, Slice
 * Id, and Indexes object (which is either the default context Indexes object, a
 * named context Indexes object, or an explicit reference).
 *
 * This component renders a Slice by iterating over its Row objects. By default
 * the Cells are in turn rendered with the CellView component, but you can
 * override this behavior by providing a `component` for each Cell in the
 * `customCells` prop. You can pass additional props to that custom component
 * with the `getComponentProps` callback. See the CustomCell type for more
 * details.
 *
 * This component uses the useSliceRowIds hook under the covers, which means
 * that any changes to the structure of the Slice will cause a re-render.
 *
 * You can use the `headerRow` and `idColumn` props to control whether labels
 * and Ids appear in a <th> element at the top of the table, and the start of
 * each row.
 * @param props The props for this component.
 * @returns A rendering of the Slice in a <table> element.
 * @example
 * This example creates a Provider context into which a default Indexes object
 * is provided. The SliceInHtmlTable component within it then renders the Slice
 * in a <table> element with a CSS class.
 *
 * ```jsx
 * import React from 'react';
 * import {createRoot} from 'react-dom/client';
 * import {createIndexes, createStore} from 'tinybase';
 * import {Provider} from 'tinybase/ui-react';
 * import {SliceInHtmlTable} from 'tinybase/ui-react-dom';
 *
 * const App = ({indexes}) => (
 *   <Provider indexes={indexes}>
 *     <Pane />
 *   </Provider>
 * );
 * const Pane = () => (
 *   <SliceInHtmlTable indexId="bySpecies" sliceId="dog" className="slice" />
 * );
 *
 * const store = createStore().setTable('pets', {
 *   fido: {species: 'dog'},
 *   felix: {species: 'cat'},
 *   cujo: {species: 'dog'},
 * });
 * const indexes = createIndexes(store);
 * indexes.setIndexDefinition('bySpecies', 'pets', 'species');
 *
 * const app = document.createElement('div');
 * createRoot(app).render(<App indexes={indexes} />); // !act
 * console.log(app.innerHTML);
 * // ->
 * `
 * <table class="slice">
 *   <thead>
 *     <tr>
 *       <th>Id</th>
 *       <th>species</th>
 *     </tr>
 *   </thead>
 *   <tbody>
 *     <tr>
 *       <th>fido</th>
 *       <td>dog</td>
 *     </tr>
 *     <tr>
 *       <th>cujo</th>
 *       <td>dog</td>
 *     </tr>
 *   </tbody>
 * </table>
 * `;
 * ```
 * @example
 * This example creates a Provider context into which a default Indexes object
 * is provided. The SliceInHtmlTable component within it then renders the Slice
 * with a custom component and a custom props callback for the `species` Cell.
 * The header row at the top of the table and the Id column at the start of each
 * row is removed.
 *
 * ```jsx
 * import React from 'react';
 * import {createRoot} from 'react-dom/client';
 * import {createIndexes, createStore} from 'tinybase';
 * import {CellView, Provider} from 'tinybase/ui-react';
 * import {SliceInHtmlTable} from 'tinybase/ui-react-dom';
 *
 * const App = ({indexes}) => (
 *   <Provider indexes={indexes}>
 *     <Pane />
 *   </Provider>
 * );
 * const Pane = () => (
 *   <SliceInHtmlTable
 *     indexId="bySpecies"
 *     sliceId="dog"
 *     customCells={customCells}
 *     headerRow={false}
 *     idColumn={false}
 *   />
 * );
 *
 * const FormattedCellView = ({tableId, rowId, cellId, bold}) => (
 *   <>
 *     {bold ? <b>{rowId}</b> : rowId}:
 *     <CellView tableId={tableId} rowId={rowId} cellId={cellId} />
 *   </>
 * );
 * const customCells = {
 *   species: {
 *     component: FormattedCellView,
 *     getComponentProps: (rowId) => ({bold: rowId == 'fido'}),
 *   },
 * };
 *
 * const store = createStore().setTable('pets', {
 *   fido: {species: 'dog', color: 'brown'},
 *   felix: {species: 'cat'},
 *   cujo: {species: 'dog'},
 * });
 * const indexes = createIndexes(store);
 * indexes.setIndexDefinition('bySpecies', 'pets', 'species');
 *
 * const app = document.createElement('div');
 * createRoot(app).render(<App indexes={indexes} />); // !act
 * console.log(app.innerHTML);
 * // ->
 * `
 * <table>
 *   <tbody>
 *     <tr>
 *       <td><b>fido</b>:</td>
 *     </tr>
 *     <tr>
 *       <td>cujo:</td>
 *     </tr>
 *   </tbody>
 * </table>
 * `;
 * ```
 * @category Indexes components
 * @since v4.1.0
 */
  SliceInHtmlTable: (
    props: SliceInHtmlTableProps<Schemas> & HtmlTableProps,
  ) => ComponentReturnType;

  /**
 * The RelationshipInHtmlTable component renders the contents of the two Tables
 * linked by a Relationship as an HTML <table> element, and registers a listener
 * so that any changes to that result will cause a re-render.
 *
 * See the <RelationshipInHtmlTable /> demo for this component in action.
 *
 * The component's props identify which Relationship to render based on
 * Relationship Id and Relationships object (which is either the default context
 * Relationships object, a named context Relationships object, or an explicit
 * reference).
 *
 * This component renders the two Table objects by iterating over their related
 * Row objects. By default the Cells are in turn rendered with the CellView
 * component, but you can override this behavior by providing a `component` for
 * each Cell in the `customCells` prop. You can pass additional props to that
 * custom component with the `getComponentProps` callback. See the CustomCell
 * type for more details.
 *
 * Note the use of dotted 'tableId.cellId' string pairs when specifying custom
 * rendering for the cells in this table, since Cells from both the
 * relationship's 'local' and 'remote' Table objects can be rendered and need to
 * be distinguished.
 *
 * This component uses the useRowIds and useRemoteRowId hooks under the covers,
 * which means that any changes to the structure of either Table resulting in a
 * change to the relationship will cause a re-render.
 *
 * You can use the `headerRow` and `idColumn` props to control whether labels
 * and Ids appear in a <th> element at the top of the table, and the start of
 * each row.
 * @param props The props for this component.
 * @returns A rendering of the two Tables linked by a Relationship in a
 * <table> element.
 * @example
 * This example creates a Provider context into which a default Relationships
 * object is provided. The RelationshipInHtmlTable component within it then
 * renders the two Tables linked by a relationship in a <table> element with a
 * CSS class. Note the dotted pairs that are used as column headings.
 *
 * ```jsx
 * import React from 'react';
 * import {createRoot} from 'react-dom/client';
 * import {createRelationships, createStore} from 'tinybase';
 * import {Provider} from 'tinybase/ui-react';
 * import {RelationshipInHtmlTable} from 'tinybase/ui-react-dom';
 *
 * const App = ({relationships}) => (
 *   <Provider relationships={relationships}>
 *     <Pane />
 *   </Provider>
 * );
 * const Pane = () => (
 *   <RelationshipInHtmlTable
 *     relationshipId="petSpecies"
 *     className="relationship"
 *   />
 * );
 *
 * const relationships = createRelationships(
 *   createStore()
 *     .setTable('pets', {fido: {species: 'dog'}, cujo: {species: 'dog'}})
 *     .setTable('species', {wolf: {price: 10}, dog: {price: 5}}),
 * ).setRelationshipDefinition('petSpecies', 'pets', 'species', 'species');
 *
 * const app = document.createElement('div');
 * const root = createRoot(app);
 * root.render(<App relationships={relationships} />); // !act
 * console.log(app.innerHTML);
 * // ->
 * `
 * <table class="relationship">
 *   <thead>
 *     <tr>
 *       <th>pets.Id</th>
 *       <th>species.Id</th>
 *       <th>pets.species</th>
 *       <th>species.price</th>
 *     </tr>
 *   </thead>
 *   <tbody>
 *     <tr>
 *       <th>fido</th>
 *       <th>dog</th>
 *       <td>dog</td>
 *       <td>5</td>
 *     </tr>
 *     <tr>
 *       <th>cujo</th>
 *       <th>dog</th>
 *       <td>dog</td>
 *       <td>5</td>
 *     </tr>
 *   </tbody>
 * </table>
 * `;
 * ```
 * @example
 * This example creates a Provider context into which a default Relationships
 * object is provided. The RelationshipInHtmlTable component within it then
 * renders the two Tables linked by a relationship with a custom component and a
 * custom props callback for the `species` Cell. The header row at the top of
 * the table and the Id column at the start of each row is removed.
 *
 * ```jsx
 * import React from 'react';
 * import {createRoot} from 'react-dom/client';
 * import {createRelationships, createStore} from 'tinybase';
 * import {CellView, Provider} from 'tinybase/ui-react';
 * import {RelationshipInHtmlTable} from 'tinybase/ui-react-dom';
 *
 * const App = ({relationships}) => (
 *   <Provider relationships={relationships}>
 *     <Pane />
 *   </Provider>
 * );
 * const Pane = () => (
 *   <RelationshipInHtmlTable
 *     relationshipId="petSpecies"
 *     customCells={customCells}
 *     idColumn={false}
 *     headerRow={false}
 *   />
 * );
 *
 * const FormattedCellView = ({tableId, rowId, cellId, store, bold}) => (
 *   <>
 *     {bold ? <b>{rowId}</b> : rowId}:
 *     <CellView
 *       tableId={tableId}
 *       rowId={rowId}
 *       cellId={cellId}
 *       store={store}
 *     />
 *   </>
 * );
 * const customCells = {
 *   'species.price': {
 *     component: FormattedCellView,
 *     getComponentProps: (rowId) => ({bold: rowId == 'dog'}),
 *   },
 * };
 *
 * const relationships = createRelationships(
 *   createStore()
 *     .setTable('pets', {fido: {species: 'dog'}, cujo: {species: 'wolf'}})
 *     .setTable('species', {wolf: {price: 10}, dog: {price: 5}}),
 * ).setRelationshipDefinition('petSpecies', 'pets', 'species', 'species');
 *
 * const app = document.createElement('div');
 * const root = createRoot(app);
 * root.render(<App relationships={relationships} />); // !act
 * console.log(app.innerHTML);
 * // ->
 * `
 * <table>
 *   <tbody>
 *     <tr>
 *       <td><b>dog</b>:5</td>
 *     </tr>
 *     <tr>
 *       <td>wolf:10</td>
 *     </tr>
 *   </tbody>
 * </table>
 * `;
 * ```
 * @category Relationships components
 * @since v4.1.0
 */
  RelationshipInHtmlTable: (
    props: RelationshipInHtmlTableProps<Schemas> & HtmlTableProps,
  ) => ComponentReturnType;

  /**
 * The ResultTableInHtmlTable component renders the contents of a single query's
 * ResultTable in a Queries object as an HTML <table> element, and registers a
 * listener so that any changes to that result will cause a re-render.
 *
 * See the <ResultTableInHtmlTable /> demo for this component in action.
 *
 * The component's props identify which ResultTable to render based on query Id,
 * and Queries object (which is either the default context Queries object, a
 * named context Queries object, or by explicit reference).
 *
 * This component renders a ResultTable by iterating over its Row objects. By
 * default the Cells are in turn rendered with the CellView component, but you
 * can override this behavior by providing a `component` for each Cell in the
 * `customCells` prop. You can pass additional props to that custom component
 * with the `getComponentProps` callback. See the ResultCustomCell type for more
 * details.
 *
 * This component uses the useRowIds hook under the covers, which means that any
 * changes to the structure of the Table will cause a re-render.
 *
 * You can use the `headerRow` and `idColumn` props to control whether the Ids
 * appear in a <th> element at the top of the table, and the start of each row.
 * @param props The props for this component.
 * @returns A rendering of the ResultTable in a <table> element.
 * @example
 * This example creates a Provider context into which a default Queries object
 * is provided. The ResultTableInHtmlTable component within it then renders the
 * ResultTable in a <table> element with a CSS class.
 *
 * ```jsx
 * import React from 'react';
 * import {createRoot} from 'react-dom/client';
 * import {createQueries, createStore} from 'tinybase';
 * import {Provider} from 'tinybase/ui-react';
 * import {ResultTableInHtmlTable} from 'tinybase/ui-react-dom';
 *
 * const App = ({queries}) => (
 *   <Provider queries={queries}>
 *     <Pane />
 *   </Provider>
 * );
 * const Pane = () => (
 *   <ResultTableInHtmlTable queryId="petColors" className="table" />
 * );
 *
 * const queries = createQueries(
 *   createStore().setTable('pets', {
 *     fido: {species: 'dog', color: 'brown'},
 *     felix: {species: 'cat', color: 'black'},
 *   }),
 * ).setQueryDefinition('petColors', 'pets', ({select}) => select('color'));
 * const app = document.createElement('div');
 * createRoot(app).render(<App queries={queries} />); // !act
 * console.log(app.innerHTML);
 * // ->
 * `
 * <table class="table">
 *   <thead>
 *     <tr>
 *       <th>Id</th>
 *       <th>color</th>
 *     </tr>
 *   </thead>
 *   <tbody>
 *     <tr>
 *       <th>fido</th>
 *       <td>brown</td>
 *     </tr>
 *     <tr>
 *       <th>felix</th>
 *       <td>black</td>
 *     </tr>
 *   </tbody>
 * </table>
 * `;
 * ```
 * @example
 * This example creates a Provider context into which a default Queries object
 * is provided. The ResultTableInHtmlTable component within it then renders the
 * ResultTable with a custom component and a custom props callback for the
 * `color` Cell. The header row at the top of the table and the Id column at
 * the start of each row is removed.
 *
 * ```jsx
 * import React from 'react';
 * import {createRoot} from 'react-dom/client';
 * import {createQueries, createStore} from 'tinybase';
 * import {Provider, ResultCellView} from 'tinybase/ui-react';
 * import {ResultTableInHtmlTable} from 'tinybase/ui-react-dom';
 *
 * const App = ({queries}) => (
 *   <Provider queries={queries}>
 *     <Pane />
 *   </Provider>
 * );
 * const Pane = () => (
 *   <ResultTableInHtmlTable
 *     queryId="petColors"
 *     customCells={customCells}
 *     headerRow={false}
 *     idColumn={false}
 *   />
 * );
 *
 * const FormattedResultCellView = ({queryId, rowId, cellId, bold}) => (
 *   <>
 *     {bold ? <b>{rowId}</b> : rowId}:
 *     <ResultCellView queryId={queryId} rowId={rowId} cellId={cellId} />
 *   </>
 * );
 * const customCells = {
 *   color: {
 *     component: FormattedResultCellView,
 *     getComponentProps: (rowId) => ({bold: rowId == 'fido'}),
 *   },
 * };
 *
 * const queries = createQueries(
 *   createStore().setTable('pets', {
 *     fido: {species: 'dog', color: 'brown'},
 *     felix: {species: 'cat', color: 'black'},
 *   }),
 * ).setQueryDefinition('petColors', 'pets', ({select}) => select('color'));
 * const app = document.createElement('div');
 * createRoot(app).render(<App queries={queries} />); // !act
 * console.log(app.innerHTML);
 * // ->
 * `
 * <table>
 *   <tbody>
 *     <tr>
 *       <td><b>fido</b>:brown</td>
 *     </tr>
 *     <tr>
 *       <td>felix:black</td>
 *     </tr>
 *   </tbody>
 * </table>
 * `;
 * ```
 * @category Queries components
 * @since v4.1.0
 */
  ResultTableInHtmlTable: (
    props: ResultTableInHtmlTableProps<Schemas> & HtmlTableProps,
  ) => ComponentReturnType;

  /**
 * The SortedTableInHtmlTable component renders the contents of a single query's
 * sorted ResultTable in a Queries object as an HTML <table> element, and
 * registers a listener so that any changes to that result will cause a
 * re-render.
 *
 * See the <ResultSortedTableInHtmlTable /> demo for this component in action.
 *
 * The component's props identify which ResultTable to render based on query Id,
 * and Queries object (which is either the default context Queries object, a
 * named context Queries object, or by explicit reference). It also takes a Cell
 * Id to sort by and a boolean to indicate that the sorting should be in
 * descending order. The `offset` and `limit` props are used to paginate
 * results, but default to `0` and `undefined` to return all available Row Ids
 * if not specified.
 *
 * This component renders a ResultTable by iterating over its Row objects, in
 * the order dictated by the sort parameters. By default the Cells are in turn
 * rendered with the CellView component, but you can override this behavior by
 * providing a `component` for each Cell in the `customCells` prop. You can pass
 * additional props to that custom component with the `getComponentProps`
 * callback. See the ResultCustomCell type for more details.
 *
 * This component uses the useSortedRowIds hook under the covers, which means
 * that any changes to the structure or sorting of the ResultTable will cause a
 * re-render.
 *
 * You can use the `headerRow` and `idColumn` props to control whether the Ids
 * appear in a <th> element at the top of the table, and the start of each row.
 *
 * The `sortOnClick` prop makes the table's sorting interactive such that the
 * user can click on a column heading to sort by that column. The style classes
 * `sorted` and `ascending` (or `descending`) are added so that you can provide
 * hints to the user how the sorting is being applied.
 *
 * Provide a paginator component for the ResultTable with the `paginator` prop.
 * Set to `true` to use the default SortedTablePaginator, or provide your own
 * component that accepts SortedTablePaginatorProps.
 *
 * Finally, the `onChange` prop lets you listen to a user's changes to the
 * ResultTable's sorting or pagination.
 * @param props The props for this component.
 * @returns A rendering of the ResultTable in a <table> element.
 * @example
 * This example creates a Provider context into which a default Queries object
 * is provided. The ResultSortedTableInHtmlTable component within it then
 * renders the ResultTable in a <table> element with a CSS class.
 *
 * ```jsx
 * import React from 'react';
 * import {createRoot} from 'react-dom/client';
 * import {createQueries, createStore} from 'tinybase';
 * import {Provider} from 'tinybase/ui-react';
 * import {ResultSortedTableInHtmlTable} from 'tinybase/ui-react-dom';
 *
 * const App = ({queries}) => (
 *   <Provider queries={queries}>
 *     <Pane />
 *   </Provider>
 * );
 * const Pane = () => (
 *   <ResultSortedTableInHtmlTable
 *     queryId="petColors"
 *     cellId="color"
 *     className="table"
 *   />
 * );
 *
 * const queries = createQueries(
 *   createStore().setTable('pets', {
 *     fido: {species: 'dog', color: 'brown'},
 *     felix: {species: 'cat', color: 'black'},
 *   }),
 * ).setQueryDefinition('petColors', 'pets', ({select}) => select('color'));
 * const app = document.createElement('div');
 * createRoot(app).render(<App queries={queries} />); // !act
 * console.log(app.innerHTML);
 * // ->
 * `
 * <table class="table">
 *   <thead>
 *     <tr>
 *       <th>Id</th>
 *       <th class="sorted ascending">↑ color</th>
 *     </tr>
 *   </thead>
 *   <tbody>
 *     <tr>
 *       <th>felix</th>
 *       <td>black</td>
 *     </tr>
 *     <tr>
 *       <th>fido</th>
 *       <td>brown</td>
 *     </tr>
 *   </tbody>
 * </table>
 * `;
 * ```
 * @example
 * This example creates a Provider context into which a default Queries object
 * is provided. The ResultSortedTableInHtmlTable component within it then
 * renders the ResultTable with a custom component and a custom props callback
 * for the `color` Cell. The header row at the top of the table and the Id
 * column at the start of each row is removed.
 *
 * ```jsx
 * import React from 'react';
 * import {createRoot} from 'react-dom/client';
 * import {createQueries, createStore} from 'tinybase';
 * import {Provider, ResultCellView} from 'tinybase/ui-react';
 * import {ResultSortedTableInHtmlTable} from 'tinybase/ui-react-dom';
 *
 * const App = ({queries}) => (
 *   <Provider queries={queries}>
 *     <Pane />
 *   </Provider>
 * );
 *
 * const Pane = () => (
 *   <ResultSortedTableInHtmlTable
 *     queryId="petColors"
 *     cellId="color"
 *     customCells={customCells}
 *     headerRow={false}
 *     idColumn={false}
 *   />
 * );
 *
 * const FormattedResultCellView = ({queryId, rowId, cellId, bold}) => (
 *   <>
 *     {bold ? <b>{rowId}</b> : rowId}:
 *     <ResultCellView queryId={queryId} rowId={rowId} cellId={cellId} />
 *   </>
 * );
 * const customCells = {
 *   color: {
 *     component: FormattedResultCellView,
 *     getComponentProps: (rowId) => ({bold: rowId == 'fido'}),
 *   },
 * };
 *
 * const queries = createQueries(
 *   createStore().setTable('pets', {
 *     fido: {species: 'dog', color: 'brown'},
 *     felix: {species: 'cat', color: 'black'},
 *   }),
 * ).setQueryDefinition('petColors', 'pets', ({select}) => select('color'));
 * const app = document.createElement('div');
 * createRoot(app).render(<App queries={queries} />); // !act
 * console.log(app.innerHTML);
 * // ->
 * `
 * <table>
 *   <tbody>
 *     <tr>
 *       <td>felix:black</td>
 *     </tr>
 *     <tr>
 *       <td><b>fido</b>:brown</td>
 *     </tr>
 *   </tbody>
 * </table>
 * `;
 * ```
 * @category Queries components
 * @since v4.1.0
 */
  ResultSortedTableInHtmlTable: (
    props: ResultSortedTableInHtmlTableProps<Schemas> & HtmlTableProps,
  ) => ComponentReturnType;

  /**
 * The EditableCellView component renders the value of a single Cell in a way
 * that can be edited in a web browser, and registers a listener so that any
 * changes to that result will cause a re-render.
 *
 * See the <EditableCellView /> demo for this component in action.
 *
 * The component's props identify which Cell to render based on Table Id, Row
 * Id, Cell Id, and Store (which is either the default context Store, a named
 * context Store, or an explicit reference).
 *
 * A Cell contains a string, number, or boolean, so the value is rendered in an
 * appropriate <input> tag and a button lets the user change type, if possible.
 *
 * Set the `showType` prop to false to remove the ability for the user to see or
 * change the Cell type. They will also not be able to change the type if there
 * is a TablesSchema applied to the Store.
 *
 * This component uses the useCell hook under the covers, which means that any
 * changes to the specified Cell outside of this component will cause a
 * re-render.
 *
 * You can provide a custom className prop which well be used on the root of the
 * resulting element. If omitted the element's class will be `editableCell`. The
 * debugIds prop has no effect on this component.
 * @param props The props for this component.
 * @returns An editable rendering of the Cell.
 * @example
 * This example creates a Provider context into which a default Store is
 * provided. The EditableCellView component within it then renders an editable
 * Cell.
 *
 * ```jsx
 * import React from 'react';
 * import {createRoot} from 'react-dom/client';
 * import {createStore} from 'tinybase';
 * import {Provider} from 'tinybase/ui-react';
 * import {EditableCellView} from 'tinybase/ui-react-dom';
 *
 * const App = ({store}) => (
 *   <Provider store={store}>
 *     <Pane />
 *   </Provider>
 * );
 * const Pane = () => (
 *   <EditableCellView tableId="pets" rowId="fido" cellId="color" />
 * );
 *
 * const store = createStore().setCell('pets', 'fido', 'color', 'brown');
 * const app = document.createElement('div');
 * createRoot(app).render(<App store={store} />); // !act
 * console.log(app.innerHTML);
 * // ->
 * `
 * <div class="editableCell">
 *   <button class="string">string</button>
 *   <input value="brown">
 * </div>
 * `;
 * ```
 * @category Store components
 * @since v4.1.0
 */
  EditableCellView: (
    props: CellProps<Schemas> & {
      className?: string;
      readonly showType?: boolean;
    },
  ) => ComponentReturnType;

  /**
 * The EditableValueView component renders the value of a single Value in a way
 * that can be edited in a web browser, and registers a listener so that any
 * changes to that result will cause a re-render.
 *
 * See the <EditableValueView /> demo for this component in action.
 *
 * The component's props identify which Value to render based on Table Id, Row
 * Id, Value Id, and Store (which is either the default context Store, a named
 * context Store, or an explicit reference).
 *
 * A Value contains a string, number, or boolean, so the value is rendered in an
 * appropriate <input> tag and a button lets the user change type, if possible.
 *
 * Set the `showType` prop to false to remove the ability for the user to see or
 * change the Value type. They will also not be able to change the type if there
 * is a ValuesSchema applied to the Store.
 *
 * This component uses the useValue hook under the covers, which means that any
 * changes to the specified Value outside of this component will cause a
 * re-render.
 *
 * You can provide a custom className prop which well be used on the root of the
 * resulting element. If omitted the element's class will be `editableValue`.
 * The debugIds prop has no effect on this component.
 * @param props The props for this component.
 * @returns An editable rendering of the Value.
 * @example
 * This example creates a Provider context into which a default Store is
 * provided. The EditableValueView component within it then renders an editable
 * Value.
 *
 * ```jsx
 * import React from 'react';
 * import {createRoot} from 'react-dom/client';
 * import {createStore} from 'tinybase';
 * import {Provider} from 'tinybase/ui-react';
 * import {EditableValueView} from 'tinybase/ui-react-dom';
 *
 * const App = ({store}) => (
 *   <Provider store={store}>
 *     <Pane />
 *   </Provider>
 * );
 * const Pane = () => <EditableValueView valueId="employees" />;
 *
 * const store = createStore().setValue('employees', 3);
 * const app = document.createElement('div');
 * createRoot(app).render(<App store={store} />); // !act
 * console.log(app.innerHTML);
 * // ->
 * `
 * <div class="editableValue">
 *   <button class="number">number</button>
 *   <input type="number" value="3">
 * </div>
 * `;
 * ```
 * @category Store components
 * @since v4.1.0
 */
  EditableValueView: (
    props: ValueProps<Schemas> & {
      className?: string;
      readonly showType?: boolean;
    },
  ) => ComponentReturnType;

  /**
 * The SortedTablePaginator component renders a paginator for a sorted table.
 *
 * See the <SortedTableInHtmlTable /> demo for this component in action.
 *
 * The component displays 'previous' and 'next' buttons for paging through the
 * Table if there are more Row Ids than fit in each page. The component will
 * also display a label that shows which Row Ids are being displayed.
 *
 * The component's props identify initial pagination settings, and it will fire
 * an event when the pagination changes.
 * @param props The props for this component.
 * @returns The rendering of a paginator control with a label, and next and
 * previous buttons, where appropriate.
 * @example
 * This example creates a Provider context into which a default Store is
 * provided. The SortedTableInHtmlTable component within it then renders the
 * Table in a <table> element with a SortedTablePaginator (the default).
 *
 * ```jsx
 * import React from 'react';
 * import {createRoot} from 'react-dom/client';
 * import {createStore} from 'tinybase';
 * import {Provider} from 'tinybase/ui-react';
 * import {SortedTableInHtmlTable} from 'tinybase/ui-react-dom';
 *
 * const App = ({store}) => (
 *   <Provider store={store}>
 *     <Pane />
 *   </Provider>
 * );
 * const Pane = () => (
 *   <SortedTableInHtmlTable
 *     tableId="pets"
 *     cellId="species"
 *     limit={2}
 *     paginator={true}
 *   />
 * );
 *
 * const store = createStore().setTables({
 *   pets: {
 *     fido: {species: 'dog'},
 *     felix: {species: 'cat'},
 *     cujo: {species: 'wolf'},
 *     lowly: {species: 'worm'},
 *     polly: {species: 'parrot'},
 *   },
 * });
 * const app = document.createElement('div');
 * createRoot(app).render(<App store={store} />); // !act
 * console.log(app.innerHTML);
 * // ->
 * `
 * <table>
 *   <caption>
 *     <button class="previous" disabled="">←</button>
 *     <button class="next">→</button>
 *     1 to 2 of 5 rows
 *   </caption>
 *   <thead>
 *     <tr>
 *       <th>Id</th>
 *       <th class="sorted ascending">↑ species</th>
 *     </tr>
 *   </thead>
 *   <tbody>
 *     <tr>
 *       <th>felix</th>
 *       <td>cat</td>
 *     </tr>
 *     <tr>
 *       <th>fido</th>
 *       <td>dog</td>
 *     </tr>
 *   </tbody>
 * </table>
 * `;
 * ```
 * @category Store components
 * @since v4.1.0
 */
  SortedTablePaginator: (
    props: SortedTablePaginatorProps,
  ) => ComponentReturnType;

  /**
 * The Inspector component renders a tool which allows you to view and edit the
 * content of a Store in a debug web environment.
 *
 * See the <Inspector /> demo for this component in action.
 *
 * The component displays a nub in the corner of the screen which you may then
 * click to interact with all the Store objects in the Provider component
 * context.
 *
 * The component's props identify the nub's initial location and panel state,
 * though subsequent user changes to that will be preserved on each reload.
 * @param props The props for this component.
 * @returns The rendering of the inspector tool.
 * @example
 * This example creates a Provider context into which a default Store is
 * provided. The Inspector component within it then renders the inspector
 * tool.
 *
 * ```jsx
 * import React from 'react';
 * import {createRoot} from 'react-dom/client';
 * import {createStore} from 'tinybase';
 * import {Provider} from 'tinybase/ui-react';
 * import {Inspector} from 'tinybase/ui-react-inspector';
 *
 * const App = ({store}) => (
 *   <Provider store={store}>
 *     <Pane />
 *   </Provider>
 * );
 * const Pane = () => <Inspector />;
 *
 * const store = createStore().setTables({pets: {fido: {species: 'dog'}}});
 * const app = document.createElement('div');
 * createRoot(app).render(<App store={store} />); // !act
 * // ... // !act
 * console.log(app.innerHTML.substring(0, 30));
 * // -> '<aside id="tinybaseInspector">'
 * ```
 * @category Development components
 * @essential Using React
 * @since v5.0.0
 */
  Inspector: (props: InspectorProps) => ComponentReturnType;
};
