@qwickapps/react-framework 1.5.13 → 1.6.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 (46) hide show
  1. package/dist/components/forms/Captcha.d.ts +33 -28
  2. package/dist/components/forms/Captcha.d.ts.map +1 -1
  3. package/dist/components/forms/FormCheckbox.d.ts +15 -12
  4. package/dist/components/forms/FormCheckbox.d.ts.map +1 -1
  5. package/dist/components/forms/FormField.d.ts +20 -23
  6. package/dist/components/forms/FormField.d.ts.map +1 -1
  7. package/dist/components/forms/FormSelect.d.ts +16 -15
  8. package/dist/components/forms/FormSelect.d.ts.map +1 -1
  9. package/dist/hooks/useBaseProps.d.ts +27 -1172
  10. package/dist/hooks/useBaseProps.d.ts.map +1 -1
  11. package/dist/index.esm.js +349 -156
  12. package/dist/index.js +348 -155
  13. package/dist/palettes/manifest.json +19 -19
  14. package/dist/schemas/CaptchaSchema.d.ts +16 -0
  15. package/dist/schemas/CaptchaSchema.d.ts.map +1 -0
  16. package/dist/schemas/FormCheckboxSchema.d.ts +16 -0
  17. package/dist/schemas/FormCheckboxSchema.d.ts.map +1 -0
  18. package/dist/schemas/FormFieldSchema.d.ts +23 -0
  19. package/dist/schemas/FormFieldSchema.d.ts.map +1 -0
  20. package/dist/schemas/FormSelectSchema.d.ts +20 -0
  21. package/dist/schemas/FormSelectSchema.d.ts.map +1 -0
  22. package/dist/schemas/index.d.ts +4 -0
  23. package/dist/schemas/index.d.ts.map +1 -1
  24. package/package.json +1 -1
  25. package/src/components/forms/Captcha.tsx +57 -63
  26. package/src/components/forms/FormCheckbox.tsx +35 -43
  27. package/src/components/forms/FormField.tsx +50 -66
  28. package/src/components/forms/FormSelect.tsx +41 -49
  29. package/src/hooks/useBaseProps.ts +34 -1
  30. package/src/schemas/CaptchaSchema.ts +65 -0
  31. package/src/schemas/FormCheckboxSchema.ts +65 -0
  32. package/src/schemas/FormFieldSchema.ts +140 -0
  33. package/src/schemas/FormSelectSchema.ts +108 -0
  34. package/src/schemas/index.ts +4 -0
  35. /package/dist/palettes/{palette-autumn.1.5.13.css → palette-autumn.1.6.0.css} +0 -0
  36. /package/dist/palettes/{palette-autumn.1.5.13.min.css → palette-autumn.1.6.0.min.css} +0 -0
  37. /package/dist/palettes/{palette-cosmic.1.5.13.css → palette-cosmic.1.6.0.css} +0 -0
  38. /package/dist/palettes/{palette-cosmic.1.5.13.min.css → palette-cosmic.1.6.0.min.css} +0 -0
  39. /package/dist/palettes/{palette-default.1.5.13.css → palette-default.1.6.0.css} +0 -0
  40. /package/dist/palettes/{palette-default.1.5.13.min.css → palette-default.1.6.0.min.css} +0 -0
  41. /package/dist/palettes/{palette-ocean.1.5.13.css → palette-ocean.1.6.0.css} +0 -0
  42. /package/dist/palettes/{palette-ocean.1.5.13.min.css → palette-ocean.1.6.0.min.css} +0 -0
  43. /package/dist/palettes/{palette-spring.1.5.13.css → palette-spring.1.6.0.css} +0 -0
  44. /package/dist/palettes/{palette-spring.1.5.13.min.css → palette-spring.1.6.0.min.css} +0 -0
  45. /package/dist/palettes/{palette-winter.1.5.13.css → palette-winter.1.6.0.css} +0 -0
  46. /package/dist/palettes/{palette-winter.1.5.13.min.css → palette-winter.1.6.0.min.css} +0 -0
