react-native-x-components 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (127) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +96 -0
  3. package/dist/XActionSheet/index.d.ts +47 -0
  4. package/dist/XActionSheet/index.js +100 -0
  5. package/dist/XAnimatedSearchPanel/index.d.ts +33 -0
  6. package/dist/XAnimatedSearchPanel/index.js +295 -0
  7. package/dist/XAnimatedView/index.d.ts +77 -0
  8. package/dist/XAnimatedView/index.js +227 -0
  9. package/dist/XButton/index.d.ts +44 -0
  10. package/dist/XButton/index.js +126 -0
  11. package/dist/XCalendar/XCalendarPopup.d.ts +38 -0
  12. package/dist/XCalendar/XCalendarPopup.js +76 -0
  13. package/dist/XCalendar/index.d.ts +50 -0
  14. package/dist/XCalendar/index.js +241 -0
  15. package/dist/XCarousel/index.d.ts +72 -0
  16. package/dist/XCarousel/index.js +183 -0
  17. package/dist/XCascadeSelect/index.d.ts +39 -0
  18. package/dist/XCascadeSelect/index.js +147 -0
  19. package/dist/XChart/index.d.ts +78 -0
  20. package/dist/XChart/index.js +162 -0
  21. package/dist/XCheckbox/index.d.ts +61 -0
  22. package/dist/XCheckbox/index.js +128 -0
  23. package/dist/XConfirmForm/index.d.ts +69 -0
  24. package/dist/XConfirmForm/index.js +113 -0
  25. package/dist/XDivider/index.d.ts +33 -0
  26. package/dist/XDivider/index.js +61 -0
  27. package/dist/XDropdownMenu/index.d.ts +66 -0
  28. package/dist/XDropdownMenu/index.js +258 -0
  29. package/dist/XElevator/index.d.ts +52 -0
  30. package/dist/XElevator/index.js +138 -0
  31. package/dist/XForm/FormStore.d.ts +82 -0
  32. package/dist/XForm/FormStore.js +279 -0
  33. package/dist/XForm/index.d.ts +116 -0
  34. package/dist/XForm/index.js +212 -0
  35. package/dist/XForm/types.d.ts +82 -0
  36. package/dist/XForm/types.js +1 -0
  37. package/dist/XForm/useForm.d.ts +2 -0
  38. package/dist/XForm/useForm.js +19 -0
  39. package/dist/XForm/utils.d.ts +42 -0
  40. package/dist/XForm/utils.js +131 -0
  41. package/dist/XForm/validate.d.ts +20 -0
  42. package/dist/XForm/validate.js +118 -0
  43. package/dist/XFormPro/components/FieldTrigger.d.ts +14 -0
  44. package/dist/XFormPro/components/FieldTrigger.js +38 -0
  45. package/dist/XFormPro/components/XDateField.d.ts +22 -0
  46. package/dist/XFormPro/components/XDateField.js +22 -0
  47. package/dist/XFormPro/components/XSelectField.d.ts +16 -0
  48. package/dist/XFormPro/components/XSelectField.js +19 -0
  49. package/dist/XFormPro/index.d.ts +44 -0
  50. package/dist/XFormPro/index.js +111 -0
  51. package/dist/XFormPro/renderers.d.ts +24 -0
  52. package/dist/XFormPro/renderers.js +53 -0
  53. package/dist/XFormPro/types.d.ts +142 -0
  54. package/dist/XFormPro/types.js +1 -0
  55. package/dist/XImage/index.d.ts +13 -0
  56. package/dist/XImage/index.js +32 -0
  57. package/dist/XInput/index.d.ts +43 -0
  58. package/dist/XInput/index.js +136 -0
  59. package/dist/XLicensePlate/index.d.ts +40 -0
  60. package/dist/XLicensePlate/index.js +172 -0
  61. package/dist/XLocale/index.d.ts +23 -0
  62. package/dist/XLocale/index.js +174 -0
  63. package/dist/XModalForm/index.d.ts +32 -0
  64. package/dist/XModalForm/index.js +85 -0
  65. package/dist/XMultiSelect/index.d.ts +31 -0
  66. package/dist/XMultiSelect/index.js +131 -0
  67. package/dist/XNumberKeyboard/index.d.ts +57 -0
  68. package/dist/XNumberKeyboard/index.js +142 -0
  69. package/dist/XPicker/index.d.ts +35 -0
  70. package/dist/XPicker/index.js +96 -0
  71. package/dist/XPickerDate/index.d.ts +58 -0
  72. package/dist/XPickerDate/index.js +234 -0
  73. package/dist/XPopupProvider/index.d.ts +23 -0
  74. package/dist/XPopupProvider/index.js +6 -0
  75. package/dist/XProgress/index.d.ts +49 -0
  76. package/dist/XProgress/index.js +196 -0
  77. package/dist/XProviders/XImagePreview/index.d.ts +44 -0
  78. package/dist/XProviders/XImagePreview/index.js +164 -0
  79. package/dist/XProviders/XLoadingModal/index.d.ts +46 -0
  80. package/dist/XProviders/XLoadingModal/index.js +119 -0
  81. package/dist/XProviders/XToast/index.d.ts +50 -0
  82. package/dist/XProviders/XToast/index.js +183 -0
  83. package/dist/XProviders/index.d.ts +31 -0
  84. package/dist/XProviders/index.js +28 -0
  85. package/dist/XProviders/usageExample.d.ts +19 -0
  86. package/dist/XProviders/usageExample.js +83 -0
  87. package/dist/XPullView/index.d.ts +76 -0
  88. package/dist/XPullView/index.js +220 -0
  89. package/dist/XRadio/index.d.ts +83 -0
  90. package/dist/XRadio/index.js +186 -0
  91. package/dist/XRecord/index.d.ts +37 -0
  92. package/dist/XRecord/index.js +160 -0
  93. package/dist/XSignature/XSignatureSkia.d.ts +39 -0
  94. package/dist/XSignature/XSignatureSkia.js +184 -0
  95. package/dist/XSignature/core.d.ts +69 -0
  96. package/dist/XSignature/core.js +108 -0
  97. package/dist/XSignature/index.d.ts +33 -0
  98. package/dist/XSignature/index.js +88 -0
  99. package/dist/XTabs/index.d.ts +65 -0
  100. package/dist/XTabs/index.js +210 -0
  101. package/dist/XTag/index.d.ts +61 -0
  102. package/dist/XTag/index.js +153 -0
  103. package/dist/XTopView/index.d.ts +25 -0
  104. package/dist/XTopView/index.js +8 -0
  105. package/dist/XTopViewStore/index.d.ts +45 -0
  106. package/dist/XTopViewStore/index.js +49 -0
  107. package/dist/XUpload/XUploadImage.d.ts +37 -0
  108. package/dist/XUpload/XUploadImage.js +142 -0
  109. package/dist/XUpload/XUploadVideo.d.ts +24 -0
  110. package/dist/XUpload/XUploadVideo.js +83 -0
  111. package/dist/XUpload/adapters.d.ts +50 -0
  112. package/dist/XUpload/adapters.js +110 -0
  113. package/dist/XUpload/helpers.d.ts +35 -0
  114. package/dist/XUpload/helpers.js +85 -0
  115. package/dist/XUpload/index.d.ts +12 -0
  116. package/dist/XUpload/index.js +5 -0
  117. package/dist/XUpload/provider.d.ts +26 -0
  118. package/dist/XUpload/provider.js +43 -0
  119. package/dist/XUpload/types.d.ts +31 -0
  120. package/dist/XUpload/types.js +4 -0
  121. package/dist/XWheel/index.d.ts +49 -0
  122. package/dist/XWheel/index.js +263 -0
  123. package/dist/index.d.ts +113 -0
  124. package/dist/index.js +127 -0
  125. package/dist/theme.d.ts +164 -0
  126. package/dist/theme.js +161 -0
  127. package/package.json +78 -0
