@skalfa/skalfa-app 1.0.0 → 1.0.1

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 (87) hide show
  1. package/.env.example +43 -43
  2. package/.github/workflows/publish.yml +39 -0
  3. package/CONTRIBUTING.md +45 -0
  4. package/LICENSE +21 -0
  5. package/README.md +91 -28
  6. package/app/auth/edit/page.tsx +65 -65
  7. package/app/auth/login/page.tsx +63 -63
  8. package/app/auth/me/page.tsx +58 -58
  9. package/app/auth/register/page.tsx +69 -69
  10. package/app/auth/verify/page.tsx +53 -53
  11. package/app/dashboard/user/page.tsx +76 -76
  12. package/app/layout.tsx +37 -37
  13. package/app/manifest.ts +25 -0
  14. package/app/page.tsx +13 -13
  15. package/barrels.json +5 -5
  16. package/blueprints/starter.blueprint.json +102 -102
  17. package/bun.lock +916 -0
  18. package/components/base.components/chip/Chip.component.tsx +39 -39
  19. package/components/base.components/document/DocumentViewer.component.tsx +163 -163
  20. package/components/base.components/document/ExportExcel.component.tsx +340 -340
  21. package/components/base.components/document/ImportExcel.component.tsx +315 -315
  22. package/components/base.components/document/PrintTable.component.tsx +204 -204
  23. package/components/base.components/document/RenderPDF.component.tsx +415 -415
  24. package/components/base.components/input/Checkbox.component.tsx +109 -109
  25. package/components/base.components/input/Input.component.tsx +332 -332
  26. package/components/base.components/input/InputCheckbox.component.tsx +174 -174
  27. package/components/base.components/input/InputCurrency.component.tsx +163 -163
  28. package/components/base.components/input/InputDate.component.tsx +352 -352
  29. package/components/base.components/input/InputDatetime.component.tsx +260 -260
  30. package/components/base.components/input/InputDocument.component.tsx +351 -351
  31. package/components/base.components/input/InputImage.component.tsx +533 -533
  32. package/components/base.components/input/InputMap.component.tsx +317 -317
  33. package/components/base.components/input/InputNumber.component.tsx +192 -192
  34. package/components/base.components/input/InputOtp.component.tsx +169 -169
  35. package/components/base.components/input/InputPassword.component.tsx +236 -236
  36. package/components/base.components/input/InputRadio.component.tsx +175 -175
  37. package/components/base.components/input/InputTime.component.tsx +275 -275
  38. package/components/base.components/input/InputValues.component.tsx +68 -68
  39. package/components/base.components/input/Radio.component.tsx +102 -102
  40. package/components/base.components/input/Select.component.tsx +541 -541
  41. package/components/base.components/modal/BottomSheet.component.tsx +245 -245
  42. package/components/base.components/supervision/FormSupervision.component.tsx +433 -433
  43. package/components/base.components/supervision/TableSupervision.component.tsx +697 -697
  44. package/components/base.components/table/ControlBar.component.tsx +497 -497
  45. package/components/base.components/table/FilterComponent.tsx +518 -518
  46. package/components/base.components/table/Table.component.tsx +469 -469
  47. package/components/base.components/typography/TypographyArticle.component.tsx +26 -26
  48. package/components/base.components/typography/TypographyColumn.component.tsx +20 -20
  49. package/components/base.components/typography/TypographyContent.component.tsx +20 -20
  50. package/components/base.components/typography/TypographyTips.component.tsx +20 -20
  51. package/components/base.components/wrap/Draggable.component.tsx +303 -303
  52. package/components/base.components/wrap/IDBProvider.tsx +12 -12
  53. package/components/base.components/wrap/Image.component.tsx +9 -9
  54. package/components/base.components/wrap/ShortcutProvider.tsx +57 -57
  55. package/components/base.components/wrap/Swipe.component.tsx +93 -93
  56. package/components/index.ts +2 -2
  57. package/contexts/AppProvider.tsx +11 -11
  58. package/contexts/Auth.context.tsx +64 -64
  59. package/contexts/Toggle.context.tsx +44 -44
  60. package/next.config.ts +15 -1
  61. package/package.json +14 -13
  62. package/public/204.svg +19 -19
  63. package/public/500.svg +39 -39
  64. package/public/icon-192.png +0 -0
  65. package/public/icon-512.png +0 -0
  66. package/public/images/logo-fill.png +0 -0
  67. package/public/images/logo-full-fill.png +0 -0
  68. package/public/images/logo-full.png +0 -0
  69. package/public/images/logo.png +0 -0
  70. package/schema/idb/app.schema.ts +8 -8
  71. package/src-tauri/Cargo.toml +14 -0
  72. package/src-tauri/build.rs +3 -0
  73. package/src-tauri/capabilities/default.json +11 -0
  74. package/src-tauri/icons/128x128.png +0 -0
  75. package/src-tauri/icons/128x128@2x.png +0 -0
  76. package/src-tauri/icons/32x32.png +0 -0
  77. package/src-tauri/icons/icon.icns +0 -0
  78. package/src-tauri/icons/icon.ico +0 -0
  79. package/src-tauri/src/main.rs +7 -0
  80. package/src-tauri/tauri.conf.json +36 -0
  81. package/styles/globals.css +231 -231
  82. package/styles/tailwind.safelist +68 -68
  83. package/utils/commands/barrels.ts +27 -27
  84. package/utils/commands/light.ts +21 -21
  85. package/utils/commands/logger.ts +42 -42
  86. package/utils/commands/stubs/table-blueprint.stub +12 -12
  87. package/utils/commands/use-pdf.ts +29 -29
