@fiscozen/input 3.0.3 → 3.2.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.
- package/CHANGELOG.md +24 -0
- package/dist/index.d.ts +1 -0
- package/dist/input.css +2 -0
- package/dist/input.js +8854 -8360
- package/dist/input.umd.cjs +5 -9
- package/dist/src/FzCurrencyInput.vue.d.ts +363 -197
- package/dist/src/FzInput.vue.d.ts +55 -243
- package/dist/src/types.d.ts +34 -2
- package/dist/src/useInputStyle.d.ts +1 -2
- package/dist/src/utils.d.ts +0 -1
- package/package.json +12 -12
- package/src/FzInput.vue +79 -1
- package/src/__tests__/FzInput.spec.ts +1332 -614
- package/src/types.ts +59 -27
- package/src/useInputStyle.ts +43 -24
- package/tsconfig.tsbuildinfo +1 -1
- package/coverage/FzCurrencyInput.vue.html +0 -640
- package/coverage/FzInput.vue.html +0 -709
- package/coverage/base.css +0 -224
- package/coverage/block-navigation.js +0 -87
- package/coverage/clover.xml +0 -494
- package/coverage/coverage-final.json +0 -4
- package/coverage/favicon.png +0 -0
- package/coverage/index.html +0 -146
- package/coverage/prettify.css +0 -1
- package/coverage/prettify.js +0 -2
- package/coverage/sort-arrow-sprite.png +0 -0
- package/coverage/sorter.js +0 -196
- package/coverage/useInputStyle.ts.html +0 -343
- package/dist/style.css +0 -1
|
@@ -1,258 +1,70 @@
|
|
|
1
1
|
import { Ref } from 'vue';
|
|
2
|
-
import { InputEnvironment } from './types';
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
modelValue
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
label: {
|
|
31
|
-
type: import('vue').PropType<string>;
|
|
32
|
-
};
|
|
33
|
-
pattern: {
|
|
34
|
-
type: import('vue').PropType<string>;
|
|
35
|
-
};
|
|
36
|
-
placeholder: {
|
|
37
|
-
type: import('vue').PropType<string>;
|
|
38
|
-
};
|
|
39
|
-
environment: {
|
|
40
|
-
type: import('vue').PropType<InputEnvironment>;
|
|
41
|
-
default: string;
|
|
42
|
-
};
|
|
43
|
-
rightIcon: {
|
|
44
|
-
type: import('vue').PropType<string>;
|
|
45
|
-
};
|
|
46
|
-
rightIconSize: {
|
|
47
|
-
type: import('vue').PropType<import('@fiscozen/icons/src/types').IconSize>;
|
|
48
|
-
};
|
|
49
|
-
rightIconVariant: {
|
|
50
|
-
type: import('vue').PropType<import('@fiscozen/icons/src/types').IconVariant>;
|
|
51
|
-
};
|
|
52
|
-
rightIconButton: {
|
|
53
|
-
type: import('vue').PropType<boolean>;
|
|
54
|
-
};
|
|
55
|
-
rightIconButtonVariant: {
|
|
56
|
-
type: import('vue').PropType<import('@fiscozen/button').CommonButtonVariant>;
|
|
57
|
-
default: string;
|
|
58
|
-
};
|
|
59
|
-
rightIconAriaLabel: {
|
|
60
|
-
type: import('vue').PropType<string>;
|
|
61
|
-
};
|
|
62
|
-
rightIconClass: {
|
|
63
|
-
type: import('vue').PropType<string>;
|
|
64
|
-
};
|
|
65
|
-
secondRightIcon: {
|
|
66
|
-
type: import('vue').PropType<string>;
|
|
67
|
-
};
|
|
68
|
-
secondRightIconClass: {
|
|
69
|
-
type: import('vue').PropType<string>;
|
|
70
|
-
};
|
|
71
|
-
secondRightIconVariant: {
|
|
72
|
-
type: import('vue').PropType<import('@fiscozen/icons/src/types').IconVariant>;
|
|
73
|
-
};
|
|
74
|
-
secondRightIconButton: {
|
|
75
|
-
type: import('vue').PropType<boolean>;
|
|
76
|
-
};
|
|
77
|
-
secondRightIconButtonVariant: {
|
|
78
|
-
type: import('vue').PropType<import('@fiscozen/button').CommonButtonVariant>;
|
|
79
|
-
default: string;
|
|
80
|
-
};
|
|
81
|
-
secondRightIconAriaLabel: {
|
|
82
|
-
type: import('vue').PropType<string>;
|
|
83
|
-
};
|
|
84
|
-
leftIcon: {
|
|
85
|
-
type: import('vue').PropType<string>;
|
|
86
|
-
};
|
|
87
|
-
leftIconVariant: {
|
|
88
|
-
type: import('vue').PropType<import('@fiscozen/icons/src/types').IconVariant>;
|
|
89
|
-
};
|
|
90
|
-
leftIconButtonVariant: {
|
|
91
|
-
type: import('vue').PropType<import('@fiscozen/button').CommonButtonVariant>;
|
|
92
|
-
};
|
|
93
|
-
leftIconAriaLabel: {
|
|
94
|
-
type: import('vue').PropType<string>;
|
|
95
|
-
};
|
|
96
|
-
valid: {
|
|
97
|
-
type: import('vue').PropType<boolean>;
|
|
98
|
-
};
|
|
99
|
-
readonly: {
|
|
100
|
-
type: import('vue').PropType<boolean>;
|
|
101
|
-
};
|
|
102
|
-
maxlength: {
|
|
103
|
-
type: import('vue').PropType<number>;
|
|
104
|
-
};
|
|
105
|
-
autocomplete: {
|
|
106
|
-
type: import('vue').PropType<boolean>;
|
|
107
|
-
default: boolean;
|
|
108
|
-
};
|
|
109
|
-
leftIconClass: {
|
|
110
|
-
type: import('vue').PropType<string>;
|
|
111
|
-
};
|
|
112
|
-
}>, {
|
|
2
|
+
import { FzInputProps, InputEnvironment } from './types';
|
|
3
|
+
type __VLS_Props = FzInputProps;
|
|
4
|
+
type __VLS_PublicProps = {
|
|
5
|
+
modelValue?: string;
|
|
6
|
+
} & __VLS_Props;
|
|
7
|
+
declare function __VLS_template(): {
|
|
8
|
+
attrs: Partial<{}>;
|
|
9
|
+
slots: Readonly<{
|
|
10
|
+
label?: () => unknown;
|
|
11
|
+
"left-icon"?: () => unknown;
|
|
12
|
+
"right-icon"?: () => unknown;
|
|
13
|
+
errorMessage?: () => unknown;
|
|
14
|
+
helpText?: () => unknown;
|
|
15
|
+
}> & {
|
|
16
|
+
label?: () => unknown;
|
|
17
|
+
"left-icon"?: () => unknown;
|
|
18
|
+
"right-icon"?: () => unknown;
|
|
19
|
+
errorMessage?: () => unknown;
|
|
20
|
+
helpText?: () => unknown;
|
|
21
|
+
};
|
|
22
|
+
refs: {
|
|
23
|
+
containerRef: HTMLDivElement;
|
|
24
|
+
inputRef: HTMLInputElement;
|
|
25
|
+
};
|
|
26
|
+
rootEl: any;
|
|
27
|
+
};
|
|
28
|
+
type __VLS_TemplateResult = ReturnType<typeof __VLS_template>;
|
|
29
|
+
declare const __VLS_component: import('vue').DefineComponent<__VLS_PublicProps, {
|
|
113
30
|
inputRef: Ref<HTMLInputElement | null, HTMLInputElement | null>;
|
|
114
31
|
containerRef: Ref<HTMLElement | null, HTMLElement | null>;
|
|
115
32
|
}, {}, {}, {}, import('vue').ComponentOptionsMixin, import('vue').ComponentOptionsMixin, {
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
"fzinput:left-icon-click": () =>
|
|
119
|
-
"fzinput:right-icon-click": () =>
|
|
120
|
-
"fzinput:second-right-icon-click": () =>
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
default: boolean;
|
|
126
|
-
};
|
|
127
|
-
name: {
|
|
128
|
-
type: import('vue').PropType<string>;
|
|
129
|
-
};
|
|
130
|
-
size: {
|
|
131
|
-
type: import('vue').PropType<"sm" | "md" | "lg">;
|
|
132
|
-
};
|
|
133
|
-
variant: {
|
|
134
|
-
type: import('vue').PropType<"normal" | "floating-label">;
|
|
135
|
-
default: string;
|
|
136
|
-
};
|
|
137
|
-
type: {
|
|
138
|
-
type: import('vue').PropType<"number" | "text" | "password" | "email" | "tel" | "url">;
|
|
139
|
-
default: string;
|
|
140
|
-
};
|
|
141
|
-
required: {
|
|
142
|
-
type: import('vue').PropType<boolean>;
|
|
143
|
-
};
|
|
144
|
-
disabled: {
|
|
145
|
-
type: import('vue').PropType<boolean>;
|
|
146
|
-
};
|
|
147
|
-
label: {
|
|
148
|
-
type: import('vue').PropType<string>;
|
|
149
|
-
};
|
|
150
|
-
pattern: {
|
|
151
|
-
type: import('vue').PropType<string>;
|
|
152
|
-
};
|
|
153
|
-
placeholder: {
|
|
154
|
-
type: import('vue').PropType<string>;
|
|
155
|
-
};
|
|
156
|
-
environment: {
|
|
157
|
-
type: import('vue').PropType<InputEnvironment>;
|
|
158
|
-
default: string;
|
|
159
|
-
};
|
|
160
|
-
rightIcon: {
|
|
161
|
-
type: import('vue').PropType<string>;
|
|
162
|
-
};
|
|
163
|
-
rightIconSize: {
|
|
164
|
-
type: import('vue').PropType<import('@fiscozen/icons/src/types').IconSize>;
|
|
165
|
-
};
|
|
166
|
-
rightIconVariant: {
|
|
167
|
-
type: import('vue').PropType<import('@fiscozen/icons/src/types').IconVariant>;
|
|
168
|
-
};
|
|
169
|
-
rightIconButton: {
|
|
170
|
-
type: import('vue').PropType<boolean>;
|
|
171
|
-
};
|
|
172
|
-
rightIconButtonVariant: {
|
|
173
|
-
type: import('vue').PropType<import('@fiscozen/button').CommonButtonVariant>;
|
|
174
|
-
default: string;
|
|
175
|
-
};
|
|
176
|
-
rightIconAriaLabel: {
|
|
177
|
-
type: import('vue').PropType<string>;
|
|
178
|
-
};
|
|
179
|
-
rightIconClass: {
|
|
180
|
-
type: import('vue').PropType<string>;
|
|
181
|
-
};
|
|
182
|
-
secondRightIcon: {
|
|
183
|
-
type: import('vue').PropType<string>;
|
|
184
|
-
};
|
|
185
|
-
secondRightIconClass: {
|
|
186
|
-
type: import('vue').PropType<string>;
|
|
187
|
-
};
|
|
188
|
-
secondRightIconVariant: {
|
|
189
|
-
type: import('vue').PropType<import('@fiscozen/icons/src/types').IconVariant>;
|
|
190
|
-
};
|
|
191
|
-
secondRightIconButton: {
|
|
192
|
-
type: import('vue').PropType<boolean>;
|
|
193
|
-
};
|
|
194
|
-
secondRightIconButtonVariant: {
|
|
195
|
-
type: import('vue').PropType<import('@fiscozen/button').CommonButtonVariant>;
|
|
196
|
-
default: string;
|
|
197
|
-
};
|
|
198
|
-
secondRightIconAriaLabel: {
|
|
199
|
-
type: import('vue').PropType<string>;
|
|
200
|
-
};
|
|
201
|
-
leftIcon: {
|
|
202
|
-
type: import('vue').PropType<string>;
|
|
203
|
-
};
|
|
204
|
-
leftIconVariant: {
|
|
205
|
-
type: import('vue').PropType<import('@fiscozen/icons/src/types').IconVariant>;
|
|
206
|
-
};
|
|
207
|
-
leftIconButtonVariant: {
|
|
208
|
-
type: import('vue').PropType<import('@fiscozen/button').CommonButtonVariant>;
|
|
209
|
-
};
|
|
210
|
-
leftIconAriaLabel: {
|
|
211
|
-
type: import('vue').PropType<string>;
|
|
212
|
-
};
|
|
213
|
-
valid: {
|
|
214
|
-
type: import('vue').PropType<boolean>;
|
|
215
|
-
};
|
|
216
|
-
readonly: {
|
|
217
|
-
type: import('vue').PropType<boolean>;
|
|
218
|
-
};
|
|
219
|
-
maxlength: {
|
|
220
|
-
type: import('vue').PropType<number>;
|
|
221
|
-
};
|
|
222
|
-
autocomplete: {
|
|
223
|
-
type: import('vue').PropType<boolean>;
|
|
224
|
-
default: boolean;
|
|
225
|
-
};
|
|
226
|
-
leftIconClass: {
|
|
227
|
-
type: import('vue').PropType<string>;
|
|
228
|
-
};
|
|
229
|
-
}>> & Readonly<{
|
|
230
|
-
onBlur?: ((event: FocusEvent) => any) | undefined;
|
|
33
|
+
focus: (event: FocusEvent) => any;
|
|
34
|
+
blur: (event: FocusEvent) => any;
|
|
35
|
+
"fzinput:left-icon-click": () => any;
|
|
36
|
+
"fzinput:right-icon-click": () => any;
|
|
37
|
+
"fzinput:second-right-icon-click": () => any;
|
|
38
|
+
"update:highlighted": (value: boolean) => any;
|
|
39
|
+
"update:aiReasoning": (value: boolean) => any;
|
|
40
|
+
"update:modelValue": (value: string) => any;
|
|
41
|
+
}, string, import('vue').PublicProps, Readonly<__VLS_PublicProps> & Readonly<{
|
|
231
42
|
onFocus?: ((event: FocusEvent) => any) | undefined;
|
|
43
|
+
onBlur?: ((event: FocusEvent) => any) | undefined;
|
|
232
44
|
"onFzinput:left-icon-click"?: (() => any) | undefined;
|
|
233
45
|
"onFzinput:right-icon-click"?: (() => any) | undefined;
|
|
234
46
|
"onFzinput:second-right-icon-click"?: (() => any) | undefined;
|
|
47
|
+
"onUpdate:highlighted"?: ((value: boolean) => any) | undefined;
|
|
48
|
+
"onUpdate:aiReasoning"?: ((value: boolean) => any) | undefined;
|
|
49
|
+
"onUpdate:modelValue"?: ((value: string) => any) | undefined;
|
|
235
50
|
}>, {
|
|
236
|
-
error: boolean;
|
|
237
51
|
variant: "normal" | "floating-label";
|
|
238
|
-
type: "
|
|
52
|
+
type: "text" | "password" | "email" | "number" | "tel" | "url";
|
|
239
53
|
environment: InputEnvironment;
|
|
240
|
-
rightIconButtonVariant: import('@fiscozen/button').
|
|
241
|
-
secondRightIconButtonVariant: import('@fiscozen/button').
|
|
54
|
+
rightIconButtonVariant: import('@fiscozen/button').IconButtonVariant;
|
|
55
|
+
secondRightIconButtonVariant: import('@fiscozen/button').IconButtonVariant;
|
|
56
|
+
error: boolean;
|
|
57
|
+
highlighted: boolean;
|
|
58
|
+
highlightedDescription: string;
|
|
59
|
+
aiReasoning: boolean;
|
|
60
|
+
aiReasoningDescription: string;
|
|
61
|
+
disableEmphasisReset: boolean;
|
|
242
62
|
autocomplete: boolean;
|
|
243
|
-
}, {}, {}, {}, string, import('vue').ComponentProvideOptions,
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
helpText?: (() => unknown) | undefined;
|
|
249
|
-
}> & {
|
|
250
|
-
label?: (() => unknown) | undefined;
|
|
251
|
-
"left-icon"?: (() => unknown) | undefined;
|
|
252
|
-
"right-icon"?: (() => unknown) | undefined;
|
|
253
|
-
errorMessage?: (() => unknown) | undefined;
|
|
254
|
-
helpText?: (() => unknown) | undefined;
|
|
255
|
-
}>;
|
|
63
|
+
}, {}, {}, {}, string, import('vue').ComponentProvideOptions, false, {
|
|
64
|
+
containerRef: HTMLDivElement;
|
|
65
|
+
inputRef: HTMLInputElement;
|
|
66
|
+
}, any>;
|
|
67
|
+
declare const _default: __VLS_WithTemplateSlots<typeof __VLS_component, __VLS_TemplateResult["slots"]>;
|
|
256
68
|
export default _default;
|
|
257
69
|
type __VLS_WithTemplateSlots<T, S> = T & {
|
|
258
70
|
new (): {
|
package/dist/src/types.d.ts
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { IconButtonVariant } from '@fiscozen/button';
|
|
2
2
|
import { IconSize, IconVariant } from '@fiscozen/icons';
|
|
3
|
-
|
|
4
3
|
export type InputEnvironment = "backoffice" | "frontoffice";
|
|
5
4
|
type FzInputProps = {
|
|
6
5
|
/**
|
|
@@ -127,7 +126,7 @@ type FzInputProps = {
|
|
|
127
126
|
* Visual presentation style. 'floating-label' moves placeholder above input when focused/filled
|
|
128
127
|
* @default 'normal'
|
|
129
128
|
*/
|
|
130
|
-
variant?:
|
|
129
|
+
variant?: "normal" | "floating-label";
|
|
131
130
|
/**
|
|
132
131
|
* HTML5 pattern attribute for native browser validation
|
|
133
132
|
*/
|
|
@@ -141,6 +140,39 @@ type FzInputProps = {
|
|
|
141
140
|
* @default false
|
|
142
141
|
*/
|
|
143
142
|
readonly?: boolean;
|
|
143
|
+
/**
|
|
144
|
+
* Shows highlighted state with warning colors (orange border, warm background, glow ring).
|
|
145
|
+
* Overridden by error, disabled, and readonly states.
|
|
146
|
+
* If both highlighted and aiReasoning are true, highlighted takes priority.
|
|
147
|
+
* @default false
|
|
148
|
+
*/
|
|
149
|
+
highlighted?: boolean;
|
|
150
|
+
/**
|
|
151
|
+
* Accessible description announced by screen readers when highlighted is active.
|
|
152
|
+
* @default 'Campo in evidenza'
|
|
153
|
+
*/
|
|
154
|
+
highlightedDescription?: string;
|
|
155
|
+
/**
|
|
156
|
+
* Shows AI reasoning state with purple colors (purple border, light purple background, glow ring).
|
|
157
|
+
* Auto-renders a sparkles icon unless leftIcon prop or left-icon slot is provided.
|
|
158
|
+
* Overridden by error, disabled, readonly, and highlighted states.
|
|
159
|
+
* @note When both aiReasoning and leftIcon are provided, leftIcon takes visual precedence
|
|
160
|
+
* and no sparkles icon is rendered.
|
|
161
|
+
* @default false
|
|
162
|
+
*/
|
|
163
|
+
aiReasoning?: boolean;
|
|
164
|
+
/**
|
|
165
|
+
* Accessible description announced by screen readers when aiReasoning is active.
|
|
166
|
+
* @default 'Suggerito dall\'intelligenza artificiale'
|
|
167
|
+
*/
|
|
168
|
+
aiReasoningDescription?: string;
|
|
169
|
+
/**
|
|
170
|
+
* When true, prevents emphasis (highlighted/aiReasoning) from being reset on user input.
|
|
171
|
+
* Used by FzSelect to prevent emphasis reset when typing in the filter input,
|
|
172
|
+
* since FzSelect resets emphasis on option selection instead.
|
|
173
|
+
* @default false
|
|
174
|
+
*/
|
|
175
|
+
disableEmphasisReset?: boolean;
|
|
144
176
|
/**
|
|
145
177
|
* Native maxlength attribute. Limits maximum number of characters
|
|
146
178
|
*/
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { ToRefs, Ref, ComputedRef } from 'vue';
|
|
2
2
|
import { FzInputProps, InputEnvironment } from './types';
|
|
3
|
-
|
|
4
3
|
/**
|
|
5
4
|
* Composable for managing FzInput component styles and computed classes
|
|
6
5
|
*
|
|
@@ -16,7 +15,7 @@ import { FzInputProps, InputEnvironment } from './types';
|
|
|
16
15
|
*/
|
|
17
16
|
export default function useInputStyle(props: ToRefs<FzInputProps>, container: Ref<HTMLElement | null>, model: Ref<string | undefined>, effectiveEnvironment: ComputedRef<InputEnvironment>, isFocused: Ref<boolean>): {
|
|
18
17
|
staticContainerClass: string;
|
|
19
|
-
computedContainerClass: ComputedRef<
|
|
18
|
+
computedContainerClass: ComputedRef<string[]>;
|
|
20
19
|
computedLabelClass: ComputedRef<string[]>;
|
|
21
20
|
staticInputClass: string;
|
|
22
21
|
computedInputClass: ComputedRef<string[]>;
|
package/dist/src/utils.d.ts
CHANGED
package/package.json
CHANGED
|
@@ -1,39 +1,39 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fiscozen/input",
|
|
3
|
-
"version": "3.0
|
|
3
|
+
"version": "3.2.0",
|
|
4
4
|
"description": "Design System Input component",
|
|
5
5
|
"main": "src/index.ts",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"keywords": [],
|
|
8
8
|
"author": "Cristian Barraco",
|
|
9
9
|
"dependencies": {
|
|
10
|
-
"@fiscozen/
|
|
10
|
+
"@fiscozen/alert": "3.0.0",
|
|
11
11
|
"@fiscozen/composables": "1.0.3",
|
|
12
|
-
"@fiscozen/
|
|
12
|
+
"@fiscozen/button": "3.0.0"
|
|
13
13
|
},
|
|
14
14
|
"peerDependencies": {
|
|
15
15
|
"tailwindcss": "^3.4.1",
|
|
16
16
|
"vue": "^3.4.13",
|
|
17
|
-
"@fiscozen/icons": "^1.0.
|
|
17
|
+
"@fiscozen/icons": "^1.0.3"
|
|
18
18
|
},
|
|
19
19
|
"devDependencies": {
|
|
20
20
|
"@rushstack/eslint-patch": "^1.3.3",
|
|
21
21
|
"@types/jsdom": "^21.1.6",
|
|
22
22
|
"@types/node": "^18.19.3",
|
|
23
|
-
"@vitejs/plugin-vue": "^
|
|
24
|
-
"@vitest/coverage-v8": "^1.
|
|
23
|
+
"@vitejs/plugin-vue": "^6.0.5",
|
|
24
|
+
"@vitest/coverage-v8": "^4.1.1",
|
|
25
25
|
"@vue/test-utils": "^2.4.3",
|
|
26
26
|
"@vue/tsconfig": "^0.5.0",
|
|
27
27
|
"eslint": "^8.49.0",
|
|
28
28
|
"jsdom": "^23.0.1",
|
|
29
29
|
"prettier": "^3.0.3",
|
|
30
|
-
"typescript": "~5.
|
|
31
|
-
"vite": "^
|
|
32
|
-
"vite-plugin-dts": "^
|
|
33
|
-
"vitest": "^1.
|
|
34
|
-
"vue-tsc": "^
|
|
35
|
-
"@fiscozen/eslint-config": "^0.1.0",
|
|
30
|
+
"typescript": "~5.7.0",
|
|
31
|
+
"vite": "^8.0.0",
|
|
32
|
+
"vite-plugin-dts": "^4.5.0",
|
|
33
|
+
"vitest": "^4.1.1",
|
|
34
|
+
"vue-tsc": "^2.2.12",
|
|
36
35
|
"@fiscozen/prettier-config": "^0.1.0",
|
|
36
|
+
"@fiscozen/eslint-config": "^0.1.0",
|
|
37
37
|
"@fiscozen/tsconfig": "^0.1.0"
|
|
38
38
|
},
|
|
39
39
|
"license": "MIT",
|
package/src/FzInput.vue
CHANGED
|
@@ -27,6 +27,11 @@ const props = withDefaults(defineProps<FzInputProps>(), {
|
|
|
27
27
|
variant: "normal",
|
|
28
28
|
environment: "frontoffice",
|
|
29
29
|
autocomplete: false,
|
|
30
|
+
highlighted: false,
|
|
31
|
+
highlightedDescription: "Campo in evidenza",
|
|
32
|
+
aiReasoning: false,
|
|
33
|
+
aiReasoningDescription: "Suggerito dall'intelligenza artificiale",
|
|
34
|
+
disableEmphasisReset: false,
|
|
30
35
|
});
|
|
31
36
|
|
|
32
37
|
defineOptions({
|
|
@@ -117,6 +122,47 @@ const inputRef: Ref<HTMLInputElement | null> = ref(null);
|
|
|
117
122
|
const uniqueId = generateInputId();
|
|
118
123
|
const isFocused = ref(false);
|
|
119
124
|
|
|
125
|
+
/**
|
|
126
|
+
* Internal visual state for emphasis props.
|
|
127
|
+
* These track the effective visual state which can differ from props when
|
|
128
|
+
* the user types into a highlighted/aiReasoning input (user input resets emphasis).
|
|
129
|
+
* Programmatic value changes (via v-model) do not affect these states.
|
|
130
|
+
*/
|
|
131
|
+
const effectiveHighlighted = ref(props.highlighted);
|
|
132
|
+
const effectiveAiReasoning = ref(props.aiReasoning);
|
|
133
|
+
|
|
134
|
+
watch(
|
|
135
|
+
() => props.highlighted,
|
|
136
|
+
(val) => {
|
|
137
|
+
effectiveHighlighted.value = val;
|
|
138
|
+
},
|
|
139
|
+
);
|
|
140
|
+
watch(
|
|
141
|
+
() => props.aiReasoning,
|
|
142
|
+
(val) => {
|
|
143
|
+
effectiveAiReasoning.value = val;
|
|
144
|
+
},
|
|
145
|
+
);
|
|
146
|
+
|
|
147
|
+
/**
|
|
148
|
+
* Resets visual emphasis (highlighted/aiReasoning) when user physically types.
|
|
149
|
+
* Only triggered by native input events (user interaction), not programmatic v-model updates.
|
|
150
|
+
* Emits update events so parents using v-model:highlighted / v-model:aiReasoning stay in sync.
|
|
151
|
+
*/
|
|
152
|
+
const handleUserInput = () => {
|
|
153
|
+
if (props.disableEmphasisReset) return;
|
|
154
|
+
if (effectiveHighlighted.value) {
|
|
155
|
+
effectiveHighlighted.value = false;
|
|
156
|
+
emit("update:highlighted", false);
|
|
157
|
+
}
|
|
158
|
+
if (effectiveAiReasoning.value) {
|
|
159
|
+
effectiveAiReasoning.value = false;
|
|
160
|
+
emit("update:aiReasoning", false);
|
|
161
|
+
}
|
|
162
|
+
};
|
|
163
|
+
|
|
164
|
+
const propsRefs = toRefs(props);
|
|
165
|
+
|
|
120
166
|
const {
|
|
121
167
|
staticContainerClass,
|
|
122
168
|
computedContainerClass,
|
|
@@ -127,7 +173,11 @@ const {
|
|
|
127
173
|
containerWidth,
|
|
128
174
|
showNormalPlaceholder,
|
|
129
175
|
} = useInputStyle(
|
|
130
|
-
|
|
176
|
+
{
|
|
177
|
+
...propsRefs,
|
|
178
|
+
highlighted: effectiveHighlighted,
|
|
179
|
+
aiReasoning: effectiveAiReasoning,
|
|
180
|
+
},
|
|
131
181
|
containerRef,
|
|
132
182
|
model,
|
|
133
183
|
effectiveEnvironment,
|
|
@@ -185,6 +235,8 @@ const emit = defineEmits<{
|
|
|
185
235
|
"fzinput:left-icon-click": [];
|
|
186
236
|
"fzinput:right-icon-click": [];
|
|
187
237
|
"fzinput:second-right-icon-click": [];
|
|
238
|
+
"update:highlighted": [value: boolean];
|
|
239
|
+
"update:aiReasoning": [value: boolean];
|
|
188
240
|
}>();
|
|
189
241
|
|
|
190
242
|
/**
|
|
@@ -305,6 +357,22 @@ const isReadonlyOrDisabled = computed(
|
|
|
305
357
|
() => !!props.disabled || !!props.readonly,
|
|
306
358
|
);
|
|
307
359
|
|
|
360
|
+
/**
|
|
361
|
+
* Computed class for the auto-rendered AI sparkles icon.
|
|
362
|
+
* Muted when the input is in error, disabled, or readonly state.
|
|
363
|
+
*/
|
|
364
|
+
const aiIconClass = computed(() => {
|
|
365
|
+
if (isReadonlyOrDisabled.value || props.error) return "text-grey-300";
|
|
366
|
+
return "text-purple-600";
|
|
367
|
+
});
|
|
368
|
+
|
|
369
|
+
const emphasisDescription = computed(() => {
|
|
370
|
+
if (isReadonlyOrDisabled.value || props.error) return undefined;
|
|
371
|
+
if (effectiveHighlighted.value) return props.highlightedDescription;
|
|
372
|
+
if (effectiveAiReasoning.value) return props.aiReasoningDescription;
|
|
373
|
+
return undefined;
|
|
374
|
+
});
|
|
375
|
+
|
|
308
376
|
/**
|
|
309
377
|
* Determines if right icon is clickable (not rendered as button)
|
|
310
378
|
*/
|
|
@@ -385,6 +453,14 @@ defineExpose({
|
|
|
385
453
|
: undefined
|
|
386
454
|
"
|
|
387
455
|
/>
|
|
456
|
+
<FzIcon
|
|
457
|
+
v-else-if="effectiveAiReasoning && !effectiveHighlighted"
|
|
458
|
+
name="sparkles"
|
|
459
|
+
variant="fas"
|
|
460
|
+
size="md"
|
|
461
|
+
aria-hidden="true"
|
|
462
|
+
:class="aiIconClass"
|
|
463
|
+
/>
|
|
388
464
|
</slot>
|
|
389
465
|
<div class="flex flex-col justify-around min-w-0 grow">
|
|
390
466
|
<span
|
|
@@ -411,7 +487,9 @@ defineExpose({
|
|
|
411
487
|
:aria-disabled="isReadonlyOrDisabled ? 'true' : 'false'"
|
|
412
488
|
:aria-labelledby="ariaLabelledBy"
|
|
413
489
|
:aria-describedby="ariaDescribedBy"
|
|
490
|
+
:aria-description="emphasisDescription"
|
|
414
491
|
v-bind="inputAttrs"
|
|
492
|
+
@input="handleUserInput"
|
|
415
493
|
@blur="
|
|
416
494
|
(e) => {
|
|
417
495
|
isFocused = false;
|