@sjsf/form
Advanced tools
@@ -16,2 +16,3 @@ // This file was copied and modified from https://github.com/rjsf-team/react-jsonschema-form/blob/f4229bf6e067d31b24de3ef9d3ca754ee52529ac/packages/utils/src/schema/getMatchingOption.ts and https://github.com/rjsf-team/react-jsonschema-form/blob/f4229bf6e067d31b24de3ef9d3ca754ee52529ac/packages/utils/src/schema/getClosestMatchingOption.ts | ||
| // - `@sjsf/zod4-validator` | ||
| // - `@sjsf/valibot-validator` | ||
| export function createAugmentSchema({ required, ...rest }) { | ||
@@ -33,7 +34,6 @@ return { | ||
| function isOptionMatching(option, validator, formData, rootSchema, discriminatorField, discriminatorFormData) { | ||
| // NOTE: This is possibly a bug since schema can be combinatorial (oneOf, anyOf) | ||
| if (!isSchemaWithProperties(option)) { | ||
| return validator.isValid(option, rootSchema, formData); | ||
| } | ||
| // NOTE: Do not transform into `&&` expression! | ||
| // WARN: Do not transform into `&&` expression! | ||
| const discriminator = discriminatorField !== undefined | ||
@@ -40,0 +40,0 @@ ? option.properties[discriminatorField] |
| <script lang="ts" module> | ||
| import type { UiSchemaDefinition } from "../form/index.js"; | ||
| import type { FormValue, UiSchemaDefinition } from "../form/index.js"; | ||
@@ -73,5 +73,17 @@ import "./extra-templates/multi-field.js"; | ||
| ); | ||
| let ignoreUpdate = false; | ||
| let lastValueSnapshot: FormValue; | ||
| const valueSnapshot = $derived.by(() => { | ||
| if (ignoreUpdate) { | ||
| ignoreUpdate = false; | ||
| return lastValueSnapshot; | ||
| } | ||
| lastValueSnapshot = $state.snapshot(value); | ||
| return lastValueSnapshot; | ||
| }); | ||
| const retrievedOptions = $derived( | ||
| (config.schema[combinationKey] ?? []).map((s) => | ||
| typeof s !== "boolean" ? retrieveSchema(ctx, s, value) : {} | ||
| typeof s !== "boolean" ? retrieveSchema(ctx, s, valueSnapshot) : {} | ||
| ) | ||
@@ -84,8 +96,12 @@ ); | ||
| ctx, | ||
| value, | ||
| valueSnapshot, | ||
| retrievedOptions, | ||
| previousSelectedOption ?? 0, | ||
| untrack(() => previousSelectedOption ?? 0), | ||
| getDiscriminatorFieldFromSchema(config.schema) | ||
| ) | ||
| ); | ||
| const currentSelectedOption = $derived( | ||
| previousSelectedOption ?? nextSelectedOption | ||
| ); | ||
| $effect(() => { | ||
@@ -96,2 +112,3 @@ const nextSelected = nextSelectedOption; | ||
| } | ||
| ignoreUpdate = true; | ||
| value = untrack(() => { | ||
@@ -200,3 +217,3 @@ const nextSchema = retrievedOptions[nextSelected]; | ||
| const combinationFieldConfig: Config | null = $derived.by(() => { | ||
| const selected = previousSelectedOption ?? nextSelectedOption; | ||
| const selected = currentSelectedOption; | ||
| if (selected < 0) { | ||
@@ -276,6 +293,3 @@ return null; | ||
| options={enumOptions} | ||
| bind:value={ | ||
| () => previousSelectedOption ?? nextSelectedOption, | ||
| (v) => (nextSelectedOption = v) | ||
| } | ||
| bind:value={() => currentSelectedOption, (v) => (nextSelectedOption = v)} | ||
| /> | ||
@@ -282,0 +296,0 @@ {/snippet} |
@@ -22,2 +22,6 @@ import { getContext, setContext } from "svelte"; | ||
| if (!isOrderedSchemaDeepEqual(lastSchemaProperties, snap)) { | ||
| // NOTE: `defaults` population | ||
| if (lastSchemaProperties !== undefined) { | ||
| markSchemaChange(ctx); | ||
| } | ||
| lastSchemaProperties = snap; | ||
@@ -27,8 +31,2 @@ } | ||
| }); | ||
| // NOTE: `defaults` population | ||
| $effect(() => { | ||
| // eslint-disable-next-line @typescript-eslint/no-unused-expressions | ||
| schemaProperties; | ||
| markSchemaChange(ctx); | ||
| }); | ||
| const uiOption = (opt) => retrieveUiOption(ctx, config(), opt); | ||
@@ -35,0 +33,0 @@ const schemaPropertiesOrder = $derived(isSchemaObjectValue(schemaProperties) |
| import type { Attachment } from "svelte/attachments"; | ||
| import type { DeepPartial } from "../lib/types.js"; | ||
| import type { SchedulerYield } from "../lib/scheduler.js"; | ||
| import { type Bind, type Ref } from "../lib/svelte.svelte.js"; | ||
| import { type Bind } from "../lib/svelte.svelte.js"; | ||
| import { type TasksCombinator, type FailedTask } from "../lib/task.svelte.js"; | ||
@@ -16,3 +16,3 @@ import { type Schema, type Validator } from "../core/index.js"; | ||
| import type { Theme } from "./components.js"; | ||
| import { type Creatable, type FormValue, type KeyedArraysMap, type Update } from "./model.js"; | ||
| import { type Creatable, type FormValue, type FormValueRef, type KeyedArraysMap, type Update } from "./model.js"; | ||
| import type { ResolveFieldType } from "./fields.js"; | ||
@@ -35,3 +35,3 @@ import { type FormState } from "./state/index.js"; | ||
| merger: FormMerger; | ||
| valueRef: Ref<FormValue>; | ||
| valueRef: FormValueRef; | ||
| } | ||
@@ -38,0 +38,0 @@ export interface ValidatorFactoryOptions { |
@@ -13,3 +13,3 @@ import { SvelteMap } from "svelte/reactivity"; | ||
| import { create, } from "./model.js"; | ||
| import { createSchemaValuesReconciler, UNCHANGED } from "./reconcile.js"; | ||
| import { createFormValueReconciler } from "./reconcile.js"; | ||
| import { setFieldState, updateErrors, updateFieldErrors, } from "./state/index.js"; | ||
@@ -89,3 +89,3 @@ import { FORM_DATA_URL_TO_BLOB, FORM_UI_EXTRA_OPTIONS, FORM_FIELDS_VALIDATION_MODE, FORM_KEYED_ARRAYS, FORM_SCHEMA, FORM_UI_SCHEMA, FORM_UI_SCHEMA_ROOT, FORM_VALUE, FORM_UI_OPTIONS_REGISTRY, FORM_DISABLED, FORM_VALIDATOR, FORM_MERGER, FORM_RESOLVER, FORM_THEME, FORM_TRANSLATION, FORM_TRANSLATE, FORM_ICONS, FORM_MARK_SCHEMA_CHANGE, FORM_FIELDS_STATE_MAP, FORM_ID_FROM_PATH, internalRegisterFieldPath, FORM_ROOT_PATH, FORM_ERRORS, FORM_PATHS_TRIE_REF, internalHasFieldState, FORM_ID_PREFIX, FormErrors, FORM_RETRIEVED_SCHEMA, FORM_CONFIGS_CACHE, } from "./internals.js"; | ||
| const keyedArrays = $derived(options.keyedArraysMap ?? new WeakMap()); | ||
| const reconcileSchemaValues = $derived(createSchemaValuesReconciler(keyedArrays)); | ||
| const reconcileFormValue = $derived(createFormValueReconciler(keyedArrays)); | ||
| const schedulerYield = $derived((options.schedulerYield ?? | ||
@@ -321,6 +321,3 @@ (typeof scheduler !== "undefined" && "yield" in scheduler)) | ||
| initialDefaultsGenerated = true; | ||
| const change = reconcileSchemaValues(valueRef.current, nextValue); | ||
| if (change !== UNCHANGED) { | ||
| valueRef.current = change; | ||
| } | ||
| reconcileFormValue(valueRef, nextValue); | ||
| } | ||
@@ -327,0 +324,0 @@ return formState; |
@@ -11,4 +11,5 @@ import type { KeyedArray } from "../lib/keyed-array.svelte.js"; | ||
| export type KeyedArraysMap = WeakMap<SchemaArrayValue, KeyedFieldValues>; | ||
| export type FormValueRef = Ref<FormValue>; | ||
| export type PathTrieRef<T> = Ref<Trie<RPath[number], T>>; | ||
| export declare const DEFAULT_BOOLEAN_ENUM: boolean[]; | ||
| export declare function create<R, O>(creatable: Creatable<R, O>, options: O): R; |
| import type { SchemaValue } from "../core/index.js"; | ||
| import type { KeyedArraysMap } from "./model.js"; | ||
| export declare const UNCHANGED: unique symbol; | ||
| export declare function createSchemaValuesReconciler(keyedArraysMap: KeyedArraysMap): (target: SchemaValue | undefined, source: SchemaValue | undefined) => SchemaValue | undefined | typeof UNCHANGED; | ||
| import type { FormValueRef, KeyedArraysMap } from "./model.js"; | ||
| export declare function createFormValueReconciler(keyedArraysMap: KeyedArraysMap): (targetRef: FormValueRef, source: SchemaValue | undefined) => void; |
| import { isRecordProto } from "../lib/object.js"; | ||
| export const UNCHANGED = Symbol("unchanged"); | ||
| export function createSchemaValuesReconciler(keyedArraysMap) { | ||
| return function reconcile(target, source) { | ||
| const UNCHANGED = Symbol("unchanged"); | ||
| export function createFormValueReconciler(keyedArraysMap) { | ||
| function reconcile(target, source) { | ||
| if (target === source) { | ||
@@ -47,6 +47,11 @@ return UNCHANGED; | ||
| const key = sKeys[i]; | ||
| const v = reconcile(target[key], source[key]); | ||
| if (v !== UNCHANGED) { | ||
| target[key] = v; | ||
| if (key in target) { | ||
| const v = reconcile(target[key], source[key]); | ||
| if (v !== UNCHANGED) { | ||
| target[key] = v; | ||
| } | ||
| } | ||
| else { | ||
| target[key] = source[key]; | ||
| } | ||
| } | ||
@@ -57,3 +62,9 @@ return UNCHANGED; | ||
| return source; | ||
| } | ||
| return (targetRef, source) => { | ||
| const change = reconcile(targetRef.current, source); | ||
| if (change !== UNCHANGED) { | ||
| targetRef.current = change; | ||
| } | ||
| }; | ||
| } |
+2
-2
| { | ||
| "name": "@sjsf/form", | ||
| "version": "3.3.1", | ||
| "version": "3.3.2", | ||
| "description": "Svelte 5 library for creating forms based on JSON schema.", | ||
@@ -59,3 +59,3 @@ "license": "(MIT AND Apache-2.0)", | ||
| "json-schema-merge-allof": "^0.8.1", | ||
| "svelte": "^5.53.6" | ||
| "svelte": "^5.55.0" | ||
| }, | ||
@@ -62,0 +62,0 @@ "types": "./dist/form/index.d.ts", |
621923
0.07%13313
0.05%