astro-reactive-form/packages/form/components/Form.astro

141 lines
3.7 KiB
Text

---
import type { HTTPSubmitMethod, Submit } from '@astro-reactive/common';
import { FormGroup, FormControl } from '../core';
import FieldSet from './FieldSet.astro';
import Field from './Field.astro';
import ShortUniqueId from 'short-unique-id';
export interface Props {
/**
* Determines how the form is rendered
*/
formGroups: FormGroup | FormGroup[];
/**
* Sets the `action` attribute for the form. Set this to the URL that processes the form submission.
* @see https://developer.mozilla.org/en-US/docs/Web/HTML/Element/form#attr-method
*/
action?: string;
/**
* Sets the `method` attribute for the form. Set this to the HTTP method to submit the form: 'post', 'get', or 'dialog'.
* @see https://developer.mozilla.org/en-US/docs/Web/HTML/Element/form#attr-method
*/
method?: HTTPSubmitMethod;
/**
* Sets the whole form as read-only.
*/
readOnly?: boolean;
/**
* When used with our `validator` package, the `Form` component is able to render validation hints when `showValidationHints` is set to true:
* - asterisks on required controls' labels
* - controls with validation errors are colored red
*/
showValidationHints?: boolean;
/**
* A special button that triggers the submit event for a form.
*/
submitControl?: Submit;
/**
* Sets the form to use light or dark mode.
*/
theme?: 'light' | 'dark';
/**
* When used with our `validator` package, the `Form` component is able to render validation errors on server-side rendering when `validateOnLoad` is set to true. Otherwise, the validation errors will only be rendered on the client-side upon user interaction.
*/
validateOnLoad?: boolean;
}
const {
submitControl,
formGroups = [],
theme,
showValidationHints = false,
validateOnLoad = true,
readOnly = false,
action = '',
method = 'get',
} = Astro.props;
const uid = new ShortUniqueId({ length: 9 });
const formTheme = theme ?? 'light';
const formName = Array.isArray(formGroups) ? null : formGroups?.name || null;
const formId = Array.isArray(formGroups) ? uid() : formGroups?.id || null;
// if `validateOnLoad` prop is true,
// it should forced all FormControl to validate on load
if (validateOnLoad) {
if (Array.isArray(formGroups)) {
formGroups.forEach((group) =>
group.controls.forEach((control) => {
if ('setValidateOnLoad' in control) {
control.setValidateOnLoad(validateOnLoad);
}
})
);
} else {
formGroups.controls.forEach((control) => {
if ('setValidateOnLoad' in control) {
control.setValidateOnLoad(validateOnLoad);
}
});
}
}
---
<form
class={formTheme}
name={formName}
id={formId}
data-validator-hints={showValidationHints.toString()}
action={action}
method={method}
>
{
Array.isArray(formGroups)
? formGroups?.map((group) => (
<FieldSet showValidationHints={showValidationHints} group={group} readOnly={readOnly} />
))
: formGroups?.controls.map((control) => (
<Field showValidationHints={showValidationHints} control={control} readOnly={readOnly} />
))
}
{
submitControl && (
<Field showValidationHints={showValidationHints} control={new FormControl(submitControl)} />
)
}
</form>
<style>
.light {
color-scheme: light;
}
.dark {
color-scheme: dark;
}
</style>
<style is:global>
[data-validator-hints='true'][data-validator-error='true'],
[data-validator-hints='true'] [data-validator-error='true'] {
color: red;
border-color: red;
}
[data-validator-hints='true'][data-validator-warn='true'],
[data-validator-hints='true'] [data-validator-warn='true'] {
color: orange;
border-color: orange;
}
[data-validator-hints='true'][data-validator-info='true'],
[data-validator-hints='true'] [data-validator-info='true'] {
color: green;
border-color: green;
}
</style>