@capyx/components-library 0.0.1 → 0.0.3

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 (72) hide show
  1. package/README.md +250 -210
  2. package/dist/addons/AutocompleteInput.d.ts +40 -0
  3. package/dist/addons/AutocompleteInput.d.ts.map +1 -0
  4. package/dist/addons/AutocompleteInput.js +101 -0
  5. package/dist/addons/CharacterCountInput.d.ts +73 -0
  6. package/dist/addons/CharacterCountInput.d.ts.map +1 -0
  7. package/dist/addons/CharacterCountInput.js +130 -0
  8. package/dist/addons/index.d.ts +5 -0
  9. package/dist/addons/index.d.ts.map +1 -0
  10. package/dist/addons/index.js +2 -0
  11. package/dist/components/CheckInput.d.ts +49 -0
  12. package/dist/components/CheckInput.d.ts.map +1 -0
  13. package/dist/components/CheckInput.js +58 -0
  14. package/dist/components/DateInput.d.ts +63 -0
  15. package/dist/components/DateInput.d.ts.map +1 -0
  16. package/dist/components/DateInput.js +86 -0
  17. package/dist/components/FileInput.d.ts +102 -0
  18. package/dist/components/FileInput.d.ts.map +1 -0
  19. package/dist/components/FileInput.js +164 -0
  20. package/dist/components/RichTextInput.d.ts +34 -0
  21. package/dist/components/RichTextInput.d.ts.map +1 -0
  22. package/dist/components/RichTextInput.js +57 -0
  23. package/dist/components/SelectInput.d.ts +54 -0
  24. package/dist/components/SelectInput.d.ts.map +1 -0
  25. package/dist/components/SelectInput.js +64 -0
  26. package/dist/components/SwitchInput.d.ts +46 -0
  27. package/dist/components/SwitchInput.d.ts.map +1 -0
  28. package/dist/components/SwitchInput.js +53 -0
  29. package/dist/components/TagsInput.d.ts +35 -0
  30. package/dist/components/TagsInput.d.ts.map +1 -0
  31. package/dist/components/TagsInput.js +67 -0
  32. package/dist/components/TextAreaInput.d.ts +71 -0
  33. package/dist/components/TextAreaInput.d.ts.map +1 -0
  34. package/dist/components/TextAreaInput.js +113 -0
  35. package/dist/components/TextInput.d.ts +68 -0
  36. package/dist/components/TextInput.d.ts.map +1 -0
  37. package/dist/components/TextInput.js +77 -0
  38. package/dist/components/index.d.ts +10 -0
  39. package/dist/components/index.d.ts.map +1 -0
  40. package/dist/index.cjs +18 -0
  41. package/dist/index.d.ts +3 -0
  42. package/dist/index.d.ts.map +1 -0
  43. package/package.json +87 -72
  44. package/.storybook/main.ts +0 -33
  45. package/.storybook/preview.ts +0 -36
  46. package/.storybook/vitest.setup.ts +0 -7
  47. package/biome.json +0 -37
  48. package/lib/addons/CharacterCountInput.tsx +0 -204
  49. package/lib/addons/index.ts +0 -2
  50. package/lib/components/CheckInput.tsx +0 -126
  51. package/lib/components/DateInput.tsx +0 -179
  52. package/lib/components/FileInput.tsx +0 -353
  53. package/lib/components/RichTextInput.tsx +0 -112
  54. package/lib/components/SelectInput.tsx +0 -144
  55. package/lib/components/SwitchInput.tsx +0 -116
  56. package/lib/components/TagsInput.tsx +0 -118
  57. package/lib/components/TextAreaInput.tsx +0 -211
  58. package/lib/components/TextInput.tsx +0 -381
  59. package/stories/CharacterCountInput.stories.tsx +0 -104
  60. package/stories/CheckInput.stories.tsx +0 -80
  61. package/stories/DateInput.stories.tsx +0 -137
  62. package/stories/FileInput.stories.tsx +0 -125
  63. package/stories/RichTextInput.stories.tsx +0 -77
  64. package/stories/SelectInput.stories.tsx +0 -131
  65. package/stories/SwitchInput.stories.tsx +0 -80
  66. package/stories/TagsInput.stories.tsx +0 -69
  67. package/stories/TextAreaInput.stories.tsx +0 -117
  68. package/stories/TextInput.stories.tsx +0 -167
  69. package/vitest.config.ts +0 -37
  70. package/vitest.shims.d.ts +0 -1
  71. /package/{lib/components/index.ts → dist/components/index.js} +0 -0
  72. /package/{lib/index.ts → dist/index.js} +0 -0
