diff --git a/zui/src/ui/types.ts b/zui/src/ui/types.ts index 60e31c5c..e9c4b65d 100644 --- a/zui/src/ui/types.ts +++ b/zui/src/ui/types.ts @@ -2,6 +2,8 @@ import { ZodEnumDef, ZodIssueCode, z } from '../z/index' import type { FC } from 'react' import { zuiKey } from './constants' +export type ZuiMetadata = string | number | boolean | null | undefined | ZuiMetadata[] | { [key: string]: ZuiMetadata } + export type ZuiExtensionObject = { tooltip?: boolean displayAs?: [string, any] @@ -11,6 +13,7 @@ export type ZuiExtensionObject = { placeholder?: string secret?: boolean coerce?: boolean + [key: string]: ZuiMetadata } export type SerializedFunction = string diff --git a/zui/src/z/types/basetype/index.ts b/zui/src/z/types/basetype/index.ts index 9c778ef9..09726bc7 100644 --- a/zui/src/z/types/basetype/index.ts +++ b/zui/src/z/types/basetype/index.ts @@ -6,6 +6,7 @@ import type { ParseSchema, EmptyComponentDefinitions, ZuiExtensionObject, + ZuiMetadata, } from '../../../ui/types' import { zuiKey } from '../../../ui/constants' import { @@ -480,45 +481,56 @@ export abstract class ZodType - const serializedValue = typeof value === 'function' ? value.toString() : value - switch (def.typeName) { - case ZodFirstPartyTypeKind.ZodNullable: - case ZodFirstPartyTypeKind.ZodDefault: - case ZodFirstPartyTypeKind.ZodOptional: - case ZodFirstPartyTypeKind.ZodReadonly: - def.innerType._def[zuiKey] = { - ...def.innerType._def[zuiKey], - [key]: serializedValue, - } - break - case ZodFirstPartyTypeKind.ZodEffects: - def.schema._def[zuiKey] = { - ...def.schema._def[zuiKey], - [key]: serializedValue, - } - break - default: - def[zuiKey] = { - ...def[zuiKey], - [key]: serializedValue, - } + /** append metadata to object */ + metadata(data: Record): this { + for (const [key, value] of Object.entries(data)) { + this._def[zuiKey] = { + ...this._def[zuiKey], + [key]: value, + } } + return this + } + + /** get metadata of object */ + getMetadata(): Record { + return { ...this._def[zuiKey] } } - get ui(): object { + /** set metadata of object */ + setMetadata(data: Record): void { + this._def[zuiKey] = { ...data } + } + + /** + * @deprecated use `getMetadata` instead + */ + get ui(): Record { + const root = this._getMetadataRoot() + return { ...root._def[zuiKey] } + } + + private _setZuiMeta(key: string, value: ZuiMetadata) { + const root = this._getMetadataRoot() + root._def[zuiKey] = { + ...root._def[zuiKey], + [key]: value, + } + } + + private _getMetadataRoot(): ZodType { + // TODO: this kind of logic should be handled in the UI layer, not here const def = this._def as KindToDef switch (def.typeName) { case ZodFirstPartyTypeKind.ZodNullable: case ZodFirstPartyTypeKind.ZodDefault: case ZodFirstPartyTypeKind.ZodOptional: case ZodFirstPartyTypeKind.ZodReadonly: - return def.innerType.ui + return def.innerType case ZodFirstPartyTypeKind.ZodEffects: - return def.schema.ui + return def.schema default: - return def[zuiKey] || {} + return this } } @@ -547,9 +559,17 @@ export abstract class ZodType( - hidden?: boolean | ((shape: T | null) => util.DeepPartialBoolean | boolean), + value?: boolean | ((shape: T | null) => util.DeepPartialBoolean | boolean), ): this { - this._setZuiMeta('hidden', typeof hidden === 'undefined' ? true : hidden) + let data: ZuiMetadata + if (value === undefined) { + data = true + } else if (typeof value === 'function') { + data = value.toString() + } else { + data = value + } + this._setZuiMeta('hidden', data) return this } @@ -558,9 +578,17 @@ export abstract class ZodType( - disabled?: boolean | ((shape: T | null) => util.DeepPartialBoolean | boolean), + value?: boolean | ((shape: T | null) => util.DeepPartialBoolean | boolean), ): this { - this._setZuiMeta('disabled', typeof disabled === 'undefined' ? true : disabled) + let data: ZuiMetadata + if (value === undefined) { + data = true + } else if (typeof value === 'function') { + data = value.toString() + } else { + data = value + } + this._setZuiMeta('disabled', data) return this } diff --git a/zui/tsconfig.json b/zui/tsconfig.json index 438af34e..251b10da 100644 --- a/zui/tsconfig.json +++ b/zui/tsconfig.json @@ -19,7 +19,7 @@ "resolveJsonModule": true, "isolatedModules": true }, - "exclude": ["node_modules", "dist", "*.test.ts", "**/benchmark/**/*.ts"], + "exclude": ["node_modules", "dist"], "include": ["src/**/*", "vitest.d.ts"], "ts-node": { "esm": true