diff --git a/src/lib/unstable/core/Entity/Entity.tsx b/src/lib/unstable/core/Entity/Entity.tsx index 818f564a..1f0249f4 100644 --- a/src/lib/unstable/core/Entity/Entity.tsx +++ b/src/lib/unstable/core/Entity/Entity.tsx @@ -138,7 +138,7 @@ const EntityComponent: React.FC = ({name, schema: schemaProps = {}} } } - return content ?
{content}
: null; + return content; }; export const Entity = React.memo(EntityComponent); diff --git a/src/lib/unstable/core/Entity/types.ts b/src/lib/unstable/core/Entity/types.ts index 5945e43b..a6374e8b 100644 --- a/src/lib/unstable/core/Entity/types.ts +++ b/src/lib/unstable/core/Entity/types.ts @@ -23,7 +23,7 @@ export type GetRenderKitReturn = { }; }; -export interface EntityState { +export interface EntityState { headName?: string; - schema?: JsonSchema; + schema?: Schema; } diff --git a/src/lib/unstable/core/index.ts b/src/lib/unstable/core/index.ts index 32c0aed9..a3276508 100644 --- a/src/lib/unstable/core/index.ts +++ b/src/lib/unstable/core/index.ts @@ -1,4 +1,4 @@ -export {Entity, type EntityProps} from './Entity'; +export {Entity, type EntityProps, type EntityState} from './Entity'; export {SchemaRenderer, type SchemaRendererProps} from './SchemaRenderer'; export {EntityType, JsonSchemaType, SchemaRendererMode} from './constants'; export type * from './types'; diff --git a/src/lib/unstable/core/types/components.ts b/src/lib/unstable/core/types/components.ts index 2ddd87bf..3e5b7ac1 100644 --- a/src/lib/unstable/core/types/components.ts +++ b/src/lib/unstable/core/types/components.ts @@ -50,6 +50,7 @@ export interface WrapperProps< copy?: boolean; required?: boolean; } & Partial; + children: React.ReactNode; } export type Wrapper< diff --git a/src/lib/unstable/core/types/schema.ts b/src/lib/unstable/core/types/schema.ts index 4851a9a9..d6cb6db8 100644 --- a/src/lib/unstable/core/types/schema.ts +++ b/src/lib/unstable/core/types/schema.ts @@ -10,6 +10,105 @@ import type { import type {ErrorMessages} from './validation'; import type {ArrayValue, FieldValue, ObjectValue} from './values'; +type ControlEntityParameters< + TypeConfig extends SchemaRendererConfig[EntityType], + Control extends ObjectKeys = ObjectKeys, +> = [Control] extends [never] + ? {} + : { + [C in Control]: { + /** + * Identifier of a control registered in `config[entityType].controls`. Selects + * which React component renders the field in form mode. When omitted, the + * renderer falls back to the default control for this entity type. + */ + controlType?: C; + /** + * Extra props forwarded to the selected control. Typed to the `controlProps` + * shape declared by the chosen control component. + */ + controlProps?: ExtractControlProps; + }; + }[Control]; + +type ControlWrapperEntityParameters< + TypeConfig extends SchemaRendererConfig[EntityType], + Wrapper extends ObjectKeys = ObjectKeys, +> = [Wrapper] extends [never] + ? {} + : { + [W in Wrapper]: { + /** + * Identifier of a wrapper registered in `config[entityType].wrappers`. The + * wrapper component is rendered around the control in form mode (e.g. to add + * a label, layout, or visibility logic). + */ + controlWrapperType?: W; + /** + * Extra props forwarded to the selected control wrapper. Typed to the + * `wrapperProps` shape declared by the chosen wrapper component. + */ + controlWrapperProps?: ExtractWrapperProps; + }; + }[Wrapper]; + +type ViewEntityParameters< + TypeConfig extends SchemaRendererConfig[EntityType], + View extends ObjectKeys = ObjectKeys, +> = [View] extends [never] + ? {} + : { + [V in View]: { + /** + * Identifier of a view registered in `config[entityType].views`. Selects which + * React component renders the field in overview (read-only) mode. When omitted, + * the renderer falls back to the default view for this entity type. + */ + viewType?: V; + /** + * Extra props forwarded to the selected view. Typed to the `viewProps` shape + * declared by the chosen view component. + */ + viewProps?: ExtractViewProps; + }; + }[View]; + +type ViewWrapperEntityParameters< + TypeConfig extends SchemaRendererConfig[EntityType], + Wrapper extends ObjectKeys = ObjectKeys, +> = [Wrapper] extends [never] + ? {} + : { + [W in Wrapper]: { + /** + * Identifier of a wrapper registered in `config[entityType].wrappers`. The + * wrapper component is rendered around the view in overview mode. + */ + viewWrapperType?: W; + /** + * Extra props forwarded to the selected view wrapper. Typed to the + * `wrapperProps` shape declared by the chosen wrapper component. + */ + viewWrapperProps?: ExtractWrapperProps; + }; + }[Wrapper]; + +type ValidatorEntityParameters = [Validator] extends [never] + ? {} + : { + [V in Validator]: { + /** + * Identifier of a custom validator registered in `config[entityType].validators`. + * Runs in addition to (or instead of, depending on the renderer policy) the + * JSON Schema validation derived from the schema keywords. + * + * TODO(verify): confirm whether the custom validator replaces or complements + * JSON Schema validation and adjust this comment. + */ + validatorType?: V; + }; + }[Validator]; + /** * Renderer-specific configuration carried on each schema node. Not part of the * JSON Schema specification — these keywords are ignored by JSON Schema @@ -41,71 +140,6 @@ interface EntityParameters< * via different `EntityType` registrations). */ type?: Type; - /** - * Identifier of a control registered in `config[entityType].controls`. Selects - * which React component renders the field in form mode. When omitted, the - * renderer falls back to the default control for this entity type. - */ - controlType?: Control; - /** - * Extra props forwarded to the selected control. Typed to the `controlProps` - * shape declared by the chosen control component. - */ - controlProps?: ExtractControlProps; - /** - * Identifier of a wrapper registered in `config[entityType].wrappers`. The - * wrapper component is rendered around the control in form mode (e.g. to add - * a label, layout, or visibility logic). - */ - controlWrapperType?: Wrapper; - /** - * Extra props forwarded to the selected control wrapper. Typed to the - * `wrapperProps` shape declared by the chosen wrapper component. - */ - controlWrapperProps?: ExtractWrapperProps; - /** - * Identifier of a view registered in `config[entityType].views`. Selects which - * React component renders the field in overview (read-only) mode. When omitted, - * the renderer falls back to the default view for this entity type. - */ - viewType?: View; - /** - * Extra props forwarded to the selected view. Typed to the `viewProps` shape - * declared by the chosen view component. - */ - viewProps?: ExtractViewProps; - /** - * Identifier of a wrapper registered in `config[entityType].wrappers`. The - * wrapper component is rendered around the view in overview mode. - */ - viewWrapperType?: Wrapper; - /** - * Extra props forwarded to the selected view wrapper. Typed to the - * `wrapperProps` shape declared by the chosen wrapper component. - */ - viewWrapperProps?: ExtractWrapperProps; - /** - * Identifier of a custom validator registered in `config[entityType].validators`. - * Runs in addition to (or instead of, depending on the renderer policy) the - * JSON Schema validation derived from the schema keywords. - * - * TODO(verify): confirm whether the custom validator replaces or complements - * JSON Schema validation and adjust this comment. - */ - validatorType?: Validator; - /** - * Map of enum value (as a string key) to a human-readable label. The renderer - * uses these labels in selects / radio groups instead of showing raw enum values. - * - * @example - * { - * enum: ['draft', 'published'], - * entityParameters: { - * enumDescription: {draft: 'Draft', published: 'Published'}, - * }, - * } - */ - enumDescription?: {[key: string]: string}; /** * Custom error messages shown by the renderer when validation fails. Keys * correspond to JSON Schema validation keywords (`minLength`, `pattern`, `enum`, @@ -143,7 +177,11 @@ interface EntityParameters< dependencies?: string | Record; required?: string | Record; }; - }; + } & ControlEntityParameters & + ControlWrapperEntityParameters & + ViewEntityParameters & + ViewWrapperEntityParameters & + ValidatorEntityParameters; } /** diff --git a/src/lib/unstable/kit/MultiSelect.tsx b/src/lib/unstable/kit/MultiSelect.tsx index f6a942d9..0c136350 100644 --- a/src/lib/unstable/kit/MultiSelect.tsx +++ b/src/lib/unstable/kit/MultiSelect.tsx @@ -42,8 +42,8 @@ export const MultiSelect: Control = ({input, schema}) => { schema.items?.enum?.map((id) => ({ id, value: id, - text: schema.entityParameters?.enumDescription?.[id] || id, - content: schema.entityParameters?.enumDescription?.[id] || id, + text: id, + content: id, key: id, })), [ diff --git a/src/lib/unstable/kit/components/ArrayRemoveButton/ArrayRemoveButton.tsx b/src/lib/unstable/kit/components/ArrayRemoveButton/ArrayRemoveButton.tsx new file mode 100644 index 00000000..d534001a --- /dev/null +++ b/src/lib/unstable/kit/components/ArrayRemoveButton/ArrayRemoveButton.tsx @@ -0,0 +1,41 @@ +import React from 'react'; + +import {TrashBin} from '@gravity-ui/icons'; +import {Button, Icon} from '@gravity-ui/uikit'; +import {useForm} from 'react-final-form'; + +import {getArrayItemIndex, getArrayItemParentName, isArrayItem, isTupleItem} from '../../utils'; + +export interface ArrayRemoveButtonProps { + name: string; +} + +export const ArrayRemoveButton: React.FC = ({name}) => { + const form = useForm(); + + const arrayItem = isArrayItem(name); + const tupleItem = isTupleItem(name, form); + + const removeItem = React.useCallback(() => { + const parentName = getArrayItemParentName(name); + const parentValue = form.getFieldState(parentName)?.value; + const index = Number(getArrayItemIndex(name)); + + if (Array.isArray(parentValue)) { + form.change( + parentName, + parentValue.filter((_, i) => i !== index), + ); + } + }, [form, name]); + + if (arrayItem && !tupleItem) { + return ( + + ); + } + + return null; +}; diff --git a/src/lib/unstable/kit/components/ArrayRemoveButton/index.ts b/src/lib/unstable/kit/components/ArrayRemoveButton/index.ts new file mode 100644 index 00000000..9579833d --- /dev/null +++ b/src/lib/unstable/kit/components/ArrayRemoveButton/index.ts @@ -0,0 +1 @@ +export {ArrayRemoveButton, type ArrayRemoveButtonProps} from './ArrayRemoveButton'; diff --git a/src/lib/unstable/kit/components/ControlError/ControlError.scss b/src/lib/unstable/kit/components/ControlError/ControlError.scss new file mode 100644 index 00000000..0dd6538f --- /dev/null +++ b/src/lib/unstable/kit/components/ControlError/ControlError.scss @@ -0,0 +1,71 @@ +@import '../../styles/variables.scss'; + +.#{$ns}control-error { + &__children { + width: 100%; + + &_errors { + .g-control-label:not(.g-control-label_disabled) { + .g-checkbox__indicator { + &:hover { + &::before { + border: 1px solid var(--g-color-text-danger); + } + } + + &::before { + border: 1px solid var(--g-color-text-danger); + } + } + } + + .g-text-input:not(.g-text-input_disabled) { + .g-text-input__content { + border-color: var(--g-color-text-danger); + + &:hover { + border-color: var(--g-color-text-danger); + } + } + } + + .g-text-area__content { + border-color: var(--g-color-text-danger); + + &:hover { + border-color: var(--g-color-text-danger); + } + } + + .g-select-control:not(.g-select-control_disabled) { + .g-select-control__button { + &:hover { + &::before { + // stylelint-disable-next-line declaration-no-important + border: 1px solid var(--g-color-text-danger) !important; + } + } + + &::before { + // stylelint-disable-next-line declaration-no-important + border: 1px solid var(--g-color-text-danger) !important; + } + } + } + + .g-segmented-radio-group:not([aria-disabled='true']) { + .g-segmented-radio-group__option_checked { + &:hover { + &::after { + border: 1px solid var(--g-color-text-danger); + } + } + + &::after { + border: 1px solid var(--g-color-text-danger); + } + } + } + } + } +} diff --git a/src/lib/unstable/kit/components/ControlError/ControlError.tsx b/src/lib/unstable/kit/components/ControlError/ControlError.tsx new file mode 100644 index 00000000..92fcdd8e --- /dev/null +++ b/src/lib/unstable/kit/components/ControlError/ControlError.tsx @@ -0,0 +1,41 @@ +import React from 'react'; + +import {Flex, Text} from '@gravity-ui/uikit'; +import _ from 'lodash'; + +import {block} from '../../utils'; + +import './ControlError.scss'; + +const b = block('control-error'); + +export interface ControlErrorProps { + className?: string; + errorMessage?: string; + validationState?: 'invalid'; + children: React.ReactNode; +} + +export const ControlError: React.FC = ({ + className, + errorMessage, + validationState, + children, +}) => { + const error = + validationState === 'invalid' && errorMessage ? ( + {errorMessage} + ) : null; + + return ( + +
{children}
+ {error} +
+ ); +}; diff --git a/src/lib/unstable/kit/components/ControlError/index.ts b/src/lib/unstable/kit/components/ControlError/index.ts new file mode 100644 index 00000000..b0a91b96 --- /dev/null +++ b/src/lib/unstable/kit/components/ControlError/index.ts @@ -0,0 +1 @@ +export {ControlError, type ControlErrorProps} from './ControlError'; diff --git a/src/lib/unstable/kit/components/HTMLContent/HTMLContent.tsx b/src/lib/unstable/kit/components/HTMLContent/HTMLContent.tsx new file mode 100644 index 00000000..4851f09f --- /dev/null +++ b/src/lib/unstable/kit/components/HTMLContent/HTMLContent.tsx @@ -0,0 +1,11 @@ +import React from 'react'; + +import {Text, type TextProps} from '@gravity-ui/uikit'; + +export interface HTMLContentProps extends TextProps { + html: string; +} + +export const HTMLContent: React.FC = ({html, ...restProps}) => { + return ; +}; diff --git a/src/lib/unstable/kit/components/HTMLContent/index.ts b/src/lib/unstable/kit/components/HTMLContent/index.ts new file mode 100644 index 00000000..0095871d --- /dev/null +++ b/src/lib/unstable/kit/components/HTMLContent/index.ts @@ -0,0 +1 @@ +export {HTMLContent, type HTMLContentProps} from './HTMLContent'; diff --git a/src/lib/unstable/kit/components/index.ts b/src/lib/unstable/kit/components/index.ts new file mode 100644 index 00000000..4a865a09 --- /dev/null +++ b/src/lib/unstable/kit/components/index.ts @@ -0,0 +1,3 @@ +export {ArrayRemoveButton, type ArrayRemoveButtonProps} from './ArrayRemoveButton'; +export {ControlError, type ControlErrorProps} from './ControlError'; +export {HTMLContent, type HTMLContentProps} from './HTMLContent'; diff --git a/src/lib/unstable/kit/constants/config.ts b/src/lib/unstable/kit/constants/config.ts new file mode 100644 index 00000000..07db2212 --- /dev/null +++ b/src/lib/unstable/kit/constants/config.ts @@ -0,0 +1,78 @@ +import {EntityType, type SchemaRendererConfig} from '../../core'; +import { + ArrayBase, + Checkbox, + CheckboxGroup, + ColorPicker, + DateInput, + MultiSelect, + NumberBase, + ObjectBase, + Password, + RadioGroup, + RangeSlider, + Select, + Slider, + StringBase, + Switch, + TextArea, +} from '../controls'; +import {Row, Transparent} from '../wrappers'; + +export const untypedConfig = { + [EntityType.Any]: { + controls: {date_input: {Component: DateInput}}, + views: {}, + wrappers: {row: Row, transparent: Transparent}, + validators: {}, + }, + [EntityType.Array]: { + controls: { + base: {Component: ArrayBase}, + checkbox_group: {Component: CheckboxGroup}, + select: {Component: MultiSelect}, + }, + views: {}, + wrappers: {row: Row, transparent: Transparent}, + validators: {}, + }, + [EntityType.Boolean]: { + controls: {base: {Component: Checkbox}, switch: {Component: Switch}}, + views: {}, + wrappers: {row: Row, transparent: Transparent}, + validators: {}, + }, + [EntityType.Number]: { + controls: { + base: {Component: NumberBase}, + slider: {Component: Slider}, + }, + views: {}, + wrappers: {row: Row, transparent: Transparent}, + validators: {}, + }, + [EntityType.Object]: { + controls: { + base: {Component: ObjectBase}, + range_slider: {Component: RangeSlider}, + }, + views: {}, + wrappers: {row: Row, transparent: Transparent}, + validators: {}, + }, + [EntityType.String]: { + controls: { + base: {Component: StringBase}, + color_picker: {Component: ColorPicker}, + password: {Component: Password}, + radio_group: {Component: RadioGroup}, + select: {Component: Select}, + textarea: {Component: TextArea}, + }, + views: {}, + wrappers: {row: Row, transparent: Transparent}, + validators: {}, + }, +} as const; + +export const config: SchemaRendererConfig = untypedConfig; diff --git a/src/lib/unstable/kit/constants/index.ts b/src/lib/unstable/kit/constants/index.ts new file mode 100644 index 00000000..93d0b36d --- /dev/null +++ b/src/lib/unstable/kit/constants/index.ts @@ -0,0 +1 @@ +export {config, untypedConfig} from './config'; diff --git a/src/lib/unstable/kit/controls/ArrayBase/ArrayBase.tsx b/src/lib/unstable/kit/controls/ArrayBase/ArrayBase.tsx new file mode 100644 index 00000000..91a236d6 --- /dev/null +++ b/src/lib/unstable/kit/controls/ArrayBase/ArrayBase.tsx @@ -0,0 +1,77 @@ +import React from 'react'; + +import {Plus} from '@gravity-ui/icons'; +import {Button, Flex, Icon} from '@gravity-ui/uikit'; + +import {type Control, Entity, type JsonSchemaArray} from '../../../core'; +import {ControlError} from '../../components'; +import {getValidationState} from '../../utils'; + +export interface ArrayBaseProps { + addButtonText?: string; + addButtonPosition?: string; + disabled?: boolean; +} + +const Component: Control = ({ + controlProps, + input, + meta, + schema, +}) => { + const addButton = React.useMemo(() => { + const itemsSchema = schema.items; + + if (Array.isArray(itemsSchema)) { + return null; + } + + const onClick = () => input.onChange([...(input.value || []), itemsSchema?.default]); + + return ( + + ); + }, [ + controlProps.addButtonText, + controlProps.disabled, + input.onChange, + input.value, + schema.default, + schema.items, + schema.readOnly, + ]); + + const items = React.useMemo(() => { + const itemsSchema = schema.items; + + if (Array.isArray(itemsSchema)) { + return itemsSchema.map((item, index) => ( + + )); + } + + return new Array(input.value?.length) + .fill(null) + .map((_, index) => ( + + )); + }, [input.name, input.value?.length, schema.items]); + + return ( + + + {items} + {addButton} + + + ); +}; + +export const ArrayBase = React.memo(Component); diff --git a/src/lib/unstable/kit/controls/ArrayBase/index.ts b/src/lib/unstable/kit/controls/ArrayBase/index.ts new file mode 100644 index 00000000..4c2b1817 --- /dev/null +++ b/src/lib/unstable/kit/controls/ArrayBase/index.ts @@ -0,0 +1 @@ +export * from './ArrayBase'; diff --git a/src/lib/unstable/kit/controls/Checkbox/Checkbox.scss b/src/lib/unstable/kit/controls/Checkbox/Checkbox.scss new file mode 100644 index 00000000..642650d0 --- /dev/null +++ b/src/lib/unstable/kit/controls/Checkbox/Checkbox.scss @@ -0,0 +1,7 @@ +@import '../../styles/variables.scss'; + +.#{$ns}checkbox { + min-height: 28px; + display: flex; + align-items: center; +} diff --git a/src/lib/unstable/kit/controls/Checkbox/Checkbox.tsx b/src/lib/unstable/kit/controls/Checkbox/Checkbox.tsx new file mode 100644 index 00000000..5b2eda28 --- /dev/null +++ b/src/lib/unstable/kit/controls/Checkbox/Checkbox.tsx @@ -0,0 +1,44 @@ +import React from 'react'; + +import type {CheckboxProps as CheckboxBaseProps} from '@gravity-ui/uikit'; +import {Checkbox as CheckboxBase} from '@gravity-ui/uikit'; + +import type {Control, JsonSchemaBoolean} from '../../../core'; +import {ControlError} from '../../components'; +import {block, getValidationState} from '../../utils'; + +import './Checkbox.scss'; + +const b = block('checkbox'); + +export interface CheckboxProps + extends Omit< + CheckboxBaseProps, + 'checked' | 'onFocus' | 'onBlur' | 'onChange' | 'onUpdate' | 'qa' + > {} + +const Component: Control = ({ + controlProps, + input, + meta, + schema, +}) => { + return ( + +
+ +
+
+ ); +}; + +export const Checkbox = React.memo(Component); diff --git a/src/lib/unstable/kit/controls/Checkbox/index.ts b/src/lib/unstable/kit/controls/Checkbox/index.ts new file mode 100644 index 00000000..fd0eb3f1 --- /dev/null +++ b/src/lib/unstable/kit/controls/Checkbox/index.ts @@ -0,0 +1 @@ +export {Checkbox, type CheckboxProps} from './Checkbox'; diff --git a/src/lib/unstable/kit/controls/CheckboxGroup/CheckboxGroup.scss b/src/lib/unstable/kit/controls/CheckboxGroup/CheckboxGroup.scss new file mode 100644 index 00000000..fe679eff --- /dev/null +++ b/src/lib/unstable/kit/controls/CheckboxGroup/CheckboxGroup.scss @@ -0,0 +1,5 @@ +@import '../../styles/variables.scss'; + +.#{$ns}checkbox-group { + padding-top: 7.5px; +} diff --git a/src/lib/unstable/kit/controls/CheckboxGroup/CheckboxGroup.tsx b/src/lib/unstable/kit/controls/CheckboxGroup/CheckboxGroup.tsx new file mode 100644 index 00000000..503357ab --- /dev/null +++ b/src/lib/unstable/kit/controls/CheckboxGroup/CheckboxGroup.tsx @@ -0,0 +1,79 @@ +import React from 'react'; + +import {Checkbox, Flex} from '@gravity-ui/uikit'; + +import type {Control, JsonSchemaArray} from '../../../core'; +import {ControlError} from '../../components'; +import {block, getValidationState} from '../../utils'; + +import './CheckboxGroup.scss'; + +const b = block('checkbox-group'); + +export interface CheckboxGroupProps { + enumDescriptions?: Record; + optionsDisabled?: Record; + direction?: 'row' | 'column'; + disabled?: boolean; +} + +const Component: Control = ({ + controlProps, + input, + meta, + schema, +}) => { + const {direction, disabled, enumDescriptions, optionsDisabled} = controlProps; + + const value = React.useMemo( + () => (Array.isArray(input.value) ? (input.value as string[]) : []), + [input.value], + ); + + const options = React.useMemo(() => { + if (schema.items && 'enum' in schema.items) { + return schema?.items?.enum?.map((el) => { + const value = `${el}`; + + return { + value, + text: enumDescriptions?.[value] || value, + }; + }); + } + + return; + }, [enumDescriptions, schema]); + + const onUpdate = React.useCallback( + (optionValue: string, selected: boolean) => { + if (selected) { + input.onChange([...value, optionValue]); + } else { + input.onChange(value.filter((el) => el !== optionValue)); + } + }, + [input.onChange, value], + ); + + return ( + + + {options?.map(({value: optionValue, text}) => ( + onUpdate(optionValue, checked)} + content={text} + disabled={disabled || optionsDisabled?.[optionValue] || schema.readOnly} + qa={`${input.name}-${optionValue}`} + key={optionValue} + /> + ))} + + + ); +}; + +export const CheckboxGroup = React.memo(Component); diff --git a/src/lib/unstable/kit/controls/CheckboxGroup/index.ts b/src/lib/unstable/kit/controls/CheckboxGroup/index.ts new file mode 100644 index 00000000..4fc534f4 --- /dev/null +++ b/src/lib/unstable/kit/controls/CheckboxGroup/index.ts @@ -0,0 +1 @@ +export {CheckboxGroup, type CheckboxGroupProps} from './CheckboxGroup'; diff --git a/src/lib/unstable/kit/controls/ColorPicker/ColorPicker.tsx b/src/lib/unstable/kit/controls/ColorPicker/ColorPicker.tsx new file mode 100644 index 00000000..b5bed066 --- /dev/null +++ b/src/lib/unstable/kit/controls/ColorPicker/ColorPicker.tsx @@ -0,0 +1,48 @@ +import React from 'react'; + +import { + unstable_ColorPicker as ColorPickerBase, + type unstable_ColorPickerProps as ColorPickerBaseProps, +} from '@gravity-ui/uikit/unstable'; + +import type {Control, JsonSchemaString} from '../../../core'; +import {ControlError} from '../../components'; +import {getValidationState} from '../../utils'; + +export interface ColorPickerProps extends Omit {} + +const Component: Control = ({ + controlProps, + input, + meta, + schema, +}) => { + const {onOpenChange: onOpenChangeProps, ...restControlProps} = controlProps; + + const onOpenChange = React.useCallback( + (open: boolean) => { + onOpenChangeProps?.(open); + + if (open) { + input.onFocus(); + } else { + input.onBlur(); + } + }, + [input.onBlur, input.onFocus, onOpenChangeProps], + ); + + return ( + + + + ); +}; + +export const ColorPicker = React.memo(Component); diff --git a/src/lib/unstable/kit/controls/ColorPicker/index.ts b/src/lib/unstable/kit/controls/ColorPicker/index.ts new file mode 100644 index 00000000..2d0196a0 --- /dev/null +++ b/src/lib/unstable/kit/controls/ColorPicker/index.ts @@ -0,0 +1 @@ +export {ColorPicker, type ColorPickerProps} from './ColorPicker'; diff --git a/src/lib/unstable/kit/controls/DateInput/DateInput.scss b/src/lib/unstable/kit/controls/DateInput/DateInput.scss new file mode 100644 index 00000000..809a65d5 --- /dev/null +++ b/src/lib/unstable/kit/controls/DateInput/DateInput.scss @@ -0,0 +1,5 @@ +@import '../../styles/variables.scss'; + +.#{$ns}date-input { + width: 100%; +} diff --git a/src/lib/unstable/kit/controls/DateInput/DateInput.tsx b/src/lib/unstable/kit/controls/DateInput/DateInput.tsx new file mode 100644 index 00000000..5c069aa1 --- /dev/null +++ b/src/lib/unstable/kit/controls/DateInput/DateInput.tsx @@ -0,0 +1,103 @@ +import React from 'react'; + +import type {DatePickerProps} from '@gravity-ui/date-components'; +import {DatePicker} from '@gravity-ui/date-components'; +import type {DateTime} from '@gravity-ui/date-utils'; +import {dateTimeParse, isValidTimeZone} from '@gravity-ui/date-utils'; + +import type {Control, JsonSchemaAny} from '../../../core'; +import {ControlError} from '../../components'; +import {block, getValidationState} from '../../utils'; + +import './DateInput.scss'; + +export const DEFAULT_DATE_FORMAT = 'DD.MM.YYYY HH:mm'; + +const b = block('date-input'); + +export interface DateInputProps + extends Omit { + outputFormat?: string; +} + +const Component: Control = ({controlProps, input, meta, schema}) => { + const {outputFormat, timeZone: timeZoneProp, ...restControlProps} = controlProps; + + const timeZone = timeZoneProp && isValidTimeZone(timeZoneProp) ? timeZoneProp : undefined; + + const onUpdate = React.useCallback( + (date: DateTime | null) => { + if (!date) { + input.onChange(undefined); + + return; + } + + if (outputFormat === 'date_time') { + input.onChange(date); + + return; + } + + if (outputFormat === 'date') { + input.onChange(date.toDate()); + + return; + } + + if (outputFormat === 'timestamp') { + input.onChange({ + seconds: Math.floor(date.toDate().getTime() / 1000), + nanos: 0, + }); + + return; + } + + if (outputFormat === 'string' || !outputFormat) { + input.onChange(date.toISOString()); + + return; + } + + input.onChange(date.format(outputFormat)); + }, + [outputFormat, input.onChange], + ); + + const value = React.useMemo(() => { + if (!input.value) { + return null; + } + + let raw = input.value as {seconds?: number} | string | number | Date | null | undefined; + + if (typeof raw === 'object' && raw !== null && 'seconds' in raw && raw.seconds) { + raw = raw.seconds * 1000; + } + + return dateTimeParse(raw, {format: outputFormat, timeZone}) || null; + }, [input.value, outputFormat, timeZone]); + + return ( + + + + ); +}; + +export const DateInput = React.memo(Component); diff --git a/src/lib/unstable/kit/controls/DateInput/index.ts b/src/lib/unstable/kit/controls/DateInput/index.ts new file mode 100644 index 00000000..277047a0 --- /dev/null +++ b/src/lib/unstable/kit/controls/DateInput/index.ts @@ -0,0 +1 @@ +export {DateInput, type DateInputProps} from './DateInput'; diff --git a/src/lib/unstable/kit/controls/MultiSelect/MultiSelect.tsx b/src/lib/unstable/kit/controls/MultiSelect/MultiSelect.tsx new file mode 100644 index 00000000..3f13b842 --- /dev/null +++ b/src/lib/unstable/kit/controls/MultiSelect/MultiSelect.tsx @@ -0,0 +1,99 @@ +import React from 'react'; + +import { + Flex, + Select as SelectBase, + type SelectProps as SelectBaseProps, + type SelectOption, + Text, +} from '@gravity-ui/uikit'; +import isString from 'lodash/isString'; + +import type {Control, JsonSchemaArray} from '../../../core'; +import {getValidationState} from '../../utils'; + +export interface MultiSelectProps + extends Omit< + SelectBaseProps, + 'value' | 'onFocus' | 'onBlur' | 'onChange' | 'onUpdate' | 'multiple' | 'qa' + > { + enumDescriptions?: Record; + optionsMeta?: Record; +} + +const Component: Control = ({ + controlProps, + input, + meta, + schema, +}) => { + const {enumDescriptions, optionsMeta, ...restControlProps} = controlProps; + + const value = React.useMemo( + () => (Array.isArray(input.value) && input.value.every(isString) ? input.value : undefined), + [input.value], + ); + + const enumValues = schema.items && 'enum' in schema.items ? schema.items.enum : undefined; + + const options = React.useMemo(() => { + if (enumValues) { + return enumValues?.map((el) => { + const value = `${el}`; + const text = enumDescriptions?.[value] || value; + const optionMeta = optionsMeta?.[value]; + let content: React.ReactNode = text; + + if (optionMeta) { + content = ( + + {text} + {optionMeta} + + ); + } + + return {value, text, content, key: value, data: {optionMeta}}; + }); + } + + return; + }, [enumDescriptions, enumValues, optionsMeta]); + + const renderOption: SelectBaseProps['renderOption'] = React.useCallback( + (option: SelectOption) => ( + + {option.content || option.text || option.value} + + ), + [], + ); + + const getOptionHeight: SelectBaseProps['getOptionHeight'] = React.useCallback( + (option: SelectOption) => (option.data?.optionMeta ? 44 : 28), + [], + ); + + return ( + 9} + renderOption={renderOption} + getOptionHeight={getOptionHeight} + disabled={schema.readOnly} + {...restControlProps} + value={value} + onFocus={input.onFocus as SelectBaseProps['onFocus']} + onBlur={input.onBlur as SelectBaseProps['onBlur']} + onUpdate={input.onChange} + errorMessage={meta.error} + validationState={getValidationState(meta)} + placeholder={`${schema.examples?.[0]?.[0]}`} + multiple + qa={input.name} + /> + ); +}; + +export const MultiSelect = React.memo(Component); diff --git a/src/lib/unstable/kit/controls/MultiSelect/index.ts b/src/lib/unstable/kit/controls/MultiSelect/index.ts new file mode 100644 index 00000000..9f420fac --- /dev/null +++ b/src/lib/unstable/kit/controls/MultiSelect/index.ts @@ -0,0 +1 @@ +export {MultiSelect, type MultiSelectProps} from './MultiSelect'; diff --git a/src/lib/unstable/kit/controls/NumberBase/Number.tsx b/src/lib/unstable/kit/controls/NumberBase/Number.tsx new file mode 100644 index 00000000..e5feb3d1 --- /dev/null +++ b/src/lib/unstable/kit/controls/NumberBase/Number.tsx @@ -0,0 +1,49 @@ +import React from 'react'; + +import {NumberInput, type NumberInputProps} from '@gravity-ui/uikit'; + +import {type Control, type JsonSchemaNumber} from '../../../core'; +import {getValidationState} from '../../utils'; + +export interface NumberBaseProps + extends Omit< + NumberInputProps, + | 'value' + | 'defaultValue' + | 'onFocus' + | 'onBlur' + | 'onChange' + | 'onUpdate' + | 'errorMessage' + | 'validationState' + | 'placeholder' + | 'qa' + > {} + +const Component: Control = ({ + controlProps, + input, + meta, + schema, +}) => { + return ( + + ); +}; + +export const NumberBase = React.memo(Component); diff --git a/src/lib/unstable/kit/controls/NumberBase/index.ts b/src/lib/unstable/kit/controls/NumberBase/index.ts new file mode 100644 index 00000000..203d991e --- /dev/null +++ b/src/lib/unstable/kit/controls/NumberBase/index.ts @@ -0,0 +1 @@ +export {NumberBase, type NumberBaseProps} from './Number'; diff --git a/src/lib/unstable/kit/controls/ObjectBase/ObjectBase.tsx b/src/lib/unstable/kit/controls/ObjectBase/ObjectBase.tsx new file mode 100644 index 00000000..4090f8e1 --- /dev/null +++ b/src/lib/unstable/kit/controls/ObjectBase/ObjectBase.tsx @@ -0,0 +1,63 @@ +import React from 'react'; + +import {Plus} from '@gravity-ui/icons'; +import {Button, Flex, Icon} from '@gravity-ui/uikit'; + +import {type Control, Entity, type JsonSchemaObject} from '../../../core'; +import {ControlError} from '../../components'; +import {getValidationState} from '../../utils'; + +export interface ObjectBaseProps { + addButtonText?: string; + disabled?: boolean; + order?: string[]; +} + +const Component: Control = ({ + controlProps, + input, + meta, + schema, +}) => { + const addButton = React.useMemo(() => { + const onClick = () => input.onChange(schema.default); + + return ( + + ); + }, [ + controlProps.addButtonText, + controlProps.disabled, + input.onChange, + schema.default, + schema.readOnly, + ]); + + return ( + + + + {(controlProps.order || Object.keys(schema.properties || {})).map( + (property: string) => ( + + ), + )} + {input.value ? null : addButton} + + + + ); +}; + +export const ObjectBase = React.memo(Component); diff --git a/src/lib/unstable/kit/controls/ObjectBase/index.ts b/src/lib/unstable/kit/controls/ObjectBase/index.ts new file mode 100644 index 00000000..e0954609 --- /dev/null +++ b/src/lib/unstable/kit/controls/ObjectBase/index.ts @@ -0,0 +1 @@ +export {ObjectBase, type ObjectBaseProps} from './ObjectBase'; diff --git a/src/lib/unstable/kit/controls/Password/Password.tsx b/src/lib/unstable/kit/controls/Password/Password.tsx new file mode 100644 index 00000000..7017bbb0 --- /dev/null +++ b/src/lib/unstable/kit/controls/Password/Password.tsx @@ -0,0 +1,46 @@ +import React from 'react'; + +import {PasswordInput, type PasswordInputProps} from '@gravity-ui/uikit'; + +import type {Control, JsonSchemaString} from '../../../core'; +import {getValidationState} from '../../utils'; + +export interface PasswordProps + extends Omit< + PasswordInputProps, + | 'value' + | 'onFocus' + | 'onBlur' + | 'onChange' + | 'onUpdate' + | 'errorMessage' + | 'validationState' + | 'placeholder' + | 'qa' + > {} + +const Component: Control = ({ + controlProps, + input, + meta, + schema, +}) => { + return ( + + ); +}; + +export const Password = React.memo(Component); diff --git a/src/lib/unstable/kit/controls/Password/index.ts b/src/lib/unstable/kit/controls/Password/index.ts new file mode 100644 index 00000000..95500f1b --- /dev/null +++ b/src/lib/unstable/kit/controls/Password/index.ts @@ -0,0 +1 @@ +export {Password, type PasswordProps} from './Password'; diff --git a/src/lib/unstable/kit/controls/RadioGroup/RadioGroup.scss b/src/lib/unstable/kit/controls/RadioGroup/RadioGroup.scss new file mode 100644 index 00000000..068e49c4 --- /dev/null +++ b/src/lib/unstable/kit/controls/RadioGroup/RadioGroup.scss @@ -0,0 +1,5 @@ +@import '../../styles/variables.scss'; + +.#{$ns}radio-group { + padding-top: 7.5px; +} diff --git a/src/lib/unstable/kit/controls/RadioGroup/RadioGroup.tsx b/src/lib/unstable/kit/controls/RadioGroup/RadioGroup.tsx new file mode 100644 index 00000000..7b23295d --- /dev/null +++ b/src/lib/unstable/kit/controls/RadioGroup/RadioGroup.tsx @@ -0,0 +1,63 @@ +import React from 'react'; + +import { + Flex, + RadioGroup as RadioGroupBase, + type RadioGroupProps as RadioGroupBaseProps, + type RadioGroupOption, +} from '@gravity-ui/uikit'; + +import type {Control, JsonSchemaString} from '../../../core'; +import {ControlError} from '../../components'; +import {block, getValidationState} from '../../utils'; + +import './RadioGroup.scss'; + +const b = block('radio-group'); + +export interface RadioGroupProps + extends Omit< + RadioGroupBaseProps, + 'value' | 'onFocus' | 'onBlur' | 'onChange' | 'onUpdate' | 'qa' + > { + enumDescriptions?: Record; + optionsDisabled?: Record; +} + +const Component: Control = ({ + controlProps, + input, + meta, + schema, +}) => { + const {enumDescriptions, optionsDisabled, ...restControlProps} = controlProps; + + const options: RadioGroupOption[] | undefined = React.useMemo( + () => + schema.enum?.map((value) => ({ + value, + content: enumDescriptions?.[value] || value, + disabled: optionsDisabled?.[value], + })), + [enumDescriptions, optionsDisabled, schema.enum], + ); + + return ( + + + + + + ); +}; + +export const RadioGroup = React.memo(Component); diff --git a/src/lib/unstable/kit/controls/RadioGroup/index.ts b/src/lib/unstable/kit/controls/RadioGroup/index.ts new file mode 100644 index 00000000..0adaccc4 --- /dev/null +++ b/src/lib/unstable/kit/controls/RadioGroup/index.ts @@ -0,0 +1 @@ +export {RadioGroup, type RadioGroupProps} from './RadioGroup'; diff --git a/src/lib/unstable/kit/controls/RangeSlider/RangeSlider.scss b/src/lib/unstable/kit/controls/RangeSlider/RangeSlider.scss new file mode 100644 index 00000000..b58c226b --- /dev/null +++ b/src/lib/unstable/kit/controls/RangeSlider/RangeSlider.scss @@ -0,0 +1,5 @@ +@import '../../styles/variables.scss'; + +.#{$ns}range-slider { + width: 100%; +} diff --git a/src/lib/unstable/kit/controls/RangeSlider/RangeSlider.tsx b/src/lib/unstable/kit/controls/RangeSlider/RangeSlider.tsx new file mode 100644 index 00000000..38327299 --- /dev/null +++ b/src/lib/unstable/kit/controls/RangeSlider/RangeSlider.tsx @@ -0,0 +1,78 @@ +import React from 'react'; + +import {Slider as SliderBase, type SliderProps as SliderBaseProps} from '@gravity-ui/uikit'; + +import type {Control, JsonSchemaObject} from '../../../core'; +import {block, getValidationState} from '../../utils'; + +import './RangeSlider.scss'; + +const b = block('range-slider'); + +export interface RangeSliderProps + extends Omit { + propertyKeys?: [string, string]; +} + +const Component: Control = ({ + controlProps, + input, + meta, + schema, +}) => { + const {propertyKeys, ...restControlProps} = controlProps; + + const [fromKey, toKey] = propertyKeys || ['from', 'to']; + + const min = + schema.properties?.[fromKey] && 'minimum' in schema.properties[fromKey] + ? schema.properties?.[fromKey]?.minimum + : undefined; + const max = + schema.properties?.[toKey] && 'maximum' in schema.properties[toKey] + ? schema.properties?.[toKey]?.maximum + : undefined; + + const value: [number, number] | undefined = + isNaN(Number(input.value?.[fromKey])) || isNaN(Number(input.value?.[toKey])) + ? undefined + : [Number(input.value?.[fromKey]), Number(input.value?.[toKey])]; + const defaultValue: [number, number] | undefined = + isNaN(Number(schema.default?.[fromKey])) || isNaN(Number(schema.default?.[toKey])) + ? undefined + : [Number(schema.default?.[fromKey]), Number(schema.default?.[toKey])]; + + const onUpdate = React.useCallback( + (next: number | [number, number]) => { + if (!Array.isArray(next)) { + return; + } + + input.onChange({[fromKey]: next[0], [toKey]: next[1]}); + }, + [fromKey, toKey, input.onChange], + ); + + return ( + + ); +}; + +export const RangeSlider = React.memo(Component); diff --git a/src/lib/unstable/kit/controls/RangeSlider/index.ts b/src/lib/unstable/kit/controls/RangeSlider/index.ts new file mode 100644 index 00000000..620f57f6 --- /dev/null +++ b/src/lib/unstable/kit/controls/RangeSlider/index.ts @@ -0,0 +1 @@ +export {RangeSlider, type RangeSliderProps} from './RangeSlider'; diff --git a/src/lib/unstable/kit/controls/Select/Select.tsx b/src/lib/unstable/kit/controls/Select/Select.tsx new file mode 100644 index 00000000..8711dc8b --- /dev/null +++ b/src/lib/unstable/kit/controls/Select/Select.tsx @@ -0,0 +1,98 @@ +import React from 'react'; + +import { + Flex, + Select as SelectBase, + type SelectProps as SelectBaseProps, + type SelectOption, + Text, +} from '@gravity-ui/uikit'; +import isString from 'lodash/isString'; + +import type {Control, JsonSchemaString} from '../../../core'; +import {getValidationState} from '../../utils'; + +export interface SelectProps + extends Omit< + SelectBaseProps, + | 'value' + | 'onFocus' + | 'onBlur' + | 'onChange' + | 'onUpdate' + | 'onOpenChange' + | 'multiple' + | 'qa' + > { + enumDescriptions?: Record; + optionsMeta?: Record; + options?: SelectBaseProps['options']; +} + +const Component: Control = ({controlProps, input, meta, schema}) => { + const {enumDescriptions, optionsMeta, ...restControlProps} = controlProps; + + const value = React.useMemo( + () => (isString(input.value) ? [input.value] : undefined), + [input.value], + ); + + const onUpdate = React.useCallback((v: string[]) => input.onChange(v[0]), [input.onChange]); + + const options = React.useMemo( + () => + schema.enum?.map((value) => { + const optionMeta = optionsMeta?.[value]; + const text = enumDescriptions?.[value] || value; + let content: React.ReactNode = text; + + if (optionMeta) { + content = ( + + {text} + {optionMeta} + + ); + } + + return {value, text, content, key: value, data: {optionMeta}}; + }), + [enumDescriptions, optionsMeta, schema.enum], + ); + + const renderOption: SelectBaseProps['renderOption'] = React.useCallback( + (option: SelectOption) => ( + + {option.content || option.text || option.value} + + ), + [], + ); + + const getOptionHeight: SelectBaseProps['getOptionHeight'] = React.useCallback( + (option: SelectOption) => (option.data?.optionMeta ? 44 : 28), + [], + ); + + return ( + 9} + renderOption={renderOption} + getOptionHeight={getOptionHeight} + disabled={schema.readOnly} + {...restControlProps} + value={value} + onFocus={input.onFocus as SelectBaseProps['onFocus']} + onBlur={input.onBlur as SelectBaseProps['onBlur']} + onUpdate={onUpdate} + errorMessage={meta.error} + validationState={getValidationState(meta)} + placeholder={schema.examples?.[0]} + qa={input.name} + /> + ); +}; + +export const Select = React.memo(Component); diff --git a/src/lib/unstable/kit/controls/Select/index.ts b/src/lib/unstable/kit/controls/Select/index.ts new file mode 100644 index 00000000..0054ce9b --- /dev/null +++ b/src/lib/unstable/kit/controls/Select/index.ts @@ -0,0 +1 @@ +export {Select, type SelectProps} from './Select'; diff --git a/src/lib/unstable/kit/controls/Slider/Slider.scss b/src/lib/unstable/kit/controls/Slider/Slider.scss new file mode 100644 index 00000000..33e259dd --- /dev/null +++ b/src/lib/unstable/kit/controls/Slider/Slider.scss @@ -0,0 +1,5 @@ +@import '../../styles/variables.scss'; + +.#{$ns}slider { + width: 100%; +} diff --git a/src/lib/unstable/kit/controls/Slider/Slider.tsx b/src/lib/unstable/kit/controls/Slider/Slider.tsx new file mode 100644 index 00000000..cd2fc52b --- /dev/null +++ b/src/lib/unstable/kit/controls/Slider/Slider.tsx @@ -0,0 +1,60 @@ +import React from 'react'; + +import {Slider as SliderBase, type SliderProps as SliderBaseProps} from '@gravity-ui/uikit'; + +import type {Control, JsonSchemaNumber} from '../../../core'; +import {block, getValidationState} from '../../utils'; + +import './Slider.scss'; + +const b = block('slider'); + +export interface SliderProps + extends Omit< + SliderBaseProps, + | 'value' + | 'onFocus' + | 'onBlur' + | 'onChange' + | 'onUpdate' + | 'errorMessage' + | 'validationState' + | 'qa' + > {} + +const Component: Control = ({controlProps, input, meta, schema}) => { + const value = isNaN(Number(input.value)) ? undefined : Number(input.value); + + const onUpdate = React.useCallback( + (next: number | [number, number]) => { + if (Array.isArray(next)) { + return; + } + + input.onChange(next); + }, + [input.onChange], + ); + + return ( + + ); +}; + +export const Slider = React.memo(Component); diff --git a/src/lib/unstable/kit/controls/Slider/index.ts b/src/lib/unstable/kit/controls/Slider/index.ts new file mode 100644 index 00000000..14bb3016 --- /dev/null +++ b/src/lib/unstable/kit/controls/Slider/index.ts @@ -0,0 +1 @@ +export {Slider, type SliderProps} from './Slider'; diff --git a/src/lib/unstable/kit/controls/StringBase/StringBase.tsx b/src/lib/unstable/kit/controls/StringBase/StringBase.tsx new file mode 100644 index 00000000..bcb3e9c8 --- /dev/null +++ b/src/lib/unstable/kit/controls/StringBase/StringBase.tsx @@ -0,0 +1,47 @@ +import React from 'react'; + +import {TextInput, type TextInputProps} from '@gravity-ui/uikit'; + +import type {Control, JsonSchemaString} from '../../../core'; +import {getValidationState} from '../../utils'; + +export interface StringBaseProps + extends Omit< + TextInputProps, + | 'type' + | 'value' + | 'onFocus' + | 'onBlur' + | 'onChange' + | 'onUpdate' + | 'errorMessage' + | 'validationState' + | 'placeholder' + | 'qa' + > {} + +const Component: Control = ({ + controlProps, + input, + meta, + schema, +}) => { + return ( + + ); +}; + +export const StringBase = React.memo(Component); diff --git a/src/lib/unstable/kit/controls/StringBase/index.ts b/src/lib/unstable/kit/controls/StringBase/index.ts new file mode 100644 index 00000000..7463f6d9 --- /dev/null +++ b/src/lib/unstable/kit/controls/StringBase/index.ts @@ -0,0 +1 @@ +export {StringBase, type StringBaseProps} from './StringBase'; diff --git a/src/lib/unstable/kit/controls/Switch/Switch.scss b/src/lib/unstable/kit/controls/Switch/Switch.scss new file mode 100644 index 00000000..eb6e48e5 --- /dev/null +++ b/src/lib/unstable/kit/controls/Switch/Switch.scss @@ -0,0 +1,7 @@ +@import '../../styles/variables.scss'; + +.#{$ns}switch { + min-height: 28px; + display: flex; + align-items: center; +} diff --git a/src/lib/unstable/kit/controls/Switch/Switch.tsx b/src/lib/unstable/kit/controls/Switch/Switch.tsx new file mode 100644 index 00000000..1d64c0c6 --- /dev/null +++ b/src/lib/unstable/kit/controls/Switch/Switch.tsx @@ -0,0 +1,43 @@ +import React from 'react'; + +import {Switch as SwitchBase, type SwitchProps as SwitchBaseProps} from '@gravity-ui/uikit'; + +import type {Control, JsonSchemaBoolean} from '../../../core'; +import {ControlError} from '../../components'; +import {block, getValidationState} from '../../utils'; + +import './Switch.scss'; + +const b = block('switch'); + +export interface SwitchProps + extends Omit< + SwitchBaseProps, + 'checked' | 'onFocus' | 'onBlur' | 'onChange' | 'onUpdate' | 'qa' + > {} + +const Component: Control = ({ + controlProps, + input, + schema, + meta, +}) => { + return ( + +
+ +
+
+ ); +}; + +export const Switch = React.memo(Component); diff --git a/src/lib/unstable/kit/controls/Switch/index.ts b/src/lib/unstable/kit/controls/Switch/index.ts new file mode 100644 index 00000000..df99c34a --- /dev/null +++ b/src/lib/unstable/kit/controls/Switch/index.ts @@ -0,0 +1 @@ +export {Switch, type SwitchProps} from './Switch'; diff --git a/src/lib/unstable/kit/controls/TextArea/TextArea.tsx b/src/lib/unstable/kit/controls/TextArea/TextArea.tsx new file mode 100644 index 00000000..c3683c30 --- /dev/null +++ b/src/lib/unstable/kit/controls/TextArea/TextArea.tsx @@ -0,0 +1,47 @@ +import React from 'react'; + +import {TextArea as TextAreaBase, type TextAreaProps as TextAreaBaseProps} from '@gravity-ui/uikit'; + +import type {Control, JsonSchemaString} from '../../../core'; +import {getValidationState} from '../../utils'; + +export interface TextAreaProps + extends Omit< + TextAreaBaseProps, + | 'value' + | 'onFocus' + | 'onBlur' + | 'onChange' + | 'onUpdate' + | 'errorMessage' + | 'validationState' + | 'placeholder' + | 'qa' + > {} + +const Component: Control = ({ + controlProps, + input, + meta, + schema, +}) => { + return ( + + ); +}; + +export const TextArea = React.memo(Component); diff --git a/src/lib/unstable/kit/controls/TextArea/index.ts b/src/lib/unstable/kit/controls/TextArea/index.ts new file mode 100644 index 00000000..f855f3db --- /dev/null +++ b/src/lib/unstable/kit/controls/TextArea/index.ts @@ -0,0 +1 @@ +export {TextArea, type TextAreaProps} from './TextArea'; diff --git a/src/lib/unstable/kit/controls/index.ts b/src/lib/unstable/kit/controls/index.ts new file mode 100644 index 00000000..9f4c57fa --- /dev/null +++ b/src/lib/unstable/kit/controls/index.ts @@ -0,0 +1,16 @@ +export {ArrayBase, type ArrayBaseProps} from './ArrayBase'; +export {Checkbox, type CheckboxProps} from './Checkbox'; +export {CheckboxGroup, type CheckboxGroupProps} from './CheckboxGroup'; +export {ColorPicker, type ColorPickerProps} from './ColorPicker'; +export {DateInput, type DateInputProps} from './DateInput'; +export {MultiSelect, type MultiSelectProps} from './MultiSelect'; +export {NumberBase, type NumberBaseProps} from './NumberBase'; +export {ObjectBase, type ObjectBaseProps} from './ObjectBase'; +export {Password, type PasswordProps} from './Password'; +export {RadioGroup, type RadioGroupProps} from './RadioGroup'; +export {RangeSlider, type RangeSliderProps} from './RangeSlider'; +export {Select, type SelectProps} from './Select'; +export {Slider, type SliderProps} from './Slider'; +export {StringBase, type StringBaseProps} from './StringBase'; +export {Switch, type SwitchProps} from './Switch'; +export {TextArea, type TextAreaProps} from './TextArea'; diff --git a/src/lib/unstable/kit/styles/functions.scss b/src/lib/unstable/kit/styles/functions.scss new file mode 100644 index 00000000..a1f2b358 --- /dev/null +++ b/src/lib/unstable/kit/styles/functions.scss @@ -0,0 +1,3 @@ +@function spacing($multiplier: 1) { + @return calc(var(--g-spacing-base) * $multiplier); +} diff --git a/src/lib/unstable/kit/styles/variables.scss b/src/lib/unstable/kit/styles/variables.scss new file mode 100644 index 00000000..8e20e348 --- /dev/null +++ b/src/lib/unstable/kit/styles/variables.scss @@ -0,0 +1 @@ +$ns: 'sr-'; diff --git a/src/lib/unstable/kit/utils/cn.ts b/src/lib/unstable/kit/utils/cn.ts new file mode 100644 index 00000000..eb1c0c2a --- /dev/null +++ b/src/lib/unstable/kit/utils/cn.ts @@ -0,0 +1,5 @@ +import {withNaming} from '@bem-react/classname'; + +const NAMESPACE = 'sr-'; + +export const block = withNaming({n: NAMESPACE, e: '__', m: '_'}); diff --git a/src/lib/unstable/kit/utils/common.ts b/src/lib/unstable/kit/utils/common.ts new file mode 100644 index 00000000..bd02c6f5 --- /dev/null +++ b/src/lib/unstable/kit/utils/common.ts @@ -0,0 +1,30 @@ +import type {FormApi} from 'final-form'; +import type {FieldMetaState} from 'react-final-form'; + +import type {EntityState, JsonSchemaArray} from '../../core'; + +export const getValidationState = (meta: FieldMetaState): 'invalid' | undefined => { + if ((meta.touched || meta.submitFailed) && meta.error) { + return 'invalid'; + } + + return undefined; +}; + +export const getArrayItemParentName = (name: string) => name.slice(0, name.lastIndexOf('[')); + +export const getArrayItemIndex = (name: string) => name.slice(name.lastIndexOf('[') + 1, -1); + +export const isArrayItem = (name: string) => name.endsWith(']'); + +export const isTupleItem = (name: string, form: FormApi) => { + if (!isArrayItem(name)) { + return false; + } + + const parentName = getArrayItemParentName(name); + const parentField = form.getFieldState(parentName); + const parentSchema = (parentField?.data as EntityState)?.schema; + + return Array.isArray(parentSchema?.items); +}; diff --git a/src/lib/unstable/kit/utils/index.ts b/src/lib/unstable/kit/utils/index.ts new file mode 100644 index 00000000..e40ce604 --- /dev/null +++ b/src/lib/unstable/kit/utils/index.ts @@ -0,0 +1,8 @@ +export {block} from './cn'; +export { + getArrayItemIndex, + getArrayItemParentName, + getValidationState, + isArrayItem, + isTupleItem, +} from './common'; diff --git a/src/lib/unstable/kit/wrappers/Row/Row.scss b/src/lib/unstable/kit/wrappers/Row/Row.scss new file mode 100644 index 00000000..7fe79623 --- /dev/null +++ b/src/lib/unstable/kit/wrappers/Row/Row.scss @@ -0,0 +1,37 @@ +@import '../../styles/functions.scss'; +@import '../../styles/variables.scss'; + +.#{$ns}row { + margin-bottom: spacing(4); + + &:last-child { + margin-bottom: 0; + } + + &__left { + display: inline; + width: 180px; + min-height: 28px; + padding-top: 5.5px; + } + + &__title { + min-height: 18px; + margin-right: spacing(1); + + &_required { + &::after { + content: '*'; + margin-left: spacing(1); + color: var(--g-color-text-danger); + } + } + } + + &__right { + display: flex; + flex-direction: column; + flex-grow: 1; + gap: spacing(0.5); + } +} diff --git a/src/lib/unstable/kit/wrappers/Row/Row.tsx b/src/lib/unstable/kit/wrappers/Row/Row.tsx new file mode 100644 index 00000000..e6929ab6 --- /dev/null +++ b/src/lib/unstable/kit/wrappers/Row/Row.tsx @@ -0,0 +1,60 @@ +import React from 'react'; + +import {Flex, HelpMark, Text} from '@gravity-ui/uikit'; + +import type {JsonSchema, Wrapper} from '../../../core'; +import {ArrayRemoveButton, HTMLContent} from '../../components'; +import {block} from '../../utils'; + +import './Row.scss'; + +const b = block('row'); + +export interface RowProps { + descriptionType?: 'tooltip' | 'bottom'; +} + +const Component: Wrapper = ({children, input, schema, wrapperProps}) => { + const tooltip = React.useMemo(() => { + if (!schema.description || wrapperProps.descriptionType === 'bottom') { + return null; + } + + return ( + + + + ); + }, [schema.description, wrapperProps.descriptionType]); + + const bottomDescription = React.useMemo(() => { + if (!schema.description || wrapperProps.descriptionType !== 'bottom') { + return null; + } + + return ; + }, [schema.description, wrapperProps.descriptionType]); + + return ( + +
+ + {schema.title} + + {tooltip} +
+
+ + {children} + + + {bottomDescription} +
+
+ ); +}; + +export const Row = React.memo(Component); diff --git a/src/lib/unstable/kit/wrappers/Row/index.ts b/src/lib/unstable/kit/wrappers/Row/index.ts new file mode 100644 index 00000000..19fc19f5 --- /dev/null +++ b/src/lib/unstable/kit/wrappers/Row/index.ts @@ -0,0 +1 @@ +export {Row, type RowProps} from './Row'; diff --git a/src/lib/unstable/kit/wrappers/Transparent/Transparent.scss b/src/lib/unstable/kit/wrappers/Transparent/Transparent.scss new file mode 100644 index 00000000..1c26e711 --- /dev/null +++ b/src/lib/unstable/kit/wrappers/Transparent/Transparent.scss @@ -0,0 +1,10 @@ +@import '../../styles/functions.scss'; +@import '../../styles/variables.scss'; + +.#{$ns}transparent { + margin-bottom: spacing(4); + + &:last-child { + margin-bottom: 0; + } +} diff --git a/src/lib/unstable/kit/wrappers/Transparent/Transparent.tsx b/src/lib/unstable/kit/wrappers/Transparent/Transparent.tsx new file mode 100644 index 00000000..52a3c025 --- /dev/null +++ b/src/lib/unstable/kit/wrappers/Transparent/Transparent.tsx @@ -0,0 +1,22 @@ +import React from 'react'; + +import {Flex} from '@gravity-ui/uikit'; + +import type {JsonSchema, Wrapper} from '../../../core'; +import {ArrayRemoveButton} from '../../components'; +import {block} from '../../utils'; + +import './Transparent.scss'; + +const b = block('transparent'); + +const Component: Wrapper = ({children, input}) => { + return ( + + {children} + + + ); +}; + +export const Transparent = React.memo(Component); diff --git a/src/lib/unstable/kit/wrappers/Transparent/index.ts b/src/lib/unstable/kit/wrappers/Transparent/index.ts new file mode 100644 index 00000000..b3214767 --- /dev/null +++ b/src/lib/unstable/kit/wrappers/Transparent/index.ts @@ -0,0 +1 @@ +export {Transparent} from './Transparent'; diff --git a/src/lib/unstable/kit/wrappers/index.ts b/src/lib/unstable/kit/wrappers/index.ts new file mode 100644 index 00000000..32ecec0c --- /dev/null +++ b/src/lib/unstable/kit/wrappers/index.ts @@ -0,0 +1,2 @@ +export {Row, type RowProps} from './Row'; +export {Transparent} from './Transparent'; diff --git a/src/stories/Unstable.stories.tsx b/src/stories/Unstable.stories.tsx index 3965b06e..c8cd955e 100644 --- a/src/stories/Unstable.stories.tsx +++ b/src/stories/Unstable.stories.tsx @@ -9,15 +9,17 @@ import {ObjectBase} from '../lib'; import {SchemaRenderer, schemaRendererMutators} from '../lib/unstable/core'; import {EntityType, JsonSchemaType, SchemaRendererMode} from '../lib/unstable/core/constants'; import type { - JsonSchema, + // JsonSchema, // JsonSchemaAny, - JsonSchemaArray, - JsonSchemaNumber, + // JsonSchemaArray, + // JsonSchemaNumber, JsonSchemaObject, - JsonSchemaString, + // JsonSchemaString, } from '../lib/unstable/core/types'; -import {type untypedConfig} from '../lib/unstable/kit/config'; -import {config} from '../lib/unstable/kit/config'; +// import {type untypedConfig} from '../lib/unstable/kit/config'; +import {type untypedConfig} from '../lib/unstable/kit/constants/config'; +import {config} from '../lib/unstable/kit/constants/config'; +// import {config} from '../lib/unstable/kit/config'; export default { title: 'Unstable/Base', @@ -26,999 +28,1280 @@ export default { // type MyJsonSchemaString = JsonSchemaString; -const stringMaxLength: JsonSchemaString = { - type: JsonSchemaType.String, - maxLength: 1, - default: 'jaja', - title: 'stringMaxLength', - entityParameters: { - type: EntityType.String, - controlType: 'baseString', - controlProps: { - // name: true, - }, - validatorType: 'baseString', - // controlType: 'base', - controlWrapperType: 'rowString', - errorMessages: { - maxLength: 'stringMaxLength', - }, - controlWrapperProps: { - // qtest: 'q', - // qwa, - }, - // viewProps: { - // form: { - // // qw: 'q', - // // clearable: true, - // name: true, - // }, - // }, - // formProps: { - // name: true, - // } - }, -}; +// const stringMaxLength: JsonSchemaString = { +// type: JsonSchemaType.String, +// maxLength: 1, +// default: 'jaja', +// title: 'stringMaxLength', +// entityParameters: { +// type: EntityType.String, +// controlType: 'baseString', +// controlProps: { +// // name: true, +// }, +// validatorType: 'baseString', +// // controlType: 'base', +// controlWrapperType: 'rowString', +// errorMessages: { +// maxLength: 'stringMaxLength', +// }, +// controlWrapperProps: { +// // qtest: 'q', +// // qwa, +// }, +// // viewProps: { +// // form: { +// // // qw: 'q', +// // // clearable: true, +// // name: true, +// // }, +// // }, +// // formProps: { +// // name: true, +// // } +// }, +// }; -const stringMinLength: JsonSchemaString = { - type: JsonSchemaType.String, - minLength: 10, - default: 'jaja', - title: 'stringMinLength', - entityParameters: { - type: EntityType.String, - // validatorType: 'async', - controlType: 'baseString', - controlProps: {}, - controlWrapperType: 'rowString', - controlWrapperProps: {}, - errorMessages: { - minLength: 'stringMinLength', - }, - }, -}; +// const stringMinLength: JsonSchemaString = { +// type: JsonSchemaType.String, +// minLength: 10, +// default: 'jaja', +// title: 'stringMinLength', +// entityParameters: { +// type: EntityType.String, +// // validatorType: 'async', +// controlType: 'baseString', +// controlProps: {}, +// controlWrapperType: 'rowString', +// controlWrapperProps: {}, +// errorMessages: { +// minLength: 'stringMinLength', +// }, +// }, +// }; -const stringPattern: JsonSchemaString = { - type: JsonSchemaType.String, - pattern: '[0-9]', - default: 'jaja', - title: 'stringPattern', - entityParameters: { - type: EntityType.String, - controlType: 'baseString', - controlWrapperType: 'rowString', - controlWrapperProps: {}, - errorMessages: { - pattern: 'stringPattern', - }, - }, -}; +// const stringPattern: JsonSchemaString = { +// type: JsonSchemaType.String, +// pattern: '[0-9]', +// default: 'jaja', +// title: 'stringPattern', +// entityParameters: { +// type: EntityType.String, +// controlType: 'baseString', +// controlWrapperType: 'rowString', +// controlWrapperProps: {}, +// errorMessages: { +// pattern: 'stringPattern', +// }, +// }, +// }; -const stringAllOf: JsonSchemaString = { - type: JsonSchemaType.String, - default: 'jaja', - title: 'stringAllOf', - allOf: [ - { - type: JsonSchemaType.String, - minLength: 9, - entityParameters: { - errorMessages: { - // minLength: 'stringAllOf/minLength from allOf', - }, - }, - }, - { - type: JsonSchemaType.String, - const: 'ja', - entityParameters: { - errorMessages: { - // const: 'stringAllOf/const from allOf', - }, - }, - }, - ], - entityParameters: { - type: EntityType.String, - controlType: 'baseString', - controlWrapperType: 'rowString', - errorMessages: { - minLength: 'stringAllOf/minLength from item', - const: 'stringAllOf/const from item', - }, - }, -}; +// const stringAllOf: JsonSchemaString = { +// type: JsonSchemaType.String, +// default: 'jaja', +// title: 'stringAllOf', +// allOf: [ +// { +// type: JsonSchemaType.String, +// minLength: 9, +// entityParameters: { +// errorMessages: { +// // minLength: 'stringAllOf/minLength from allOf', +// }, +// }, +// }, +// { +// type: JsonSchemaType.String, +// const: 'ja', +// entityParameters: { +// errorMessages: { +// // const: 'stringAllOf/const from allOf', +// }, +// }, +// }, +// ], +// entityParameters: { +// type: EntityType.String, +// controlType: 'baseString', +// controlWrapperType: 'rowString', +// errorMessages: { +// minLength: 'stringAllOf/minLength from item', +// const: 'stringAllOf/const from item', +// }, +// }, +// }; -const stringAnyOf: JsonSchemaString = { - type: JsonSchemaType.String, - default: 'jaja', - title: 'stringAnyOf', - anyOf: [ - { - type: JsonSchemaType.String, - minLength: 9, - entityParameters: { - errorMessages: { - // minLength: 'stringAnyOf/minLength from anyOf', - }, - }, - }, - { - type: JsonSchemaType.String, - const: 'ja', - entityParameters: { - errorMessages: { - // const: 'stringAnyOf/const from anyOf', - }, - }, - }, - ], - entityParameters: { - type: EntityType.String, - controlType: 'baseString', - controlWrapperType: 'rowString', - errorMessages: { - minLength: 'stringAnyOf/minLength from item', - const: 'stringAnyOf/const from item', - anyOf: 'stringAnyOf', - }, - }, -}; +// const stringAnyOf: JsonSchemaString = { +// type: JsonSchemaType.String, +// default: 'jaja', +// title: 'stringAnyOf', +// anyOf: [ +// { +// type: JsonSchemaType.String, +// minLength: 9, +// entityParameters: { +// errorMessages: { +// // minLength: 'stringAnyOf/minLength from anyOf', +// }, +// }, +// }, +// { +// type: JsonSchemaType.String, +// const: 'ja', +// entityParameters: { +// errorMessages: { +// // const: 'stringAnyOf/const from anyOf', +// }, +// }, +// }, +// ], +// entityParameters: { +// type: EntityType.String, +// controlType: 'baseString', +// controlWrapperType: 'rowString', +// errorMessages: { +// minLength: 'stringAnyOf/minLength from item', +// const: 'stringAnyOf/const from item', +// anyOf: 'stringAnyOf', +// }, +// }, +// }; -const stringConst: JsonSchemaString = { - type: JsonSchemaType.String, - const: 'jajajaja', - default: 'jaja', - title: 'stringConst', - entityParameters: { - type: EntityType.String, - controlType: 'baseString', - controlWrapperType: 'rowString', - errorMessages: { - const: 'stringConst', - }, - }, -}; +// const stringConst: JsonSchemaString = { +// type: JsonSchemaType.String, +// const: 'jajajaja', +// default: 'jaja', +// title: 'stringConst', +// entityParameters: { +// type: EntityType.String, +// controlType: 'baseString', +// controlWrapperType: 'rowString', +// errorMessages: { +// const: 'stringConst', +// }, +// }, +// }; -const stringEnum: JsonSchemaString = { - type: JsonSchemaType.String, - enum: ['jajaja', 'bobobo'], - default: 'jaja', - title: 'stringEnum', - entityParameters: { - type: EntityType.String, - controlType: 'baseString', - controlWrapperType: 'rowString', - errorMessages: { - enum: 'stringEnum', - }, - validatorType: 'cccString', - }, -}; +// const stringEnum: JsonSchemaString = { +// type: JsonSchemaType.String, +// enum: ['jajaja', 'bobobo'], +// default: 'jaja', +// title: 'stringEnum', +// entityParameters: { +// type: EntityType.String, +// controlType: 'baseString', +// controlWrapperType: 'rowString', +// errorMessages: { +// enum: 'stringEnum', +// }, +// validatorType: 'cccString', +// }, +// }; -const stringThen: JsonSchemaString = { - type: JsonSchemaType.String, - default: 'jaja', - title: 'stringThen', - if: { - type: JsonSchemaType.String, - const: 'jaja', - }, - else: { - type: JsonSchemaType.String, - }, - then: { - type: JsonSchemaType.String, - minLength: 5, - }, - entityParameters: { - type: EntityType.String, - controlType: 'baseString', - controlWrapperType: 'rowString', - errorMessages: { - // then: 'stringThen', - }, - }, -}; +// const stringThen: JsonSchemaString = { +// type: JsonSchemaType.String, +// default: 'jaja', +// title: 'stringThen', +// if: { +// type: JsonSchemaType.String, +// const: 'jaja', +// }, +// else: { +// type: JsonSchemaType.String, +// }, +// then: { +// type: JsonSchemaType.String, +// minLength: 5, +// }, +// entityParameters: { +// type: EntityType.String, +// controlType: 'baseString', +// controlWrapperType: 'rowString', +// errorMessages: { +// // then: 'stringThen', +// }, +// }, +// }; -const stringElse: JsonSchemaString = { - type: JsonSchemaType.String, - default: 'jaja', - title: 'stringElse', - if: { - type: JsonSchemaType.String, - const: 'ja', - }, - else: { - type: JsonSchemaType.String, - minLength: 5, - }, - then: { - type: JsonSchemaType.String, - }, - entityParameters: { - type: EntityType.String, - controlType: 'baseString', - controlWrapperType: 'rowString', - errorMessages: { - // else: 'stringElse', - }, - }, -}; +// const stringElse: JsonSchemaString = { +// type: JsonSchemaType.String, +// default: 'jaja', +// title: 'stringElse', +// if: { +// type: JsonSchemaType.String, +// const: 'ja', +// }, +// else: { +// type: JsonSchemaType.String, +// minLength: 5, +// }, +// then: { +// type: JsonSchemaType.String, +// }, +// entityParameters: { +// type: EntityType.String, +// controlType: 'baseString', +// controlWrapperType: 'rowString', +// errorMessages: { +// // else: 'stringElse', +// }, +// }, +// }; -const stringNot: JsonSchemaString = { - type: JsonSchemaType.String, - default: 'jaja', - title: 'stringNot', - not: { - type: JsonSchemaType.String, - const: 'jaja', - }, - entityParameters: { - type: EntityType.String, - controlType: 'baseString', - controlWrapperType: 'rowString', - errorMessages: { - not: 'stringNot', - }, - }, -}; +// const stringNot: JsonSchemaString = { +// type: JsonSchemaType.String, +// default: 'jaja', +// title: 'stringNot', +// not: { +// type: JsonSchemaType.String, +// const: 'jaja', +// }, +// entityParameters: { +// type: EntityType.String, +// controlType: 'baseString', +// controlWrapperType: 'rowString', +// errorMessages: { +// not: 'stringNot', +// }, +// }, +// }; -const stringOneOf: JsonSchemaString = { - type: JsonSchemaType.String, - default: 'jaja', - title: 'stringOneOf', - oneOf: [ - { - type: JsonSchemaType.String, - minLength: 9, - entityParameters: { - errorMessages: { - // minLength: 'stringOneOf/minLength from oneOf', - }, - }, - }, - { - type: JsonSchemaType.String, - const: 'ja', - entityParameters: { - errorMessages: { - // const: 'stringOneOf/const from oneOf', - }, - }, - }, - ], - entityParameters: { - type: EntityType.String, - controlType: 'baseString', - controlWrapperType: 'rowString', - errorMessages: { - minLength: 'stringOneOf from item', - const: 'stringOneOf from item', - oneOf: 'stringOneOf', - }, - }, -}; +// const stringOneOf: JsonSchemaString = { +// type: JsonSchemaType.String, +// default: 'jaja', +// title: 'stringOneOf', +// oneOf: [ +// { +// type: JsonSchemaType.String, +// minLength: 9, +// entityParameters: { +// errorMessages: { +// // minLength: 'stringOneOf/minLength from oneOf', +// }, +// }, +// }, +// { +// type: JsonSchemaType.String, +// const: 'ja', +// entityParameters: { +// errorMessages: { +// // const: 'stringOneOf/const from oneOf', +// }, +// }, +// }, +// ], +// entityParameters: { +// type: EntityType.String, +// controlType: 'baseString', +// controlWrapperType: 'rowString', +// errorMessages: { +// minLength: 'stringOneOf from item', +// const: 'stringOneOf from item', +// oneOf: 'stringOneOf', +// }, +// }, +// }; -const numberExclusiveMaximum: JsonSchemaNumber = { - type: JsonSchemaType.Number, - exclusiveMaximum: 2, - default: 2, - title: 'numberExclusiveMaximum', - entityParameters: { - type: EntityType.Number, - controlType: 'baseNumber', - controlWrapperType: 'rowNumber', - errorMessages: { - exclusiveMaximum: 'numberExclusiveMaximum', - }, - }, -}; +// const numberExclusiveMaximum: JsonSchemaNumber = { +// type: JsonSchemaType.Number, +// exclusiveMaximum: 2, +// default: 2, +// title: 'numberExclusiveMaximum', +// entityParameters: { +// type: EntityType.Number, +// controlType: 'baseNumber', +// controlWrapperType: 'rowNumber', +// errorMessages: { +// exclusiveMaximum: 'numberExclusiveMaximum', +// }, +// }, +// }; -const numberExclusiveMinimum: JsonSchemaNumber = { - type: JsonSchemaType.Number, - exclusiveMinimum: 2, - default: 2, - title: 'numberExclusiveMinimum', - entityParameters: { - type: EntityType.Number, - controlType: 'baseNumber', - controlWrapperType: 'rowNumber', - errorMessages: { - exclusiveMinimum: 'numberExclusiveMinimum', - }, - }, -}; +// const numberExclusiveMinimum: JsonSchemaNumber = { +// type: JsonSchemaType.Number, +// exclusiveMinimum: 2, +// default: 2, +// title: 'numberExclusiveMinimum', +// entityParameters: { +// type: EntityType.Number, +// controlType: 'baseNumber', +// controlWrapperType: 'rowNumber', +// errorMessages: { +// exclusiveMinimum: 'numberExclusiveMinimum', +// }, +// }, +// }; -const numberMaximum: JsonSchemaNumber = { - type: JsonSchemaType.Number, - maximum: 2, - default: 3, - title: 'numberMaximum', - entityParameters: { - type: EntityType.Number, - controlType: 'baseNumber', - controlWrapperType: 'rowNumber', - errorMessages: { - maximum: 'numberMaximum', - }, - }, -}; +// const numberMaximum: JsonSchemaNumber = { +// type: JsonSchemaType.Number, +// maximum: 2, +// default: 3, +// title: 'numberMaximum', +// entityParameters: { +// type: EntityType.Number, +// controlType: 'baseNumber', +// controlWrapperType: 'rowNumber', +// errorMessages: { +// maximum: 'numberMaximum', +// }, +// }, +// }; -const numberMinimum: JsonSchemaNumber = { - type: JsonSchemaType.Number, - minimum: 3, - default: 2, - title: 'numberMinimum', - entityParameters: { - type: EntityType.Number, - controlType: 'baseNumber', - controlWrapperType: 'rowNumber', - errorMessages: { - minimum: 'numberMinimum', - }, - }, -}; +// const numberMinimum: JsonSchemaNumber = { +// type: JsonSchemaType.Number, +// minimum: 3, +// default: 2, +// title: 'numberMinimum', +// entityParameters: { +// type: EntityType.Number, +// controlType: 'baseNumber', +// controlWrapperType: 'rowNumber', +// errorMessages: { +// minimum: 'numberMinimum', +// }, +// }, +// }; -const numberMultipleOf: JsonSchemaNumber = { - type: JsonSchemaType.Number, - multipleOf: 3, - default: 2, - title: 'numberMultipleOf', - entityParameters: { - type: EntityType.Number, - controlType: 'baseNumber', - controlWrapperType: 'rowNumber', - errorMessages: { - multipleOf: 'numberMultipleOf', - }, - }, -}; +// const numberMultipleOf: JsonSchemaNumber = { +// type: JsonSchemaType.Number, +// multipleOf: 3, +// default: 2, +// title: 'numberMultipleOf', +// entityParameters: { +// type: EntityType.Number, +// controlType: 'baseNumber', +// controlWrapperType: 'rowNumber', +// errorMessages: { +// multipleOf: 'numberMultipleOf', +// }, +// }, +// }; -const objectAdditionalProperties: JsonSchemaObject = { - type: JsonSchemaType.Object, - properties: { - stringConst, - }, - default: {extra: 'test'}, - title: 'objectAdditionalProperties', - // additionalProperties: false, - additionalProperties: { - type: JsonSchemaType.String, - const: 'jaja', - entityParameters: { - errorMessages: {const: 'objectAdditionalProperties/const'}, - }, - }, - entityParameters: { - type: EntityType.Object, - controlType: 'baseObject', - controlWrapperType: 'accordeonObject', - controlWrapperProps: { - open: true, - }, - errorMessages: { - additionalProperties: 'objectAdditionalProperties', - }, - }, -}; +// const objectAdditionalProperties: JsonSchemaObject = { +// type: JsonSchemaType.Object, +// properties: { +// stringConst, +// }, +// default: {extra: 'test'}, +// title: 'objectAdditionalProperties', +// // additionalProperties: false, +// additionalProperties: { +// type: JsonSchemaType.String, +// const: 'jaja', +// entityParameters: { +// errorMessages: {const: 'objectAdditionalProperties/const'}, +// }, +// }, +// entityParameters: { +// type: EntityType.Object, +// controlType: 'baseObject', +// controlWrapperType: 'accordeonObject', +// controlWrapperProps: { +// open: true, +// }, +// errorMessages: { +// additionalProperties: 'objectAdditionalProperties', +// }, +// }, +// }; -const objectDependencies: JsonSchemaObject = { - // - type: JsonSchemaType.Object, - properties: { - stringConst, - stringEnum: { - ...stringEnum, - default: undefined, - }, - numberMinimum: { - ...numberMinimum, - default: undefined, - }, - }, - title: 'objectDependencies', - default: {}, - dependencies: { - stringConst: ['stringEnum', 'numberMinimum'], - // stringConst: { - // type: JsonSchemaType.Object, - // properties: { - // stringEnum: { - // type: JsonSchemaType.String, - // maxLength: 1, - // }, - // }, - // }, - }, - entityParameters: { - type: EntityType.Object, - controlType: 'baseObject', - controlWrapperType: 'accordeonObject', - controlWrapperProps: { - open: true, - }, - errorMessages: { - // dependencies: 'objectDependencies', - dependencies: { - stringEnum: 'objectDependencies/stringEnum', - numberMinimum: 'objectDependencies/numberMinimum', - }, - }, - }, -}; +// const objectDependencies: JsonSchemaObject = { +// // +// type: JsonSchemaType.Object, +// properties: { +// stringConst, +// stringEnum: { +// ...stringEnum, +// default: undefined, +// }, +// numberMinimum: { +// ...numberMinimum, +// default: undefined, +// }, +// }, +// title: 'objectDependencies', +// default: {}, +// dependencies: { +// stringConst: ['stringEnum', 'numberMinimum'], +// // stringConst: { +// // type: JsonSchemaType.Object, +// // properties: { +// // stringEnum: { +// // type: JsonSchemaType.String, +// // maxLength: 1, +// // }, +// // }, +// // }, +// }, +// entityParameters: { +// type: EntityType.Object, +// controlType: 'baseObject', +// controlWrapperType: 'accordeonObject', +// controlWrapperProps: { +// open: true, +// }, +// errorMessages: { +// // dependencies: 'objectDependencies', +// dependencies: { +// stringEnum: 'objectDependencies/stringEnum', +// numberMinimum: 'objectDependencies/numberMinimum', +// }, +// }, +// }, +// }; -const objectMaxProperties: JsonSchemaObject = { - type: JsonSchemaType.Object, - properties: { - stringConst, - stringEnum, - }, - title: 'objectMaxProperties', - maxProperties: 1, - default: {}, - entityParameters: { - type: EntityType.Object, - controlType: 'baseObject', - controlWrapperType: 'accordeonObject', - controlWrapperProps: { - open: true, - }, - errorMessages: { - maxProperties: 'objectMaxProperties', - }, - }, -}; +// const objectMaxProperties: JsonSchemaObject = { +// type: JsonSchemaType.Object, +// properties: { +// stringConst, +// stringEnum, +// }, +// title: 'objectMaxProperties', +// maxProperties: 1, +// default: {}, +// entityParameters: { +// type: EntityType.Object, +// controlType: 'baseObject', +// controlWrapperType: 'accordeonObject', +// controlWrapperProps: { +// open: true, +// }, +// errorMessages: { +// maxProperties: 'objectMaxProperties', +// }, +// }, +// }; -const objectMinProperties: JsonSchemaObject = { - type: JsonSchemaType.Object, - properties: { - stringConst, - stringEnum, - }, - title: 'objectMinProperties', - minProperties: 3, - default: {}, - entityParameters: { - type: EntityType.Object, - controlType: 'baseObject', - controlWrapperType: 'accordeonObject', - controlWrapperProps: { - open: true, - }, - errorMessages: { - minProperties: 'objectMinProperties', - }, - }, -}; +// const objectMinProperties: JsonSchemaObject = { +// type: JsonSchemaType.Object, +// properties: { +// stringConst, +// stringEnum, +// }, +// title: 'objectMinProperties', +// minProperties: 3, +// default: {}, +// entityParameters: { +// type: EntityType.Object, +// controlType: 'baseObject', +// controlWrapperType: 'accordeonObject', +// controlWrapperProps: { +// open: true, +// }, +// errorMessages: { +// minProperties: 'objectMinProperties', +// }, +// }, +// }; -const objectPatternProperties: JsonSchemaObject = { - type: JsonSchemaType.Object, - properties: { - stringConst, - stringEnum, - }, - title: 'objectPatternProperties', - default: {}, - patternProperties: { - '^string': { - type: JsonSchemaType.Number, - entityParameters: {errorMessages: {type: 'patternProperties/type'}}, - }, - }, - entityParameters: { - type: EntityType.Object, - controlType: 'baseObject', - controlWrapperType: 'accordeonObject', - controlWrapperProps: { - open: true, - }, - }, -}; +// const objectPatternProperties: JsonSchemaObject = { +// type: JsonSchemaType.Object, +// properties: { +// stringConst, +// stringEnum, +// }, +// title: 'objectPatternProperties', +// default: {}, +// patternProperties: { +// '^string': { +// type: JsonSchemaType.Number, +// entityParameters: {errorMessages: {type: 'patternProperties/type'}}, +// }, +// }, +// entityParameters: { +// type: EntityType.Object, +// controlType: 'baseObject', +// controlWrapperType: 'accordeonObject', +// controlWrapperProps: { +// open: true, +// }, +// }, +// }; -const objectPropertyNames: JsonSchemaObject = { +// const objectPropertyNames: JsonSchemaObject = { +// type: JsonSchemaType.Object, +// properties: { +// stringConst, +// stringEnum, +// }, +// title: 'objectPropertyNames', +// default: {}, +// propertyNames: { +// type: JsonSchemaType.String, +// maxLength: 5, +// }, +// entityParameters: { +// type: EntityType.Object, +// controlType: 'baseObject', +// controlWrapperType: 'accordeonObject', +// controlWrapperProps: { +// open: true, +// }, +// errorMessages: { +// propertyNames: 'objectPropertyNames', +// }, +// }, +// }; + +// const arrayContains: JsonSchemaArray = { +// type: JsonSchemaType.Array, +// items: { +// type: JsonSchemaType.String, +// title: 'item', +// entityParameters: { +// controlType: 'baseString', +// controlWrapperType: 'rowString', +// }, +// }, +// // contains: true, +// contains: { +// type: JsonSchemaType.String, +// const: 'test', +// }, +// title: 'arrayContains', +// default: [], +// entityParameters: { +// type: EntityType.Array, +// controlType: 'baseArray', +// // controlWrapperType: 'row', +// // controlWrapperProps: { +// // open: true, +// // }, +// errorMessages: { +// contains: 'arrayContains', +// }, +// }, +// }; + +// const arrayMaxItems: JsonSchemaArray = { +// type: JsonSchemaType.Array, +// items: { +// type: JsonSchemaType.String, +// title: 'item', +// minLength: 2, +// entityParameters: { +// type: EntityType.String, +// controlType: 'baseString', +// controlWrapperType: 'rowString', +// errorMessages: { +// minLength: 'stringMinLength', +// }, +// }, +// }, +// maxItems: 1, +// title: 'arrayMaxItems', +// default: ['1', '2'], +// entityParameters: { +// type: EntityType.Array, +// controlType: 'baseArray', +// controlWrapperType: 'rowArray', +// controlWrapperProps: { +// open: true, +// }, +// errorMessages: { +// maxItems: 'arrayMaxItems', +// }, +// }, +// }; + +// const arrayMinItems: JsonSchemaArray = { +// type: JsonSchemaType.Array, +// items: { +// type: JsonSchemaType.String, +// title: 'item', +// entityParameters: { +// type: EntityType.String, +// controlType: 'baseString', +// controlWrapperType: 'rowString', +// }, +// }, +// minItems: 3, +// title: 'arrayMinItems', +// default: ['1', '2'], +// entityParameters: { +// type: EntityType.Array, +// controlType: 'baseArray', +// controlWrapperType: 'rowArray', +// controlWrapperProps: { +// open: true, +// }, +// errorMessages: { +// minItems: 'arrayMinItems', +// }, +// }, +// }; + +// const arrayUniqueItems: JsonSchemaArray = { +// type: JsonSchemaType.Array, +// items: { +// type: JsonSchemaType.String, +// title: 'item', +// entityParameters: { +// type: EntityType.String, +// controlType: 'baseString', +// controlWrapperType: 'rowString', +// }, +// }, +// uniqueItems: true, +// title: 'arrayUniqueItems', +// default: ['1', '1'], +// entityParameters: { +// type: EntityType.Array, +// controlType: 'baseArray', +// controlWrapperType: 'rowArray', +// controlWrapperProps: { +// open: true, +// }, +// errorMessages: { +// uniqueItems: 'arrayUniqueItems', +// }, +// }, +// }; + +// const anySpec: JsonSchema = { +// title: 'anySpec', +// entityParameters: { +// type: EntityType.Any, +// controlType: 'baseAny', +// // controlWrapperType: 'rowAny', +// // validatorType: 'cccAny', +// }, +// oneOf: [stringEnum, stringConst], +// items: [stringEnum, arrayUniqueItems], +// properties: { +// stringEnum, +// arrayUniqueItems, +// }, +// required: ['stringEnum', 'arrayUniqueItems'], +// additionalProperties: false, +// additionalItems: false, +// uniqueItems: true, +// }; + +// const baseSpec: JsonSchemaObject = { +// definitions: { +// jajaja: { +// type: JsonSchemaType.String, +// title: 'jajaja', +// minLength: 10, +// entityParameters: { +// type: EntityType.String, +// controlType: 'baseString', +// }, +// }, +// }, +// type: JsonSchemaType.Object, +// properties: { +// test: { +// type: [JsonSchemaType.Object, JsonSchemaType.Null], +// title: 'test', +// properties: { +// test: { +// type: JsonSchemaType.String, +// $ref: '#/definitions/jajaja', +// title: 'test', +// minLength: 5, +// maxLength: 2, +// entityParameters: { +// type: EntityType.String, +// controlType: 'baseString', +// controlWrapperType: 'rowString', +// }, +// }, +// }, +// entityParameters: { +// type: EntityType.Object, +// controlType: 'baseObject', +// // controlWrapperType: 'row', +// // controlProps: {qq: true}, +// }, +// }, +// anySpec, +// arrayContains, +// arrayMaxItems, +// arrayMinItems, +// arrayUniqueItems, +// stringMaxLength, +// stringMinLength, +// stringPattern, +// stringAllOf, +// stringAnyOf, +// stringConst, +// stringEnum, +// stringThen, +// stringElse, +// stringNot, +// stringOneOf, +// numberExclusiveMaximum, +// numberExclusiveMinimum, +// numberMaximum, +// numberMinimum, +// numberMultipleOf, +// objectAdditionalProperties, +// objectDependencies, +// objectMaxProperties, +// objectMinProperties, +// objectPatternProperties, +// objectPropertyNames, +// // test: { +// // type: JsonSchemaType.String, +// // title: 'test', +// // entityParameters: { +// // controlType: 'baseString', +// // controlWrapperType: 'rowString', +// // }, +// // }, +// }, +// title: 'Candidate', +// entityParameters: { +// type: EntityType.Object, +// controlType: 'baseObject', +// controlWrapperType: 'accordeonObject', +// controlWrapperProps: { +// open: true, +// }, +// }, +// const: {}, +// }; + +// const baseSpec2: JsonSchemaObject = { +// definitions: { +// jajaja: { +// type: JsonSchemaType.String, +// title: 'jajaja', +// minLength: 10, +// entityParameters: { +// type: EntityType.String, +// controlType: 'baseString', +// }, +// }, +// }, +// type: JsonSchemaType.Object, +// properties: { +// test: { +// type: [JsonSchemaType.Object, JsonSchemaType.Null], +// title: 'test', +// properties: { +// test: { +// type: JsonSchemaType.String, +// $ref: '#/definitions/jajaja', +// title: 'test', +// minLength: 5, +// maxLength: 2, +// entityParameters: { +// type: EntityType.String, +// controlType: 'baseString', +// controlWrapperType: 'rowString', +// }, +// }, +// }, +// entityParameters: { +// type: EntityType.Object, +// controlType: 'baseObject', +// // controlWrapperType: 'row', +// // controlProps: {qq: true}, +// }, +// }, +// anySpec, +// arrayContains, +// arrayMaxItems, +// arrayMinItems, +// arrayUniqueItems, +// stringMaxLength, +// stringMinLength, +// stringPattern, +// stringAllOf, +// stringAnyOf, +// stringConst, +// stringEnum, +// stringThen, +// stringElse, +// stringNot, +// stringOneOf, +// numberExclusiveMaximum, +// numberExclusiveMinimum, +// numberMaximum, +// numberMinimum, +// numberMultipleOf, +// objectAdditionalProperties, +// objectDependencies, +// objectMaxProperties, +// objectMinProperties, +// objectPatternProperties, +// objectPropertyNames, +// baseSpec, +// s: baseSpec, +// ss: baseSpec, +// sss: baseSpec, +// ssss: baseSpec, +// sssss: baseSpec, +// ssssss: baseSpec, +// sssssss: baseSpec, +// ssssssss: baseSpec, +// sssssssss: baseSpec, +// ssssssssss: baseSpec, +// sssssssssss: baseSpec, +// ssssssssssss: baseSpec, +// sssssssssssss: baseSpec, +// ssssssssssssss: baseSpec, +// sssssssssssssss: baseSpec, +// ssssssssssssssss: baseSpec, +// sssssssssssssssss: baseSpec, +// ssssssssssssssssss: baseSpec, +// sssssssssssssssssss: baseSpec, +// ssssssssssssssssssss: baseSpec, +// // test: { +// // title: 'test', +// // properties: { +// // test: { +// // title: 'test', +// // entityParameters: { +// // type: EntityType.String, +// // controlType: 'baseString', +// // }, +// // }, +// // }, +// // entityParameters: { +// // type: EntityType.Object, +// // controlType: 'baseObject', +// // // controlWrapperType: 'row', +// // // controlProps: {qq: true}, +// // }, +// // }, +// }, +// title: 'Candidate', +// entityParameters: { +// type: EntityType.Object, +// controlType: 'baseObject', +// controlWrapperType: 'accordeonObject', +// controlWrapperProps: { +// open: true, +// }, +// }, +// const: {}, +// }; + +// const baseValue = { +// qwe: { +// test: { +// jajaja: { +// // name: 'bocemb', +// age: 13, +// nameQ: 'jaja', +// obj: {name: 'bocemb', age: 13}, +// baseSpec: {}, +// s: {}, +// ss: {}, +// sss: {}, +// ssss: {}, +// sssss: {}, +// ssssss: {}, +// sssssss: {}, +// ssssssss: {}, +// sssssssss: {}, +// ssssssssss: {}, +// sssssssssss: {}, +// ssssssssssss: {}, +// sssssssssssss: {}, +// ssssssssssssss: {}, +// sssssssssssssss: {}, +// ssssssssssssssss: {}, +// sssssssssssssssss: {}, +// ssssssssssssssssss: {}, +// sssssssssssssssssss: {}, +// ssssssssssssssssssss: {}, +// }, +// bocem: { +// // name: 'bocemb', +// age: 13, +// nameQ: 'jaja', +// obj: {name: 'bocemb', age: 13}, +// baseSpec: {}, +// s: {}, +// ss: {}, +// sss: {}, +// ssss: {}, +// sssss: {}, +// ssssss: {}, +// sssssss: {}, +// ssssssss: {}, +// sssssssss: {}, +// ssssssssss: {}, +// sssssssssss: {}, +// ssssssssssss: {}, +// sssssssssssss: {}, +// ssssssssssssss: {}, +// sssssssssssssss: {}, +// ssssssssssssssss: {}, +// sssssssssssssssss: {}, +// ssssssssssssssssss: {}, +// sssssssssssssssssss: {}, +// ssssssssssssssssssss: {}, +// }, +// bocembocem: { +// // name: 'bocemb', +// age: 13, +// nameQ: 'jaja', +// obj: {name: 'bocemb', age: 13}, +// baseSpec: {}, +// s: {}, +// ss: {}, +// sss: {}, +// ssss: {}, +// sssss: {}, +// ssssss: {}, +// sssssss: {}, +// ssssssss: {}, +// sssssssss: {}, +// ssssssssss: {}, +// sssssssssss: {}, +// ssssssssssss: {}, +// sssssssssssss: {}, +// ssssssssssssss: {}, +// sssssssssssssss: {}, +// ssssssssssssssss: {}, +// sssssssssssssssss: {}, +// ssssssssssssssssss: {}, +// sssssssssssssssssss: {}, +// ssssssssssssssssssss: {}, +// }, +// bocembocembocem: { +// // name: 'bocemb', +// age: 13, +// nameQ: 'jaja', +// obj: {name: 'bocemb', age: 13}, +// baseSpec: {}, +// s: {}, +// ss: {}, +// sss: {}, +// ssss: {}, +// sssss: {}, +// ssssss: {}, +// sssssss: {}, +// ssssssss: {}, +// sssssssss: {}, +// ssssssssss: {}, +// sssssssssss: {}, +// ssssssssssss: {}, +// sssssssssssss: {}, +// ssssssssssssss: {}, +// sssssssssssssss: {}, +// ssssssssssssssss: {}, +// sssssssssssssssss: {}, +// ssssssssssssssssss: {}, +// sssssssssssssssssss: {}, +// ssssssssssssssssssss: {}, +// }, +// }, +// }, +// }; + +// new Array(1200).fill('test').forEach((_, idx) => { +// baseSpec.properties![`test${idx}`] = { +// type: JsonSchemaType.String, +// title: 'Name', +// entityParameters: { +// controlType: 'base', +// controlWrapperType: 'row', +// }, +// // minLength: 10, +// // pattern: '^[0-9]', +// // pattern: '[-_a-zA-Z0-9/.]+$', +// }; +// baseSpec.required?.push(`test${idx}`); +// baseSpec.allOf![0].properties![`test${idx}`] = { +// type: JsonSchemaType.String, +// minLength: 15, +// }; +// }); + +const schema: JsonSchemaObject = { type: JsonSchemaType.Object, properties: { - stringConst, - stringEnum, - }, - title: 'objectPropertyNames', - default: {}, - propertyNames: { - type: JsonSchemaType.String, - maxLength: 5, - }, - entityParameters: { - type: EntityType.Object, - controlType: 'baseObject', - controlWrapperType: 'accordeonObject', - controlWrapperProps: { - open: true, - }, - errorMessages: { - propertyNames: 'objectPropertyNames', - }, - }, -}; - -const arrayContains: JsonSchemaArray = { - type: JsonSchemaType.Array, - items: { - type: JsonSchemaType.String, - title: 'item', - entityParameters: { - controlType: 'baseString', - controlWrapperType: 'rowString', - }, - }, - // contains: true, - contains: { - type: JsonSchemaType.String, - const: 'test', - }, - title: 'arrayContains', - default: [], - entityParameters: { - type: EntityType.Array, - controlType: 'baseArray', - // controlWrapperType: 'row', - // controlWrapperProps: { - // open: true, - // }, - errorMessages: { - contains: 'arrayContains', + array: { + type: JsonSchemaType.Array, + title: 'array', + description: 'array description', + items: { + type: JsonSchemaType.String, + title: 'item', + description: 'item description', + entityParameters: { + type: EntityType.String, + controlType: 'base', + controlWrapperType: 'transparent', + }, + }, + entityParameters: { + type: EntityType.Array, + controlType: 'base', + controlWrapperType: 'row', + }, }, - }, -}; - -const arrayMaxItems: JsonSchemaArray = { - type: JsonSchemaType.Array, - items: { - type: JsonSchemaType.String, - title: 'item', - minLength: 2, - entityParameters: { - type: EntityType.String, - controlType: 'baseString', - controlWrapperType: 'rowString', - errorMessages: { - minLength: 'stringMinLength', + tuple: { + type: JsonSchemaType.Array, + title: 'tuple', + description: 'tuple description', + items: [ + { + type: JsonSchemaType.String, + title: 'item', + description: 'string item description', + entityParameters: { + type: EntityType.String, + controlType: 'base', + controlWrapperType: 'row', + }, + }, + { + type: JsonSchemaType.Number, + title: 'item', + description: 'number item description', + entityParameters: { + type: EntityType.Number, + controlType: 'base', + controlWrapperType: 'row', + }, + }, + ], + entityParameters: { + type: EntityType.Array, + controlType: 'base', + controlWrapperType: 'row', }, }, - }, - maxItems: 1, - title: 'arrayMaxItems', - default: ['1', '2'], - entityParameters: { - type: EntityType.Array, - controlType: 'baseArray', - controlWrapperType: 'rowArray', - controlWrapperProps: { - open: true, + number: { + type: JsonSchemaType.Number, + title: 'number', + description: 'number description', + entityParameters: { + type: EntityType.Number, + controlType: 'base', + controlWrapperType: 'row', + }, }, - errorMessages: { - maxItems: 'arrayMaxItems', + string: { + type: JsonSchemaType.String, + title: 'string sdjlaksdlj askljdlkasjd asjkldajsl;sadjklajsdklajsllll as', + description: 'string description', + entityParameters: { + type: EntityType.String, + controlType: 'base', + controlWrapperType: 'row', + controlWrapperProps: { + descriptionType: 'bottom', + required: true, + }, + }, }, - }, -}; - -const arrayMinItems: JsonSchemaArray = { - type: JsonSchemaType.Array, - items: { - type: JsonSchemaType.String, - title: 'item', - entityParameters: { - type: EntityType.String, - controlType: 'baseString', - controlWrapperType: 'rowString', + boolean: { + type: JsonSchemaType.Boolean, + title: 'boolean', + description: 'boolean description', + entityParameters: { + type: EntityType.Boolean, + controlType: 'base', + controlWrapperType: 'row', + }, }, - }, - minItems: 3, - title: 'arrayMinItems', - default: ['1', '2'], - entityParameters: { - type: EntityType.Array, - controlType: 'baseArray', - controlWrapperType: 'rowArray', - controlWrapperProps: { - open: true, + switch: { + type: JsonSchemaType.Boolean, + title: 'switch', + description: 'switch description', + entityParameters: { + type: EntityType.Boolean, + controlType: 'switch', + controlWrapperType: 'row', + }, }, - errorMessages: { - minItems: 'arrayMinItems', + textarea: { + type: JsonSchemaType.String, + title: 'textarea', + description: 'textarea description', + entityParameters: { + type: EntityType.String, + controlType: 'textarea', + controlWrapperType: 'row', + }, }, - }, -}; - -const arrayUniqueItems: JsonSchemaArray = { - type: JsonSchemaType.Array, - items: { - type: JsonSchemaType.String, - title: 'item', - entityParameters: { - type: EntityType.String, - controlType: 'baseString', - controlWrapperType: 'rowString', + password: { + type: JsonSchemaType.String, + title: 'password', + description: 'password description', + entityParameters: { + type: EntityType.String, + controlType: 'password', + controlWrapperType: 'row', + }, }, - }, - uniqueItems: true, - title: 'arrayUniqueItems', - default: ['1', '1'], - entityParameters: { - type: EntityType.Array, - controlType: 'baseArray', - controlWrapperType: 'rowArray', - controlWrapperProps: { - open: true, + color_picker: { + type: JsonSchemaType.String, + default: '#5282ff', + title: 'color_picker', + description: 'color picker description', + entityParameters: { + type: EntityType.String, + controlType: 'color_picker', + controlWrapperType: 'row', + }, }, - errorMessages: { - uniqueItems: 'arrayUniqueItems', + date_input: { + default: '2020-01-01', + title: 'date_input', + description: 'date input description', + entityParameters: { + type: EntityType.Any, + controlType: 'date_input', + controlWrapperType: 'row', + }, }, - }, -}; - -const anySpec: JsonSchema = { - title: 'anySpec', - entityParameters: { - type: EntityType.Any, - controlType: 'baseAny', - // controlWrapperType: 'rowAny', - // validatorType: 'cccAny', - }, - oneOf: [stringEnum, stringConst], - items: [stringEnum, arrayUniqueItems], - properties: { - stringEnum, - arrayUniqueItems, - }, - required: ['stringEnum', 'arrayUniqueItems'], - additionalProperties: false, - additionalItems: false, - uniqueItems: true, -}; - -const baseSpec: JsonSchemaObject = { - definitions: { - jajaja: { + radio_group: { type: JsonSchemaType.String, - title: 'jajaja', - minLength: 10, + enum: ['foo', 'bar', 'rab'], + default: 'foo', + title: 'radio_group', + description: 'radio group description', entityParameters: { type: EntityType.String, - controlType: 'baseString', + controlType: 'radio_group', + controlWrapperType: 'row', + controlProps: { + direction: 'vertical', + enumDescriptions: { + foo: 'Option 1', + bar: 'Option 2', + rab: 'Option 3', + }, + }, }, }, - }, - type: JsonSchemaType.Object, - properties: { - test: { - type: [JsonSchemaType.Object, JsonSchemaType.Null], - title: 'test', - properties: { - test: { - type: JsonSchemaType.String, - $ref: '#/definitions/jajaja', - title: 'test', - minLength: 5, - maxLength: 2, - entityParameters: { - type: EntityType.String, - controlType: 'baseString', - controlWrapperType: 'rowString', + select: { + type: JsonSchemaType.String, + enum: ['draft', 'published', 'archived'], + default: 'draft', + title: 'select', + description: 'select description', + examples: ['Choose status'], + entityParameters: { + type: EntityType.String, + controlType: 'select', + controlWrapperType: 'row', + controlProps: { + enumDescriptions: { + draft: 'Draft', + published: 'Published', + archived: 'Archived', + }, + optionsMeta: { + draft: 'Draft', + published: 'Published', + archived: 'Archived', }, }, }, + }, + checkbox_group: { + type: JsonSchemaType.Array, + items: { + type: JsonSchemaType.String, + enum: ['monday', 'tuesday', 'wednesday'], + }, + default: ['monday'], + title: 'checkbox_group', entityParameters: { - type: EntityType.Object, - controlType: 'baseObject', - // controlWrapperType: 'row', - // controlProps: {qq: true}, + type: EntityType.Array, + controlType: 'checkbox_group', + controlWrapperType: 'row', + controlProps: { + direction: 'column', + enumDescriptions: { + monday: 'Mon', + tuesday: 'Tue', + wednesday: 'Wed', + }, + optionsDisabled: { + monday: true, + }, + }, }, }, - anySpec, - arrayContains, - arrayMaxItems, - arrayMinItems, - arrayUniqueItems, - stringMaxLength, - stringMinLength, - stringPattern, - stringAllOf, - stringAnyOf, - stringConst, - stringEnum, - stringThen, - stringElse, - stringNot, - stringOneOf, - numberExclusiveMaximum, - numberExclusiveMinimum, - numberMaximum, - numberMinimum, - numberMultipleOf, - objectAdditionalProperties, - objectDependencies, - objectMaxProperties, - objectMinProperties, - objectPatternProperties, - objectPropertyNames, - // test: { - // type: JsonSchemaType.String, - // title: 'test', - // entityParameters: { - // controlType: 'baseString', - // controlWrapperType: 'rowString', - // }, - // }, - }, - title: 'Candidate', - entityParameters: { - type: EntityType.Object, - controlType: 'baseObject', - controlWrapperType: 'accordeonObject', - controlWrapperProps: { - open: true, + multi_select: { + type: JsonSchemaType.Array, + items: {enum: ['draft', 'published', 'archived']}, + default: ['draft'], + examples: [['Choose status']], + title: 'multi_select', + entityParameters: { + type: EntityType.Array, + controlType: 'select', + controlWrapperType: 'row', + controlProps: { + enumDescriptions: { + draft: 'Draft', + published: 'Published', + archived: 'Archived', + }, + optionsMeta: { + draft: 'Not visible yet', + published: 'Live', + }, + }, + }, }, - }, - const: {}, -}; - -const baseSpec2: JsonSchemaObject = { - definitions: { - jajaja: { - type: JsonSchemaType.String, - title: 'jajaja', - minLength: 10, + slider: { + type: JsonSchemaType.Number, + title: 'slider', + description: 'slider description', entityParameters: { - type: EntityType.String, - controlType: 'baseString', + type: EntityType.Number, + controlType: 'slider', + controlWrapperType: 'row', }, }, - }, - type: JsonSchemaType.Object, - properties: { - test: { - type: [JsonSchemaType.Object, JsonSchemaType.Null], - title: 'test', + range_slider: { + default: {from: 0, to: 100}, + type: JsonSchemaType.Object, + title: 'range_slider', properties: { - test: { - type: JsonSchemaType.String, - $ref: '#/definitions/jajaja', - title: 'test', - minLength: 5, - maxLength: 2, - entityParameters: { - type: EntityType.String, - controlType: 'baseString', - controlWrapperType: 'rowString', - }, - }, + from: {type: JsonSchemaType.Number, minimum: 0}, + to: {type: JsonSchemaType.Number, maximum: 100}, }, entityParameters: { type: EntityType.Object, - controlType: 'baseObject', - // controlWrapperType: 'row', - // controlProps: {qq: true}, + controlType: 'range_slider', + controlWrapperType: 'row', }, }, - anySpec, - arrayContains, - arrayMaxItems, - arrayMinItems, - arrayUniqueItems, - stringMaxLength, - stringMinLength, - stringPattern, - stringAllOf, - stringAnyOf, - stringConst, - stringEnum, - stringThen, - stringElse, - stringNot, - stringOneOf, - numberExclusiveMaximum, - numberExclusiveMinimum, - numberMaximum, - numberMinimum, - numberMultipleOf, - objectAdditionalProperties, - objectDependencies, - objectMaxProperties, - objectMinProperties, - objectPatternProperties, - objectPropertyNames, - baseSpec, - s: baseSpec, - ss: baseSpec, - sss: baseSpec, - ssss: baseSpec, - sssss: baseSpec, - ssssss: baseSpec, - sssssss: baseSpec, - ssssssss: baseSpec, - sssssssss: baseSpec, - ssssssssss: baseSpec, - sssssssssss: baseSpec, - ssssssssssss: baseSpec, - sssssssssssss: baseSpec, - ssssssssssssss: baseSpec, - sssssssssssssss: baseSpec, - ssssssssssssssss: baseSpec, - sssssssssssssssss: baseSpec, - ssssssssssssssssss: baseSpec, - sssssssssssssssssss: baseSpec, - ssssssssssssssssssss: baseSpec, - // test: { - // title: 'test', - // properties: { - // test: { - // title: 'test', - // entityParameters: { - // type: EntityType.String, - // controlType: 'baseString', - // }, - // }, - // }, - // entityParameters: { - // type: EntityType.Object, - // controlType: 'baseObject', - // // controlWrapperType: 'row', - // // controlProps: {qq: true}, - // }, - // }, }, - title: 'Candidate', entityParameters: { type: EntityType.Object, - controlType: 'baseObject', - controlWrapperType: 'accordeonObject', - controlWrapperProps: { - open: true, - }, + controlType: 'base', }, - const: {}, }; const value = { - qwe: { - test: { - jajaja: { - // name: 'bocemb', - age: 13, - nameQ: 'jaja', - obj: {name: 'bocemb', age: 13}, - baseSpec: {}, - s: {}, - ss: {}, - sss: {}, - ssss: {}, - sssss: {}, - ssssss: {}, - sssssss: {}, - ssssssss: {}, - sssssssss: {}, - ssssssssss: {}, - sssssssssss: {}, - ssssssssssss: {}, - sssssssssssss: {}, - ssssssssssssss: {}, - sssssssssssssss: {}, - ssssssssssssssss: {}, - sssssssssssssssss: {}, - ssssssssssssssssss: {}, - sssssssssssssssssss: {}, - ssssssssssssssssssss: {}, - }, - bocem: { - // name: 'bocemb', - age: 13, - nameQ: 'jaja', - obj: {name: 'bocemb', age: 13}, - baseSpec: {}, - s: {}, - ss: {}, - sss: {}, - ssss: {}, - sssss: {}, - ssssss: {}, - sssssss: {}, - ssssssss: {}, - sssssssss: {}, - ssssssssss: {}, - sssssssssss: {}, - ssssssssssss: {}, - sssssssssssss: {}, - ssssssssssssss: {}, - sssssssssssssss: {}, - ssssssssssssssss: {}, - sssssssssssssssss: {}, - ssssssssssssssssss: {}, - sssssssssssssssssss: {}, - ssssssssssssssssssss: {}, - }, - bocembocem: { - // name: 'bocemb', - age: 13, - nameQ: 'jaja', - obj: {name: 'bocemb', age: 13}, - baseSpec: {}, - s: {}, - ss: {}, - sss: {}, - ssss: {}, - sssss: {}, - ssssss: {}, - sssssss: {}, - ssssssss: {}, - sssssssss: {}, - ssssssssss: {}, - sssssssssss: {}, - ssssssssssss: {}, - sssssssssssss: {}, - ssssssssssssss: {}, - sssssssssssssss: {}, - ssssssssssssssss: {}, - sssssssssssssssss: {}, - ssssssssssssssssss: {}, - sssssssssssssssssss: {}, - ssssssssssssssssssss: {}, - }, - bocembocembocem: { - // name: 'bocemb', - age: 13, - nameQ: 'jaja', - obj: {name: 'bocemb', age: 13}, - baseSpec: {}, - s: {}, - ss: {}, - sss: {}, - ssss: {}, - sssss: {}, - ssssss: {}, - sssssss: {}, - ssssssss: {}, - sssssssss: {}, - ssssssssss: {}, - sssssssssss: {}, - ssssssssssss: {}, - sssssssssssss: {}, - ssssssssssssss: {}, - sssssssssssssss: {}, - ssssssssssssssss: {}, - sssssssssssssssss: {}, - ssssssssssssssssss: {}, - sssssssssssssssssss: {}, - ssssssssssssssssssss: {}, - }, - }, + test: { + array: ['test', 'test2'], + tuple: ['test', 123], + number: 123, + string: 'test', + boolean: true, }, }; -// new Array(1200).fill('test').forEach((_, idx) => { -// baseSpec.properties![`test${idx}`] = { -// type: JsonSchemaType.String, -// title: 'Name', -// entityParameters: { -// controlType: 'base', -// controlWrapperType: 'row', -// }, -// // minLength: 10, -// // pattern: '^[0-9]', -// // pattern: '[-_a-zA-Z0-9/.]+$', -// }; -// baseSpec.required?.push(`test${idx}`); -// baseSpec.allOf![0].properties![`test${idx}`] = { -// type: JsonSchemaType.String, -// minLength: 15, -// }; -// }); - const template = () => { const Template: StoryFn = (__) => (
{(form) => ( + + {/* { schema={baseSpec} config={config} mode={SchemaRendererMode.Form} - /> + /> */} )}