@@ -0,0 +1,38 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { Pressable, StyleSheet, Text } from 'react-native';
3
+ import { useXTheme } from '../../theme';
4
+ import { useXLocale } from '../../XLocale';
5
+ import AntDesign from '@react-native-vector-icons/ant-design';
6
+ export function FieldTrigger({ text, placeholder, onPress, disabled }) {
7
+ const t = useXTheme();
8
+ const { t: i18n } = useXLocale();
9
+ const resolvedPlaceholder = placeholder ?? i18n('pleaseSelect');
10
+ return (_jsxs(Pressable, { style: ({ pressed }) => [
11
+ styles.trigger,
12
+ { borderColor: t.colorBorder, backgroundColor: disabled ? t.colorBgContainerDisabled : t.colorBgLayout },
13
+ pressed && styles.pressed,
14
+ disabled && styles.disabled,
15
+ ], onPress: onPress, disabled: disabled, children: [_jsx(Text, { style: [styles.text, { color: text ? t.colorText : t.colorTextQuaternary }, !text && styles.placeholder], allowFontScaling: false, children: text || resolvedPlaceholder }), _jsx(AntDesign, { name: 'right', size: 16, color: t.colorTextTertiary })] }));
16
+ }
17
+ const styles = StyleSheet.create({
18
+ trigger: {
19
+ flexDirection: 'row',
20
+ alignItems: 'center',
21
+ justifyContent: 'space-between',
22
+ borderWidth: StyleSheet.hairlineWidth,
23
+ borderRadius: 8,
24
+ paddingHorizontal: 12,
25
+ paddingVertical: 10,
26
+ minHeight: 40,
27
+ },
28
+ pressed: {
29
+ opacity: 0.75,
30
+ },
31
+ disabled: {},
32
+ text: {
33
+ flex: 1,
34
+ fontSize: 15,
35
+ marginRight: 8,
36
+ },
37
+ placeholder: {},
38
+ });
@@ -0,0 +1,22 @@
1
+ /**
2
+ * XDateField —— XFormPro 的 datePicker 类型控件:触发区 + XPickerDate 弹层。
3
+ *
4
+ * 日期/日期时间/时间统一走 format:
5
+ * - 'YYYY-MM-DD' 日期
6
+ * - 'YYYY-MM-DD HH:mm' 日期时间
7
+ * - 'HH:mm:ss' / 'HH:mm' 时间(原 timePicker 类型)
8
+ */
9
+ import React from 'react';
10
+ export interface XDateFieldProps {
11
+ value?: string;
12
+ onChange?: (value: string) => void;
13
+ /** 列配置(见 XPickerDate),如 'YYYY-MM-DD'、'HH:mm' */
14
+ format?: string;
15
+ placeholder?: string;
16
+ title?: string;
17
+ minYear?: number;
18
+ maxYear?: number;
19
+ disabled?: boolean;
20
+ }
21
+ export declare function XDateField({ value, onChange, format, placeholder, title, minYear, maxYear, disabled }: XDateFieldProps): React.JSX.Element;
22
+ export default XDateField;
@@ -0,0 +1,22 @@
1
+ import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
2
+ /**
3
+ * XDateField —— XFormPro 的 datePicker 类型控件:触发区 + XPickerDate 弹层。
4
+ *
5
+ * 日期/日期时间/时间统一走 format:
6
+ * - 'YYYY-MM-DD' 日期
7
+ * - 'YYYY-MM-DD HH:mm' 日期时间
8
+ * - 'HH:mm:ss' / 'HH:mm' 时间(原 timePicker 类型)
9
+ */
10
+ import { useState } from 'react';
11
+ import { XPickerDate } from '../../XPickerDate';
12
+ import { FieldTrigger } from './FieldTrigger';
13
+ import { useXLocale } from '../../XLocale';
14
+ export function XDateField({ value, onChange, format, placeholder, title, minYear, maxYear, disabled }) {
15
+ const { t } = useXLocale();
16
+ const [visible, setVisible] = useState(false);
17
+ return (_jsxs(_Fragment, { children: [_jsx(FieldTrigger, { text: value, placeholder: placeholder ?? t('selectDate'), disabled: disabled, onPress: () => setVisible(true) }), _jsx(XPickerDate, { visible: visible, onClose: () => setVisible(false), value: value, title: title ?? t('selectDate'), format: format, minYear: minYear, maxYear: maxYear, onChange: v => {
18
+ onChange?.(v);
19
+ setVisible(false);
20
+ } })] }));
21
+ }
22
+ export default XDateField;
@@ -0,0 +1,16 @@
1
+ /**
2
+ * XSelectField —— XFormPro 的 select 类型控件:触发区 + XPicker 弹层。
3
+ * Form.Item 注入 value/onChange 后即可作为表单控件使用。
4
+ */
5
+ import React from 'react';
6
+ import { XPickerOption } from '../../XPicker';
7
+ export interface XSelectFieldProps {
8
+ value?: any;
9
+ onChange?: (value: any) => void;
10
+ options: XPickerOption[];
11
+ placeholder?: string;
12
+ title?: string;
13
+ disabled?: boolean;
14
+ }
15
+ export declare function XSelectField({ value, onChange, options, placeholder, title, disabled }: XSelectFieldProps): React.JSX.Element;
16
+ export default XSelectField;
@@ -0,0 +1,19 @@
1
+ import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
2
+ /**
3
+ * XSelectField —— XFormPro 的 select 类型控件:触发区 + XPicker 弹层。
4
+ * Form.Item 注入 value/onChange 后即可作为表单控件使用。
5
+ */
6
+ import { useState } from 'react';
7
+ import { XPicker } from '../../XPicker';
8
+ import { FieldTrigger } from './FieldTrigger';
9
+ import { useXLocale } from '../../XLocale';
10
+ export function XSelectField({ value, onChange, options, placeholder, title, disabled }) {
11
+ const { t } = useXLocale();
12
+ const [visible, setVisible] = useState(false);
13
+ const option = options.find(o => o.value === value);
14
+ return (_jsxs(_Fragment, { children: [_jsx(FieldTrigger, { text: option?.label, placeholder: placeholder ?? t('pleaseSelectLabel', { n: title ?? '' }), disabled: disabled, onPress: () => setVisible(true) }), _jsx(XPicker, { visible: visible, onClose: () => setVisible(false), options: options, value: value, title: title ?? t('pleaseSelect'), onChange: v => {
15
+ onChange?.(v);
16
+ setVisible(false);
17
+ } })] }));
18
+ }
19
+ export default XSelectField;
@@ -0,0 +1,44 @@
1
+ /**
2
+ * ============================================================================
3
+ * XFormPro —— 低代码表单(老 FormPro 的 X 系列重制版,基于 XForm 实现)
4
+ * ============================================================================
5
+ *
6
+ * 对外 API 与老 FormPro 同名同义(value/onUpdateValue/formItemOptions/
7
+ * ref.validate + restoreValidation),老页面迁移只改 import 和组件名。
8
+ *
9
+ * 与老 FormPro 的差异:
10
+ * 1. 内部用 XForm(自研)替代 @ant-design/react-native 的 Form;
11
+ * 2. 控件全部换 X 系列(详见 types.ts 的 XFm 映射说明);
12
+ * 3. 新增 hiddenValues:编辑场景把 id 等字段带进表单 —— 不渲染表单项,
13
+ * 但值进 store,validate/onUpdateValue 的结果里都带,且不受 resetFields 影响。
14
+ *
15
+ * 使用方式:
16
+ * ```tsx
17
+ * const [formValue, setFormValue] = useState({name: '', sex: undefined});
18
+ * const formRef = useRef<XFormProInst>(null);
19
+ *
20
+ * const options: XFormItemOptions<typeof formValue> = {
21
+ * name: {required: true, type: 'input', label: '姓名'},
22
+ * sex: {required: true, type: 'radioGroup', label: '性别',
23
+ * options: [{label: '男', value: 1}, {label: '女', value: 0}]},
24
+ * };
25
+ *
26
+ * <XFormPro ref={formRef} value={formValue} onUpdateValue={setFormValue}
27
+ * formItemOptions={options} hiddenValues={{id: 'xxx'}} />
28
+ *
29
+ * const values = await formRef.current.validate(); // 含 hiddenValues
30
+ * ```
31
+ */
32
+ import React from 'react';
33
+ import type { XFormProInst, XFormProProps } from './types';
34
+ export type { XFormModelValue, XOptionItem, XFormProRule, XBaseFormItemProps, XFormProItemProps, XFormItemOptions, XFormProProps, XFormProInst, XFm } from './types';
35
+ export { registerXFormProRenderer } from './renderers';
36
+ export type { XFormProCustomRenderer } from './renderers';
37
+ /**
38
+ * forwardRef + 泛型断言:让 <XFormPro<FieldType>> 正确推导 props 和 ref 类型
39
+ * (与老 FormPro 相同的手法)。
40
+ */
41
+ declare const XFormPro: <ModelValue extends Record<string, any>>(props: XFormProProps<ModelValue> & {
42
+ ref?: React.Ref<XFormProInst<ModelValue>>;
43
+ }) => React.ReactElement;
44
+ export default XFormPro;
@@ -0,0 +1,111 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ /**
3
+ * ============================================================================
4
+ * XFormPro —— 低代码表单(老 FormPro 的 X 系列重制版,基于 XForm 实现)
5
+ * ============================================================================
6
+ *
7
+ * 对外 API 与老 FormPro 同名同义(value/onUpdateValue/formItemOptions/
8
+ * ref.validate + restoreValidation),老页面迁移只改 import 和组件名。
9
+ *
10
+ * 与老 FormPro 的差异:
11
+ * 1. 内部用 XForm(自研)替代 @ant-design/react-native 的 Form;
12
+ * 2. 控件全部换 X 系列(详见 types.ts 的 XFm 映射说明);
13
+ * 3. 新增 hiddenValues:编辑场景把 id 等字段带进表单 —— 不渲染表单项,
14
+ * 但值进 store,validate/onUpdateValue 的结果里都带,且不受 resetFields 影响。
15
+ *
16
+ * 使用方式:
17
+ * ```tsx
18
+ * const [formValue, setFormValue] = useState({name: '', sex: undefined});
19
+ * const formRef = useRef<XFormProInst>(null);
20
+ *
21
+ * const options: XFormItemOptions<typeof formValue> = {
22
+ * name: {required: true, type: 'input', label: '姓名'},
23
+ * sex: {required: true, type: 'radioGroup', label: '性别',
24
+ * options: [{label: '男', value: 1}, {label: '女', value: 0}]},
25
+ * };
26
+ *
27
+ * <XFormPro ref={formRef} value={formValue} onUpdateValue={setFormValue}
28
+ * formItemOptions={options} hiddenValues={{id: 'xxx'}} />
29
+ *
30
+ * const values = await formRef.current.validate(); // 含 hiddenValues
31
+ * ```
32
+ */
33
+ import { forwardRef, useCallback, useEffect, useImperativeHandle, useMemo, useRef } from 'react';
34
+ import XForm from '../XForm';
35
+ import { deepClone } from '../XForm/utils';
36
+ import { renderXFormField } from './renderers';
37
+ import { useXLocale } from '../XLocale';
38
+ export { registerXFormProRenderer } from './renderers';
39
+ /**
40
+ * 通用非空校验(老 FormPro 的 universalValidator 同款):
41
+ * null/undefined/纯空格串/空数组 视为空
42
+ */
43
+ function isValueEmpty(value) {
44
+ return (value === null ||
45
+ value === undefined ||
46
+ (typeof value === 'string' && value.trim() === '') ||
47
+ (Array.isArray(value) && value.length === 0));
48
+ }
49
+ function XFormProInner(props, ref) {
50
+ const { value, onUpdateValue, labelWidth, layout = 'vertical', formItemOptions, hiddenValues } = props;
51
+ const { t } = useXLocale();
52
+ const [form] = XForm.useForm();
53
+ /** 用户输入产生的值变化(外部 value 同步不回声) */
54
+ const isInternalChange = useRef(false);
55
+ // --- 构建表单元数据:补必填规则(老 FormPro 同款逻辑) ---
56
+ const formMeta = useMemo(() => {
57
+ if (!formItemOptions)
58
+ return {};
59
+ const cloned = deepClone(formItemOptions);
60
+ for (const [key, raw] of Object.entries(cloned)) {
61
+ const entry = raw;
62
+ entry.path = key;
63
+ if (entry.required && !entry.rules && !entry.rule) {
64
+ entry.rules = [{ required: true, message: `${entry.label ?? key}${t('cannotBeEmpty')}` }];
65
+ }
66
+ }
67
+ return cloned;
68
+ }, [formItemOptions]);
69
+ // --- 用户输入:上报父级(含 hiddenValues,因为它们在 store 里) ---
70
+ const handleValuesChange = useCallback((_changed, allValues) => {
71
+ isInternalChange.current = true;
72
+ onUpdateValue?.(deepClone(allValues));
73
+ }, [onUpdateValue]);
74
+ // --- 外部 value 变化 -> 回显(编辑回填/重置场景) ---
75
+ useEffect(() => {
76
+ if (isInternalChange.current) {
77
+ isInternalChange.current = false;
78
+ return;
79
+ }
80
+ form.setFieldsValue(value);
81
+ }, [value, form]);
82
+ // --- hiddenValues:进 store 不渲染(编辑场景的 id 等字段原样带回) ---
83
+ useEffect(() => {
84
+ if (hiddenValues) {
85
+ form.setFieldsValue(hiddenValues);
86
+ }
87
+ }, [hiddenValues, form]);
88
+ // --- 实例方法(老 FormPro 同名同义) ---
89
+ useImperativeHandle(ref, () => ({
90
+ validate: () => form.validateFields(),
91
+ restoreValidation: () => {
92
+ const names = Object.keys(formMeta);
93
+ form.setFields(names.map(name => ({ name, errors: [] })));
94
+ },
95
+ }), [form, formMeta]);
96
+ return (_jsx(XForm, { form: form, initialValues: value, onValuesChange: handleValuesChange, layout: layout, labelWidth: labelWidth, children: Object.entries(formMeta).map(([field, raw]) => {
97
+ const entry = raw;
98
+ if (entry.hide)
99
+ return null;
100
+ const rules = entry.rules ?? (entry.rule ? [entry.rule] : undefined);
101
+ return (_jsx(XForm.Item, { name: field, label: entry.label, rules: rules,
102
+ // XInput 走 RN 原生 onChangeText 值回调,其余控件都是 onChange
103
+ trigger: entry.type === 'input' ? 'onChangeText' : 'onChange', children: renderXFormField(entry, form, t) }, field));
104
+ }) }));
105
+ }
106
+ /**
107
+ * forwardRef + 泛型断言:让 <XFormPro<FieldType>> 正确推导 props 和 ref 类型
108
+ * (与老 FormPro 相同的手法)。
109
+ */
110
+ const XFormPro = forwardRef(XFormProInner);
111
+ export default XFormPro;
@@ -0,0 +1,24 @@
1
+ /**
2
+ * XFormPro 的控件渲染分发:type -> 具体组件
3
+ *
4
+ * 自定义类型(如 skiaSignature 等需额外依赖的组件)通过 registerXFormProRenderer
5
+ * 注册,避免组件库硬依赖重型第三方包。未注册的类型返回 null。
6
+ */
7
+ import React from 'react';
8
+ import type { XFormInstance } from '../XForm';
9
+ import type { XFormProItemProps } from './types';
10
+ import type { XLocaleKey } from '../XLocale';
11
+ export type XFormProCustomRenderer = (props: Record<string, any> | undefined, form: XFormInstance<any>) => React.ReactNode;
12
+ /**
13
+ * 注册自定义控件渲染器(按 type 名匹配)。
14
+ *
15
+ * 例如注册签名组件:
16
+ * ```ts
17
+ * registerXFormProRenderer('skiaSignature', (props) => <SkiaSignature {...props} />);
18
+ * ```
19
+ */
20
+ export declare function registerXFormProRenderer(type: string, renderer: XFormProCustomRenderer): void;
21
+ /**
22
+ * 渲染单个表单项的输入控件(value/onChange 由 XForm.Item 注入,这里只管组件形态)
23
+ */
24
+ export declare function renderXFormField(item: XFormProItemProps<any, any>, form: XFormInstance<any>, t: (key: XLocaleKey, params?: Record<string, string | number>) => string): string | number | bigint | boolean | Iterable<React.ReactNode> | Promise<string | number | bigint | boolean | React.ReactPortal | React.ReactElement<unknown, string | React.JSXElementConstructor<any>> | Iterable<React.ReactNode> | null | undefined> | React.JSX.Element | null | undefined;
@@ -0,0 +1,53 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { XInput } from '../XInput';
3
+ import { XRadio } from '../XRadio';
4
+ import { XCheckbox } from '../XCheckbox';
5
+ import { XCascadeSelect } from '../XCascadeSelect';
6
+ import { XMultiSelect } from '../XMultiSelect';
7
+ import { XSelectField } from './components/XSelectField';
8
+ import { XDateField } from './components/XDateField';
9
+ const customRenderers = {};
10
+ /**
11
+ * 注册自定义控件渲染器(按 type 名匹配)。
12
+ *
13
+ * 例如注册签名组件:
14
+ * ```ts
15
+ * registerXFormProRenderer('skiaSignature', (props) => <SkiaSignature {...props} />);
16
+ * ```
17
+ */
18
+ export function registerXFormProRenderer(type, renderer) {
19
+ customRenderers[type] = renderer;
20
+ }
21
+ /**
22
+ * 渲染单个表单项的输入控件(value/onChange 由 XForm.Item 注入,这里只管组件形态)
23
+ */
24
+ export function renderXFormField(item, form, t) {
25
+ const placeholder = item.componentsProps?.placeholder ??
26
+ (item.type === 'input' ? t('pleaseInputLabel', { n: item.label ?? '' }) : t('pleaseSelectLabel', { n: item.label ?? '' }));
27
+ switch (item.type) {
28
+ case 'custom':
29
+ return item.customRender ? item.customRender(form.getFieldsValue(), form) : null;
30
+ case 'input':
31
+ return _jsx(XInput, { placeholder: placeholder, style: { width: item.inputWidth ?? '100%' }, ...item.componentsProps });
32
+ case 'radioGroup':
33
+ return _jsx(XRadio.Group, { options: item.options ?? [], ...item.componentsProps });
34
+ case 'checkboxGroup':
35
+ return _jsx(XCheckbox.Group, { options: item.options ?? [], ...item.componentsProps });
36
+ case 'select':
37
+ return _jsx(XSelectField, { options: item.options ?? [], placeholder: placeholder, ...item.componentsProps });
38
+ case 'cascadeSelect':
39
+ return _jsx(XCascadeSelect, { options: item.cascadeOptions ?? [], placeholder: placeholder, ...item.componentsProps });
40
+ case 'multiSelect':
41
+ return _jsx(XMultiSelect, { options: item.options ?? [], placeholder: placeholder, ...item.componentsProps });
42
+ case 'datePicker':
43
+ return _jsx(XDateField, { placeholder: placeholder, ...item.componentsProps });
44
+ default: {
45
+ // 自定义类型(如 skiaSignature):通过 registerXFormProRenderer 注册
46
+ const customRenderer = customRenderers[item.type];
47
+ if (customRenderer) {
48
+ return customRenderer(item.componentsProps, form);
49
+ }
50
+ return _jsx(XInput, { placeholder: placeholder, ...item.componentsProps });
51
+ }
52
+ }
53
+ }
@@ -0,0 +1,142 @@
1
+ /**
2
+ * XFormPro 类型定义 —— 低代码表单(基于 XForm,对标老 FormPro 的配置式 API)
3
+ */
4
+ import type { ReactNode } from 'react';
5
+ import type { XInputProps } from '../XInput';
6
+ import type { XRadioGroupProps } from '../XRadio';
7
+ import type { XCheckboxGroupProps } from '../XCheckbox';
8
+ import type { XCascadeSelectProps } from '../XCascadeSelect';
9
+ import type { XMultiSelectProps } from '../XMultiSelect';
10
+ import type { XPickerProps } from '../XPicker';
11
+ import type { XPickerDateProps } from '../XPickerDate';
12
+ import type { XFormInstance } from '../XForm';
13
+ /** 表单数据对象 */
14
+ export type XFormModelValue = {
15
+ [k: string]: any;
16
+ };
17
+ /** 平铺选项数据(radioGroup / checkboxGroup / select / multiSelect 用) */
18
+ export type XOptionItem = {
19
+ label: string;
20
+ value: any;
21
+ disabled?: boolean;
22
+ };
23
+ /**
24
+ * 支持的表单控件类型映射(componentsProps 的类型按 type 收窄)
25
+ *
26
+ * 与老 FormPro 的差异:
27
+ * - input -> XInput(multiline 即多行文本,textarea 取消)
28
+ * - inputItem / inputNumber / textarea -> 移除
29
+ * - radioGroup -> XRadio.Group
30
+ * - checkboxGroup -> XCheckbox.Group
31
+ * - select -> XPicker(XSelectField 触发器包装)
32
+ * - cascadeSelect -> XCascadeSelect(自研级联,antd Cascader 数据结构)
33
+ * - multiSelect -> XMultiSelect(XPullView + XCheckbox 重制)
34
+ * - datePicker -> XPickerDate(时间模式通过 componentsProps.format 传 'HH:mm:ss' 等,timePicker 类型取消)
35
+ * - skiaSignature -> SkiaSignature
36
+ * - imageUpload / videoUpload -> 后续再加
37
+ */
38
+ export type XFm = {
39
+ custom: {
40
+ props: Record<string, any>;
41
+ };
42
+ input: {
43
+ props: Partial<Omit<XInputProps, 'value' | 'onChangeText'>>;
44
+ };
45
+ radioGroup: {
46
+ props: Partial<Omit<XRadioGroupProps, 'value' | 'onChange' | 'options'>>;
47
+ };
48
+ checkboxGroup: {
49
+ props: Partial<Omit<XCheckboxGroupProps, 'value' | 'onChange' | 'options'>>;
50
+ };
51
+ select: {
52
+ props: Partial<Omit<XPickerProps, 'visible' | 'value' | 'onChange' | 'options' | 'onClose'>> & {
53
+ placeholder?: string;
54
+ };
55
+ };
56
+ cascadeSelect: {
57
+ props: Partial<Omit<XCascadeSelectProps, 'value' | 'onChange' | 'options'>>;
58
+ };
59
+ multiSelect: {
60
+ props: Partial<Omit<XMultiSelectProps, 'value' | 'onChange' | 'options'>>;
61
+ };
62
+ datePicker: {
63
+ props: Partial<Omit<XPickerDateProps, 'visible' | 'value' | 'onChange' | 'onClose'>> & {
64
+ placeholder?: string;
65
+ };
66
+ };
67
+ skiaSignature: {
68
+ props: Partial<Record<string, any>>;
69
+ };
70
+ };
71
+ /** 单条校验规则(对应 XForm 的 XRule 子集) */
72
+ export type XFormProRule = {
73
+ required?: boolean;
74
+ message?: string;
75
+ pattern?: RegExp;
76
+ min?: number;
77
+ max?: number;
78
+ validator?: (_rule: any, value: any) => Promise<void>;
79
+ };
80
+ /** 表单项基础配置 */
81
+ export type XBaseFormItemProps<ModelValue = Record<string, any>> = {
82
+ /** 标签文本 */
83
+ label?: string;
84
+ /** 是否必填(为 true 且未配置 rules 时自动生成必填校验) */
85
+ required?: boolean;
86
+ /** 校验规则(单条),不传则 required 为 true 时自动生成 */
87
+ rule?: XFormProRule;
88
+ /** 校验规则(多条),优先级高于 rule */
89
+ rules?: XFormProRule[];
90
+ /** 是否隐藏(编辑场景按状态隐藏字段) */
91
+ hide?: boolean;
92
+ /** 输入框宽度(input 类型),默认 100% */
93
+ inputWidth?: number | string;
94
+ /** 自定义渲染函数,仅 type 为 custom 时生效 */
95
+ customRender?: (modelValue: ModelValue, form: XFormInstance<any>) => ReactNode;
96
+ /** 选项数据(radioGroup / checkboxGroup / select / multiSelect 用) */
97
+ options?: XOptionItem[];
98
+ /** 级联数据(cascadeSelect 用,antd Cascader 同款树结构) */
99
+ cascadeOptions?: XCascadeSelectProps['options'];
100
+ };
101
+ /** 表单项完整配置(判别联合:componentsProps 类型随 type 收窄) */
102
+ export type XFormProItemProps<ModelValue, TK extends keyof XFm = keyof XFm> = XBaseFormItemProps<ModelValue> & {
103
+ /** 控件类型 */
104
+ type: TK;
105
+ /** 控件 props(透传给具体组件,value/onChange 由表单注入) */
106
+ componentsProps?: XFm[TK]['props'];
107
+ };
108
+ /**
109
+ * 表单配置对象:key 对应 model 字段名,value 为表单项配置。
110
+ * 键可选:hiddenValues 托管的字段(如 id)无需配置表单项。
111
+ */
112
+ export type XFormItemOptions<ModelValue> = {
113
+ [K in keyof ModelValue]?: {
114
+ [T in keyof XFm]: XFormProItemProps<ModelValue, T>;
115
+ }[keyof XFm];
116
+ };
117
+ /** XFormPro 组件 Props */
118
+ export interface XFormProProps<ModelValue = Record<string, any>> {
119
+ /** 表单数据(受控;编辑回显/重置场景改这个值即可) */
120
+ value: ModelValue;
121
+ /** 值变化回调(用户输入触发,含 hiddenValues) */
122
+ onUpdateValue?: (value: ModelValue) => void;
123
+ /** 标签宽度(horizontal 布局用) */
124
+ labelWidth?: number;
125
+ /** 标签位置,默认 vertical */
126
+ layout?: 'vertical' | 'horizontal';
127
+ /** 表单配置 */
128
+ formItemOptions?: XFormItemOptions<ModelValue>;
129
+ /**
130
+ * 隐藏字段(编辑场景的关键):不渲染表单项,但值会进 store,
131
+ * validate/提交/onUpdateValue 的结果里都带(如 id、createBy 原样带回);
132
+ * 不受 resetFields 影响。
133
+ */
134
+ hiddenValues?: Partial<ModelValue>;
135
+ }
136
+ /** XFormPro 暴露的实例方法(老 FormPro 同名同义) */
137
+ export interface XFormProInst<ModelValue = Record<string, any>> {
138
+ /** 校验表单,成功 resolve 全量值(含 hiddenValues),失败 reject {values, errorFields} */
139
+ validate: () => Promise<ModelValue>;
140
+ /** 清除全部校验错误 */
141
+ restoreValidation: () => void;
142
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,13 @@
1
+ import React from 'react';
2
+ import { ImageStyle } from 'react-native';
3
+ import { ImageResizeMode } from 'react-native';
4
+ export interface ImageWithLoaderProps {
5
+ uri: string;
6
+ style?: ImageStyle;
7
+ onPress?: () => void;
8
+ onLongPress?: () => void;
9
+ delayLongPress?: number;
10
+ resizeMode?: ImageResizeMode | undefined;
11
+ onDelete?: () => void;
12
+ }
13
+ export declare const XImage: React.FC<ImageWithLoaderProps>;
@@ -0,0 +1,32 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { useState } from 'react';
3
+ import { ActivityIndicator, Image, StyleSheet, TouchableOpacity, View } from 'react-native';
4
+ import AntDesign from '@react-native-vector-icons/ant-design';
5
+ import { useXTheme } from '../theme';
6
+ export const XImage = ({ resizeMode, uri, style, onPress, onLongPress, delayLongPress, onDelete }) => {
7
+ const t = useXTheme();
8
+ const [loading, setLoading] = useState(true);
9
+ return (_jsxs(View, { children: [_jsxs(TouchableOpacity, { delayLongPress: delayLongPress, onPress: onPress, onLongPress: onLongPress, activeOpacity: 0.8, children: [loading && (_jsx(View, { style: [style, styles.loadingContainer, { backgroundColor: t.colorSplit }], children: _jsx(ActivityIndicator, { size: 'small', color: t.colorPrimary }) })), _jsx(Image, { resizeMode: resizeMode, source: { uri }, style: [style, loading && { opacity: 0 }], onLoad: () => setLoading(false), onError: () => setLoading(false) })] }), onDelete && (_jsx(TouchableOpacity, { style: [styles.deleteBtn, { backgroundColor: t.colorError }], onPress: onDelete, activeOpacity: 0.7, hitSlop: { top: 4, right: 4, bottom: 4, left: 4 }, children: _jsx(AntDesign, { name: 'close', size: 14, color: t.colorTextLightSolid }) }))] }));
10
+ };
11
+ const styles = StyleSheet.create({
12
+ loadingContainer: {
13
+ position: 'absolute',
14
+ top: 0,
15
+ left: 0,
16
+ right: 0,
17
+ bottom: 0,
18
+ justifyContent: 'center',
19
+ alignItems: 'center',
20
+ },
21
+ deleteBtn: {
22
+ position: 'absolute',
23
+ top: -6,
24
+ right: -6,
25
+ width: 20,
26
+ height: 20,
27
+ borderRadius: 10,
28
+ alignItems: 'center',
29
+ justifyContent: 'center',
30
+ zIndex: 10,
31
+ },
32
+ });
@@ -0,0 +1,43 @@
1
+ /**
2
+ * ============================================================================
3
+ * XInput —— 项目通用输入框(样式取自 componentsTest 的 styles.input)
4
+ * ============================================================================
5
+ *
6
+ * 把项目里反复手写的输入框样式沉淀成组件:
7
+ * 发丝边框 + 8 圆角 + 浅灰底,多行模式自动变成"备注"样式(minHeight + 顶部对齐)。
8
+ *
9
+ * 用法:
10
+ * ```tsx
11
+ * <XInput value={name} onChangeText={setName} placeholder='请输入姓名' />
12
+ * <XInput multiline placeholder='请输入备注' />
13
+ * <XInput disabled value='只读' />
14
+ * ```
15
+ *
16
+ * 与 antd Input 的对应:
17
+ * - value / onChangeText:RN 原生命名(方便 XForm.Item 直接注入,trigger='onChangeText')
18
+ * - disabled:对应 antd disabled(不可编辑 + 禁用样式)
19
+ * - multiline:对应 antd Input.TextArea
20
+ * - allowClear:对应 antd allowClear(非多行时显示清空按钮)
21
+ * - 其余 props(maxLength/keyboardType/secureTextEntry 等)原样透传给 TextInput
22
+ *
23
+ * 注意:value 是完全受控透传,不做任何 trim/transform —— 改写会打断
24
+ * Android 中文输入法的合成过程(XForm 的同值守卫也依赖原样透传)。
25
+ */
26
+ import React from 'react';
27
+ import { TextInput, TextInputProps, StyleProp, TextStyle, ViewStyle } from 'react-native';
28
+ export interface XInputProps extends TextInputProps {
29
+ value?: string;
30
+ onChangeText?: (text: string) => void;
31
+ multiline?: boolean;
32
+ /** 禁用:不可编辑 + 禁用底色(antd disabled) */
33
+ disabled?: boolean;
34
+ /** 有内容时显示清空按钮(antd allowClear;multiline 下不生效) */
35
+ allowClear?: boolean;
36
+ style?: StyleProp<TextStyle>;
37
+ /** 外层容器样式(有 allowClear 按钮时想要撑满/贴边用) */
38
+ containerStyle?: StyleProp<ViewStyle>;
39
+ }
40
+ export declare const XInput: React.ForwardRefExoticComponent<XInputProps & React.RefAttributes<TextInput>>;
41
+ /** antd Input.TextArea 的对应形态 */
42
+ export declare const XTextArea: (props: XInputProps) => React.JSX.Element;
43
+ export default XInput;