1
2// Standard path pattern
3{apps,libs}/*/lib/[model]/[Model].Template.tsx
4
5// Examples:
6libs/game/lib/map/Map.Template.tsx
7apps/lu/lib/feeling/Feeling.Template.tsx
8 1
2// Single-file pattern
3export const General = () => { /* main form */ }
4export const Advanced = () => { /* advanced fields */ }
5
6// Multi-file pattern (recommended)
7[Model].Template/
8├─ General.tsx
9├─ Sections/
10│ ├─ BasicInfo.tsx
11│ ├─ ContactDetails.tsx
12 1
2useEffect(() => {
3 if (id) {
4 // Load existing data
5 void st.do.load[Model](id);
6 }
7
8 return () => {
9 // Reset form on unmount
10 st.do.reset[Model]Form();
11 };
12}, [id]);
13 | field | Description | Example |
|---|---|---|
| Text | Standard text input field | |
| TextArea | Multi-line text input | |
| Select | Dropdown selection input | |
| ToggleSelect | Toggleable options selector | |
| Img | Image upload component | |
| Parent | Relationship selector | |
Standard text input field
1<Field.Text />Multi-line text input
1<Field.TextArea />Dropdown selection input
1<Field.Select />Toggleable options selector
1<Field.ToggleSelect />Image upload component
1<Field.Img sliceName='model' />Relationship selector
1<Field.Parent sliceName='relatedModel' />1
2<Field.List
3 label={l("map.spawnPositions")}
4 value={form.spawnPositions}
5 onAdd={() => st.do.addSpawnPosition(defaultPosition)}
6 renderItem={(position, idx) => (
7 <div className="flex gap-4">
8 <Field.Text
9 value={position.key}
10 onChange={(v) => st.do.writeOnMap(["spawnPositions", idx, "key"], v)}
11 />
12 <Field.DoubleNumber
13 value={position.position}
14 onChange={(v) => st.do.writeOnMap(["spawnPositions", idx, "position"], v)}
15 />
16 </div>
17 )}
18/>
19 1
2<Field.Email
3 value={form.email}
4 validate={(v) => /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(v)}
5 errorMessage="Invalid email format"
6 required
7/>
8 | Option | Type | Default | Description | Example |
|---|---|---|---|---|
| required | boolean | false | Makes field mandatory | |
| min/max | number | - | Number range constraints | |
| validate | function | - | Custom validation function | |
| errorMessage | string | - | Custom error message | |
Makes field mandatory
1requiredNumber range constraints
1min={0} max={100}Custom validation function
1validate={(v) => isValidEmail(v)}Custom error message
1errorMessage="Invalid format"1
2<div className="grid grid-cols-1 gap-4 md:grid-cols-2">
3 <Field.Text label="First Name" />
4 <Field.Text label="Last Name" />
5 <Field.Email label="Email" className="md:col-span-2" />
6</div>
7 1
2{form.type === "business" && (
3 <section className="mt-6 p-4 bg-base-200 rounded-lg">
4 <h3 className="text-lg font-semibold mb-3">Business Details</h3>
5 <Field.Text label="Company Name" />
6 <Field.Text label="Tax ID" />
7 </section>
8)}
9 1
2// Simple field update
3st.do.setNameOn[Model](value);
4
5// Nested field update
6st.do.writeOn[Model](["address", "city"], value);
7
8// List operations
9st.do.addItemOn[Model](newItem);
10st.do.removeItemOn[Model](index);
11 1
2const FormSection = React.memo(({ fields }) => {
3 // Component implementation
4});
5
6// Debounced inputs
7import { useDebounce } from "@akanjs/hooks";
8const [input, setInput] = useState("");
9const debouncedInput = useDebounce(input, 300);
10 1
2// Proper labeling
3<label htmlFor="email-field">Email</label>
4<input id="email-field" type="email" />
5
6// Error messaging
7<div role="alert" aria-live="polite">
8 {error && <p className="text-error">{error}</p>}
9</div>
10 1
2// AddressSection.tsx
3export const AddressSection = () => (
4 <div className="space-y-3">
5 <Field.Text label="Street" />
6 <Field.Text label="City" />
7 <Field.Text label="Zip Code" />
8 </div>
9);
10 1
2const handleSubmit = async () => {
3 try {
4 // Validate form
5 const errors = validateForm(form);
6 if (Object.keys(errors).length) throw errors;
7
8 // Submit data
9 if (id) await st.do.updateModel(id, form);
10 else await st.do.createModel(form);
11
12 // Redirect on success
13 router.push("/success");
14 } catch (error) {
15 // Handle API errors
16 st.do.setFormErrors(error);
17 }
18};
19 | issue | Description | Example |
|---|---|---|
| Form Not Updating | Verify Zustand store actions are properly connected | |
| Type Mismatches | Ensure constant types match form state | |
| Missing Translations | Verify dictionary keys and scopes | |
Verify Zustand store actions are properly connected
1st.do.setNameOn[Model]Ensure constant types match form state
1ProjectInput vs ProjectFormVerify dictionary keys and scopes
1l("model.name")