import type { JSX, ValidComponent } from "@solidjs/web"; import { dynamic } from "@solidjs/web"; import { createSignal, omit } from "solid-js"; import { FieldsetContext, type FieldsetContextValue, } from "../../internals/fieldset-context.ts"; import { mergeRootProps } from "../../internals/merge-root-props"; import { resolveClassStyle } from "../../internals/resolve-class-style"; import type { BaseUIComponentProps } from "../../internals/types"; export interface FieldsetRootState { /** Whether the fieldset group is disabled. */ disabled: boolean; } export interface FieldsetRootProps extends Omit< BaseUIComponentProps<"fieldset", FieldsetRootState>, "aria-labelledby" > { /** Tag/component to render. Defaults to `"fieldset"`. */ as?: ValidComponent; /** * Whether the whole fieldset group should ignore user interaction. * @default false */ disabled?: boolean | undefined; } /** * Groups a shared legend with related controls. * Renders a `
` element (or `as` override). * * Documentation: [Base UI Fieldset](https://base-ui.com/react/components/fieldset) */ export function FieldsetRoot(props: FieldsetRootProps): JSX.Element { const disabled = (): boolean => props.disabled ?? false; // Internal legend-id registration: `` writes its // generated id here during setup (owned scope) and clears it on cleanup. // `ownedWrite` opts out of Solid 2's write-in-owned-scope check — this is // pure internal plumbing, never surfaced to consumers. const [legendId, setLegendId] = createSignal(undefined, { ownedWrite: true, name: "fieldset.legendId", }); const contextValue: FieldsetContextValue = { disabled, legendId, setLegendId, present: true, }; const userStyling = resolveClassStyle(props, () => ({ disabled: disabled(), })); const userHtmlProps = omit( props, "class", "style", "attrs", "as", "disabled", "children", ) as Record; const internalProps = { get disabled() { // Emit the native `disabled` attribute so the browser actually // disables form controls inside the fieldset. return disabled(); }, get "data-disabled"(): "" | undefined { return disabled() ? "" : undefined; }, get "aria-labelledby"() { // Empty string keeps the key present in ownKeys from first render // so a late-mounting legend can write into `legendId` and have // the binding update. Matches progress/meter-root pattern. return legendId() ?? ""; }, }; const styledUserProps = mergeRootProps(userStyling, userHtmlProps); const merged = mergeRootProps(internalProps, styledUserProps); const Tag = dynamic(() => props.as ?? "fieldset"); return ( {props.children} ); }