diff --git a/demo/package-lock.json b/demo/package-lock.json index c2a0f6b..e08f752 100644 --- a/demo/package-lock.json +++ b/demo/package-lock.json @@ -18,8 +18,8 @@ "react-native": "0.74.1", "react-native-svg": "15.2.0", "react-native-web": "~0.19.6", - "rn-declarative": "^0.0.56", - "rn-declarative-eva": "^0.0.44" + "rn-declarative": "^0.0.57", + "rn-declarative-eva": "^0.0.45" }, "devDependencies": { "@babel/core": "^7.19.3", @@ -10975,9 +10975,9 @@ } }, "node_modules/rn-declarative": { - "version": "0.0.56", - "resolved": "https://registry.npmjs.org/rn-declarative/-/rn-declarative-0.0.56.tgz", - "integrity": "sha512-VPooIaU75AVCUHLt1EaPV2O6lvTFwQSyMg5kRfjQJ5Sc3X9UbSPG05OOYySWZb9DWN73sXRo2itr3uJhSM52pg==", + "version": "0.0.57", + "resolved": "https://registry.npmjs.org/rn-declarative/-/rn-declarative-0.0.57.tgz", + "integrity": "sha512-YqWspE8lFnuW9Ss0G2mdfnsP27k3MVhQHDkFL5B/Jfd70H99Jhb41gvDWGrq6LV4chZf9lOvVm6vqxgYAN1jUA==", "hasInstallScript": true, "dependencies": { "rimraf": "3.0.2" @@ -10995,9 +10995,9 @@ } }, "node_modules/rn-declarative-eva": { - "version": "0.0.44", - "resolved": "https://registry.npmjs.org/rn-declarative-eva/-/rn-declarative-eva-0.0.44.tgz", - "integrity": "sha512-omeZkeyjB7cm3D7VqI2XFYqbzQuvotHAKNBfYb6K8AiRwRvwH6lf9WRD0/grErA/RiYfYwX+S2koaWDnCxsiUA==", + "version": "0.0.45", + "resolved": "https://registry.npmjs.org/rn-declarative-eva/-/rn-declarative-eva-0.0.45.tgz", + "integrity": "sha512-Z0N4z1kvVMMDBBmZNgZ8ncUnqqtwqig2ToSAbUelwlu8xvMeqjwGqVQnwHJ7LNBrtmwMst6teRhabQS8aAIwqA==", "hasInstallScript": true, "dependencies": { "rimraf": "3.0.2" diff --git a/demo/package.json b/demo/package.json index ce6ace9..5c27264 100644 --- a/demo/package.json +++ b/demo/package.json @@ -10,8 +10,8 @@ "react-native": "0.74.1", "react-native-svg": "15.2.0", "react-native-web": "~0.19.6", - "rn-declarative": "^0.0.56", - "rn-declarative-eva": "^0.0.44" + "rn-declarative": "^0.0.57", + "rn-declarative-eva": "^0.0.45" }, "devDependencies": { "@babel/core": "^7.19.3", diff --git a/packages/rn-declarative-eva/package-lock.json b/packages/rn-declarative-eva/package-lock.json index 9788ee0..0352a6d 100644 --- a/packages/rn-declarative-eva/package-lock.json +++ b/packages/rn-declarative-eva/package-lock.json @@ -1,12 +1,12 @@ { "name": "rn-declarative-eva", - "version": "0.0.44", + "version": "0.0.45", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "rn-declarative-eva", - "version": "0.0.44", + "version": "0.0.45", "hasInstallScript": true, "license": "MIT", "dependencies": { @@ -28,7 +28,7 @@ "react": "18.2.0", "react-native": "0.71.6", "react-native-svg": "9.4.0", - "rn-declarative": "0.0.56", + "rn-declarative": "0.0.57", "typescript": "4.6.2" }, "engines": { @@ -9449,12 +9449,11 @@ } }, "node_modules/rn-declarative": { - "version": "0.0.56", - "resolved": "https://registry.npmjs.org/rn-declarative/-/rn-declarative-0.0.56.tgz", - "integrity": "sha512-VPooIaU75AVCUHLt1EaPV2O6lvTFwQSyMg5kRfjQJ5Sc3X9UbSPG05OOYySWZb9DWN73sXRo2itr3uJhSM52pg==", + "version": "0.0.57", + "resolved": "https://registry.npmjs.org/rn-declarative/-/rn-declarative-0.0.57.tgz", + "integrity": "sha512-YqWspE8lFnuW9Ss0G2mdfnsP27k3MVhQHDkFL5B/Jfd70H99Jhb41gvDWGrq6LV4chZf9lOvVm6vqxgYAN1jUA==", "dev": true, "hasInstallScript": true, - "license": "MIT", "dependencies": { "rimraf": "3.0.2" }, diff --git a/packages/rn-declarative-eva/package.json b/packages/rn-declarative-eva/package.json index 2254d30..cdcfc67 100644 --- a/packages/rn-declarative-eva/package.json +++ b/packages/rn-declarative-eva/package.json @@ -1,6 +1,6 @@ { "name": "rn-declarative-eva", - "version": "0.0.44", + "version": "0.0.45", "description": "A responsive layout for the react-native", "private": false, "author": { @@ -77,7 +77,7 @@ "react-native": "0.71.6", "react-native-svg": "9.4.0", "typescript": "4.6.2", - "rn-declarative": "0.0.56" + "rn-declarative": "0.0.57" }, "dependencies": { "rimraf": "3.0.2" diff --git a/packages/rn-declarative/package-lock.json b/packages/rn-declarative/package-lock.json index f0f707a..50436cb 100644 --- a/packages/rn-declarative/package-lock.json +++ b/packages/rn-declarative/package-lock.json @@ -1,12 +1,12 @@ { "name": "rn-declarative", - "version": "0.0.56", + "version": "0.0.57", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "rn-declarative", - "version": "0.0.56", + "version": "0.0.57", "hasInstallScript": true, "license": "MIT", "dependencies": { diff --git a/packages/rn-declarative/package.json b/packages/rn-declarative/package.json index fa903f5..be883e4 100644 --- a/packages/rn-declarative/package.json +++ b/packages/rn-declarative/package.json @@ -1,6 +1,6 @@ { "name": "rn-declarative", - "version": "0.0.56", + "version": "0.0.57", "description": "A responsive layout for the react-native", "private": false, "author": { diff --git a/packages/rn-declarative/src/components/One/components/SlotFactory/ISlotFactoryContext.ts b/packages/rn-declarative/src/components/One/components/SlotFactory/ISlotFactoryContext.ts index e88d265..9392b3c 100644 --- a/packages/rn-declarative/src/components/One/components/SlotFactory/ISlotFactoryContext.ts +++ b/packages/rn-declarative/src/components/One/components/SlotFactory/ISlotFactoryContext.ts @@ -17,6 +17,7 @@ import { ISliderSlot } from '../../slots/SliderSlot'; import { ITimeSlot } from '../../slots/TimeSlot'; import { IChooseSlot } from '../../slots/ChooseSlot'; import { ITypographySlot } from '../../slots/TypographySlot'; +import { ITreeSlot } from '../../slots/TreeSlot'; /** * A context object that provides access to various component types used by the slot factory. @@ -47,6 +48,7 @@ export interface ISlotFactoryContext { Time: ComponentType; Choose: ComponentType; Typography: ComponentType; + Tree: ComponentType; } export default ISlotFactoryContext; diff --git a/packages/rn-declarative/src/components/One/components/SlotFactory/SlotContext.ts b/packages/rn-declarative/src/components/One/components/SlotFactory/SlotContext.ts index 1e9025e..364c254 100644 --- a/packages/rn-declarative/src/components/One/components/SlotFactory/SlotContext.ts +++ b/packages/rn-declarative/src/components/One/components/SlotFactory/SlotContext.ts @@ -17,6 +17,7 @@ import Slider from './components/Slider'; import Time from './components/Time'; import Choose from './components/Choose'; import Typography from './components/Typography'; +import Tree from './components/Tree'; import ISlotFactoryContext from './ISlotFactoryContext'; @@ -48,6 +49,7 @@ export const defaultSlots: ISlotFactoryContext = { Time, Choose, Typography, + Tree, }; export const SlotContext = createContext(defaultSlots); diff --git a/packages/rn-declarative/src/components/One/components/SlotFactory/components/Tree.tsx b/packages/rn-declarative/src/components/One/components/SlotFactory/components/Tree.tsx new file mode 100644 index 0000000..883024f --- /dev/null +++ b/packages/rn-declarative/src/components/One/components/SlotFactory/components/Tree.tsx @@ -0,0 +1,13 @@ +import * as React from 'react'; + +import { Text } from 'react-native'; + +import { ITreeSlot } from '../../../slots/TreeSlot'; + +export const Tree = ({}: ITreeSlot) => ( + + FieldType.Tree is not provided (see OneSlotFactory) + +) + +export default Tree; diff --git a/packages/rn-declarative/src/components/One/config/createField.tsx b/packages/rn-declarative/src/components/One/config/createField.tsx index 2c762bf..dc5213a 100644 --- a/packages/rn-declarative/src/components/One/config/createField.tsx +++ b/packages/rn-declarative/src/components/One/config/createField.tsx @@ -23,6 +23,7 @@ import SliderField from "../fields/SliderField"; import TimeField from "../fields/TimeField"; import ChooseField from "../fields/ChooseField"; import TypographyField from "../fields/TypographyField"; +import TreeField from "../fields/TreeField"; const fieldMap: { [key in FieldType]?: React.ComponentType } = Object.create(null); @@ -60,6 +61,7 @@ Object.assign(fieldMap, { [FieldType.Time]: TimeField, [FieldType.Choose]: ChooseField, [FieldType.Typography]: TypographyField, + [FieldType.Tree]: TreeField, }); /** diff --git a/packages/rn-declarative/src/components/One/config/initialValue.ts b/packages/rn-declarative/src/components/One/config/initialValue.ts index 39ac488..91f7c24 100644 --- a/packages/rn-declarative/src/components/One/config/initialValue.ts +++ b/packages/rn-declarative/src/components/One/config/initialValue.ts @@ -32,6 +32,7 @@ const initialValueMap = { [FieldType.Time]: null, [FieldType.Choose]: null, [FieldType.Typography]: "", + [FieldType.Tree]: null, }; type InitialValue = typeof initialValueMap; diff --git a/packages/rn-declarative/src/components/One/config/isBaseline.ts b/packages/rn-declarative/src/components/One/config/isBaseline.ts index e3cd39f..a8172f2 100644 --- a/packages/rn-declarative/src/components/One/config/isBaseline.ts +++ b/packages/rn-declarative/src/components/One/config/isBaseline.ts @@ -24,6 +24,7 @@ export const baselineFields = new Set([ FieldType.Time, FieldType.Choose, FieldType.Typography, + FieldType.Tree, ]); /** diff --git a/packages/rn-declarative/src/components/One/fields/TreeField.tsx b/packages/rn-declarative/src/components/One/fields/TreeField.tsx new file mode 100644 index 0000000..3820d1e --- /dev/null +++ b/packages/rn-declarative/src/components/One/fields/TreeField.tsx @@ -0,0 +1,170 @@ +import * as React from "react"; + +import Tree from '../../../components/One/slots/TreeSlot'; + +import makeField from "../components/makeField"; + +import IManaged, { PickProp } from "../../../model/IManaged"; +import IAnything from "../../../model/IAnything"; +import IField from "../../../model/IField"; + +/** + * Interface for the props of the ITreeField component. + * + * @template Data The type of data in the field. + * @template Payload The type of payload in the field. + */ +export interface ITreeFieldProps { + /** + * Validation factory config + * + * @template IField - Type representing the field object. + * @template Data - Type representing the data object. + * @template Payload - Type representing the payload object. + * + * @returns The value of the "validation" property. + */ + validation?: PickProp, 'validation'>; + /** + * Returns the "description" property of a given object. + * + * @template T - The type of the object. + * @template K - The literal key type. + * + * @param obj - The object from which to extract the property. + * @param key - The literal key representing the property to extract. + * + * @returns - The value of the specified property. + */ + description?: PickProp, "description">; + /** + * Type definition for the "title" property picked from the given object type. + * + * @template IField - The object type that contains the "title" property. + * @template Data - The data type of the "title" property. + * @template Payload - The payload type of the "title" property. + * + * @param - The object from which the "title" property will be picked. + * + * @returns - The resulting object that only contains the "title" property. + */ + title?: PickProp, "title">; + /** + * Type definition for the variable placeholder. + * + * @template Data - The type of data for the field. + * @template Payload - The type of payload for the field. + * @typedef placeholder + */ + placeholder?: PickProp, "placeholder">; + /** + * Specifies if a field is readOnly. + * + * @typedef Readonly + * + * @typedef IField + * @typedef Payload + * @typedef PickProp + * @typedef Data + * + * @param readonly - The field being checked for readOnly status. + * + * @returns - A boolean value indicating if the field is readOnly. + */ + readonly?: PickProp, "readonly">; + /** + * Represents the `disabled` property of a field in a form. + * + * @typedef Disabled + * + * @property disabled - Indicates whether the field is disabled or not. + * @template Data - The type of data stored in the form. + * @template Payload - The type of payload used for form submission. + */ + disabled?: PickProp, "disabled">; + /** + * Represents the item tree of a specific field in the data payload. + * + * @typedef ItemTree + */ + itemTree?: PickProp, 'itemTree'>; +} + +/** + * Represents the private interface for the TreeField component. + * + * @template Data The type of data for the TreeField component. + */ +export interface ITreeFieldPrivate { + onChange: PickProp, "onChange">; + invalid: PickProp, "invalid">; + incorrect: PickProp, "incorrect">; + value: PickProp, "value">; + loading: PickProp, "loading">; + disabled: PickProp, "disabled">; + dirty: PickProp, "dirty">; + name: PickProp, "name">; +} + +/** + * Renders a TreeField component. + * + * @param props - The props object containing the necessary data for rendering the TreeField. + * @param props.invalid - Determines if the TreeField is invalid. + * @param props.value - The value of the TreeField. + * @param props.disabled - Determines if the TreeField is disabled. + * @param props.readonly - Determines if the TreeField is readonly. + * @param props.incorrect - Determines if the TreeField is incorrect. + * @param props.description - The description text for the TreeField. + * @param props.outlined - Determines if the TreeField should have an outlined style. + * @param props.title - The title text for the TreeField. + * @param props.placeholder - The placeholder text for the TreeField. + * @param props.itemTree - The itemTree object for rendering the Tree. + * @param props.dirty - Determines if the TreeField has been modified. + * @param props.loading - Determines if the TreeField is currently loading. + * @param props.onChange - The callback function to be called when the value of the TreeField changes. + * @param props.name - The name attribute of the TreeField. + * @param props.withContextMenu - Determines if the TreeField should have a context menu. + * + * @returns The rendered TreeField component. + */ +export const TreeField = ({ + invalid, + value, + disabled, + readonly, + incorrect, + description = "", + title = "", + placeholder = "", + itemTree, + dirty, + loading, + onChange, + name, +}: ITreeFieldProps & ITreeFieldPrivate) => ( + +); + +TreeField.displayName = 'TreeField'; + +export default makeField(TreeField, { + withApplyQueue: true, + skipDirtyPressListener: true, + skipFocusReadonly: true, + skipDebounce: true, +}); diff --git a/packages/rn-declarative/src/components/One/slots/TreeSlot/ITreeSlot.ts b/packages/rn-declarative/src/components/One/slots/TreeSlot/ITreeSlot.ts new file mode 100644 index 0000000..28cfae2 --- /dev/null +++ b/packages/rn-declarative/src/components/One/slots/TreeSlot/ITreeSlot.ts @@ -0,0 +1,14 @@ +import { ITreeFieldProps, ITreeFieldPrivate } from "../../fields/TreeField"; + +type ITreeBase = ITreeFieldProps & ITreeFieldPrivate; + +/** + * Represents a slot in a tree structure. + * Extends the interface ITreeBase. + * + * @interface + * @extends ITreeBase + */ +export interface ITreeSlot extends ITreeBase { } + +export default ITreeSlot; diff --git a/packages/rn-declarative/src/components/One/slots/TreeSlot/TreeSlot.tsx b/packages/rn-declarative/src/components/One/slots/TreeSlot/TreeSlot.tsx new file mode 100644 index 0000000..846a5d9 --- /dev/null +++ b/packages/rn-declarative/src/components/One/slots/TreeSlot/TreeSlot.tsx @@ -0,0 +1,19 @@ +import * as React from 'react'; +import { useContext } from 'react'; + +import { SlotContext } from '../../components/SlotFactory'; + +import ITreeSlot from './ITreeSlot'; + +/** + * Represents a slot for a tree component. + * + * @param props - The props for the TreeSlot component. + * @returns - The rendered Tree component. + */ +export const TreeSlot = (props: ITreeSlot) => { + const { Tree } = useContext(SlotContext); + return ; +}; + +export default TreeSlot; diff --git a/packages/rn-declarative/src/components/One/slots/TreeSlot/index.ts b/packages/rn-declarative/src/components/One/slots/TreeSlot/index.ts new file mode 100644 index 0000000..f2e8b15 --- /dev/null +++ b/packages/rn-declarative/src/components/One/slots/TreeSlot/index.ts @@ -0,0 +1,3 @@ +export * from './ITreeSlot'; +export * from './TreeSlot'; +export { default } from './TreeSlot'; diff --git a/packages/rn-declarative/src/components/One/slots/index.ts b/packages/rn-declarative/src/components/One/slots/index.ts index 8a552ed..bff7f17 100644 --- a/packages/rn-declarative/src/components/One/slots/index.ts +++ b/packages/rn-declarative/src/components/One/slots/index.ts @@ -14,3 +14,4 @@ export * from './SliderSlot'; export * from './TimeSlot'; export * from './ChooseSlot'; export * from './TypographySlot'; +export * from './TreeSlot'; \ No newline at end of file diff --git a/packages/rn-declarative/src/index.ts b/packages/rn-declarative/src/index.ts index 369bb26..c336915 100644 --- a/packages/rn-declarative/src/index.ts +++ b/packages/rn-declarative/src/index.ts @@ -2,6 +2,7 @@ export type { ISize } from './model/ISize'; import { TypedField as TypedFieldInternal } from './model/TypedField'; import { IValidation as IValidationInternal } from './model/IValidation'; +import { ITreeNode as ITreeNodeInternal } from './model/ITreeNode'; import { IInvalidField as IInvalidFieldInternal } from './model/IInvalidField'; import { StyleProperties as StylePropertiesInternal } from './model/StyleProperties'; import { CompiledStyles as CompiledStylesInternal } from './model/CompiledStyles'; @@ -49,6 +50,7 @@ export type IFieldEntity = IEntityInterna export type IFieldManaged = IManagedInternal; export type IInvalidField = IInvalidFieldInternal; export type IValidation = IValidationInternal; +export type ITreeNode = ITreeNodeInternal; export type StyleProperties = StylePropertiesInternal; export type CompiledStyles = CompiledStylesInternal; @@ -112,6 +114,8 @@ import { ISliderSlot as ISliderSlotInternal } from './components'; import { ITimeSlot as ITimeSlotInternal } from './components'; import { IChooseSlot as IChooseSlotInternal } from './components'; import { ITypographySlot as ITypographySlotInternal } from './components'; +import { ITreeSlot as ITreeSlotInternal } from './components'; + export type ICheckBoxSlot = ICheckBoxSlotInternal; export type IComboSlot = IComboSlotInternal; @@ -130,6 +134,7 @@ export type ISliderSlot = ISliderSlotInternal; export type ITimeSlot = ITimeSlotInternal; export type IChooseSlot = IChooseSlotInternal; export type ITypographySlot = ITypographySlotInternal; +export type ITreeSlot = ITreeSlotInternal; export { randomString } from './utils/randomString'; export { compareFulltext } from './utils/compareFulltext'; diff --git a/packages/rn-declarative/src/model/FieldType.ts b/packages/rn-declarative/src/model/FieldType.ts index 2100a85..b593b69 100644 --- a/packages/rn-declarative/src/model/FieldType.ts +++ b/packages/rn-declarative/src/model/FieldType.ts @@ -26,6 +26,7 @@ export enum FieldType { Time = 'time-field', Choose = 'choose-field', Typography = 'typography-field', + Tree = 'Tree-field', }; Object.entries(FieldType).forEach(([key, value]) => { diff --git a/packages/rn-declarative/src/model/IField.ts b/packages/rn-declarative/src/model/IField.ts index 8f79649..0a2e925 100644 --- a/packages/rn-declarative/src/model/IField.ts +++ b/packages/rn-declarative/src/model/IField.ts @@ -6,6 +6,8 @@ import type { IDebug } from './ComponentFieldInstance'; import FieldType from './FieldType'; import IAnything from './IAnything'; import IValidation from './IValidation'; +import ITreeNode from './ITreeNode'; + import StyleProperties from './StyleProperties'; /** @@ -176,6 +178,11 @@ export interface IField { */ itemList?: string[] | ((data: Data, payload: Payload) => string[]) | ((data: Data, payload: Payload) => Promise), + /** + * Вариант выбора для TreeField + */ + itemTree?: ITreeNode[] | ((data: Data, payload: Payload) => ITreeNode[]) | ((data: Data, payload: Payload) => Promise); + /** * Отключает возможность сброса выбора значения для Items и Combo */ diff --git a/packages/rn-declarative/src/model/ITreeNode.ts b/packages/rn-declarative/src/model/ITreeNode.ts new file mode 100644 index 0000000..005b792 --- /dev/null +++ b/packages/rn-declarative/src/model/ITreeNode.ts @@ -0,0 +1,15 @@ +/** + * Represents a Node in a tree structure. + */ +export interface ITreeNode { + label: string; + value: string; + /** + * Represents an array of child nodes excluding the "child" property (recursion). + * + * @typedef ChildArray + */ + child?: Omit[]; +} + +export default ITreeNode; diff --git a/packages/rn-declarative/src/model/TypedField.ts b/packages/rn-declarative/src/model/TypedField.ts index 9dfa015..714a20a 100644 --- a/packages/rn-declarative/src/model/TypedField.ts +++ b/packages/rn-declarative/src/model/TypedField.ts @@ -35,6 +35,7 @@ import { ISliderFieldProps } from '../components/One/fields/SliderField'; import { ITimeFieldProps } from '../components/One/fields/TimeField'; import { IChooseFieldProps } from '../components/One/fields/ChooseField'; import { ITypographyFieldProps } from '../components/One/fields/TypographyField'; +import { ITreeFieldProps } from '../components/One/fields/TreeField'; /** * Исключения из правила @@ -111,7 +112,7 @@ type Slider = TypedFieldFactoryShallow = TypedFieldFactoryShallow, Data, Payload>; type Choose = TypedFieldFactoryShallow, Data, Payload>; type Typography = TypedFieldFactoryShallow, Data, Payload>; - +type Tree = TypedFieldFactoryShallow, Data, Payload>; /** * Логическое ветвление компонентов @@ -130,6 +131,7 @@ export type TypedFieldRegistry ? Time : Target extends Choose ? Choose : Target extends Typography ? Typography + : Target extends Tree ? Tree : Target extends Component ? Component : Target extends Items ? Items : Target extends Radio ? Radio