Skip to content

Commit

Permalink
Improvements
Browse files Browse the repository at this point in the history
  • Loading branch information
widoz committed Jan 21, 2024
1 parent 6b5de4d commit cb45612
Show file tree
Hide file tree
Showing 4 changed files with 82 additions and 59 deletions.
26 changes: 16 additions & 10 deletions @types/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import React from 'react';

import { BaseEntityRecords, Context } from '@wordpress/core-data';

import type { Set } from '../sources/client/src/vo/set';
import type { Set } from '../sources/client/src';

export default EntitiesSearch;

Expand All @@ -12,6 +12,10 @@ declare namespace EntitiesSearch {
type PostType<C extends Context = 'view'> = BaseEntityRecords.Type<C>;
type Taxonomy<C extends Context = 'view'> = BaseEntityRecords.Taxonomy<C>;

type Entities<V> = Set<V>;
type Kind<V> = Set<V>;
type Options<V> = Set<ControlOption<V>>;

interface QueryArguments<V>
extends Partial<
Readonly<{
Expand All @@ -31,6 +35,12 @@ declare namespace EntitiesSearch {
subtype: string;
}> {}

type SearchEntitiesFunction<E, K> = (
phrase: string,
kind: Kind<K>,
queryArguments?: EntitiesSearch.QueryArguments<E>
) => Promise<Options<E>>;

type ControlOption<V extends any> = Readonly<{
value: V;
label: string;
Expand All @@ -47,7 +57,7 @@ declare namespace EntitiesSearch {
interface BaseControl<V>
extends Readonly<{
value: Set<V>;
options: Set<ControlOption<V>>;
options: Options<V>;
onChange(values: BaseControl<V>['value']): void;
}> {}

Expand Down Expand Up @@ -91,8 +101,8 @@ declare namespace EntitiesSearch {
K,
OptionSet = Set<EntitiesSearch.ControlOption<E>>
> extends Readonly<{
entities: BaseControl<E>['value'];
kind: BaseControl<K>['value'];
entities: Entities<E>;
kind: Kind<K>;
contextualEntitiesOptions: OptionSet;
currentEntitiesOptions: OptionSet;
selectedEntitiesOptions: OptionSet;
Expand Down Expand Up @@ -150,18 +160,14 @@ declare namespace EntitiesSearch {
extends Readonly<{
kind: BaseControl<K>;
entities: Omit<BaseControl<E>, 'options'>;
searchEntities: (
phrase: string,
kind: CompositeEntitiesKinds<E, K>['kind']['value'],
queryArguments?: QueryArguments<E>
) => Promise<BaseControl<E>['options']>;
searchEntities: SearchEntitiesFunction<E, K>;
children(
entities: CompositeEntitiesKinds<E, K>['entities'] & {
options: BaseControl<E>['options'];
},
kind: CompositeEntitiesKinds<E, K>['kind'],
search: (
phrase: Parameters<SearchControl<E, K>['search']>[0]
phrase: Parameters<SearchEntitiesFunction<E, K>>[0]
) => ReturnType<SearchControl<E, K>['search']>
): React.ReactNode;
}> {}
Expand Down
53 changes: 9 additions & 44 deletions sources/client/src/components/composite-entities-by-kind.tsx
Original file line number Diff line number Diff line change
@@ -1,18 +1,14 @@
import type EntitiesSearch from '@types';
import React, { JSX, useState } from 'react';

import { useThrottle } from '@wordpress/compose';
import { doAction } from '@wordpress/hooks';

import { useEntitiesOptionsStorage } from '../hooks/use-entities-options-storage';
import { useSearch } from '../hooks/use-search';
import { orderSelectedOptionsAtTheTop } from '../utils/order-selected-options-at-the-top';
import { uniqueControlOptions } from '../utils/unique-control-options';
import { Set } from '../vo/set';

type SearchPhrase = Parameters<EntitiesSearch.SearchControl['onChange']>[0];
type Entities<V> = EntitiesSearch.BaseControl<V>['value'];
type Kind<V> = EntitiesSearch.BaseControl<V>['value'] | V;

export function CompositeEntitiesByKind<E, K>(
props: EntitiesSearch.CompositeEntitiesKinds<E, K>
): JSX.Element {
Expand All @@ -24,37 +20,15 @@ export function CompositeEntitiesByKind<E, K>(
props.searchEntities
);
const [searchPhrase, setSearchPhrase] = useState('');
const search = useThrottle(
(phrase: SearchPhrase) => {
const _phrase = extractPhrase(phrase);

setSearchPhrase(_phrase);

props
.searchEntities(_phrase, state.kind, {
exclude: state.entities,
})
.then((result) =>
dispatch({
type: 'UPDATE_CURRENT_ENTITIES_OPTIONS',
currentEntitiesOptions: result,
})
)
.catch((error) => {
doAction('wp-entities-search.on-search.error', error);
const emptySet = new Set<EntitiesSearch.ControlOption<E>>();
dispatch({
type: 'UPDATE_CURRENT_ENTITIES_OPTIONS',
currentEntitiesOptions: emptySet,
});
return emptySet;
});
},
500,
{ leading: false, trailing: true }
const search = useSearch<E, K>(
setSearchPhrase,
props.searchEntities,
state.kind,
state.entities,
dispatch
);

const onChangeEntities = (entities: Entities<E>) => {
const onChangeEntities = (entities: EntitiesSearch.Entities<E>) => {
props.entities.onChange(entities);

if ((entities?.length() ?? 0) <= 0) {
Expand Down Expand Up @@ -90,7 +64,7 @@ export function CompositeEntitiesByKind<E, K>(
});
};

const onChangeKind = (kind: Kind<K>) => {
const onChangeKind = (kind: EntitiesSearch.Kind<K>) => {
const _kind = kind instanceof Set ? kind : new Set([kind]);
const emptySet = new Set<any>();

Expand Down Expand Up @@ -145,12 +119,3 @@ export function CompositeEntitiesByKind<E, K>(

return <>{props.children(entities, kind, search)}</>;
}

function extractPhrase(phraseOrEvent: SearchPhrase): string {
const phrase =
typeof phraseOrEvent === 'string'
? phraseOrEvent
: phraseOrEvent.target.value;

return phrase.trim();
}
6 changes: 1 addition & 5 deletions sources/client/src/hooks/use-entities-options-storage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,7 @@ type _Reducer<E, K> = Reducer<

export function useEntitiesOptionsStorage<E, K>(
initialState: Partial<EntitiesSearch.EntitiesState<E, K>>,
searchEntities: (
phrase: string,
kind: Set<K>,
queryArguments?: EntitiesSearch.QueryArguments<E>
) => Promise<EntitiesSearch.BaseControl<E>['options']>
searchEntities: EntitiesSearch.SearchEntitiesFunction<E, K>
): Readonly<{
state: EntitiesSearch.EntitiesState<E, K>;
dispatch: Dispatch<EntitiesSearch.StoreAction<E, K>>;
Expand Down
56 changes: 56 additions & 0 deletions sources/client/src/hooks/use-search.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
import EntitiesSearch from '@types';
import React from 'react';

import { useThrottle } from '@wordpress/compose';
import { doAction } from '@wordpress/hooks';

import { Set } from '../vo/set';

type SearchPhrase = Parameters<EntitiesSearch.SearchControl['onChange']>[0];
type SearchFunc = (phrase: SearchPhrase) => void;

export function useSearch<E, K>(
setSearchPhrase: (search: string) => void,
searchEntities: EntitiesSearch.SearchEntitiesFunction<E, K>,
kind: EntitiesSearch.Kind<K>,
entities: EntitiesSearch.Entities<E>,
dispatch: React.Dispatch<EntitiesSearch.StoreAction<E, K>>
): SearchFunc {
return useThrottle(
(phrase: SearchPhrase) => {
const _phrase = extractPhrase(phrase);

setSearchPhrase(_phrase);

searchEntities(_phrase, kind, {
exclude: entities,
})
.then((result) =>
dispatch({
type: 'UPDATE_CURRENT_ENTITIES_OPTIONS',
currentEntitiesOptions: result,
})
)
.catch((error) => {
doAction('wp-entities-search.on-search.error', error);
const emptySet = new Set<EntitiesSearch.ControlOption<E>>();
dispatch({
type: 'UPDATE_CURRENT_ENTITIES_OPTIONS',
currentEntitiesOptions: emptySet,
});
return emptySet;
});
},
300,
{ leading: false, trailing: true }
);
}

function extractPhrase(phraseOrEvent: SearchPhrase): string {
const phrase =
typeof phraseOrEvent === 'string'
? phraseOrEvent
: phraseOrEvent.target.value;

return phrase.trim();
}

0 comments on commit cb45612

Please sign in to comment.