Skip to content

Commit

Permalink
fix: rework loading mechanism
Browse files Browse the repository at this point in the history
  • Loading branch information
cristinecula committed Nov 19, 2024
1 parent e86fffb commit d09bb44
Show file tree
Hide file tree
Showing 8 changed files with 64 additions and 72 deletions.
51 changes: 27 additions & 24 deletions src/autocomplete/autocomplete.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,17 @@
import { html } from 'lit-html'; // eslint-disable-line object-curly-newline
import '@neovici/cosmoz-input';
import './skeleton-span';

import { useHost } from '@neovici/cosmoz-utils/hooks/use-host';
import { useImperativeApi } from '@neovici/cosmoz-utils/hooks/use-imperative-api';
import { useCallback } from '@pionjs/pion';
import { html, nothing } from 'lit-html'; // eslint-disable-line object-curly-newline
import { live } from 'lit-html/directives/live.js';
import { until } from 'lit-html/directives/until.js';
import { when } from 'lit-html/directives/when.js';
import { useCallback, useEffect, useState } from '@pionjs/pion';
import { useHost } from '@neovici/cosmoz-utils/hooks/use-host';
import { useImperativeApi } from '@neovici/cosmoz-utils/hooks/use-imperative-api';
import '@neovici/cosmoz-input';
import { useAutocomplete, Props as Base, RProps } from './use-autocomplete';
import { listbox } from '../listbox';
import style from './styles.css';
import { selection } from './selection';
import style from './styles.css';
import { Props as Base, RProps, useAutocomplete } from './use-autocomplete';
import { useOverflow } from './use-overflow';

