import type { JSX, ValidComponent } from "@solidjs/web"; import { dynamic } from "@solidjs/web"; import { omit } from "solid-js"; import { useCompositeRootContext } from "../internals/composite/composite-context.ts"; import { useCompositeListItem } from "../internals/composite/composite-list.tsx"; import { mergeRootProps } from "../internals/merge-root-props"; import { resolveClassStyle } from "../internals/resolve-class-style"; import type { BaseUIComponentProps, Orientation } from "../internals/types"; import { type ToolbarRootItemMetadata, useToolbarRootContext, } from "./toolbar-root-context.ts"; export interface ToolbarLinkState { orientation: Orientation; } export interface ToolbarLinkProps extends BaseUIComponentProps<"a", ToolbarLinkState> { /** Tag/component to render. Defaults to `"a"`. */ as?: ValidComponent; } // Links participate in arrow navigation but cannot be "disabled" in HTML — so // their metadata always reports `focusableWhenDisabled: true` (matches React: // the flag is only used for deriving `disabledIndices`). const LINK_METADATA: ToolbarRootItemMetadata = { focusableWhenDisabled: true, }; /** * A link inside a ``. Renders an `` element (or `as` override) * and participates in arrow-key navigation through the composite root. */ export function ToolbarLink(props: ToolbarLinkProps): JSX.Element { const toolbar = useToolbarRootContext(); const rootContext = useCompositeRootContext(true); const orientation = (): Orientation => toolbar.orientation(); const { ref: listItemRef, index: itemIndex } = useCompositeListItem({ metadata: LINK_METADATA, }); // Metadata reaches `` via the composite-list sorted map // (see the header comment in toolbar-root.tsx) — no separate registry. const composedRef = (el: HTMLElement | null): void => { listItemRef(el); }; const compositeTabIndex = (): number | undefined => { if (!rootContext) return undefined; return rootContext.highlightedIndex() === itemIndex() ? 0 : -1; }; const onCompositeFocus = (): void => { if (!rootContext) return; const i = itemIndex(); if (i >= 0) rootContext.onHighlightedIndexChange(i); }; const userClassStyle = resolveClassStyle(props, () => ({ orientation: orientation(), })); const userHtmlProps = omit(props, "as", "class", "style", "attrs") as Record< string, unknown >; const internalProps = { ref: composedRef, get tabIndex() { return compositeTabIndex(); }, onFocus: onCompositeFocus, get "data-orientation"() { return orientation(); }, }; const merged = mergeRootProps( mergeRootProps(internalProps, userClassStyle), userHtmlProps, ); const Tag = dynamic(() => props.as ?? "a"); return ; }