@@ -0,0 +1,164 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { useRef, useState, } from 'react';
3
+ import { Button, Form } from 'react-bootstrap';
4
+ import { Controller, useFormContext } from 'react-hook-form';
5
+ /**
6
+ * A customizable file input component with validation, upload lifecycle hooks,
7
+ * and react-hook-form integration.
8
+ *
9
+ * Features:
10
+ * - Single or multiple file selection
11
+ * - File type filtering via accept attribute
12
+ * - File size validation with configurable max size
13
+ * - Custom file validation logic
14
+ * - Upload lifecycle callbacks (start, complete, error)
15
+ * - Fully customizable UI with className props
16
+ * - Integration with react-hook-form for form validation
17
+ * - Custom formatting for file information display
18
+ *
19
+ * @example
20
+ * // Basic file upload with react-hook-form
21
+ * <FileInput
22
+ * name="avatar"
23
+ * label="Profile Picture"
24
+ * accept="image/*"
25
+ * required
26
+ * maxSize={5 * 1024 * 1024} // 5MB
27
+ * />
28
+ *
29
+ * @example
30
+ * // Multiple files with custom validation
31
+ * <FileInput
32
+ * name="documents"
33
+ * label="Upload Documents"
34
+ * multiple
35
+ * accept=".pdf,.doc,.docx"
36
+ * validateFile={(file) => {
37
+ * if (file.name.length > 100) {
38
+ * return { valid: false, error: "Filename too long" };
39
+ * }
40
+ * return { valid: true };
41
+ * }}
42
+ * onChange={(files) => console.log(files)}
43
+ * />
44
+ *
45
+ * @example
46
+ * // With upload lifecycle hooks
47
+ * <FileInput
48
+ * name="report"
49
+ * onUploadStart={() => console.log("Starting upload...")}
50
+ * onUploadComplete={() => console.log("Upload complete!")}
51
+ * onUploadError={(error) => console.error(error)}
52
+ * />
53
+ */
54
+ export const FileInput = ({ name, accept, multiple = false, onChange, onUploadStart, onUploadComplete, onUploadError, disabled = false, maxSize, containerClassName = '', labelClassName = '', buttonClassName = '', fileInfoClassName = '', errorClassName = '', label = 'Upload File', buttonText = 'Choose File', noFileText = 'No file selected', uploadingText = 'Uploading...', formatFileInfo, validateFile, required = false, }) => {
55
+ const fileInputRef = useRef(null);
56
+ const [selectedFiles, setSelectedFiles] = useState(null);
57
+ const [isUploading, setIsUploading] = useState(false);
58
+ const [error, setError] = useState(null);
59
+ const formContext = useFormContext();
60
+ // Helper to safely get nested error
61
+ const getFieldError = (fieldName) => {
62
+ try {
63
+ const error = formContext?.formState?.errors?.[fieldName];
64
+ return error?.message;
65
+ }
66
+ catch {
67
+ return undefined;
68
+ }
69
+ };
70
+ const formErrorMessage = name ? getFieldError(name) : undefined;
71
+ const handleFileUploadClick = () => {
72
+ if (isUploading || disabled)
73
+ return;
74
+ fileInputRef.current?.click();
75
+ };
76
+ const validateFiles = (files) => {
77
+ for (const file of files) {
78
+ // Check file size
79
+ if (maxSize && file.size > maxSize) {
80
+ return {
81
+ valid: false,
82
+ error: `File size exceeds maximum allowed size of ${(maxSize / 1024 / 1024).toFixed(2)}MB`,
83
+ };
84
+ }
85
+ // Custom validation
86
+ if (validateFile) {
87
+ const result = validateFile(file);
88
+ if (!result.valid) {
89
+ return result;
90
+ }
91
+ }
92
+ }
93
+ return { valid: true };
94
+ };
95
+ const handleFileChange = (event, fieldOnChange) => {
96
+ setError(null);
97
+ const files = event.target.files;
98
+ if (!files || files.length === 0) {
99
+ setSelectedFiles(null);
100
+ onChange?.(null);
101
+ fieldOnChange?.(null);
102
+ return;
103
+ }
104
+ const fileArray = Array.from(files);
105
+ const validation = validateFiles(fileArray);
106
+ if (!validation.valid) {
107
+ setError(validation.error ?? 'Invalid file');
108
+ if (fileInputRef.current) {
109
+ fileInputRef.current.value = '';
110
+ }
111
+ return;
112
+ }
113
+ const result = multiple ? fileArray : fileArray[0];
114
+ setSelectedFiles(result);
115
+ // Reset input value to allow re-selecting the same file
116
+ if (fileInputRef.current) {
117
+ fileInputRef.current.value = '';
118
+ }
119
+ try {
120
+ onUploadStart?.();
121
+ setIsUploading(true);
122
+ onChange?.(result);
123
+ fieldOnChange?.(result);
124
+ onUploadComplete?.();
125
+ }
126
+ catch (err) {
127
+ const error = err instanceof Error ? err : new Error('Upload failed');
128
+ setError(error.message);
129
+ onUploadError?.(error);
130
+ }
131
+ finally {
132
+ setIsUploading(false);
133
+ }
134
+ };
135
+ const renderFileInfo = () => {
136
+ if (isUploading) {
137
+ return (_jsx(Form.Text, { className: fileInfoClassName, children: uploadingText }));
138
+ }
139
+ if (!selectedFiles) {
140
+ return _jsx(Form.Text, { className: fileInfoClassName, children: noFileText });
141
+ }
142
+ if (formatFileInfo) {
143
+ return (_jsx(Form.Text, { className: fileInfoClassName, children: formatFileInfo(selectedFiles) }));
144
+ }
145
+ if (Array.isArray(selectedFiles)) {
146
+ return (_jsxs(Form.Text, { className: fileInfoClassName, children: [selectedFiles.length, " file", selectedFiles.length !== 1 ? 's' : '', ' ', "selected"] }));
147
+ }
148
+ return (_jsx(Form.Text, { className: fileInfoClassName, children: selectedFiles.name }));
149
+ };
150
+ const displayError = error || formErrorMessage;
151
+ // Render with form context integration
152
+ if (formContext && name) {
153
+ return (_jsx(Controller, { name: name, control: formContext.control, rules: {
154
+ required: required
155
+ ? `${typeof label === 'string' ? label : 'File'} is required`
156
+ : false,
157
+ }, render: ({ field }) => (_jsxs(Form.Group, { className: containerClassName, children: [_jsx("input", { type: "file", ref: (e) => {
158
+ fileInputRef.current = e;
159
+ field.ref(e);
160
+ }, style: { display: 'none' }, accept: accept, multiple: multiple, onChange: (e) => handleFileChange(e, field.onChange), onBlur: field.onBlur, disabled: disabled || isUploading, "aria-invalid": !!displayError, "aria-describedby": displayError ? `${name}-error` : undefined }), label && (_jsx(Form.Label, { className: labelClassName, children: label })), _jsxs("div", { children: [_jsx(Button, { variant: "secondary", className: buttonClassName, onClick: handleFileUploadClick, disabled: disabled || isUploading, children: buttonText }), ' ', renderFileInfo()] }), displayError && (_jsx(Form.Control.Feedback, { type: "invalid", className: errorClassName, style: { display: 'block' }, children: displayError }))] })) }));
161
+ }
162
+ // Standalone mode (no form context)
163
+ return (_jsxs(Form.Group, { className: containerClassName, children: [_jsx("input", { type: "file", ref: fileInputRef, style: { display: 'none' }, accept: accept, multiple: multiple, onChange: (e) => handleFileChange(e), disabled: disabled || isUploading }), label && _jsx(Form.Label, { className: labelClassName, children: label }), _jsxs("div", { children: [_jsx(Button, { variant: "secondary", className: buttonClassName, onClick: handleFileUploadClick, disabled: disabled || isUploading, children: buttonText }), ' ', renderFileInfo()] }), displayError && (_jsx(Form.Control.Feedback, { type: "invalid", className: errorClassName, style: { display: 'block' }, children: displayError }))] }));
164
+ };
@@ -0,0 +1,34 @@
1
+ import { type FC } from 'react';
2
+ import 'react-quill-new/dist/quill.snow.css';
3
+ /**
4
+ * Props for the RichTextInput component
5
+ */
6
+ export type RichTextInputProps = {
7
+ /** Whether the editor is in read-only mode */
8
+ readonly?: boolean;
9
+ /** Maximum number of characters allowed in the editor */
10
+ maxLength?: number;
11
+ /** Current value of the editor (HTML string) */
12
+ value?: string;
13
+ /** Callback function called when the content changes */
14
+ onChange?: (value: string) => void;
15
+ /** Whether the input should be styled as invalid */
16
+ isInvalid?: boolean;
17
+ };
18
+ /**
19
+ * RichTextInput - A rich text editor component using ReactQuill
20
+ *
21
+ * Provides a WYSIWYG editor with support for headers, bold, italic, underline, and lists.
22
+ * Includes optional character counting and length validation.
23
+ *
24
+ * @example
25
+ * ```tsx
26
+ * <RichTextInput
27
+ * value={content}
28
+ * onChange={setContent}
29
+ * maxLength={1000}
30
+ * />
31
+ * ```
32
+ */
33
+ export declare const RichTextInput: FC<RichTextInputProps>;
34
+ //# sourceMappingURL=RichTextInput.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"RichTextInput.d.ts","sourceRoot":"","sources":["../../lib/components/RichTextInput.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,EAAwC,MAAM,OAAO,CAAC;AAGtE,OAAO,qCAAqC,CAAC;AAE7C;;GAEG;AACH,MAAM,MAAM,kBAAkB,GAAG;IAChC,8CAA8C;IAC9C,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,yDAAyD;IACzD,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,gDAAgD;IAChD,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,wDAAwD;IACxD,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IACnC,oDAAoD;IACpD,SAAS,CAAC,EAAE,OAAO,CAAC;CACpB,CAAC;AAEF;;;;;;;;;;;;;;GAcG;AACH,eAAO,MAAM,aAAa,EAAE,EAAE,CAAC,kBAAkB,CA2EhD,CAAC"}
@@ -0,0 +1,57 @@
1
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
+ import { useRef, useState } from 'react';
3
+ import { Form } from 'react-bootstrap';
4
+ import ReactQuill from 'react-quill-new';
5
+ import 'react-quill-new/dist/quill.snow.css';
6
+ /**
7
+ * RichTextInput - A rich text editor component using ReactQuill
8
+ *
9
+ * Provides a WYSIWYG editor with support for headers, bold, italic, underline, and lists.
10
+ * Includes optional character counting and length validation.
11
+ *
12
+ * @example
13
+ * ```tsx
14
+ * <RichTextInput
15
+ * value={content}
16
+ * onChange={setContent}
17
+ * maxLength={1000}
18
+ * />
19
+ * ```
20
+ */
21
+ export const RichTextInput = ({ readonly = false, maxLength, value = '', onChange, isInvalid = false, }) => {
22
+ const reactQuillRef = useRef(null);
23
+ const [count, setCount] = useState(value.length);
24
+ const checkCharacterCount = (event) => {
25
+ const currentRef = reactQuillRef.current;
26
+ if (currentRef != null && maxLength != null) {
27
+ const unprivilegedEditor = currentRef.unprivilegedEditor;
28
+ if (unprivilegedEditor) {
29
+ const length = unprivilegedEditor.getHTML().length;
30
+ if (length >= maxLength && event.key !== 'Backspace') {
31
+ event.preventDefault();
32
+ }
33
+ }
34
+ }
35
+ };
36
+ const setContentLength = () => {
37
+ const currentRef = reactQuillRef.current;
38
+ if (currentRef != null && maxLength != null) {
39
+ const unprivilegedEditor = currentRef.unprivilegedEditor;
40
+ if (unprivilegedEditor) {
41
+ const length = unprivilegedEditor.getHTML().length;
42
+ setCount(length);
43
+ }
44
+ }
45
+ };
46
+ const modules = {
47
+ toolbar: readonly
48
+ ? false
49
+ : [
50
+ [{ header: [1, 2, 3, 4, 5, 6, false] }],
51
+ ['bold', 'italic', 'underline'],
52
+ [{ list: 'ordered' }, { list: 'bullet' }],
53
+ ],
54
+ };
55
+ const formats = ['header', 'bold', 'italic', 'underline', 'list', 'bullet'];
56
+ return (_jsxs(_Fragment, { children: [_jsx(ReactQuill, { ref: reactQuillRef, theme: "snow", onKeyDown: checkCharacterCount, onKeyUp: setContentLength, formats: formats, modules: modules, value: value, onChange: onChange, readOnly: readonly, className: isInvalid ? 'is-invalid' : '' }), maxLength && (_jsxs(Form.Text, { className: count > maxLength ? 'text-danger' : 'text-muted', children: [count, "/", maxLength, " characters"] }))] }));
57
+ };
@@ -0,0 +1,54 @@
1
+ import type { FC } from 'react';
2
+ /**
3
+ * Props for the SelectInput component
4
+ */
5
+ export type SelectInputProps = {
6
+ /** The name of the select input field */
7
+ name: string;
8
+ /** Label text displayed for the select */
9
+ label?: string;
10
+ /** Array of option strings to display in the dropdown */
11
+ options: string[];
12
+ /** Placeholder text shown when no option is selected (default: "Select...") */
13
+ helpText?: string;
14
+ /** Size of the select control */
15
+ controlSize?: 'sm' | 'lg';
16
+ /** Current selected value (standalone mode) */
17
+ value?: string;
18
+ /** Callback function called when the selection changes */
19
+ onChange?: (value: string) => void;
20
+ /** Whether the select is disabled */
21
+ disabled?: boolean;
22
+ /** Whether the select is required */
23
+ required?: boolean;
24
+ /** Array of option values to display in bold */
25
+ highlightValues?: string[];
26
+ };
27
+ /**
28
+ * SelectInput - A dropdown select component with react-hook-form integration
29
+ *
30
+ * Provides a select dropdown that works both standalone and with react-hook-form.
31
+ * Supports option highlighting, custom placeholder text, and automatic validation.
32
+ *
33
+ * @example
34
+ * ```tsx
35
+ * // With react-hook-form
36
+ * <SelectInput
37
+ * name="country"
38
+ * label="Country"
39
+ * options={["USA", "Canada", "UK"]}
40
+ * required
41
+ * />
42
+ *
43
+ * // Standalone mode
44
+ * <SelectInput
45
+ * name="role"
46
+ * options={["Admin", "User", "Guest"]}
47
+ * value={selectedRole}
48
+ * onChange={setSelectedRole}
49
+ * highlightValues={["Admin"]}
50
+ * />
51
+ * ```
52
+ */
53
+ export declare const SelectInput: FC<SelectInputProps>;
54
+ //# sourceMappingURL=SelectInput.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SelectInput.d.ts","sourceRoot":"","sources":["../../lib/components/SelectInput.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAe,EAAE,EAAE,MAAM,OAAO,CAAC;AAI7C;;GAEG;AACH,MAAM,MAAM,gBAAgB,GAAG;IAC9B,yCAAyC;IACzC,IAAI,EAAE,MAAM,CAAC;IACb,0CAA0C;IAC1C,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,yDAAyD;IACzD,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,+EAA+E;IAC/E,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,iCAAiC;IACjC,WAAW,CAAC,EAAE,IAAI,GAAG,IAAI,CAAC;IAC1B,+CAA+C;IAC/C,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,0DAA0D;IAC1D,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IACnC,qCAAqC;IACrC,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,qCAAqC;IACrC,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,gDAAgD;IAChD,eAAe,CAAC,EAAE,MAAM,EAAE,CAAC;CAC3B,CAAC;AAEF;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,eAAO,MAAM,WAAW,EAAE,EAAE,CAAC,gBAAgB,CAuF5C,CAAC"}
@@ -0,0 +1,64 @@
1
+ import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { Form } from 'react-bootstrap';
3
+ import { Controller, useFormContext } from 'react-hook-form';
4
+ /**
5
+ * SelectInput - A dropdown select component with react-hook-form integration
6
+ *
7
+ * Provides a select dropdown that works both standalone and with react-hook-form.
8
+ * Supports option highlighting, custom placeholder text, and automatic validation.
9
+ *
10
+ * @example
11
+ * ```tsx
12
+ * // With react-hook-form
13
+ * <SelectInput
14
+ * name="country"
15
+ * label="Country"
16
+ * options={["USA", "Canada", "UK"]}
17
+ * required
18
+ * />
19
+ *
20
+ * // Standalone mode
21
+ * <SelectInput
22
+ * name="role"
23
+ * options={["Admin", "User", "Guest"]}
24
+ * value={selectedRole}
25
+ * onChange={setSelectedRole}
26
+ * highlightValues={["Admin"]}
27
+ * />
28
+ * ```
29
+ */
30
+ export const SelectInput = ({ name, label, options = [], helpText = 'Select...', controlSize, value, onChange, disabled = false, required = false, highlightValues = [], }) => {
31
+ const formContext = useFormContext();
32
+ const getFieldError = (fieldName) => {
33
+ try {
34
+ const error = formContext?.formState?.errors?.[fieldName];
35
+ return error?.message;
36
+ }
37
+ catch {
38
+ return undefined;
39
+ }
40
+ };
41
+ const errorMessage = getFieldError(name);
42
+ const isInvalid = !!errorMessage;
43
+ const handleSelectChange = (event) => {
44
+ onChange?.(event.currentTarget.value);
45
+ };
46
+ const renderOptions = () => (_jsxs(_Fragment, { children: [_jsx("option", { value: "", children: helpText.trim() }), options.map((option) => {
47
+ const style = highlightValues.includes(option)
48
+ ? { fontWeight: 'bold' }
49
+ : {};
50
+ const key = option.replace(/ /g, '');
51
+ return (_jsx("option", { style: style, value: key, children: option.trim() }, key));
52
+ })] }));
53
+ // Integrated with react-hook-form
54
+ if (formContext) {
55
+ return (_jsx(Controller, { name: name, control: formContext.control, rules: {
56
+ required: required ? `${label || 'This field'} is required` : false,
57
+ }, render: ({ field }) => (_jsx(Form.Select, { ...field, onChange: (e) => {
58
+ field.onChange(e);
59
+ onChange?.(e.target.value);
60
+ }, required: required, size: controlSize, disabled: disabled, isInvalid: isInvalid, children: renderOptions() })) }));
61
+ }
62
+ // Standalone mode
63
+ return (_jsx(Form.Select, { required: required, size: controlSize, value: value || '', onChange: handleSelectChange, disabled: disabled, children: renderOptions() }));
64
+ };
@@ -0,0 +1,46 @@
1
+ import type { FC } from 'react';
2
+ /**
3
+ * Props for the SwitchInput component
4
+ */
5
+ export type SwitchInputProps = {
6
+ /** The name of the switch input field */
7
+ name: string;
8
+ /** Label text displayed next to the switch */
9
+ label?: string;
10
+ /** Whether the switch is required */
11
+ required?: boolean;
12
+ /** Current on/off state (standalone mode) */
13
+ value?: boolean;
14
+ /** Callback function called when the switch state changes */
15
+ onChange?: (checked: boolean) => void;
16
+ /** Whether the switch is disabled */
17
+ disabled?: boolean;
18
+ /** Custom HTML id for the switch element */
19
+ id?: string;
20
+ };
21
+ /**
22
+ * SwitchInput - A toggle switch component with react-hook-form integration
23
+ *
24
+ * Provides a toggle switch input that works both standalone and with react-hook-form.
25
+ * Automatically integrates with FormProvider when available, providing validation
26
+ * and error handling.
27
+ *
28
+ * @example
29
+ * ```tsx
30
+ * // With react-hook-form
31
+ * <SwitchInput
32
+ * name="notifications"
33
+ * label="Enable notifications"
34
+ * />
35
+ *
36
+ * // Standalone mode
37
+ * <SwitchInput
38
+ * name="darkMode"
39
+ * label="Dark mode"
40
+ * value={isDarkMode}
41
+ * onChange={setIsDarkMode}
42
+ * />
43
+ * ```
44
+ */
45
+ export declare const SwitchInput: FC<SwitchInputProps>;
46
+ //# sourceMappingURL=SwitchInput.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SwitchInput.d.ts","sourceRoot":"","sources":["../../lib/components/SwitchInput.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,EAAE,EAAE,MAAM,OAAO,CAAC;AAIhC;;GAEG;AACH,MAAM,MAAM,gBAAgB,GAAG;IAC9B,yCAAyC;IACzC,IAAI,EAAE,MAAM,CAAC;IACb,8CAA8C;IAC9C,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,qCAAqC;IACrC,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,6CAA6C;IAC7C,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,6DAA6D;IAC7D,QAAQ,CAAC,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,IAAI,CAAC;IACtC,qCAAqC;IACrC,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,4CAA4C;IAC5C,EAAE,CAAC,EAAE,MAAM,CAAC;CACZ,CAAC;AAEF;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,eAAO,MAAM,WAAW,EAAE,EAAE,CAAC,gBAAgB,CAmE5C,CAAC"}
@@ -0,0 +1,53 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { Form } from 'react-bootstrap';
3
+ import { Controller, useFormContext } from 'react-hook-form';
4
+ /**
5
+ * SwitchInput - A toggle switch component with react-hook-form integration
6
+ *
7
+ * Provides a toggle switch input that works both standalone and with react-hook-form.
8
+ * Automatically integrates with FormProvider when available, providing validation
9
+ * and error handling.
10
+ *
11
+ * @example
12
+ * ```tsx
13
+ * // With react-hook-form
14
+ * <SwitchInput
15
+ * name="notifications"
16
+ * label="Enable notifications"
17
+ * />
18
+ *
19
+ * // Standalone mode
20
+ * <SwitchInput
21
+ * name="darkMode"
22
+ * label="Dark mode"
23
+ * value={isDarkMode}
24
+ * onChange={setIsDarkMode}
25
+ * />
26
+ * ```
27
+ */
28
+ export const SwitchInput = ({ name, label, required = false, value, onChange, disabled = false, id, }) => {
29
+ const formContext = useFormContext();
30
+ const getFieldError = (fieldName) => {
31
+ try {
32
+ const error = formContext?.formState?.errors?.[fieldName];
33
+ return error?.message;
34
+ }
35
+ catch {
36
+ return undefined;
37
+ }
38
+ };
39
+ const errorMessage = getFieldError(name);
40
+ const inputId = id || `switch-input-${name}`;
41
+ // Integrated with react-hook-form
42
+ if (formContext) {
43
+ return (_jsx(Controller, { name: name, control: formContext.control, rules: {
44
+ required: required ? `${label || 'This field'} is required` : false,
45
+ }, render: ({ field }) => (_jsx(Form.Check, { ...field, id: inputId, type: "switch", label: label, checked: field.value ?? false, onChange: (e) => {
46
+ const checked = e.target.checked;
47
+ field.onChange(checked);
48
+ onChange?.(checked);
49
+ }, disabled: disabled, required: required, isInvalid: !!errorMessage, feedback: errorMessage, feedbackType: "invalid" })) }));
50
+ }
51
+ // Standalone mode
52
+ return (_jsx(Form.Check, { id: inputId, type: "switch", label: label, checked: value ?? false, onChange: (e) => onChange?.(e.target.checked), disabled: disabled, required: required }));
53
+ };
@@ -0,0 +1,35 @@
1
+ import type { FC } from 'react';
2
+ /**
3
+ * Props for the TagsInput component
4
+ */
5
+ export type TagsInputProps = {
6
+ /** Array of current tag values */
7
+ value: string[];
8
+ /** Callback function called when tags change */
9
+ onChange: (value: string[]) => void;
10
+ /** Placeholder text shown when no tags are entered (default: "Add tags...") */
11
+ placeholder?: string;
12
+ /** Whether the input is disabled */
13
+ disabled?: boolean;
14
+ /** Name attribute for the input field */
15
+ name?: string;
16
+ };
17
+ /**
18
+ * TagsInput - A multi-tag input component using Material-UI Autocomplete
19
+ *
20
+ * Provides a tag input interface where users can add/remove multiple tags.
21
+ * Automatically trims whitespace and filters empty values. Tags are displayed
22
+ * as chips with delete functionality.
23
+ *
24
+ * @example
25
+ * ```tsx
26
+ * <TagsInput
27
+ * name="skills"
28
+ * value={tags}
29
+ * onChange={setTags}
30
+ * placeholder="Add skills..."
31
+ * />
32
+ * ```
33
+ */
34
+ export declare const TagsInput: FC<TagsInputProps>;
35
+ //# sourceMappingURL=TagsInput.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"TagsInput.d.ts","sourceRoot":"","sources":["../../lib/components/TagsInput.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,EAAE,EAAE,MAAM,OAAO,CAAC;AAEhC;;GAEG;AACH,MAAM,MAAM,cAAc,GAAG;IAC5B,kCAAkC;IAClC,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,gDAAgD;IAChD,QAAQ,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,IAAI,CAAC;IACpC,+EAA+E;IAC/E,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,oCAAoC;IACpC,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,yCAAyC;IACzC,IAAI,CAAC,EAAE,MAAM,CAAC;CACd,CAAC;AAEF;;;;;;;;;;;;;;;;GAgBG;AACH,eAAO,MAAM,SAAS,EAAE,EAAE,CAAC,cAAc,CAiFxC,CAAC"}
@@ -0,0 +1,67 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { createElement as _createElement } from "react";
3
+ import { Autocomplete, Chip, TextField } from '@mui/material';
4
+ /**
5
+ * TagsInput - A multi-tag input component using Material-UI Autocomplete
6
+ *
7
+ * Provides a tag input interface where users can add/remove multiple tags.
8
+ * Automatically trims whitespace and filters empty values. Tags are displayed
9
+ * as chips with delete functionality.
10
+ *
11
+ * @example
12
+ * ```tsx
13
+ * <TagsInput
14
+ * name="skills"
15
+ * value={tags}
16
+ * onChange={setTags}
17
+ * placeholder="Add skills..."
18
+ * />
19
+ * ```
20
+ */
21
+ export const TagsInput = ({ value = [], onChange, placeholder = 'Add tags...', disabled = false, name, }) => {
22
+ return (_jsx(Autocomplete, { multiple: true, freeSolo: true, options: [], value: value, onChange: (_event, newValue) => {
23
+ // Filter out empty strings and trim whitespace
24
+ const cleanedValues = newValue
25
+ .map((v) => (typeof v === 'string' ? v.trim() : v))
26
+ .filter((v) => v.length > 0);
27
+ onChange(cleanedValues);
28
+ }, disabled: disabled, renderValue: (tagValue, getTagProps) => tagValue.map((option, index) => (_createElement(Chip, { ...getTagProps({ index }), key: option, label: option, sx: {
29
+ backgroundColor: '#212529',
30
+ color: '#ffffff',
31
+ '& .MuiChip-deleteIcon': {
32
+ color: 'rgba(255, 255, 255, 0.7)',
33
+ userSelect: 'none',
34
+ WebkitUserSelect: 'none',
35
+ MozUserSelect: 'none',
36
+ msUserSelect: 'none',
37
+ pointerEvents: 'auto',
38
+ '&::selection': {
39
+ backgroundColor: 'transparent',
40
+ color: 'transparent',
41
+ },
42
+ '& svg': {
43
+ userSelect: 'none',
44
+ WebkitUserSelect: 'none',
45
+ pointerEvents: 'none',
46
+ },
47
+ '&:hover': {
48
+ color: '#dc3545',
49
+ },
50
+ },
51
+ } }))), renderInput: (params) => (_jsx(TextField, { ...params, name: name, placeholder: value.length === 0 ? placeholder : undefined, variant: "outlined", size: "small", sx: {
52
+ '& .MuiOutlinedInput-root': {
53
+ padding: '4px',
54
+ minHeight: '38px',
55
+ '& fieldset': {
56
+ borderColor: '#ced4da',
57
+ },
58
+ '&:hover fieldset': {
59
+ borderColor: '#86b7fe',
60
+ },
61
+ '&.Mui-focused fieldset': {
62
+ borderColor: '#86b7fe',
63
+ borderWidth: '1px',
64
+ },
65
+ },
66
+ } })) }));
67
+ };
@@ -0,0 +1,71 @@
1
+ import { type FC } from 'react';
2
+ /**
3
+ * Props for the TextAreaInput component
4
+ */
5
+ export type TextAreaInputProps = {
6
+ /** The name of the textarea field */
7
+ name: string;
8
+ /** Label text displayed for the textarea */
9
+ label?: string;
10
+ /** Whether the field is required */
11
+ required?: boolean;
12
+ /** Maximum number of characters allowed */
13
+ maxLength?: number;
14
+ /** Size variant of the textarea control */
15
+ controlSize?: 'sm' | 'lg';
16
+ /** Placeholder text shown when textarea is empty */
17
+ placeholder?: string;
18
+ /** Controlled value of the textarea */
19
+ value?: string;
20
+ /** Callback fired when the value changes */
21
+ onChange?: (value: string) => void;
22
+ /** Whether the textarea is disabled */
23
+ disabled?: boolean;
24
+ /** Whether the textarea is read-only */
25
+ isReadOnly?: boolean;
26
+ /** Whether to render as plain text */
27
+ isPlainText?: boolean;
28
+ /** Debounce delay in milliseconds for value changes */
29
+ debounceMs?: number;
30
+ };
31
+ /**
32
+ * A flexible textarea input component with automatic height adjustment,
33
+ * react-hook-form integration, and optional debouncing.
34
+ *
35
+ * Features:
36
+ * - Auto-expands height based on content
37
+ * - Seamless integration with react-hook-form for validation
38
+ * - Debounced onChange callback to reduce update frequency
39
+ * - Built-in validation rules (required, maxLength)
40
+ * - Works in both controlled and standalone modes
41
+ *
42
+ * @example
43
+ * // Basic usage with react-hook-form
44
+ * <TextAreaInput
45
+ * name="description"
46
+ * label="Description"
47
+ * required
48
+ * maxLength={500}
49
+ * placeholder="Enter description..."
50
+ * />
51
+ *
52
+ * @example
53
+ * // With custom onChange and debouncing
54
+ * <TextAreaInput
55
+ * name="notes"
56
+ * label="Notes"
57
+ * debounceMs={300}
58
+ * onChange={(value) => console.log(value)}
59
+ * />
60
+ *
61
+ * @example
62
+ * // Standalone mode without form context
63
+ * <TextAreaInput
64
+ * name="comment"
65
+ * value={commentText}
66
+ * onChange={setCommentText}
67
+ * placeholder="Add your comment..."
68
+ * />
69
+ */
70
+ export declare const TextAreaInput: FC<TextAreaInputProps>;
71
+ //# sourceMappingURL=TextAreaInput.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"TextAreaInput.d.ts","sourceRoot":"","sources":["../../lib/components/TextAreaInput.tsx"],"names":[],"mappings":"AACA,OAAO,EAEN,KAAK,EAAE,EAKP,MAAM,OAAO,CAAC;AAIf;;GAEG;AACH,MAAM,MAAM,kBAAkB,GAAG;IAChC,qCAAqC;IACrC,IAAI,EAAE,MAAM,CAAC;IACb,4CAA4C;IAC5C,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,oCAAoC;IACpC,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,2CAA2C;IAC3C,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,2CAA2C;IAC3C,WAAW,CAAC,EAAE,IAAI,GAAG,IAAI,CAAC;IAC1B,oDAAoD;IACpD,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,uCAAuC;IACvC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,4CAA4C;IAC5C,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IACnC,uCAAuC;IACvC,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,wCAAwC;IACxC,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,sCAAsC;IACtC,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,uDAAuD;IACvD,UAAU,CAAC,EAAE,MAAM,CAAC;CACpB,CAAC;AAIF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAsCG;AACH,eAAO,MAAM,aAAa,EAAE,EAAE,CAAC,kBAAkB,CA+HhD,CAAC"}