Skip to content

Commit

Permalink
fix(runtime): input tag in svelte
Browse files Browse the repository at this point in the history
  • Loading branch information
danielo515 committed Jun 19, 2024
1 parent 37f5236 commit 879aba9
Show file tree
Hide file tree
Showing 5 changed files with 36 additions and 15 deletions.
9 changes: 6 additions & 3 deletions src/FormModal.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@
import { FormDefinition } from "src/core/formDefinition";
import { makeFormEngine } from "src/store/formStore";
import InputField from "src/views/components/Form/InputField.svelte";
import ObsidianInput from "src/views/components/Form/ObsidianInputWrapper.svelte";
import ObsidianInputWrapper from "src/views/components/Form/ObsidianInputWrapper.svelte";
import InputTag from "./views/components/Form/InputTag.svelte";
import MultiSelectField from "./views/components/Form/MultiSelectField.svelte";
import ObsidianSelect from "./views/components/Form/ObsidianSelect.svelte";
import ObsidianToggle from "./views/components/Form/ObsidianToggle.svelte";
Expand All @@ -19,17 +20,19 @@
{:else if definition.input.type === "toggle"}
<ObsidianToggle field={definition} {value} />
{:else}
<ObsidianInput
<ObsidianInputWrapper
{errors}
label={definition.label || definition.name}
description={definition.description}
required={definition.isRequired}
>
{#if definition.input.type === "multiselect"}
<MultiSelectField input={definition.input} {value} {errors} {app} />
{:else if definition.input.type === "tag"}
<InputTag input={definition.input} {value} {errors} {app} />
{:else}
<InputField {value} inputType={definition.input.type} />
{/if}
</ObsidianInput>
</ObsidianInputWrapper>
{/if}
{/each}
2 changes: 1 addition & 1 deletion src/FormModal.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ export class FormModal extends Modal {
svelteComponents: SvelteComponent[] = [];
initialFormValues: ModalFormData;
subscriptions: (() => void)[] = [];
formEngine: FormEngine<FieldValue>;
formEngine: FormEngine;
constructor(
app: App,
private modalDefinition: FormDefinition,
Expand Down
1 change: 1 addition & 0 deletions src/core/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * as input from "./InputDefinitionSchema";
23 changes: 12 additions & 11 deletions src/store/formStore.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import * as O from "fp-ts/Option";
import { Option } from "fp-ts/Option";
import { fromEntries, toEntries } from "fp-ts/Record";
import { absurd } from "fp-ts/function";
import { FieldDefinition } from "src/core/formDefinition";
import { Readable, Writable, derived, get, writable } from "svelte/store";

type Rule = { tag: "required"; message: string }; //| { tag: 'minLength', length: number, message: string } | { tag: 'maxLength', length: number, message: string } | { tag: 'pattern', pattern: RegExp, message: string };
Expand Down Expand Up @@ -37,22 +38,22 @@ type FormStore<T extends FieldValue> = {

// TODO: instead of making the whole engine generic, make just the addField method generic extending the type of the field value
// Then, the whole formEngine can be typed as FormEngine<FieldValue>
export interface FormEngine<T extends FieldValue> {
export interface FormEngine {
/**
* Adds a field to the form engine.
* It returns an object with a writable store that represents the value of the field,
* and a readable store that represents the errors of the field.
* Use them to bind the field to the form and be notified of errors.
* @param field a field definition to start tracking
*/
addField: (field: { name: string; label?: string; isRequired?: boolean }) => {
value: Writable<T>;
addField(field: { name: string; label?: string; isRequired?: boolean }): {
value: Writable<FieldValue>;
errors: Readable<string[]>;
};
/**
* Subscribes to the form store. This method is required to conform to the svelte store interface.
*/
subscribe: Readable<FormStore<T>>["subscribe"];
subscribe: Readable<FormStore<FieldValue>>["subscribe"];
/**
* Readable store that represents the validity of the form.
* If any of the fields in the form have errors, this will be false.
Expand Down Expand Up @@ -144,12 +145,12 @@ type makeFormEngineArgs<T> = {
defaultValues?: Record<string, T>;
};

export function makeFormEngine<T extends FieldValue>({
export function makeFormEngine({
onSubmit,
onCancel,
defaultValues = {},
}: makeFormEngineArgs<T>): FormEngine<T> {
const formStore: Writable<FormStore<T>> = writable({ fields: {}, status: "draft" });
}: makeFormEngineArgs<FieldValue>): FormEngine {
const formStore: Writable<FormStore<FieldValue>> = writable({ fields: {}, status: "draft" });
/** Creates helper functions to modify the store immutably*/
function setFormField(name: string) {
/** Set the initial value of the field*/
Expand All @@ -164,7 +165,7 @@ export function makeFormEngine<T extends FieldValue>({
};
});
}
function setValue(value: T) {
function setValue<T extends FieldValue>(value: T) {
formStore.update((form) => {
const field = form.fields[name];
if (!field) {
Expand All @@ -183,7 +184,7 @@ export function makeFormEngine<T extends FieldValue>({
return { initField, setValue };
}

function setErrors(failedFields: Field<T>[]) {
function setErrors<T extends FieldValue>(failedFields: Field<T>[]) {
formStore.update((form) => {
return pipe(
failedFields,
Expand Down Expand Up @@ -222,11 +223,11 @@ export function makeFormEngine<T extends FieldValue>({
formStore.update((form) => ({ ...form, status: "cancelled" }));
onCancel?.();
},
addField: (field) => {
addField(field: FieldDefinition) {
const { initField: setField, setValue } = setFormField(field.name);
setField([], field.isRequired ? requiredRule(field.label || field.name) : undefined);
const fieldStore = derived(formStore, ({ fields }) => fields[field.name]);
const fieldValueStore: Writable<T> = {
const fieldValueStore: Writable<FieldValue> = {
subscribe(cb) {
return fieldStore.subscribe((x) =>
pipe(
Expand Down
16 changes: 16 additions & 0 deletions src/views/components/Form/InputTag.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<script lang="ts">
import { App } from "obsidian";
import { input as I } from "src/core";
import { FieldValue } from "src/store/formStore";
import { Readable, Writable } from "svelte/store";
import MultiSelect from "../MultiSelect.svelte";
import { MultiSelectTags } from "../MultiSelectModel";
export let input: I.inputTag;
export let app: App;
export let errors: Readable<string[]>;
export let value: Writable<FieldValue>;
$: model = MultiSelectTags(input, app, value as Writable<string[]>);
$: values = value as Writable<string[]>;
</script>

<MultiSelect {values} {errors} model={Promise.resolve(model)} />

0 comments on commit 879aba9

Please sign in to comment.