UNPKG

@kobalte/core

Version:

Unstyled components and primitives for building accessible web apps and design systems with SolidJS.

120 lines (115 loc) 3.89 kB
import { createRegisterId } from "./JNCCF6MP.jsx"; import { Polymorphic } from "./FLVHQV4A.jsx"; // src/form-control/create-form-control.tsx import { access, createGenerateId, mergeDefaultProps } from "@kobalte/utils"; import { createMemo, createSignal, createUniqueId } from "solid-js"; var FORM_CONTROL_PROP_NAMES = [ "id", "name", "validationState", "required", "disabled", "readOnly" ]; function createFormControl(props) { const defaultId = `form-control-${createUniqueId()}`; const mergedProps = mergeDefaultProps({ id: defaultId }, props); const [labelId, setLabelId] = createSignal(); const [fieldId, setFieldId] = createSignal(); const [descriptionId, setDescriptionId] = createSignal(); const [errorMessageId, setErrorMessageId] = createSignal(); const getAriaLabelledBy = (fieldId2, fieldAriaLabel, fieldAriaLabelledBy) => { const hasAriaLabelledBy = fieldAriaLabelledBy != null || labelId() != null; return [ fieldAriaLabelledBy, labelId(), // If there is both an aria-label and aria-labelledby, add the field itself has an aria-labelledby hasAriaLabelledBy && fieldAriaLabel != null ? fieldId2 : void 0 ].filter(Boolean).join(" ") || void 0; }; const getAriaDescribedBy = (fieldAriaDescribedBy) => { return [ descriptionId(), // Use aria-describedby for error message because aria-errormessage is unsupported using VoiceOver or NVDA. // See https://github.com/adobe/react-spectrum/issues/1346#issuecomment-740136268 errorMessageId(), fieldAriaDescribedBy ].filter(Boolean).join(" ") || void 0; }; const dataset = createMemo(() => ({ "data-valid": access(mergedProps.validationState) === "valid" ? "" : void 0, "data-invalid": access(mergedProps.validationState) === "invalid" ? "" : void 0, "data-required": access(mergedProps.required) ? "" : void 0, "data-disabled": access(mergedProps.disabled) ? "" : void 0, "data-readonly": access(mergedProps.readOnly) ? "" : void 0 })); const formControlContext = { name: () => access(mergedProps.name) ?? access(mergedProps.id), dataset, validationState: () => access(mergedProps.validationState), isRequired: () => access(mergedProps.required), isDisabled: () => access(mergedProps.disabled), isReadOnly: () => access(mergedProps.readOnly), labelId, fieldId, descriptionId, errorMessageId, getAriaLabelledBy, getAriaDescribedBy, generateId: createGenerateId(() => access(mergedProps.id)), registerLabel: createRegisterId(setLabelId), registerField: createRegisterId(setFieldId), registerDescription: createRegisterId(setDescriptionId), registerErrorMessage: createRegisterId(setErrorMessageId) }; return { formControlContext }; } // src/form-control/form-control-context.tsx import { createContext, useContext } from "solid-js"; var FormControlContext = createContext(); function useFormControlContext() { const context = useContext(FormControlContext); if (context === void 0) { throw new Error( "[kobalte]: `useFormControlContext` must be used within a `FormControlContext.Provider` component" ); } return context; } // src/form-control/form-control-description.tsx import { mergeDefaultProps as mergeDefaultProps2 } from "@kobalte/utils"; import { createEffect, onCleanup } from "solid-js"; function FormControlDescription(props) { const context = useFormControlContext(); const mergedProps = mergeDefaultProps2( { id: context.generateId("description") }, props ); createEffect(() => onCleanup(context.registerDescription(mergedProps.id))); return <Polymorphic as="div" {...context.dataset()} {...mergedProps} />; } export { FORM_CONTROL_PROP_NAMES, createFormControl, FormControlContext, useFormControlContext, FormControlDescription };