import type { JSX } from 'solid-js'; import { createComponent, createUniqueId, mergeProps } from 'solid-js'; import { omitProps } from 'solid-use/props'; import createDynamic from '../../utils/create-dynamic'; import type { DynamicProps, HeadlessPropsWithRef, ValidConstructor, } from '../../utils/dynamic-prop'; import { createForwardRef } from '../../utils/dynamic-prop'; import { focusNext, focusPrev } from '../../utils/focus-navigation'; import getFocusableElements from '../../utils/focus-query'; import { FeedContext } from './FeedContext'; import { FEED_TAG } from './tags'; export interface FeedBaseProps { size: number; busy?: boolean; } export type FeedProps = HeadlessPropsWithRef; /** * A stream of articles with the feed keyboard pattern: Page Down * and Page Up move between articles, * Ctrl+Home and Ctrl+End jump to * the ends. Set `size` to the total number of articles, or `-1` when it is * unknown, and `busy` while more are loading. * * Renders a `
` by default. * * @see {@link https://github.com/lxsmnsyc/terracotta/blob/main/docs/components/feed.md} */ export function Feed(props: FeedProps): JSX.Element { const ownerID = createUniqueId(); const labelID = createUniqueId(); const contentID = createUniqueId(); const [ref, setRef] = createForwardRef(props); return createComponent(FeedContext.Provider, { value: { ownerID, labelID, contentID, get size() { return props.size; }, get busy() { return !!props.busy; }, focusNext() { const current = ref(); if (current instanceof HTMLElement) { focusNext(getFocusableElements(document.documentElement), current, false, false); } }, focusPrev() { const current = ref(); if (current instanceof HTMLElement) { focusPrev(getFocusableElements(document.documentElement), current, false, false); } }, }, get children() { return createDynamic( () => props.as ?? ('div' as T), mergeProps( FEED_TAG, { id: ownerID, ref: setRef, }, omitProps(props, ['as', 'busy', 'size']), ) as DynamicProps, ); }, }); }