import type { JSX, ValidComponent } from "@solidjs/web"; /** * `` — visual indicator shown inside a checked * ``. Mirrors React. */ import { dynamic } from "@solidjs/web"; import { createMemo, omit, Show } from "solid-js"; import { composeRefs, userRef } from "../../internals/compose-refs"; import type { MutableRef } from "../../internals/floating-ui/types"; import { mergeRootProps } from "../../internals/merge-root-props"; import { useOpenChangeComplete } from "../../internals/popups/use-open-change-complete"; import { resolveClassStyle } from "../../internals/resolve-class-style"; import type { BaseUIComponentProps } from "../../internals/types"; import { type TransitionStatus, useTransitionStatus, } from "../../internals/use-transition-status/use-transition-status"; import { useMenuCheckboxItemContext } from "../checkbox-item/menu-checkbox-item-context"; export interface MenuCheckboxItemIndicatorState { checked: boolean; disabled: boolean; highlighted: boolean; transitionStatus: TransitionStatus; } export interface MenuCheckboxItemIndicatorProps extends BaseUIComponentProps<"span", MenuCheckboxItemIndicatorState> { /** * Tag/component to render. Defaults to `"span"`. Replaces the * pre-spike `render` prop (axis G). */ as?: ValidComponent; /** @default false */ keepMounted?: boolean | undefined; } export function MenuCheckboxItemIndicator( props: MenuCheckboxItemIndicatorProps, ): JSX.Element { const item = useMenuCheckboxItemContext(); const indicatorRef: MutableRef = { current: null }; const setRef = (el: HTMLElement | null): void => { indicatorRef.current = el; }; const { mounted, transitionStatus, setMounted } = useTransitionStatus( item.checked, ); useOpenChangeComplete({ open: item.checked, ref: indicatorRef, onComplete: () => { if (!item.checked()) setMounted(false); }, }); const keepMounted = (): boolean => props.keepMounted ?? false; const shouldRender = (): boolean => keepMounted() || mounted(); const state = createMemo(() => ({ checked: item.checked(), disabled: item.disabled(), highlighted: item.highlighted(), transitionStatus: transitionStatus(), })); const internal = { "aria-hidden": true, get "data-highlighted"() { return state().highlighted ? "" : undefined; }, get "data-disabled"() { return state().disabled ? "" : undefined; }, get "data-checked"() { return state().checked ? "" : undefined; }, get "data-unchecked"() { return state().checked ? undefined : ""; }, get "data-starting-style"() { return state().transitionStatus === "starting" ? "" : undefined; }, get "data-ending-style"() { return state().transitionStatus === "ending" ? "" : undefined; }, }; const userClassStyle = resolveClassStyle(props, () => state()); const userProps = omit( props, "as", "class", "style", "attrs", "keepMounted", ); let merged: Record = mergeRootProps( internal, userClassStyle, ); merged = mergeRootProps(merged, userProps); const Tag = dynamic(() => props.as ?? "span"); return ( ); }