export interface Props<I> extends Base<I> {
Expand All @@ -35,6 +37,8 @@ const inputParts = ['input', 'control', 'label', 'line', 'error', 'wrap']
.map((part) => `${part}: input-${part}`)
.join();

const blank = () => nothing;

const autocomplete = <I>(props: AProps<I>) => {
const {
active,
Expand Down Expand Up @@ -67,14 +71,6 @@ const autocomplete = <I>(props: AProps<I>) => {
[host, value],
);

const [loading, setLoading] = useState(false);
useEffect(() => {
// TODO: handle `source$` changes that occur while `loading`
setLoading(true);
const endLoading = setLoading.bind(null, false);
source$.then(endLoading, endLoading);
}, [source$]);

useImperativeApi(
{
focus: () =>
Expand Down Expand Up @@ -130,14 +126,21 @@ const autocomplete = <I>(props: AProps<I>) => {
})}
</cosmoz-input>
${when(active && (loading || items.length > 0) && !(isSingle && !showSingle), () =>
listbox<I>({
...props,
anchor,
items,
multi: !isOne,
loading,
}),
${when(active && !(isSingle && !showSingle), () =>
listbox<I>(
{
...props,
anchor,
items,
multi: !isOne,
},
when(items.length < 5, () =>
until(
source$.then(blank, blank),
html`<cosmoz-autocomplete-skeleton-span></cosmoz-autocomplete-skeleton-span>`,
),
),
),
)}`;
},
Autocomplete = <I>(props: Props<I>) => {
Expand Down Expand Up @@ -167,4 +170,4 @@ const autocomplete = <I>(props: AProps<I>) => {
'wrap',
] as const;

export { autocomplete, Autocomplete, observedAttributes, style };
export { Autocomplete, autocomplete, observedAttributes, style };
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,14 @@ const style = css`
background-position: right;
animation: sweep 1.5s cubic-bezier(0.3, 1, 0.3, 1) infinite;
border-radius: 3px;
width: calc(100% - 35px);
width: calc(100% - 50px);
max-width: 150px;
height: 20px;
margin: 10px 0 10px 33px;
}
:host-context([show-single]) {
margin-left: 20px;
}
@keyframes sweep {
Expand Down
39 changes: 20 additions & 19 deletions src/listbox/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,18 +37,19 @@ const Listbox = <I>(props: Props<I>) => {
);

return html`<div
class="items"
${ref((el) => (listRef.current = el))}
style="min-height: ${height}px"
>
<div virtualizer-sizer></div>
${virtualize({
items,
renderItem,
scroller: true,
layout,
})}
</div>`;
class="items"
${ref((el) => (listRef.current = el))}
style="min-height: ${height}px"
>
<div virtualizer-sizer></div>
${virtualize({
items,
renderItem,
scroller: true,
layout,
})}
</div>
<slot></slot>`;
};

const supportsPopover = () => {
Expand All @@ -71,15 +72,15 @@ customElements.define(
component<Props<unknown>>(Listbox, { styleSheets: [sheet(style)] }),
);

export const listbox = <I>({
multi,
...thru
}: Props<I> & { multi?: boolean }) => {
return html`<cosmoz-listbox
export const listbox = <I>(
{ multi, ...thru }: Props<I> & { multi?: boolean },
content: unknown,
) =>
html`<cosmoz-listbox
${ref(showPopover)}
popover="manual"
part="listbox"
?multi=${multi}
...=${spreadProps(props(properties)(thru))}
></cosmoz-listbox>`;
};
>${content}</cosmoz-listbox
>`;
14 changes: 3 additions & 11 deletions src/listbox/item-renderer.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
import './skeleton-span';

import { identity } from '@neovici/cosmoz-utils/function';
import { html, TemplateResult } from 'lit-html';
import { loadingSymbol, mark } from './util';
import { mark } from './util';

export interface Opts<I> {
highlight: (i: number) => void;
Expand All @@ -15,15 +13,15 @@ export interface Opts<I> {
export type Render<I> = (content: unknown, item: I, i: number) => unknown;

export type ItemRenderer<I> = (
item: I | typeof loadingSymbol,
item: I,
i: number,
opts: Opts<I>,
) => TemplateResult;

export const itemRenderer =
<I>(render: Render<I> = identity) =>
(
item: I | typeof loadingSymbol,
item: I,
i: number,
{
highlight,
Expand All @@ -39,12 +37,6 @@ export const itemRenderer =
textual: (i: I) => string;
},
): TemplateResult => {
if (item === loadingSymbol) {
return html`<div class="item">
<cosmoz-autocomplete-skeleton-span></cosmoz-autocomplete-skeleton-span>
</div>`;
}

const text = textual(item),
content = mark(text, query),
rendered = render(content, item, i);
Expand Down
6 changes: 3 additions & 3 deletions src/listbox/style.css.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ const style = css`
0 1px 8px 0 rgba(0, 0, 0, 0.12),
0 3px 3px -2px rgba(0, 0, 0, 0.4);
text-transform: var(--cosmoz-autocomplete-listbox-text-transform, initial);
overflow: hidden;
}
:host(:popover-open) {
box-sizing: border-box;
Expand All @@ -32,7 +33,6 @@ const style = css`
position: relative;
overflow-y: auto;
contain: layout paint !important;
height: 100%;
}
.item {
font-size: 14px;
Expand Down Expand Up @@ -112,8 +112,8 @@ export const styles = ({
itemHeight: number;
}) => css`
:host {
min-height: ${itemHeight}px;
height: ${height}px;
xmin-height: ${itemHeight}px;
xheight: ${height}px;
}
.item {
Expand Down
12 changes: 3 additions & 9 deletions src/listbox/use-listbox.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { useMemo } from '@pionjs/pion';
import { useHost } from '@neovici/cosmoz-utils/hooks/use-host';
import { usePosition, Placement } from '@neovici/cosmoz-dropdown/use-position';
import { byValue, loadingSymbol } from './util';
import { byValue } from './util';
import { useItems } from './use-items';
import { useRenderItem, ItemRenderer } from './use-render-item';

Expand Down Expand Up @@ -36,7 +36,6 @@ export interface Props<I> {
anchor?: () => HTMLElement | null;
confinement?: HTMLElement;
placement?: Placement;
loading?: boolean;
}

export const useListbox = <I>({
Expand All @@ -50,21 +49,16 @@ export const useListbox = <I>({
itemRenderer,
itemHeight = 40,
itemLimit = 5,
loading,
...thru
}: Props<I>) => {
const isSelected = useMemo(
() => byValue(value, valueProperty),
[value, valueProperty],
),
// TODO: investigate if we can drop this
__items = useMemo(() => _items.slice(), [_items, isSelected]),
items: (I | typeof loadingSymbol)[] = useMemo(
() => (loading ? [...__items, loadingSymbol] : __items),
[loading, __items],
),
items = useMemo(() => _items.slice(), [_items, isSelected]),
{ position, highlight, select } = useItems({
items: __items,
items,
onSelect,
defaultIndex: isNaN(defaultIndex as number)
? undefined
Expand Down
3 changes: 1 addition & 2 deletions src/listbox/use-render-item.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,14 @@ import {
ItemRenderer,
Opts,
} from './item-renderer';
import { loadingSymbol } from './util';

export const useRenderItem = <I>({
itemRenderer = mkItemRenderer<I>(),
...meta
}: Opts<I> & { itemRenderer?: ItemRenderer<I> }) => {
const info = useMeta<Opts<I>>(meta);
return useCallback(
(item: I | typeof loadingSymbol, i: number) => itemRenderer(item, i, info),
(item: I, i: number) => itemRenderer(item, i, info),
[info, itemRenderer]
);
};
Expand Down
4 changes: 1 addition & 3 deletions src/listbox/util.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,4 @@ export const mark = (text: string, query: string) => {
html`<mark>${text.slice(i, end)}</mark>`,
text.slice(end),
];
};

export const loadingSymbol: unique symbol = Symbol('loading');
};

0 comments on commit d09bb44

Please sign in to comment.