@@ -4,10 +4,10 @@
4
4
  * Features:
5
5
  * - Uses QwickApps CSS theme variables for consistent styling
6
6
  * - Supports text, number, password, and email input types
7
- * - Integrated with MUI FormControl, Input, and Select
7
+ * - Integrated with MUI FormControl, Input
8
8
  * - Handles readonly, disabled, and required states
9
9
  * - Support for adornments and helper text
10
- * - Base props support for grid behavior and styling
10
+ * - Schema-driven architecture with serialization support
11
11
  *
12
12
  * Copyright (c) 2025 QwickApps.com. All rights reserved.
13
13
  */
@@ -20,63 +20,54 @@ import {
20
20
  FormHelperText,
21
21
  InputAdornment,
22
22
  } from '@mui/material';
23
- import { useBaseProps, WithBaseProps, QWICKAPP_COMPONENT } from '../../hooks/useBaseProps';
23
+ import type { SchemaProps } from '@qwickapps/schema';
24
+ import FormFieldModel from '../../schemas/FormFieldSchema';
25
+ import { ViewProps } from '../shared/viewProps';
26
+ import { createSerializableView, SerializableComponent } from '../shared/createSerializableView';
24
27
 
25
- export interface FormFieldOption {
26
- value: string | number;
27
- label: string;
28
- }
29
-
30
- interface FormFieldBaseProps {
31
- label: string;
32
- value: string | number;
28
+ /**
29
+ * Props interface for FormField component
30
+ * Combines schema props with callback handlers and adornments
31
+ */
32
+ export interface FormFieldProps extends ViewProps, SchemaProps<typeof FormFieldModel> {
33
+ /** Callback when value changes */
33
34
  onChange?: (value: string | number) => void;
35
+ /** Raw change handler with event */
34
36
  onChangeRaw?: (e: React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement>) => void;
35
- type?: 'text' | 'number' | 'password' | 'email' | 'tel';
36
- helperText?: string;
37
- required?: boolean;
38
- readOnly?: boolean;
39
- disabled?: boolean;
40
- disabledColor?: string;
41
- fullWidth?: boolean;
42
- multiline?: boolean;
43
- rows?: number;
44
- placeholder?: string;
37
+ /** Start adornment (icon, text, etc.) */
45
38
  startAdornment?: React.ReactNode;
39
+ /** End adornment (icon, text, etc.) */
46
40
  endAdornment?: React.ReactNode;
41
+ /** Additional input props */
47
42
  inputProps?: unknown;
48
43
  }
49
44
 
50
- export interface FormFieldProps extends WithBaseProps<FormFieldBaseProps> {}
51
-
52
- export const FormField = React.forwardRef<HTMLDivElement, FormFieldProps>((props, ref) => {
53
- const { gridProps, styleProps, htmlProps, restProps } = useBaseProps(props);
54
-
55
- const {
56
- label,
57
- value,
58
- onChange,
59
- onChangeRaw,
60
- type = 'text',
61
- helperText,
62
- required = false,
63
- readOnly = false,
64
- disabled = false,
65
- disabledColor,
66
- fullWidth = true,
67
- multiline = false,
68
- rows,
69
- placeholder,
70
- startAdornment,
71
- endAdornment,
72
- inputProps,
73
- } = restProps as FormFieldBaseProps;
74
-
75
- // Generate a unique ID for the input field
45
+ /**
46
+ * FormFieldView - Pure view component that renders the input field
47
+ */
48
+ function FormFieldView({
49
+ label,
50
+ value,
51
+ onChange,
52
+ onChangeRaw,
53
+ type = 'text',
54
+ helperText,
55
+ required = false,
56
+ readOnly = false,
57
+ disabled = false,
58
+ disabledColor,
59
+ fullWidth = true,
60
+ multiline = false,
61
+ rows,
62
+ placeholder,
63
+ startAdornment,
64
+ endAdornment,
65
+ inputProps,
66
+ ...restProps
67
+ }: FormFieldProps) {
76
68
  const fieldId = React.useId();
77
69
 
78
70
  const handleChange = (e: React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement>) => {
79
- // If onChangeRaw is provided, use it instead
80
71
  if (onChangeRaw) {
81
72
  onChangeRaw(e);
82
73
  return;
@@ -107,7 +98,6 @@ export const FormField = React.forwardRef<HTMLDivElement, FormFieldProps>((props
107
98
  color: disabledColor,
108
99
  WebkitTextFillColor: disabledColor,
109
100
  } : undefined,
110
- ...styleProps.sx,
111
101
  };
112
102
 
113
103
  const labelStyles = {
@@ -122,19 +112,8 @@ export const FormField = React.forwardRef<HTMLDivElement, FormFieldProps>((props
122
112
 
123
113
  return (
124
114
  <FormControl
125
- ref={ref}
126
115
  fullWidth={fullWidth}
127
- {...htmlProps}
128
- {...styleProps}
129
- // Store grid props as data attributes for ColumnLayout to pick up
130
- {...(gridProps && {
131
- 'data-grid-span': gridProps.span,
132
- 'data-grid-xs': gridProps.xs,
133
- 'data-grid-sm': gridProps.sm,
134
- 'data-grid-md': gridProps.md,
135
- 'data-grid-lg': gridProps.lg,
136
- 'data-grid-xl': gridProps.xl,
137
- })}
116
+ {...restProps}
138
117
  >
139
118
  <InputLabel htmlFor={fieldId} sx={labelStyles} shrink>
140
119
  {label}
@@ -170,11 +149,16 @@ export const FormField = React.forwardRef<HTMLDivElement, FormFieldProps>((props
170
149
  )}
171
150
  </FormControl>
172
151
  );
173
- });
174
-
175
- FormField.displayName = 'FormField';
152
+ }
176
153
 
177
- // Mark as QwickApp component
178
- Object.assign(FormField, { [QWICKAPP_COMPONENT]: true });
154
+ /**
155
+ * Create FormField component using the factory pattern
156
+ */
157
+ export const FormField: SerializableComponent<FormFieldProps> = createSerializableView<FormFieldProps>({
158
+ tagName: 'FormField',
159
+ version: '1.0.0',
160
+ role: 'input',
161
+ View: FormFieldView,
162
+ });
179
163
 
180
164
  export default FormField;
@@ -6,7 +6,7 @@
6
6
  * - Simplified select-only interface (use FormField for mixed inputs)
7
7
  * - Support for placeholder, size variants, and helper text
8
8
  * - Integrated with MUI FormControl and Select
9
- * - Base props support for grid behavior and styling
9
+ * - Schema-driven architecture with serialization support
10
10
  *
11
11
  * Copyright (c) 2025 QwickApps.com. All rights reserved.
12
12
  */
@@ -19,46 +19,45 @@ import {
19
19
  MenuItem,
20
20
  FormHelperText,
21
21
  } from '@mui/material';
22
- import { useBaseProps, WithBaseProps, QWICKAPP_COMPONENT } from '../../hooks/useBaseProps';
22
+ import type { SchemaProps } from '@qwickapps/schema';
23
+ import FormSelectModel from '../../schemas/FormSelectSchema';
24
+ import { ViewProps } from '../shared/viewProps';
25
+ import { createSerializableView, SerializableComponent } from '../shared/createSerializableView';
23
26
 
24
27
  export interface FormSelectOption {
25
28
  value: string | number;
26
29
  label: string;
27
30
  }
28
31
 
29
- interface FormSelectBaseProps {
30
- label?: string;
31
- value: string | number;
32
+ /**
33
+ * Props interface for FormSelect component
34
+ * Combines schema props with callback handlers
35
+ */
36
+ export interface FormSelectProps extends ViewProps, SchemaProps<typeof FormSelectModel> {
37
+ /** Callback when value changes */
32
38
  onChange: (value: string | number) => void;
39
+ /** Options array (runtime prop, overrides schema) */
33
40
  options: FormSelectOption[];
34
- helperText?: string;
35
- required?: boolean;
36
- disabled?: boolean;
37
- fullWidth?: boolean;
38
- size?: 'small' | 'medium';
39
- placeholder?: string;
40
41
  }
41
42
 
42
- export interface FormSelectProps extends WithBaseProps<FormSelectBaseProps> {}
43
-
44
- export const FormSelect = React.forwardRef<HTMLDivElement, FormSelectProps>((props, ref) => {
45
- const { gridProps, styleProps, htmlProps, restProps } = useBaseProps(props);
46
-
47
- const {
48
- label,
49
- value,
50
- onChange,
51
- options,
52
- helperText,
53
- required = false,
54
- disabled = false,
55
- fullWidth = true,
56
- size = 'small',
57
- placeholder,
58
- } = restProps as FormSelectBaseProps;
59
-
60
- const handleChange = (e: unknown) => {
61
- onChange(e.target.value);
43
+ /**
44
+ * FormSelectView - Pure view component that renders the select field
45
+ */
46
+ function FormSelectView({
47
+ label,
48
+ value,
49
+ onChange,
50
+ options,
51
+ helperText,
52
+ required = false,
53
+ disabled = false,
54
+ fullWidth = true,
55
+ size = 'small',
56
+ placeholder,
57
+ ...restProps
58
+ }: FormSelectProps) {
59
+ const handleChange = (e: { target: { value: unknown } }) => {
60
+ onChange(e.target.value as string | number);
62
61
  };
63
62
 
64
63
  const selectStyles = {
@@ -69,7 +68,6 @@ export const FormSelect = React.forwardRef<HTMLDivElement, FormSelectProps>((pro
69
68
  borderColor: 'var(--theme-surface)',
70
69
  color: 'var(--theme-text-primary)',
71
70
  borderRadius: 1,
72
- ...styleProps.sx,
73
71
  };
74
72
 
75
73
  const labelStyles = {
@@ -84,20 +82,9 @@ export const FormSelect = React.forwardRef<HTMLDivElement, FormSelectProps>((pro
84
82
 
85
83
  return (
86
84
  <FormControl
87
- ref={ref}
88
85
  fullWidth={fullWidth}
89
86
  size={size}
90
- {...htmlProps}
91
- {...styleProps}
92
- // Store grid props as data attributes for ColumnLayout to pick up
93
- {...(gridProps && {
94
- 'data-grid-span': gridProps.span,
95
- 'data-grid-xs': gridProps.xs,
96
- 'data-grid-sm': gridProps.sm,
97
- 'data-grid-md': gridProps.md,
98
- 'data-grid-lg': gridProps.lg,
99
- 'data-grid-xl': gridProps.xl,
100
- })}
87
+ {...restProps}
101
88
  >
102
89
  {label && (
103
90
  <InputLabel sx={labelStyles} shrink>
@@ -130,11 +117,16 @@ export const FormSelect = React.forwardRef<HTMLDivElement, FormSelectProps>((pro
130
117
  )}
131
118
  </FormControl>
132
119
  );
133
- });
134
-
135
- FormSelect.displayName = 'FormSelect';
120
+ }
136
121
 
137
- // Mark as QwickApp component
138
- Object.assign(FormSelect, { [QWICKAPP_COMPONENT]: true });
122
+ /**
123
+ * Create FormSelect component using the factory pattern
124
+ */
125
+ export const FormSelect: SerializableComponent<FormSelectProps> = createSerializableView<FormSelectProps>({
126
+ tagName: 'FormSelect',
127
+ version: '1.0.0',
128
+ role: 'input',
129
+ View: FormSelectView,
130
+ });
139
131
 
140
132
  export default FormSelect;
@@ -82,10 +82,43 @@ export interface BaseComponentProps {
82
82
  */
83
83
  export const QWICKAPP_COMPONENT = Symbol('QwickAppComponent');
84
84
 
85
+ /**
86
+ * Return type for useBaseProps hook
87
+ */
88
+ export interface BasePropsResult<T extends BaseComponentProps> {
89
+ gridProps: {
90
+ span?: number | 'auto' | 'grow';
91
+ xs?: number | 'auto';
92
+ sm?: number | 'auto';
93
+ md?: number | 'auto';
94
+ lg?: number | 'auto';
95
+ xl?: number | 'auto';
96
+ } | null;
97
+ styleProps: {
98
+ className?: string;
99
+ sx?: SxProps<Theme>;
100
+ style?: React.CSSProperties;
101
+ };
102
+ htmlProps: {
103
+ id?: string;
104
+ role?: string;
105
+ 'aria-label'?: string;
106
+ 'aria-labelledby'?: string;
107
+ 'aria-describedby'?: string;
108
+ 'data-testid'?: string;
109
+ onClick?: React.MouseEventHandler<unknown>;
110
+ onMouseEnter?: React.MouseEventHandler<unknown>;
111
+ onMouseLeave?: React.MouseEventHandler<unknown>;
112
+ onFocus?: React.FocusEventHandler<unknown>;
113
+ onBlur?: React.FocusEventHandler<unknown>;
114
+ };
115
+ restProps: Omit<T, keyof BaseComponentProps>;
116
+ }
117
+
85
118
  /**
86
119
  * Hook to process base component props
87
120
  */
88
- export function useBaseProps<T extends BaseComponentProps>(props: T) {
121
+ export function useBaseProps<T extends BaseComponentProps>(props: T): BasePropsResult<T> {
89
122
  const {
90
123
  // Grid props
91
124
  span,
@@ -0,0 +1,65 @@
1
+ /**
2
+ * Schema for Captcha component - Universal CAPTCHA widget
3
+ *
4
+ * Copyright (c) 2025 QwickApps.com. All rights reserved.
5
+ */
6
+
7
+ import { IsIn, IsOptional, IsString } from 'class-validator';
8
+ import 'reflect-metadata';
9
+ import { Editor, Field, Schema, FieldType } from '@qwickapps/schema';
10
+ import ViewSchema from './ViewSchema';
11
+
12
+ @Schema('Captcha', '1.0.0')
13
+ export class CaptchaModel extends ViewSchema {
14
+ @Field()
15
+ @Editor({
16
+ field_type: FieldType.SELECT,
17
+ label: 'CAPTCHA Provider',
18
+ description: 'Which CAPTCHA service to use'
19
+ })
20
+ @IsIn(['recaptcha-v2', 'recaptcha-v3', 'hcaptcha', 'turnstile'])
21
+ provider!: 'recaptcha-v2' | 'recaptcha-v3' | 'hcaptcha' | 'turnstile';
22
+
23
+ @Field()
24
+ @Editor({
25
+ field_type: FieldType.TEXT,
26
+ label: 'Site Key',
27
+ description: 'Public site key from CAPTCHA provider',
28
+ placeholder: 'Enter site key...'
29
+ })
30
+ @IsString()
31
+ siteKey!: string;
32
+
33
+ @Field({ defaultValue: 'light' })
34
+ @Editor({
35
+ field_type: FieldType.SELECT,
36
+ label: 'Theme',
37
+ description: 'CAPTCHA widget theme'
38
+ })
39
+ @IsOptional()
40
+ @IsIn(['light', 'dark'])
41
+ theme?: 'light' | 'dark';
42
+
43
+ @Field({ defaultValue: 'normal' })
44
+ @Editor({
45
+ field_type: FieldType.SELECT,
46
+ label: 'Size',
47
+ description: 'CAPTCHA widget size'
48
+ })
49
+ @IsOptional()
50
+ @IsIn(['normal', 'compact', 'invisible'])
51
+ size?: 'normal' | 'compact' | 'invisible';
52
+
53
+ @Field({ defaultValue: 'submit' })
54
+ @Editor({
55
+ field_type: FieldType.TEXT,
56
+ label: 'Action',
57
+ description: 'reCAPTCHA v3 action name',
58
+ placeholder: 'submit'
59
+ })
60
+ @IsOptional()
61
+ @IsString()
62
+ action?: string;
63
+ }
64
+
65
+ export default CaptchaModel;
@@ -0,0 +1,65 @@
1
+ /**
2
+ * Schema for FormCheckbox component - Themed checkbox input
3
+ *
4
+ * Copyright (c) 2025 QwickApps.com. All rights reserved.
5
+ */
6
+
7
+ import { IsBoolean, IsOptional, IsString } from 'class-validator';
8
+ import 'reflect-metadata';
9
+ import { Editor, Field, Schema, FieldType } from '@qwickapps/schema';
10
+ import ViewSchema from './ViewSchema';
11
+
12
+ @Schema('FormCheckbox', '1.0.0')
13
+ export class FormCheckboxModel extends ViewSchema {
14
+ @Field()
15
+ @Editor({
16
+ field_type: FieldType.TEXT,
17
+ label: 'Label',
18
+ description: 'Label text for the checkbox',
19
+ placeholder: 'Enter label...'
20
+ })
21
+ @IsString()
22
+ label!: string;
23
+
24
+ @Field({ defaultValue: false })
25
+ @Editor({
26
+ field_type: FieldType.BOOLEAN,
27
+ label: 'Checked',
28
+ description: 'Checkbox checked state'
29
+ })
30
+ @IsBoolean()
31
+ checked!: boolean;
32
+
33
+ @Field()
34
+ @Editor({
35
+ field_type: FieldType.TEXT,
36
+ label: 'Helper Text',
37
+ description: 'Helper text displayed below the checkbox',
38
+ placeholder: 'Enter helper text...'
39
+ })
40
+ @IsOptional()
41
+ @IsString()
42
+ helperText?: string;
43
+
44
+ @Field({ defaultValue: false })
45
+ @Editor({
46
+ field_type: FieldType.BOOLEAN,
47
+ label: 'Required',
48
+ description: 'Mark checkbox as required'
49
+ })
50
+ @IsOptional()
51
+ @IsBoolean()
52
+ required?: boolean;
53
+
54
+ @Field({ defaultValue: false })
55
+ @Editor({
56
+ field_type: FieldType.BOOLEAN,
57
+ label: 'Disabled',
58
+ description: 'Disable the checkbox'
59
+ })
60
+ @IsOptional()
61
+ @IsBoolean()
62
+ disabled?: boolean;
63
+ }
64
+
65
+ export default FormCheckboxModel;
@@ -0,0 +1,140 @@
1
+ /**
2
+ * Schema for FormField component - Themed text/number input field
3
+ *
4
+ * Copyright (c) 2025 QwickApps.com. All rights reserved.
5
+ */
6
+
7
+ import { IsBoolean, IsIn, IsInt, IsOptional, IsString, Min } from 'class-validator';
8
+ import 'reflect-metadata';
9
+ import { Editor, Field, Schema, FieldType } from '@qwickapps/schema';
10
+ import ViewSchema from './ViewSchema';
11
+
12
+ @Schema('FormField', '1.0.0')
13
+ export class FormFieldModel extends ViewSchema {
14
+ @Field()
15
+ @Editor({
16
+ field_type: FieldType.TEXT,
17
+ label: 'Label',
18
+ description: 'Label text for the input field',
19
+ placeholder: 'Enter label...'
20
+ })
21
+ @IsString()
22
+ label!: string;
23
+
24
+ @Field()
25
+ @Editor({
26
+ field_type: FieldType.TEXT,
27
+ label: 'Value',
28
+ description: 'Current input value',
29
+ placeholder: ''
30
+ })
31
+ @IsString()
32
+ value!: string | number;
33
+
34
+ @Field({ defaultValue: 'text' })
35
+ @Editor({
36
+ field_type: FieldType.SELECT,
37
+ label: 'Input Type',
38
+ description: 'Type of input field'
39
+ })
40
+ @IsOptional()
41
+ @IsIn(['text', 'number', 'password', 'email', 'tel'])
42
+ type?: 'text' | 'number' | 'password' | 'email' | 'tel';
43
+
44
+ @Field()
45
+ @Editor({
46
+ field_type: FieldType.TEXT,
47
+ label: 'Helper Text',
48
+ description: 'Helper text displayed below the input',
49
+ placeholder: 'Enter helper text...'
50
+ })
51
+ @IsOptional()
52
+ @IsString()
53
+ helperText?: string;
54
+
55
+ @Field({ defaultValue: false })
56
+ @Editor({
57
+ field_type: FieldType.BOOLEAN,
58
+ label: 'Required',
59
+ description: 'Mark field as required'
60
+ })
61
+ @IsOptional()
62
+ @IsBoolean()
63
+ required?: boolean;
64
+
65
+ @Field({ defaultValue: false })
66
+ @Editor({
67
+ field_type: FieldType.BOOLEAN,
68
+ label: 'Read Only',
69
+ description: 'Make field read-only'
70
+ })
71
+ @IsOptional()
72
+ @IsBoolean()
73
+ readOnly?: boolean;
74
+
75
+ @Field({ defaultValue: false })
76
+ @Editor({
77
+ field_type: FieldType.BOOLEAN,
78
+ label: 'Disabled',
79
+ description: 'Disable the input field'
80
+ })
81
+ @IsOptional()
82
+ @IsBoolean()
83
+ disabled?: boolean;
84
+
85
+ @Field()
86
+ @Editor({
87
+ field_type: FieldType.TEXT,
88
+ label: 'Disabled Color',
89
+ description: 'Custom color for disabled state (CSS color value)',
90
+ placeholder: 'var(--theme-text-disabled)'
91
+ })
92
+ @IsOptional()
93
+ @IsString()
94
+ disabledColor?: string;
95
+
96
+ @Field({ defaultValue: true })
97
+ @Editor({
98
+ field_type: FieldType.BOOLEAN,
99
+ label: 'Full Width',
100
+ description: 'Make input take full width of container'
101
+ })
102
+ @IsOptional()
103
+ @IsBoolean()
104
+ fullWidth?: boolean;
105
+
106
+ @Field({ defaultValue: false })
107
+ @Editor({
108
+ field_type: FieldType.BOOLEAN,
109
+ label: 'Multiline',
110
+ description: 'Enable multiline textarea mode'
111
+ })
112
+ @IsOptional()
113
+ @IsBoolean()
114
+ multiline?: boolean;
115
+
116
+ @Field()
117
+ @Editor({
118
+ field_type: FieldType.TEXT,
119
+ label: 'Rows',
120
+ description: 'Number of rows for multiline textarea',
121
+ placeholder: '4'
122
+ })
123
+ @IsOptional()
124
+ @IsInt()
125
+ @Min(1)
126
+ rows?: number;
127
+
128
+ @Field()
129
+ @Editor({
130
+ field_type: FieldType.TEXT,
131
+ label: 'Placeholder',
132
+ description: 'Placeholder text',
133
+ placeholder: 'Enter text...'
134
+ })
135
+ @IsOptional()
136
+ @IsString()
137
+ placeholder?: string;
138
+ }
139
+
140
+ export default FormFieldModel;