import type { JSX } from 'solid-js'; import { createComponent, createUniqueId, mergeProps } from 'solid-js'; import { omitProps } from 'solid-use/props'; import type { DisclosureStateControlledOptions, DisclosureStateRenderProps, DisclosureStateUncontrolledOptions, } from '../../states/create-disclosure-state'; import { DisclosureStateProvider, createDisclosureState, } from '../../states/create-disclosure-state'; import createDynamic from '../../utils/create-dynamic'; import type { DynamicProps, HeadlessProps, ValidConstructor } from '../../utils/dynamic-prop'; import { createARIADisabledState, createDisabledState, createExpandedState, } from '../../utils/state-props'; import type { Prettify } from '../../utils/types'; import { DisclosureContext } from './DisclosureContext'; import { DISCLOSURE_TAG } from './tags'; export type DisclosureControlledBaseProps = Prettify< DisclosureStateControlledOptions & DisclosureStateRenderProps >; export type DisclosureControlledProps = HeadlessProps< T, DisclosureControlledBaseProps >; export type DisclosureUncontrolledBaseProps = Prettify< DisclosureStateUncontrolledOptions & DisclosureStateRenderProps >; export type DisclosureUncontrolledProps = HeadlessProps< T, DisclosureUncontrolledBaseProps >; export type DisclosureProps = | DisclosureControlledProps | DisclosureUncontrolledProps; function isDisclosureUncontrolled( props: DisclosureProps, ): props is DisclosureUncontrolledProps { return 'defaultOpen' in props; } /** * A button that shows and hides a section. The simplest stateful component in * the library, and the base the dialog-like components are built on. * * Renders a `
` by default. * * @see {@link https://github.com/lxsmnsyc/terracotta/blob/main/docs/components/disclosure.md} */ export function Disclosure( props: DisclosureProps, ): JSX.Element { const ownerID = createUniqueId(); const buttonID = createUniqueId(); const panelID = createUniqueId(); const state = createDisclosureState(props); return createComponent(DisclosureContext.Provider, { value: { ownerID, buttonID, panelID, }, get children() { return createDynamic( () => props.as ?? 'div', mergeProps( DISCLOSURE_TAG, createDisabledState(() => state.disabled()), createARIADisabledState(() => state.disabled()), createExpandedState(() => state.isOpen()), isDisclosureUncontrolled(props) ? omitProps(props, [ 'as', 'children', 'defaultOpen', 'disabled', 'onChange', 'onClose', 'onOpen', ]) : omitProps(props, [ 'as', 'children', 'isOpen', 'disabled', 'onChange', 'onClose', 'onOpen', ]), { get children() { return createComponent(DisclosureStateProvider, { state, get children() { return props.children; }, }); }, }, ) as DynamicProps, ); }, }); }