Components
Kensaku provides a set of components you can use to build your search UI.
We have to distinguish between two types of components:
- Base Components: These are the basic building blocks of the search UI. They are the smallest components and are used to build more complex components.
- Composite Components: These are more complex components that are built using the base ones.
The Composite Component does not have a direct dependency on the Base Components, indeed a composite component encapsulate the logic that deal with the state management of the data and pass it down to the base components in form of properties via the children
function.
In a nutshell, a Composite Component is configured from the external via props, dialog with the Rest API and pass the data down to the Base Components.
Base Components
PluralSelectControl
- A select control that allows multiple selections.SingleSelectControl
- A select control that allows a single selection.SearchControl
- An input control that allows the user to enter a search query.ToggleControl
- A multi selection control that allows the user to toggle between multiple options.RadioControl
- A single selection control that allows the user to select a single option.
Composite Components
CompositeEntitiesByKind
- A composite component that displays a list of entities by kind. In this context kind ispost
orterm
and entity is the entity type of the content e.g. apage
or acategory
term.
Preset Components
PresetEntitiesByKind
- A top level component simplifying the DX with a preconfigured path of how to manage the data based on the context given.
Composite Entities by Kind
The CompositeEntitiesByKind
is a generic component that can be used to display a list of entities by kind. It acts as a controller that fetches the data from the Rest API using a given function and pass it down to one or more Base Components. It is up to you how to consume the data given to the children. Note, even if you consume just one part of the given data, the component will fetch all the data necessary to render the UI.
This component is intended to fulfill a scenario where the user is looking for some entities belonging to a certain kind, for instance, selecting the page
kind will return a list of the available pages and to filter the result further it is possible to use a search function in conjunction with a search
field.
An example of its usage is:
import { CompositeEntitiesByKind } from 'kensaku';
export function MyComponent(props) {
const entities = {
value: new Set([13, 24, 55]),
onChange: (value) => {
// Do something with the selected entities
// Notice, here you'll receive the value as a string Set.
}
};
const kind = {
value: new Set(['page']),
options: [
{ label: 'Pages', value: 'page' },
{ label: 'Posts', value: 'post' },
],
onChange={(value) => {
// Do something with the selected kind
}}
};
const searchEntities = async (phrase, kind, queryArguments) => convertEntitiesToControlOptions(
await searchEntities('post', kind, phrase, queryArguments),
'title',
'id'
);
return <CompositeEntitiesByKind
searchEntities={searchEntities}
entities={entities}
kind={kind}
>
{(entities, kind, search) => (
<>
<ToggleControl
value={kind.value}
options={kind.options}
onChange={kind.onChange}
/>
<SearchControl
onChange={search.onChange}
/>
<ToggleControl
value={entities.value}
onChange={entities.onChange}
/>
</>
)}
</CompositeEntitiesByKind>;
}
In the example above we are passing a searchEntities
function that will be used to fetch the entities from the Rest API. This function is documented in the api section.
What’s important to know is that the queryArguments
do not include the _fields
property because it’s not a concern of the component decide which fields to retrieve, it’s up to the consumer to decide which fields to retrieve. Anyhow, you can still override the given configuration, but you have to be aware this might produce an incorrect result if not done correctly. The component might pass arguments necessary to guarantee the consistency of the Set of the entities and the kind.
In the following example we require title
and slug
fields to be retrieved from the Rest API.
async (phrase, kind, queryArguments) => {
const fields = ['title', 'slug'];
return convertEntitiesToControlOptions(
await searchEntities('post', kind, phrase, {...queryArguments, fields}),
...fields
)
}
The entities
and kind
properties are the initial configuration, they’ll change depending on what happen within the respective onChange
functions.
The children
function will receive the entities
, kind
and search
properties; notice the search
is a function, and it’s up to the SearchControl
to maintain the status of the value, the composite does hold the search value internally, but it does not share it outside.
You’re not forced to consume all the properties given to the children
, you can remove the SearchControl
and let the user select only the retrieved entities. Moreover, you can also not have the Kind control at all and just allow the search for one single kind.
In the example below we only allow to select the entities belonging to the page
or landing-page
kind not permitting the user to switch between them.
import { CompositeEntitiesByKind } from 'kensaku';
export function MyComponent(props) {
const entities = {
value: new Set([13, 24, 55]),
onChange: (value) => {
// Do something with the selected entities
}
};
const kind = {
value: new Set(['page', 'landing-page']),
options: Set([]),
onChange={() => {}}
};
const searchEntities = async (phrase, kind, queryArguments) => convertEntitiesToControlOptions(
await searchEntities('post', kind, phrase, queryArguments),
'title',
'id'
);
return <CompositeEntitiesByKind
searchEntities={searchEntities}
entities={entities}
kind={kind}
>
{(entities, _, search) => (
<>
<SearchControl
onChange={search.onChange}
/>
<ToggleControl
value={entities.value}
options={entities.options}
onChange={entities.onChange}
/>
</>
)}
</CompositeEntitiesByKind>;
}
Obviously depending on what you want to achieve you can use different Base Components or create new ones, as mentioned above the package comes with a set of Base Components that can be used out of the box.
Preset Entities By Kind
This component can be used for different scenarios since it allows you to pass all the necessary information to render the Selectors.
It gets passed the entitiesFinder
which is the function performing the request to retrieve the Entities, but also it gives you the freedom to decide which components to render as Controls UI.
Below you can see how easy is to create a new control set compared to use the low level api CompositeEntitiesByKind
.
const entitiesFinder = createSearchEntitiesOptions( 'post' );
const postTypesEntities = convertEntitiesToControlOptions(useQueryViewablePostTypes().records(), 'name', 'slug');
const props = {
entitiesFinder,
entities: new Set( [ 1, 2, 3 ] ),
onChangeEntities: (entities) => {
// Do something with the new set of entities
},
entitiesComponent: ToggleControl,
kind: new Set(['post']),
kindOptions: stubControlOptionsSet(),
onChangeKind: (kinds) => {
// Do something with the new set of kinds
},
kindComponent: ToggleControl
};
return (<PresetEntitiesByKind { ...props } />);
Therefore, the preset simplify and take care of some parts that you would have to configure otherwise. In the chapter below you can read the available properties.
Properties
entitiesFinder
- The function which perform the search of the contextual entities. You can use thecreateSearchEntitiesOptions
function by passing theroot
value such asterm
orpost
.className
- For better customization you can pass your own custom classes.entities
- AKensaku.Entities
set of selected entities. For when you want some entities already selected.onChangeEntities
- A task to perform when the selection change due to a user interaction.entitiesComponent
- The component to use to render the control ui for the entities.kind
- The predefined set of kind (e.g. post-types or taxonomies) you want to have already selected.kindOptions
- A collection ofKensaku.ControlOption
among which the user can choose to retrieve the entities from.onChangeKind
- A task to perform when the selection change due to a user interaction.kindComponent
- The component to use to render the control ui for the kinds.entitiesFields
- Additional fields you want to retrieve and have available within yourentitiesComponent
andkindComponent
. For more info read the Control Option documentation.
About Singular Base Components
The Composite Component always give a collection of Entities and Kind even though you are consuming a Single* Base Component.
The Singular Components always get a single value, therefore you have to consider to extract the first element out of the Set
.
import { CompositeEntitiesByKind } from 'kensaku';
export function MyComponent(props) {
return <CompositeEntitiesByKind
/* ... */
>
{(entities, kind, search) => (
<>
<RadioControl
value={kind.value.first()}
options={kind.options}
onChange={(value) => kind.onChange(new Set([value]))}
/>
/* ... */
</>
)}
</CompositeEntitiesByKind>;
}