@@ -1,174 +1,174 @@
1
- "use client"
2
-
3
- import { ReactNode, useEffect, useState } from "react";
4
- import { api, ApiType, cn, pcn, useInputHandler, useValidation, validation, ValidationRules } from "@utils";
5
- import { CheckboxComponent } from "@components";
6
-
7
-
8
-
9
- type CT = "label" | "tip" | "error" | "input" | "icon";
10
-
11
- export interface InputCheckboxOptionProps {
12
- value: string | number;
13
- label: string;
14
- };
15
-
16
- export interface InputCheckboxProps {
17
- name : string;
18
- label ?: string;
19
- tip ?: string | ReactNode;
20
- vertical ?: boolean;
21
-
22
- value ?: string[] | number[];
23
- disabled ?: boolean;
24
- invalid ?: string;
25
-
26
- options ?: InputCheckboxOptionProps[];
27
- serverOptionControl ?: ApiType;
28
- customOptions ?: any;
29
- validations ?: ValidationRules;
30
-
31
- onChange ?: (value: string[] | number[]) => any;
32
- register ?: (name: string, validations?: ValidationRules) => void;
33
- unregister ?: (name: string) => void;
34
-
35
- /** Use custom class with: "label::", "tip::", "error::", "icon::". */
36
- className ?: string;
37
-
38
- /** Use custom class with: "label::", "checked::", "error::". */
39
- classNameCheckbox ?: string;
40
- };
41
-
42
-
43
-
44
- export function InputCheckboxComponent({
45
- name,
46
- label,
47
- tip,
48
- vertical,
49
- className="",
50
- classNameCheckbox="",
51
-
52
- value,
53
- disabled,
54
- invalid,
55
-
56
- options,
57
- serverOptionControl,
58
- customOptions,
59
- validations,
60
-
61
- register,
62
- unregister,
63
- onChange,
64
- }: InputCheckboxProps) {
65
-
66
- const [dataOptions, setDataOptions] = useState<InputCheckboxOptionProps[]>([]);
67
- const [loading, setLoading] = useState(false);
68
-
69
-
70
- // =========================>
71
- // ## initial
72
- // =========================>
73
- const inputHandler = useInputHandler(name, value, validations, register, unregister, false)
74
-
75
-
76
- // =========================>
77
- // ## Invalid handler
78
- // =========================>
79
- const [invalidMessage] = useValidation(inputHandler.value, validations, invalid, inputHandler.idle);
80
-
81
-
82
- // =========================>
83
- // ## fetch option
84
- // =========================>
85
- useEffect(() => {
86
- const fetchOptions = async () => {
87
- setLoading(true);
88
- const mutateOptions = await api(serverOptionControl || {});
89
- if (mutateOptions?.status == 200) {
90
- customOptions ? setDataOptions([customOptions, ...mutateOptions.data]) : setDataOptions(mutateOptions.data);
91
- setLoading(false);
92
- }
93
- };
94
-
95
- if (serverOptionControl?.path || serverOptionControl?.url) {
96
- fetchOptions();
97
- } else {
98
- !options && setDataOptions([]);
99
- }
100
- }, [serverOptionControl?.path, serverOptionControl?.url]);
101
-
102
-
103
- return (
104
- <>
105
- <div className="w-full relative flex flex-col gap-y-0.5">
106
- <label
107
- className={cn(
108
- "input-label",
109
- pcn<CT>(className, "label"),
110
- disabled && "opacity-50",
111
- disabled && pcn<CT>(className, "label", "disabled"),
112
- invalidMessage && "text-danger",
113
- invalidMessage && pcn<CT>(className, "label", "focus"),
114
- )}
115
- >
116
- {label}
117
- {validations && validation.hasRules(validations, "required") && <span className="text-danger ml-1">*</span>}
118
- </label>
119
-
120
- {tip && (
121
- <small
122
- className={cn(
123
- "input-tip",
124
- pcn<CT>(className, "tip"),
125
- disabled && "opacity-60",
126
- disabled && pcn<CT>(className, "tip", "disabled"),
127
- )}
128
- >{tip}</small>
129
- )}
130
-
131
- <div
132
- className={cn(
133
- `input overflow-auto input-scroll w-full flex flex-nowrap gap-y-2 gap-4`,
134
- vertical && "flex-col flex-wrap",
135
- pcn<CT>(className, "input"),
136
- invalidMessage && "input-error",
137
- invalidMessage && pcn<CT>(className, "input", "error"),
138
- )}
139
- >
140
- {loading && (vertical ? [1, 2, 3, 4, 5, 6, 7, 8, 9] : [1, 2, 3]).map((_, key) => {
141
- return <div key={key} className="w-1/3 h-6 rounded-lg"></div>;
142
- })}
143
-
144
- {(options || dataOptions) && (options || dataOptions)?.map((option, key) => {
145
- const checked = Array().concat(inputHandler.value).find((val) => val == option.value);
146
-
147
- return (
148
- <CheckboxComponent
149
- key={key}
150
- label={option.label}
151
- name={`option[${option.value}]#${name}`}
152
- checked={!!checked}
153
- disabled={disabled}
154
- className={classNameCheckbox}
155
- onChange={() => {
156
- const newVal = (Array.isArray(inputHandler.value) ? inputHandler.value : [])
157
- .filter((val) => val !== option.value)
158
- .concat(checked ? [] : [option.value]);
159
-
160
- inputHandler.setValue(newVal);
161
- onChange?.(newVal);
162
- }}
163
- />
164
- );
165
- })}
166
- </div>
167
-
168
- {invalidMessage && (
169
- <small className={cn("input-error-message", pcn<CT>(className, "error"))}>{invalidMessage}</small>
170
- )}
171
- </div>
172
- </>
173
- );
174
- }
1
+ "use client"
2
+
3
+ import { ReactNode, useEffect, useState } from "react";
4
+ import { api, ApiType, cn, pcn, useInputHandler, useValidation, validation, ValidationRules } from "@utils";
5
+ import { CheckboxComponent } from "@components";
6
+
7
+
8
+
9
+ type CT = "label" | "tip" | "error" | "input" | "icon";
10
+
11
+ export interface InputCheckboxOptionProps {
12
+ value: string | number;
13
+ label: string;
14
+ };
15
+
16
+ export interface InputCheckboxProps {
17
+ name : string;
18
+ label ?: string;
19
+ tip ?: string | ReactNode;
20
+ vertical ?: boolean;
21
+
22
+ value ?: string[] | number[];
23
+ disabled ?: boolean;
24
+ invalid ?: string;
25
+
26
+ options ?: InputCheckboxOptionProps[];
27
+ serverOptionControl ?: ApiType;
28
+ customOptions ?: any;
29
+ validations ?: ValidationRules;
30
+
31
+ onChange ?: (value: string[] | number[]) => any;
32
+ register ?: (name: string, validations?: ValidationRules) => void;
33
+ unregister ?: (name: string) => void;
34
+
35
+ /** Use custom class with: "label::", "tip::", "error::", "icon::". */
36
+ className ?: string;
37
+
38
+ /** Use custom class with: "label::", "checked::", "error::". */
39
+ classNameCheckbox ?: string;
40
+ };
41
+
42
+
43
+
44
+ export function InputCheckboxComponent({
45
+ name,
46
+ label,
47
+ tip,
48
+ vertical,
49
+ className="",
50
+ classNameCheckbox="",
51
+
52
+ value,
53
+ disabled,
54
+ invalid,
55
+
56
+ options,
57
+ serverOptionControl,
58
+ customOptions,
59
+ validations,
60
+
61
+ register,
62
+ unregister,
63
+ onChange,
64
+ }: InputCheckboxProps) {
65
+
66
+ const [dataOptions, setDataOptions] = useState<InputCheckboxOptionProps[]>([]);
67
+ const [loading, setLoading] = useState(false);
68
+
69
+
70
+ // =========================>
71
+ // ## initial
72
+ // =========================>
73
+ const inputHandler = useInputHandler(name, value, validations, register, unregister, false)
74
+
75
+
76
+ // =========================>
77
+ // ## Invalid handler
78
+ // =========================>
79
+ const [invalidMessage] = useValidation(inputHandler.value, validations, invalid, inputHandler.idle);
80
+
81
+
82
+ // =========================>
83
+ // ## fetch option
84
+ // =========================>
85
+ useEffect(() => {
86
+ const fetchOptions = async () => {
87
+ setLoading(true);
88
+ const mutateOptions = await api(serverOptionControl || {});
89
+ if (mutateOptions?.status == 200) {
90
+ customOptions ? setDataOptions([customOptions, ...mutateOptions.data]) : setDataOptions(mutateOptions.data);
91
+ setLoading(false);
92
+ }
93
+ };
94
+
95
+ if (serverOptionControl?.path || serverOptionControl?.url) {
96
+ fetchOptions();
97
+ } else {
98
+ !options && setDataOptions([]);
99
+ }
100
+ }, [serverOptionControl?.path, serverOptionControl?.url]);
101
+
102
+
103
+ return (
104
+ <>
105
+ <div className="w-full relative flex flex-col gap-y-0.5">
106
+ <label
107
+ className={cn(
108
+ "input-label",
109
+ pcn<CT>(className, "label"),
110
+ disabled && "opacity-50",
111
+ disabled && pcn<CT>(className, "label", "disabled"),
112
+ invalidMessage && "text-danger",
113
+ invalidMessage && pcn<CT>(className, "label", "focus"),
114
+ )}
115
+ >
116
+ {label}
117
+ {validations && validation.hasRules(validations, "required") && <span className="text-danger ml-1">*</span>}
118
+ </label>
119
+
120
+ {tip && (
121
+ <small
122
+ className={cn(
123
+ "input-tip",
124
+ pcn<CT>(className, "tip"),
125
+ disabled && "opacity-60",
126
+ disabled && pcn<CT>(className, "tip", "disabled"),
127
+ )}
128
+ >{tip}</small>
129
+ )}
130
+
131
+ <div
132
+ className={cn(
133
+ `input overflow-auto input-scroll w-full flex flex-nowrap gap-y-2 gap-4`,
134
+ vertical && "flex-col flex-wrap",
135
+ pcn<CT>(className, "input"),
136
+ invalidMessage && "input-error",
137
+ invalidMessage && pcn<CT>(className, "input", "error"),
138
+ )}
139
+ >
140
+ {loading && (vertical ? [1, 2, 3, 4, 5, 6, 7, 8, 9] : [1, 2, 3]).map((_, key) => {
141
+ return <div key={key} className="w-1/3 h-6 rounded-lg"></div>;
142
+ })}
143
+
144
+ {(options || dataOptions) && (options || dataOptions)?.map((option, key) => {
145
+ const checked = Array().concat(inputHandler.value).find((val) => val == option.value);
146
+
147
+ return (
148
+ <CheckboxComponent
149
+ key={key}
150
+ label={option.label}
151
+ name={`option[${option.value}]#${name}`}
152
+ checked={!!checked}
153
+ disabled={disabled}
154
+ className={classNameCheckbox}
155
+ onChange={() => {
156
+ const newVal = (Array.isArray(inputHandler.value) ? inputHandler.value : [])
157
+ .filter((val) => val !== option.value)
158
+ .concat(checked ? [] : [option.value]);
159
+
160
+ inputHandler.setValue(newVal);
161
+ onChange?.(newVal);
162
+ }}
163
+ />
164
+ );
165
+ })}
166
+ </div>
167
+
168
+ {invalidMessage && (
169
+ <small className={cn("input-error-message", pcn<CT>(className, "error"))}>{invalidMessage}</small>
170
+ )}
171
+ </div>
172
+ </>
173
+ );
174
+ }
@@ -1,163 +1,163 @@
1
- "use client"
2
-
3
- import { InputHTMLAttributes, ReactNode } from "react";
4
- import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
5
- import { cn, conversion, pcn, useInputHandler, useInputRandomId, useValidation, validation, ValidationRules } from "@utils";
6
-
7
-
8
-
9
- type CT = "label" | "tip" | "error" | "input" | "icon";
10
-
11
- export interface InputCurrencyProps extends Omit<InputHTMLAttributes<HTMLInputElement>, "onChange"> {
12
- label ?: string;
13
- tip ?: string | ReactNode;
14
- leftIcon ?: any;
15
- rightIcon ?: any;
16
-
17
- value ?: number;
18
- invalid ?: string;
19
- validations ?: ValidationRules;
20
- format ?: {
21
- locale ?: string;
22
- currency ?: string;
23
- };
24
-
25
- onChange ?: (value: number) => any;
26
- register ?: (name: string, validations?: ValidationRules) => void;
27
- unregister ?: (name: string) => void;
28
-
29
- /** Use custom class with: "label::", "tip::", "error::", "icon::". */
30
- className ?: string;
31
- }
32
-
33
-
34
-
35
- export function InputCurrencyComponent({
36
- label,
37
- tip,
38
- leftIcon,
39
- rightIcon,
40
-
41
- value,
42
- invalid,
43
-
44
- validations,
45
- format,
46
-
47
- register,
48
- unregister,
49
- onChange,
50
-
51
- className = "",
52
- ...props
53
- }: InputCurrencyProps) {
54
-
55
- // =========================>
56
- // ## Initial
57
- // =========================>
58
- const inputHandler = useInputHandler(props.name, value, validations, register, unregister, false)
59
- const randomId = useInputRandomId()
60
-
61
-
62
- // =========================>
63
- // ## Invalid handler
64
- // =========================>
65
- const [invalidMessage] = useValidation(inputHandler.value, validations, invalid, inputHandler.idle);
66
-
67
-
68
- return (
69
- <div className="relative flex flex-col gap-y-0.5">
70
- <label
71
- htmlFor={randomId}
72
- className={cn(
73
- "input-label",
74
- pcn<CT>(className, "label"),
75
- props.disabled && "opacity-50",
76
- props.disabled && pcn<CT>(className, "label", "disabled"),
77
- inputHandler.focus && "text-primary",
78
- inputHandler.focus && pcn<CT>(className, "label", "focus"),
79
- !!invalidMessage && "text-danger",
80
- !!invalidMessage && pcn<CT>(className, "label", "focus"),
81
- )}
82
- >
83
- {label}
84
- {validations && validation.hasRules(validations, "required") && <span className="text-danger ml-1">*</span>}
85
- </label>
86
-
87
- {tip && (
88
- <small
89
- className={cn(
90
- "input-tip",
91
- pcn<CT>(className, "tip"),
92
- props.disabled && "opacity-60",
93
- props.disabled && pcn<CT>(className, "tip", "disabled"),
94
- )}
95
- >{tip}</small>
96
- )}
97
-
98
- <div className="relative">
99
- <input
100
- {...props}
101
- id={randomId}
102
- className={cn(
103
- "input",
104
- leftIcon && "pl-12",
105
- rightIcon && "pr-12",
106
- pcn<CT>(className, "input"),
107
- !!invalidMessage && "input-error",
108
- !!invalidMessage && pcn<CT>(className, "input", "error"),
109
- )}
110
- value={inputHandler.value ? conversion.currency(inputHandler.value, format?.locale, format?.currency) : ""}
111
- onChange={(e) => {
112
- const val = Number(e.target.value.replace(/[^0-9]/g,""));
113
-
114
- inputHandler.setValue(val);
115
- inputHandler.setIdle(false);
116
-
117
- onChange?.(val);
118
- }}
119
- onFocus={(e) => {
120
- props.onFocus?.(e);
121
- inputHandler.setFocus(true);
122
- }}
123
- onBlur={(e) => {
124
- props.onBlur?.(e);
125
- setTimeout(() => inputHandler.setFocus(false), 100);
126
- }}
127
- autoComplete="off"
128
- />
129
-
130
- {leftIcon && (
131
- <FontAwesomeIcon
132
- className={cn(
133
- "left-4 input-icon",
134
- pcn<CT>(className, "icon"),
135
- props.disabled && "opacity-60",
136
- props.disabled && pcn<CT>(className, "icon", "disabled"),
137
- inputHandler.focus && "text-primary",
138
- inputHandler.focus && pcn<CT>(className, "icon", "focus"),
139
- )}
140
- icon={leftIcon}
141
- />
142
- )}
143
- {rightIcon && (
144
- <FontAwesomeIcon
145
- className={cn(
146
- "right-4 input-icon",
147
- pcn<CT>(className, "icon"),
148
- props.disabled && "opacity-60",
149
- props.disabled && pcn<CT>(className, "icon", "disabled"),
150
- inputHandler.focus && "text-primary",
151
- inputHandler.focus && pcn<CT>(className, "icon", "focus"),
152
- )}
153
- icon={rightIcon}
154
- />
155
- )}
156
- </div>
157
-
158
- {invalidMessage && (
159
- <small className={cn("input-error-message", pcn<CT>(className, "error"))}>{invalidMessage}</small>
160
- )}
161
- </div>
162
- );
163
- }
1
+ "use client"
2
+
3
+ import { InputHTMLAttributes, ReactNode } from "react";
4
+ import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
5
+ import { cn, conversion, pcn, useInputHandler, useInputRandomId, useValidation, validation, ValidationRules } from "@utils";
6
+
7
+
8
+
9
+ type CT = "label" | "tip" | "error" | "input" | "icon";
10
+
11
+ export interface InputCurrencyProps extends Omit<InputHTMLAttributes<HTMLInputElement>, "onChange"> {
12
+ label ?: string;
13
+ tip ?: string | ReactNode;
14
+ leftIcon ?: any;
15
+ rightIcon ?: any;
16
+
17
+ value ?: number;
18
+ invalid ?: string;
19
+ validations ?: ValidationRules;
20
+ format ?: {
21
+ locale ?: string;
22
+ currency ?: string;
23
+ };
24
+
25
+ onChange ?: (value: number) => any;
26
+ register ?: (name: string, validations?: ValidationRules) => void;
27
+ unregister ?: (name: string) => void;
28
+
29
+ /** Use custom class with: "label::", "tip::", "error::", "icon::". */
30
+ className ?: string;
31
+ }
32
+
33
+
34
+
35
+ export function InputCurrencyComponent({
36
+ label,
37
+ tip,
38
+ leftIcon,
39
+ rightIcon,
40
+
41
+ value,
42
+ invalid,
43
+
44
+ validations,
45
+ format,
46
+
47
+ register,
48
+ unregister,
49
+ onChange,
50
+
51
+ className = "",
52
+ ...props
53
+ }: InputCurrencyProps) {
54
+
55
+ // =========================>
56
+ // ## Initial
57
+ // =========================>
58
+ const inputHandler = useInputHandler(props.name, value, validations, register, unregister, false)
59
+ const randomId = useInputRandomId()
60
+
61
+
62
+ // =========================>
63
+ // ## Invalid handler
64
+ // =========================>
65
+ const [invalidMessage] = useValidation(inputHandler.value, validations, invalid, inputHandler.idle);
66
+
67
+
68
+ return (
69
+ <div className="relative flex flex-col gap-y-0.5">
70
+ <label
71
+ htmlFor={randomId}
72
+ className={cn(
73
+ "input-label",
74
+ pcn<CT>(className, "label"),
75
+ props.disabled && "opacity-50",
76
+ props.disabled && pcn<CT>(className, "label", "disabled"),
77
+ inputHandler.focus && "text-primary",
78
+ inputHandler.focus && pcn<CT>(className, "label", "focus"),
79
+ !!invalidMessage && "text-danger",
80
+ !!invalidMessage && pcn<CT>(className, "label", "focus"),
81
+ )}
82
+ >
83
+ {label}
84
+ {validations && validation.hasRules(validations, "required") && <span className="text-danger ml-1">*</span>}
85
+ </label>
86
+
87
+ {tip && (
88
+ <small
89
+ className={cn(
90
+ "input-tip",
91
+ pcn<CT>(className, "tip"),
92
+ props.disabled && "opacity-60",
93
+ props.disabled && pcn<CT>(className, "tip", "disabled"),
94
+ )}
95
+ >{tip}</small>
96
+ )}
97
+
98
+ <div className="relative">
99
+ <input
100
+ {...props}
101
+ id={randomId}
102
+ className={cn(
103
+ "input",
104
+ leftIcon && "pl-12",
105
+ rightIcon && "pr-12",
106
+ pcn<CT>(className, "input"),
107
+ !!invalidMessage && "input-error",
108
+ !!invalidMessage && pcn<CT>(className, "input", "error"),
109
+ )}
110
+ value={inputHandler.value ? conversion.currency(inputHandler.value, format?.locale, format?.currency) : ""}
111
+ onChange={(e) => {
112
+ const val = Number(e.target.value.replace(/[^0-9]/g,""));
113
+
114
+ inputHandler.setValue(val);
115
+ inputHandler.setIdle(false);
116
+
117
+ onChange?.(val);
118
+ }}
119
+ onFocus={(e) => {
120
+ props.onFocus?.(e);
121
+ inputHandler.setFocus(true);
122
+ }}
123
+ onBlur={(e) => {
124
+ props.onBlur?.(e);
125
+ setTimeout(() => inputHandler.setFocus(false), 100);
126
+ }}
127
+ autoComplete="off"
128
+ />
129
+
130
+ {leftIcon && (
131
+ <FontAwesomeIcon
132
+ className={cn(
133
+ "left-4 input-icon",
134
+ pcn<CT>(className, "icon"),
135
+ props.disabled && "opacity-60",
136
+ props.disabled && pcn<CT>(className, "icon", "disabled"),
137
+ inputHandler.focus && "text-primary",
138
+ inputHandler.focus && pcn<CT>(className, "icon", "focus"),
139
+ )}
140
+ icon={leftIcon}
141
+ />
142
+ )}
143
+ {rightIcon && (
144
+ <FontAwesomeIcon
145
+ className={cn(
146
+ "right-4 input-icon",
147
+ pcn<CT>(className, "icon"),
148
+ props.disabled && "opacity-60",
149
+ props.disabled && pcn<CT>(className, "icon", "disabled"),
150
+ inputHandler.focus && "text-primary",
151
+ inputHandler.focus && pcn<CT>(className, "icon", "focus"),
152
+ )}
153
+ icon={rightIcon}
154
+ />
155
+ )}
156
+ </div>
157
+
158
+ {invalidMessage && (
159
+ <small className={cn("input-error-message", pcn<CT>(className, "error"))}>{invalidMessage}</small>
160
+ )}
161
+ </div>
162
+ );
163
+ }