feat(form): implement unique IDs (#182)
* Added Short Unique ID npm library * Added unique ID to form-control * Added unique ID to form-group * Unique ID added to <form> * Added unique IDs to control components * Added IDs to label and fieldset * Update Form.astro with requested changes Co-authored-by: Ayo Ayco <ayo@ayco.io> * Adjustments for requested changes. Co-authored-by: Ayo Ayco <ayo@ayco.io>
This commit is contained in:
parent
d02c1e4081
commit
93a8d49f0a
11 changed files with 41 additions and 9 deletions
17
package-lock.json
generated
17
package-lock.json
generated
|
@ -17,7 +17,8 @@
|
||||||
"packages/common"
|
"packages/common"
|
||||||
],
|
],
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"prettier-plugin-astro": "^0.7.0"
|
"prettier-plugin-astro": "^0.7.0",
|
||||||
|
"short-unique-id": "^4.4.4"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"apps/demo": {
|
"apps/demo": {
|
||||||
|
@ -7578,6 +7579,15 @@
|
||||||
"resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.2.0.tgz",
|
||||||
"integrity": "sha512-gfFQZrcTc8CnKXp6Y4/CBT3fTc0OVuDofpre4aEeEpSBPV5X5v4+Vmx+8snU7RLPrNHPKSgLxGo9YuQzz20o+w=="
|
"integrity": "sha512-gfFQZrcTc8CnKXp6Y4/CBT3fTc0OVuDofpre4aEeEpSBPV5X5v4+Vmx+8snU7RLPrNHPKSgLxGo9YuQzz20o+w=="
|
||||||
},
|
},
|
||||||
|
"node_modules/short-unique-id": {
|
||||||
|
"version": "4.4.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/short-unique-id/-/short-unique-id-4.4.4.tgz",
|
||||||
|
"integrity": "sha512-oLF1NCmtbiTWl2SqdXZQbo5KM1b7axdp0RgQLq8qCBBLoq+o3A5wmLrNM6bZIh54/a8BJ3l69kTXuxwZ+XCYuw==",
|
||||||
|
"bin": {
|
||||||
|
"short-unique-id": "bin/short-unique-id",
|
||||||
|
"suid": "bin/short-unique-id"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/signal-exit": {
|
"node_modules/signal-exit": {
|
||||||
"version": "3.0.7",
|
"version": "3.0.7",
|
||||||
"resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz",
|
"resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz",
|
||||||
|
@ -14421,6 +14431,11 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"short-unique-id": {
|
||||||
|
"version": "4.4.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/short-unique-id/-/short-unique-id-4.4.4.tgz",
|
||||||
|
"integrity": "sha512-oLF1NCmtbiTWl2SqdXZQbo5KM1b7axdp0RgQLq8qCBBLoq+o3A5wmLrNM6bZIh54/a8BJ3l69kTXuxwZ+XCYuw=="
|
||||||
|
},
|
||||||
"signal-exit": {
|
"signal-exit": {
|
||||||
"version": "3.0.7",
|
"version": "3.0.7",
|
||||||
"resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz",
|
"resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz",
|
||||||
|
|
|
@ -38,6 +38,7 @@
|
||||||
"packages/common"
|
"packages/common"
|
||||||
],
|
],
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"prettier-plugin-astro": "^0.7.0"
|
"prettier-plugin-astro": "^0.7.0",
|
||||||
|
"short-unique-id": "^4.4.4"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,7 +11,7 @@ export interface Props {
|
||||||
const { group, showValidationHints, readOnly = false } = Astro.props;
|
const { group, showValidationHints, readOnly = false } = Astro.props;
|
||||||
---
|
---
|
||||||
|
|
||||||
<fieldset id={group.name} name={group.name}>
|
<fieldset id={group.id} name={group.name}>
|
||||||
{group.name && <legend>{group.name}</legend>}
|
{group.name && <legend>{group.name}</legend>}
|
||||||
{
|
{
|
||||||
group?.controls?.map((control) => (
|
group?.controls?.map((control) => (
|
||||||
|
|
|
@ -3,6 +3,7 @@ import type { Submit } from '@astro-reactive/common';
|
||||||
import { FormGroup, FormControl } from '../core';
|
import { FormGroup, FormControl } from '../core';
|
||||||
import FieldSet from './FieldSet.astro';
|
import FieldSet from './FieldSet.astro';
|
||||||
import Field from './Field.astro';
|
import Field from './Field.astro';
|
||||||
|
import ShortUniqueId from 'short-unique-id';
|
||||||
|
|
||||||
export interface Props {
|
export interface Props {
|
||||||
formGroups: FormGroup | FormGroup[];
|
formGroups: FormGroup | FormGroup[];
|
||||||
|
@ -20,14 +21,16 @@ const {
|
||||||
readOnly = false,
|
readOnly = false,
|
||||||
} = Astro.props;
|
} = Astro.props;
|
||||||
|
|
||||||
|
const uid = new ShortUniqueId({ length: 9 });
|
||||||
const formTheme = theme ?? 'light';
|
const formTheme = theme ?? 'light';
|
||||||
const formName = Array.isArray(formGroups) ? null : formGroups?.name || null;
|
const formName = Array.isArray(formGroups) ? null : formGroups?.name || null;
|
||||||
|
const formId = Array.isArray(formGroups) ? uid() : formGroups?.id || null;
|
||||||
---
|
---
|
||||||
|
|
||||||
<form
|
<form
|
||||||
class={formTheme}
|
class={formTheme}
|
||||||
name={formName}
|
name={formName}
|
||||||
id={formName}
|
id={formId}
|
||||||
data-validator-hints={showValidationHints.toString()}
|
data-validator-hints={showValidationHints.toString()}
|
||||||
>
|
>
|
||||||
{
|
{
|
||||||
|
|
|
@ -16,7 +16,7 @@ const isRequired: boolean = showValidationHints && validators.includes('validato
|
||||||
|
|
||||||
{
|
{
|
||||||
control.label && control.type !== "checkbox" && (
|
control.label && control.type !== "checkbox" && (
|
||||||
<label for={control.name} data-validation-required={isRequired ? "true" : null}>
|
<label for={control.id} data-validation-required={isRequired ? "true" : null}>
|
||||||
{control.label}
|
{control.label}
|
||||||
</label>
|
</label>
|
||||||
)
|
)
|
||||||
|
@ -26,7 +26,7 @@ const isRequired: boolean = showValidationHints && validators.includes('validato
|
||||||
|
|
||||||
{
|
{
|
||||||
control.label && control.type === "checkbox" && (
|
control.label && control.type === "checkbox" && (
|
||||||
<label for={control.name} data-validation-required={isRequired ? "true" : null}>
|
<label for={control.id} data-validation-required={isRequired ? "true" : null}>
|
||||||
{control.label}
|
{control.label}
|
||||||
</label>
|
</label>
|
||||||
)
|
)
|
||||||
|
|
|
@ -24,7 +24,7 @@ const options = control.options.map((option: string | ControlOption) => {
|
||||||
|
|
||||||
<select
|
<select
|
||||||
name={control.name}
|
name={control.name}
|
||||||
id={control.name}
|
id={control.id}
|
||||||
disabled={readOnly || null}
|
disabled={readOnly || null}
|
||||||
>
|
>
|
||||||
{
|
{
|
||||||
|
|
|
@ -30,7 +30,7 @@ const validatorAttributes: Record<string, string> = validators?.reduce((prev, va
|
||||||
|
|
||||||
<input
|
<input
|
||||||
name={control.name}
|
name={control.name}
|
||||||
id={control.name}
|
id={control.id}
|
||||||
type={control.type as InputType}
|
type={control.type as InputType}
|
||||||
value={control.value?.toString()}
|
value={control.value?.toString()}
|
||||||
checked={control.value === 'checked'}
|
checked={control.value === 'checked'}
|
||||||
|
|
|
@ -27,6 +27,7 @@ const options = control.options.map((option: string | ControlOption) => {
|
||||||
<div class="radio-option">
|
<div class="radio-option">
|
||||||
<input
|
<input
|
||||||
type="radio"
|
type="radio"
|
||||||
|
id={control.id}
|
||||||
name={control.name}
|
name={control.name}
|
||||||
value={option.value}
|
value={option.value}
|
||||||
checked={option.value === control.value}
|
checked={option.value === control.value}
|
||||||
|
|
|
@ -27,7 +27,7 @@ const validatorAttributes: Record<string, string> = validators?.reduce((prev, va
|
||||||
|
|
||||||
<textarea
|
<textarea
|
||||||
name={control.name}
|
name={control.name}
|
||||||
id={control.name}
|
id={control.id}
|
||||||
placeholder={control?.placeholder}
|
placeholder={control?.placeholder}
|
||||||
rows={control?.rows ?? 3}
|
rows={control?.rows ?? 3}
|
||||||
cols={control?.cols ?? 21}
|
cols={control?.cols ?? 21}
|
||||||
|
|
|
@ -10,10 +10,12 @@ import type {
|
||||||
TextArea,
|
TextArea,
|
||||||
ControlBase,
|
ControlBase,
|
||||||
} from '@astro-reactive/common';
|
} from '@astro-reactive/common';
|
||||||
|
import ShortUniqueId from 'short-unique-id';
|
||||||
|
|
||||||
export type ControlConfig = ControlBase | Checkbox | Radio | Submit | Button | Dropdown | TextArea;
|
export type ControlConfig = ControlBase | Checkbox | Radio | Submit | Button | Dropdown | TextArea;
|
||||||
|
|
||||||
export class FormControl {
|
export class FormControl {
|
||||||
|
private _id = '';
|
||||||
private _name = '';
|
private _name = '';
|
||||||
private _type: ControlType = 'text';
|
private _type: ControlType = 'text';
|
||||||
private _value?: string | number | null | string[] | ControlOption[];
|
private _value?: string | number | null | string[] | ControlOption[];
|
||||||
|
@ -46,6 +48,8 @@ export class FormControl {
|
||||||
validators = [],
|
validators = [],
|
||||||
} = config;
|
} = config;
|
||||||
|
|
||||||
|
const uid = new ShortUniqueId({ length: 9 });
|
||||||
|
this._id = 'arl-' + uid();
|
||||||
this._name = name;
|
this._name = name;
|
||||||
this._type = type;
|
this._type = type;
|
||||||
this._value = value;
|
this._value = value;
|
||||||
|
@ -80,6 +84,10 @@ export class FormControl {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
get id() {
|
||||||
|
return this._id;
|
||||||
|
}
|
||||||
|
|
||||||
get name() {
|
get name() {
|
||||||
return this._name;
|
return this._name;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,11 +1,15 @@
|
||||||
import { ControlConfig, FormControl } from './form-control';
|
import { ControlConfig, FormControl } from './form-control';
|
||||||
|
import ShortUniqueId from 'short-unique-id';
|
||||||
|
|
||||||
export class FormGroup {
|
export class FormGroup {
|
||||||
controls: FormControl[];
|
controls: FormControl[];
|
||||||
name?: string;
|
name?: string;
|
||||||
|
id?: string;
|
||||||
|
|
||||||
constructor(controls: ControlConfig[], name = '') {
|
constructor(controls: ControlConfig[], name = '') {
|
||||||
|
const uid = new ShortUniqueId({ length: 9 });
|
||||||
this.name = name;
|
this.name = name;
|
||||||
|
this.id = 'arl-' + uid();
|
||||||
this.controls = controls
|
this.controls = controls
|
||||||
.filter((control) => control.type !== 'submit')
|
.filter((control) => control.type !== 'submit')
|
||||||
.map((control) => new FormControl(control));
|
.map((control) => new FormControl(control));
|
||||||
|
|
Loading…
Reference in a new issue